~ubuntu-cloud-archive/ubuntu/precise/nova/trunk

« back to all changes in this revision

Viewing changes to nova/tests/compute/test_compute.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-05-24 13:12:53 UTC
  • mfrom: (1.1.55)
  • Revision ID: package-import@ubuntu.com-20120524131253-ommql08fg1en06ut
Tags: 2012.2~f1-0ubuntu1
* New upstream release.
* Prepare for quantal:
  - Dropped debian/patches/upstream/0006-Use-project_id-in-ec2.cloud._format_image.patch
  - Dropped debian/patches/upstream/0005-Populate-image-properties-with-project_id-again.patch
  - Dropped debian/patches/upstream/0004-Fixed-bug-962840-added-a-test-case.patch
  - Dropped debian/patches/upstream/0003-Allow-unprivileged-RADOS-users-to-access-rbd-volumes.patch
  - Dropped debian/patches/upstream/0002-Stop-libvirt-test-from-deleting-instances-dir.patch
  - Dropped debian/patches/upstream/0001-fix-bug-where-nova-ignores-glance-host-in-imageref.patch 
  - Dropped debian/patches/0001-fix-useexisting-deprecation-warnings.patch
* debian/control: Add python-keystone as a dependency. (LP: #907197)
* debian/patches/kombu_tests_timeout.patch: Refreshed.
* debian/nova.conf, debian/nova-common.postinst: Convert to new ini
  file configuration
* debian/patches/nova-manage_flagfile_location.patch: Refreshed

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
# Copyright 2010 United States Government as represented by the
 
4
# Administrator of the National Aeronautics and Space Administration.
 
5
# Copyright 2011 Piston Cloud Computing, Inc.
 
6
# All Rights Reserved.
 
7
#
 
8
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
9
#    not use this file except in compliance with the License. You may obtain
 
10
#    a copy of the License at
 
11
#
 
12
#         http://www.apache.org/licenses/LICENSE-2.0
 
13
#
 
14
#    Unless required by applicable law or agreed to in writing, software
 
15
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
16
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
17
#    License for the specific language governing permissions and limitations
 
18
#    under the License.
 
19
"""Tests for compute service"""
 
20
 
 
21
import copy
 
22
import datetime
 
23
import sys
 
24
import time
 
25
 
 
26
import mox
 
27
 
 
28
import nova
 
29
import nova.common.policy
 
30
from nova import compute
 
31
from nova.compute import aggregate_states
 
32
from nova.compute import api as compute_api
 
33
from nova.compute import instance_types
 
34
from nova.compute import manager as compute_manager
 
35
from nova.compute import power_state
 
36
from nova.compute import rpcapi as compute_rpcapi
 
37
from nova.compute import task_states
 
38
from nova.compute import vm_states
 
39
from nova import context
 
40
from nova import db
 
41
from nova import exception
 
42
from nova import flags
 
43
from nova.image import fake as fake_image
 
44
from nova import log as logging
 
45
from nova.notifier import test_notifier
 
46
from nova.openstack.common import importutils
 
47
import nova.policy
 
48
from nova import rpc
 
49
from nova.rpc import common as rpc_common
 
50
from nova.scheduler import driver as scheduler_driver
 
51
from nova import test
 
52
from nova.tests import fake_network
 
53
from nova import utils
 
54
import nova.volume
 
55
 
 
56
 
 
57
LOG = logging.getLogger(__name__)
 
58
FLAGS = flags.FLAGS
 
59
flags.DECLARE('stub_network', 'nova.compute.manager')
 
60
flags.DECLARE('live_migration_retry_count', 'nova.compute.manager')
 
61
flags.DECLARE('additional_compute_capabilities', 'nova.compute.manager')
 
62
 
 
63
 
 
64
FAKE_IMAGE_REF = 'fake-image-ref'
 
65
orig_rpc_call = rpc.call
 
66
orig_rpc_cast = rpc.cast
 
67
 
 
68
 
 
69
def rpc_call_wrapper(context, topic, msg, do_cast=True):
 
70
    """Stub out the scheduler creating the instance entry"""
 
71
    if (topic == FLAGS.scheduler_topic and
 
72
        msg['method'] == 'run_instance'):
 
73
        request_spec = msg['args']['request_spec']
 
74
        scheduler = scheduler_driver.Scheduler
 
75
        num_instances = request_spec.get('num_instances', 1)
 
76
        instances = []
 
77
        for num in xrange(num_instances):
 
78
            request_spec['instance_properties']['launch_index'] = num
 
79
            instance = scheduler().create_instance_db_entry(
 
80
                    context, request_spec)
 
81
            encoded = scheduler_driver.encode_instance(instance)
 
82
            instances.append(encoded)
 
83
        return instances
 
84
    else:
 
85
        if do_cast:
 
86
            orig_rpc_cast(context, topic, msg)
 
87
        else:
 
88
            return orig_rpc_call(context, topic, msg)
 
89
 
 
90
 
 
91
def rpc_cast_wrapper(context, topic, msg):
 
92
    """Stub out the scheduler creating the instance entry in
 
93
    the reservation_id case.
 
94
    """
 
95
    rpc_call_wrapper(context, topic, msg, do_cast=True)
 
96
 
 
97
 
 
98
def nop_report_driver_status(self):
 
99
    pass
 
100
 
 
101
 
 
102
class BaseTestCase(test.TestCase):
 
103
 
 
104
    def setUp(self):
 
105
        super(BaseTestCase, self).setUp()
 
106
        self.flags(connection_type='fake',
 
107
                   stub_network=True,
 
108
                   notification_driver='nova.notifier.test_notifier',
 
109
                   network_manager='nova.network.manager.FlatManager')
 
110
        self.compute = importutils.import_object(FLAGS.compute_manager)
 
111
 
 
112
        self.user_id = 'fake'
 
113
        self.project_id = 'fake'
 
114
        self.context = context.RequestContext(self.user_id,
 
115
                                              self.project_id)
 
116
        test_notifier.NOTIFICATIONS = []
 
117
 
 
118
        def fake_show(meh, context, id):
 
119
            return {'id': id, 'min_disk': None, 'min_ram': None,
 
120
                    'properties': {'kernel_id': 'fake_kernel_id',
 
121
                                   'ramdisk_id': 'fake_ramdisk_id',
 
122
                                   'something_else': 'meow'}}
 
123
 
 
124
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
125
        self.stubs.Set(rpc, 'call', rpc_call_wrapper)
 
126
        self.stubs.Set(rpc, 'cast', rpc_cast_wrapper)
 
127
 
 
128
    def tearDown(self):
 
129
        instances = db.instance_get_all(self.context.elevated())
 
130
        for instance in instances:
 
131
            db.instance_destroy(self.context.elevated(), instance['id'])
 
132
        super(BaseTestCase, self).tearDown()
 
133
 
 
134
    def _create_fake_instance(self, params=None, type_name='m1.tiny'):
 
135
        """Create a test instance"""
 
136
        if not params:
 
137
            params = {}
 
138
 
 
139
        inst = {}
 
140
        inst['vm_state'] = vm_states.ACTIVE
 
141
        inst['image_ref'] = FAKE_IMAGE_REF
 
142
        inst['reservation_id'] = 'r-fakeres'
 
143
        inst['launch_time'] = '10'
 
144
        inst['user_id'] = self.user_id
 
145
        inst['project_id'] = self.project_id
 
146
        inst['host'] = 'fake_host'
 
147
        type_id = instance_types.get_instance_type_by_name(type_name)['id']
 
148
        inst['instance_type_id'] = type_id
 
149
        inst['ami_launch_index'] = 0
 
150
        inst['memory_mb'] = 0
 
151
        inst['root_gb'] = 0
 
152
        inst['ephemeral_gb'] = 0
 
153
        inst.update(params)
 
154
        return db.instance_create(self.context, inst)
 
155
 
 
156
    def _create_instance(self, params=None, type_name='m1.tiny'):
 
157
        """Create a test instance. Returns uuid"""
 
158
        return self._create_fake_instance(params, type_name=type_name)['uuid']
 
159
 
 
160
    def _create_instance_type(self, params=None):
 
161
        """Create a test instance type"""
 
162
        if not params:
 
163
            params = {}
 
164
 
 
165
        context = self.context.elevated()
 
166
        inst = {}
 
167
        inst['name'] = 'm1.small'
 
168
        inst['memory_mb'] = 1024
 
169
        inst['vcpus'] = 1
 
170
        inst['root_gb'] = 20
 
171
        inst['ephemeral_gb'] = 10
 
172
        inst['flavorid'] = '1'
 
173
        inst['swap'] = 2048
 
174
        inst['rxtx_factor'] = 1
 
175
        inst.update(params)
 
176
        return db.instance_type_create(context, inst)['id']
 
177
 
 
178
    def _create_group(self):
 
179
        values = {'name': 'testgroup',
 
180
                  'description': 'testgroup',
 
181
                  'user_id': self.user_id,
 
182
                  'project_id': self.project_id}
 
183
        return db.security_group_create(self.context, values)
 
184
 
 
185
 
 
186
class ComputeTestCase(BaseTestCase):
 
187
    def setUp(self):
 
188
        def fake_get_nw_info(cls, ctxt, instance, *args, **kwargs):
 
189
            self.assertTrue(ctxt.is_admin)
 
190
            return fake_network.fake_get_instance_nw_info(self.stubs, 1, 1,
 
191
                                                          spectacular=True)
 
192
 
 
193
        super(ComputeTestCase, self).setUp()
 
194
        self.stubs.Set(nova.network.API, 'get_instance_nw_info',
 
195
                       fake_get_nw_info)
 
196
        self.stubs.Set(nova.network.API, 'allocate_for_instance',
 
197
                       fake_get_nw_info)
 
198
 
 
199
    def tearDown(self):
 
200
        super(ComputeTestCase, self).tearDown()
 
201
        utils.clear_time_override()
 
202
 
 
203
    def test_wrap_instance_fault(self):
 
204
        inst_uuid = "fake_uuid"
 
205
 
 
206
        called = {'fault_added': False}
 
207
 
 
208
        def did_it_add_fault(*args):
 
209
            called['fault_added'] = True
 
210
 
 
211
        self.stubs.Set(self.compute, 'add_instance_fault_from_exc',
 
212
                       did_it_add_fault)
 
213
 
 
214
        @nova.compute.manager.wrap_instance_fault
 
215
        def failer(self2, context, instance_uuid):
 
216
            raise NotImplementedError()
 
217
 
 
218
        self.assertRaises(NotImplementedError, failer,
 
219
                          self.compute, self.context, inst_uuid)
 
220
 
 
221
        self.assertTrue(called['fault_added'])
 
222
 
 
223
    def test_wrap_instance_fault_no_instance(self):
 
224
        inst_uuid = "fake_uuid"
 
225
 
 
226
        called = {'fault_added': False}
 
227
 
 
228
        def did_it_add_fault(*args):
 
229
            called['fault_added'] = True
 
230
 
 
231
        self.stubs.Set(self.compute, 'add_instance_fault_from_exc',
 
232
                       did_it_add_fault)
 
233
 
 
234
        @nova.compute.manager.wrap_instance_fault
 
235
        def failer(self2, context, instance_uuid):
 
236
            raise exception.InstanceNotFound()
 
237
 
 
238
        self.assertRaises(exception.InstanceNotFound, failer,
 
239
                          self.compute, self.context, inst_uuid)
 
240
 
 
241
        self.assertFalse(called['fault_added'])
 
242
 
 
243
    def test_create_instance_with_img_ref_associates_config_drive(self):
 
244
        """Make sure create associates a config drive."""
 
245
 
 
246
        instance = self._create_fake_instance(
 
247
                        params={'config_drive': '1234', })
 
248
 
 
249
        try:
 
250
            self.compute.run_instance(self.context, instance['uuid'])
 
251
            instances = db.instance_get_all(context.get_admin_context())
 
252
            instance = instances[0]
 
253
 
 
254
            self.assertTrue(instance.config_drive)
 
255
        finally:
 
256
            db.instance_destroy(self.context, instance['id'])
 
257
 
 
258
    def test_create_instance_associates_config_drive(self):
 
259
        """Make sure create associates a config drive."""
 
260
 
 
261
        instance = self._create_fake_instance(
 
262
                        params={'config_drive': '1234', })
 
263
 
 
264
        try:
 
265
            self.compute.run_instance(self.context, instance['uuid'])
 
266
            instances = db.instance_get_all(context.get_admin_context())
 
267
            instance = instances[0]
 
268
 
 
269
            self.assertTrue(instance.config_drive)
 
270
        finally:
 
271
            db.instance_destroy(self.context, instance['id'])
 
272
 
 
273
    def test_default_access_ip(self):
 
274
        self.flags(default_access_ip_network_name='test1', stub_network=False)
 
275
        instance = self._create_fake_instance()
 
276
 
 
277
        try:
 
278
            self.compute.run_instance(self.context, instance['uuid'],
 
279
                    is_first_time=True)
 
280
            instances = db.instance_get_all(context.get_admin_context())
 
281
            instance = instances[0]
 
282
 
 
283
            self.assertEqual(instance.access_ip_v4, '192.168.1.100')
 
284
            self.assertEqual(instance.access_ip_v6, '2001:db8:0:1::1')
 
285
        finally:
 
286
            db.instance_destroy(self.context, instance['id'])
 
287
 
 
288
    def test_no_default_access_ip(self):
 
289
        instance = self._create_fake_instance()
 
290
 
 
291
        try:
 
292
            self.compute.run_instance(self.context, instance['uuid'],
 
293
                    is_first_time=True)
 
294
            instances = db.instance_get_all(context.get_admin_context())
 
295
            instance = instances[0]
 
296
 
 
297
            self.assertFalse(instance.access_ip_v4)
 
298
            self.assertFalse(instance.access_ip_v6)
 
299
        finally:
 
300
            db.instance_destroy(self.context, instance['id'])
 
301
 
 
302
    def test_fail_to_schedule_persists(self):
 
303
        """check the persistence of the ERROR(scheduling) state"""
 
304
        self._create_instance(params={'vm_state': vm_states.ERROR,
 
305
                                      'task_state': task_states.SCHEDULING})
 
306
        #check state is failed even after the periodic poll
 
307
        self.compute.periodic_tasks(context.get_admin_context())
 
308
        self._assert_state({'vm_state': vm_states.ERROR,
 
309
                            'task_state': task_states.SCHEDULING})
 
310
 
 
311
    def test_run_instance_setup_block_device_mapping_fail(self):
 
312
        """ block device mapping failure test.
 
313
 
 
314
        Make sure that when there is a block device mapping problem,
 
315
        the instance goes to ERROR state, keeping the task state
 
316
        """
 
317
        def fake(*args, **kwargs):
 
318
            raise test.TestingException()
 
319
        self.stubs.Set(nova.compute.manager.ComputeManager,
 
320
                       '_setup_block_device_mapping', fake)
 
321
        instance_uuid = self._create_instance()
 
322
        self.assertRaises(test.TestingException, self.compute.run_instance,
 
323
                          self.context, instance_uuid)
 
324
        #check state is failed even after the periodic poll
 
325
        self._assert_state({'vm_state': vm_states.ERROR,
 
326
                            'task_state': task_states.BLOCK_DEVICE_MAPPING})
 
327
        self.compute.periodic_tasks(context.get_admin_context())
 
328
        self._assert_state({'vm_state': vm_states.ERROR,
 
329
                            'task_state': task_states.BLOCK_DEVICE_MAPPING})
 
330
 
 
331
    def test_run_instance_spawn_fail(self):
 
332
        """ spawn failure test.
 
333
 
 
334
        Make sure that when there is a spawning problem,
 
335
        the instance goes to ERROR state, keeping the task state"""
 
336
        def fake(*args, **kwargs):
 
337
            raise test.TestingException()
 
338
        self.stubs.Set(self.compute.driver, 'spawn', fake)
 
339
        instance_uuid = self._create_instance()
 
340
        self.assertRaises(test.TestingException, self.compute.run_instance,
 
341
                          self.context, instance_uuid)
 
342
        #check state is failed even after the periodic poll
 
343
        self._assert_state({'vm_state': vm_states.ERROR,
 
344
                            'task_state': task_states.SPAWNING})
 
345
        self.compute.periodic_tasks(context.get_admin_context())
 
346
        self._assert_state({'vm_state': vm_states.ERROR,
 
347
                            'task_state': task_states.SPAWNING})
 
348
 
 
349
    def test_can_terminate_on_error_state(self):
 
350
        """Make sure that the instance can be terminated in ERROR state"""
 
351
        elevated = context.get_admin_context()
 
352
        #check failed to schedule --> terminate
 
353
        instance_uuid = self._create_instance(params={'vm_state':
 
354
                                                vm_states.ERROR})
 
355
        self.compute.terminate_instance(self.context, instance_uuid)
 
356
        self.assertRaises(exception.InstanceNotFound, db.instance_get_by_uuid,
 
357
                          elevated, instance_uuid)
 
358
 
 
359
    def test_run_terminate(self):
 
360
        """Make sure it is possible to  run and terminate instance"""
 
361
        instance = self._create_fake_instance()
 
362
 
 
363
        self.compute.run_instance(self.context, instance['uuid'])
 
364
 
 
365
        instances = db.instance_get_all(context.get_admin_context())
 
366
        LOG.info(_("Running instances: %s"), instances)
 
367
        self.assertEqual(len(instances), 1)
 
368
 
 
369
        self.compute.terminate_instance(self.context, instance['uuid'])
 
370
 
 
371
        instances = db.instance_get_all(context.get_admin_context())
 
372
        LOG.info(_("After terminating instances: %s"), instances)
 
373
        self.assertEqual(len(instances), 0)
 
374
 
 
375
    def test_run_terminate_timestamps(self):
 
376
        """Make sure timestamps are set for launched and destroyed"""
 
377
        instance = self._create_fake_instance()
 
378
        self.assertEqual(instance['launched_at'], None)
 
379
        self.assertEqual(instance['deleted_at'], None)
 
380
        launch = utils.utcnow()
 
381
        self.compute.run_instance(self.context, instance['uuid'])
 
382
        instance = db.instance_get_by_uuid(self.context, instance['uuid'])
 
383
        self.assert_(instance['launched_at'] > launch)
 
384
        self.assertEqual(instance['deleted_at'], None)
 
385
        terminate = utils.utcnow()
 
386
        self.compute.terminate_instance(self.context, instance['uuid'])
 
387
        context = self.context.elevated(read_deleted="only")
 
388
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
389
        self.assert_(instance['launched_at'] < terminate)
 
390
        self.assert_(instance['deleted_at'] > terminate)
 
391
 
 
392
    def test_stop(self):
 
393
        """Ensure instance can be stopped"""
 
394
        instance = self._create_fake_instance()
 
395
        instance_uuid = instance['uuid']
 
396
        self.compute.run_instance(self.context, instance_uuid)
 
397
        self.compute.stop_instance(self.context, instance_uuid)
 
398
        self.compute.terminate_instance(self.context, instance_uuid)
 
399
 
 
400
    def test_start(self):
 
401
        """Ensure instance can be started"""
 
402
        instance = self._create_fake_instance()
 
403
        instance_uuid = instance['uuid']
 
404
        self.compute.run_instance(self.context, instance_uuid)
 
405
        self.compute.stop_instance(self.context, instance_uuid)
 
406
        self.compute.start_instance(self.context, instance_uuid)
 
407
        self.compute.terminate_instance(self.context, instance_uuid)
 
408
 
 
409
    def test_rescue(self):
 
410
        """Ensure instance can be rescued and unrescued"""
 
411
 
 
412
        called = {'rescued': False,
 
413
                  'unrescued': False}
 
414
 
 
415
        def fake_rescue(self, context, instance_ref, network_info, image_meta):
 
416
            called['rescued'] = True
 
417
 
 
418
        self.stubs.Set(nova.virt.fake.FakeConnection, 'rescue', fake_rescue)
 
419
 
 
420
        def fake_unrescue(self, instance_ref, network_info):
 
421
            called['unrescued'] = True
 
422
 
 
423
        self.stubs.Set(nova.virt.fake.FakeConnection, 'unrescue',
 
424
                       fake_unrescue)
 
425
 
 
426
        instance = self._create_fake_instance()
 
427
        instance_uuid = instance['uuid']
 
428
        self.compute.run_instance(self.context, instance_uuid)
 
429
        self.compute.rescue_instance(self.context, instance_uuid)
 
430
        self.assertTrue(called['rescued'])
 
431
        self.compute.unrescue_instance(self.context, instance_uuid)
 
432
        self.assertTrue(called['unrescued'])
 
433
        self.compute.terminate_instance(self.context, instance_uuid)
 
434
 
 
435
    def test_power_on(self):
 
436
        """Ensure instance can be powered on"""
 
437
 
 
438
        called = {'power_on': False}
 
439
 
 
440
        def fake_driver_power_on(self, instance):
 
441
            called['power_on'] = True
 
442
 
 
443
        self.stubs.Set(nova.virt.driver.ComputeDriver, 'power_on',
 
444
                       fake_driver_power_on)
 
445
 
 
446
        instance = self._create_fake_instance()
 
447
        instance_uuid = instance['uuid']
 
448
        self.compute.run_instance(self.context, instance_uuid)
 
449
        self.compute.power_on_instance(self.context, instance_uuid)
 
450
        self.assertTrue(called['power_on'])
 
451
        self.compute.terminate_instance(self.context, instance_uuid)
 
452
 
 
453
    def test_power_off(self):
 
454
        """Ensure instance can be powered off"""
 
455
 
 
456
        called = {'power_off': False}
 
457
 
 
458
        def fake_driver_power_off(self, instance):
 
459
            called['power_off'] = True
 
460
 
 
461
        self.stubs.Set(nova.virt.driver.ComputeDriver, 'power_off',
 
462
                       fake_driver_power_off)
 
463
 
 
464
        instance = self._create_fake_instance()
 
465
        instance_uuid = instance['uuid']
 
466
        self.compute.run_instance(self.context, instance_uuid)
 
467
        self.compute.power_off_instance(self.context, instance_uuid)
 
468
        self.assertTrue(called['power_off'])
 
469
        self.compute.terminate_instance(self.context, instance_uuid)
 
470
 
 
471
    def test_pause(self):
 
472
        """Ensure instance can be paused and unpaused"""
 
473
        instance = self._create_fake_instance()
 
474
        instance_uuid = instance['uuid']
 
475
        self.compute.run_instance(self.context, instance_uuid)
 
476
        self.compute.pause_instance(self.context, instance_uuid)
 
477
        self.compute.unpause_instance(self.context, instance_uuid)
 
478
        self.compute.terminate_instance(self.context, instance_uuid)
 
479
 
 
480
    def test_suspend(self):
 
481
        """ensure instance can be suspended and resumed"""
 
482
        instance = self._create_fake_instance()
 
483
        instance_uuid = instance['uuid']
 
484
        self.compute.run_instance(self.context, instance_uuid)
 
485
        self.compute.suspend_instance(self.context, instance_uuid)
 
486
        self.compute.resume_instance(self.context, instance_uuid)
 
487
        self.compute.terminate_instance(self.context, instance_uuid)
 
488
 
 
489
    def test_rebuild(self):
 
490
        """Ensure instance can be rebuilt"""
 
491
        instance = self._create_fake_instance()
 
492
        instance_uuid = instance['uuid']
 
493
        image_ref = instance['image_ref']
 
494
 
 
495
        self.compute.run_instance(self.context, instance_uuid)
 
496
        self.compute.rebuild_instance(self.context, instance_uuid,
 
497
                image_ref, image_ref)
 
498
        self.compute.terminate_instance(self.context, instance_uuid)
 
499
 
 
500
    def test_rebuild_launch_time(self):
 
501
        """Ensure instance can be rebuilt"""
 
502
        old_time = datetime.datetime(2012, 4, 1)
 
503
        cur_time = datetime.datetime(2012, 12, 21, 12, 21)
 
504
        utils.set_time_override(old_time)
 
505
        instance = self._create_fake_instance()
 
506
        instance_uuid = instance['uuid']
 
507
        image_ref = instance['image_ref']
 
508
 
 
509
        self.compute.run_instance(self.context, instance_uuid)
 
510
        utils.set_time_override(cur_time)
 
511
        self.compute.rebuild_instance(self.context, instance_uuid,
 
512
                image_ref, image_ref)
 
513
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
514
        self.assertEquals(cur_time, instance['launched_at'])
 
515
        self.compute.terminate_instance(self.context, instance_uuid)
 
516
 
 
517
    def test_reboot_soft(self):
 
518
        """Ensure instance can be soft rebooted"""
 
519
        instance = self._create_fake_instance()
 
520
        instance_uuid = instance['uuid']
 
521
 
 
522
        self.compute.run_instance(self.context, instance_uuid)
 
523
        db.instance_update(self.context, instance_uuid,
 
524
                           {'task_state': task_states.REBOOTING})
 
525
 
 
526
        reboot_type = "SOFT"
 
527
        self.compute.reboot_instance(self.context, instance_uuid, reboot_type)
 
528
 
 
529
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
530
        self.assertEqual(inst_ref['power_state'], power_state.RUNNING)
 
531
        self.assertEqual(inst_ref['task_state'], None)
 
532
 
 
533
        self.compute.terminate_instance(self.context, inst_ref['uuid'])
 
534
 
 
535
    def test_reboot_hard(self):
 
536
        """Ensure instance can be hard rebooted"""
 
537
        instance = self._create_fake_instance()
 
538
        instance_uuid = instance['uuid']
 
539
 
 
540
        self.compute.run_instance(self.context, instance_uuid)
 
541
        db.instance_update(self.context, instance_uuid,
 
542
                           {'task_state': task_states.REBOOTING_HARD})
 
543
 
 
544
        reboot_type = "HARD"
 
545
        self.compute.reboot_instance(self.context, instance_uuid, reboot_type)
 
546
 
 
547
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
548
        self.assertEqual(inst_ref['power_state'], power_state.RUNNING)
 
549
        self.assertEqual(inst_ref['task_state'], None)
 
550
 
 
551
        self.compute.terminate_instance(self.context, inst_ref['uuid'])
 
552
 
 
553
    def test_set_admin_password(self):
 
554
        """Ensure instance can have its admin password set"""
 
555
        instance = self._create_fake_instance()
 
556
        instance_uuid = instance['uuid']
 
557
        self.compute.run_instance(self.context, instance_uuid)
 
558
        db.instance_update(self.context, instance_uuid,
 
559
                           {'task_state': task_states.UPDATING_PASSWORD})
 
560
 
 
561
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
562
        self.assertEqual(inst_ref['vm_state'], vm_states.ACTIVE)
 
563
        self.assertEqual(inst_ref['task_state'], task_states.UPDATING_PASSWORD)
 
564
 
 
565
        self.compute.set_admin_password(self.context, instance_uuid)
 
566
 
 
567
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
568
        self.assertEqual(inst_ref['vm_state'], vm_states.ACTIVE)
 
569
        self.assertEqual(inst_ref['task_state'], None)
 
570
 
 
571
        self.compute.terminate_instance(self.context, inst_ref['uuid'])
 
572
 
 
573
    def test_set_admin_password_bad_state(self):
 
574
        """Test setting password while instance is rebuilding."""
 
575
        instance = self._create_fake_instance()
 
576
        self.compute.run_instance(self.context, instance['uuid'])
 
577
        db.instance_update(self.context, instance['uuid'], {
 
578
            "power_state": power_state.NOSTATE,
 
579
        })
 
580
        instance = db.instance_get_by_uuid(self.context, instance['uuid'])
 
581
 
 
582
        self.assertEqual(instance['power_state'], power_state.NOSTATE)
 
583
 
 
584
        def fake_driver_get_info(self2, _instance):
 
585
            return {'state': power_state.NOSTATE,
 
586
                    'max_mem': 0,
 
587
                    'mem': 0,
 
588
                    'num_cpu': 2,
 
589
                    'cpu_time': 0}
 
590
 
 
591
        self.stubs.Set(nova.virt.fake.FakeConnection, 'get_info',
 
592
                       fake_driver_get_info)
 
593
 
 
594
        self.assertRaises(exception.Invalid,
 
595
                          self.compute.set_admin_password,
 
596
                          self.context,
 
597
                          instance['uuid'])
 
598
        self.compute.terminate_instance(self.context, instance['uuid'])
 
599
 
 
600
    def test_set_admin_password_driver_error(self):
 
601
        """Ensure error is raised admin password set"""
 
602
 
 
603
        def fake_sleep(_time):
 
604
            pass
 
605
 
 
606
        self.stubs.Set(time, 'sleep', fake_sleep)
 
607
 
 
608
        def fake_driver_set_pass(self2, _instance, _pwd):
 
609
            raise exception.NotAuthorized(_('Internal error'))
 
610
 
 
611
        self.stubs.Set(nova.virt.fake.FakeConnection, 'set_admin_password',
 
612
                       fake_driver_set_pass)
 
613
 
 
614
        instance = self._create_fake_instance()
 
615
        instance_uuid = instance['uuid']
 
616
        self.compute.run_instance(self.context, instance_uuid)
 
617
        db.instance_update(self.context, instance_uuid,
 
618
                           {'task_state': task_states.UPDATING_PASSWORD})
 
619
 
 
620
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
621
        self.assertEqual(inst_ref['vm_state'], vm_states.ACTIVE)
 
622
        self.assertEqual(inst_ref['task_state'], task_states.UPDATING_PASSWORD)
 
623
 
 
624
        #error raised from the driver should not reveal internal information
 
625
        #so a new error is raised
 
626
        self.assertRaises(exception.NovaException,
 
627
                          self.compute.set_admin_password,
 
628
                          self.context, instance_uuid)
 
629
 
 
630
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
631
        self.assertEqual(inst_ref['vm_state'], vm_states.ERROR)
 
632
        self.assertEqual(inst_ref['task_state'], task_states.UPDATING_PASSWORD)
 
633
 
 
634
        self.compute.terminate_instance(self.context, inst_ref['uuid'])
 
635
 
 
636
    def test_inject_file(self):
 
637
        """Ensure we can write a file to an instance"""
 
638
        called = {'inject': False}
 
639
 
 
640
        def fake_driver_inject_file(self2, instance, path, contents):
 
641
            self.assertEqual(path, "/tmp/test")
 
642
            self.assertEqual(contents, "File Contents")
 
643
            called['inject'] = True
 
644
 
 
645
        self.stubs.Set(nova.virt.fake.FakeConnection, 'inject_file',
 
646
                       fake_driver_inject_file)
 
647
 
 
648
        instance = self._create_fake_instance()
 
649
        self.compute.run_instance(self.context, instance['uuid'])
 
650
        self.compute.inject_file(self.context, instance['uuid'], "/tmp/test",
 
651
                "File Contents")
 
652
        self.assertTrue(called['inject'])
 
653
        self.compute.terminate_instance(self.context, instance['uuid'])
 
654
 
 
655
    def test_inject_network_info(self):
 
656
        """Ensure we can inject network info"""
 
657
        called = {'inject': False}
 
658
 
 
659
        def fake_driver_inject_network(self, instance, network_info):
 
660
            called['inject'] = True
 
661
 
 
662
        self.stubs.Set(nova.virt.fake.FakeConnection, 'inject_network_info',
 
663
                       fake_driver_inject_network)
 
664
 
 
665
        instance = self._create_fake_instance()
 
666
        instance_uuid = instance['uuid']
 
667
        self.compute.run_instance(self.context, instance_uuid)
 
668
        self.compute.inject_network_info(self.context, instance_uuid)
 
669
        self.assertTrue(called['inject'])
 
670
        self.compute.terminate_instance(self.context, instance_uuid)
 
671
 
 
672
    def test_reset_network(self):
 
673
        """Ensure we can reset networking on an instance"""
 
674
        called = {'reset': False}
 
675
 
 
676
        def fake_driver_reset_network(self, instance):
 
677
            called['reset'] = True
 
678
 
 
679
        self.stubs.Set(nova.virt.fake.FakeConnection, 'reset_network',
 
680
                       fake_driver_reset_network)
 
681
 
 
682
        instance = self._create_fake_instance()
 
683
        instance_uuid = instance['uuid']
 
684
        self.compute.run_instance(self.context, instance_uuid)
 
685
        self.compute.reset_network(self.context, instance_uuid)
 
686
        self.assertTrue(called['reset'])
 
687
        self.compute.terminate_instance(self.context, instance_uuid)
 
688
 
 
689
    def test_agent_update(self):
 
690
        """Ensure instance can have its agent updated"""
 
691
        called = {'agent_update': False}
 
692
 
 
693
        def fake_driver_agent_update(self2, instance, url, md5hash):
 
694
            called['agent_update'] = True
 
695
            self.assertEqual(url, 'http://fake/url/')
 
696
            self.assertEqual(md5hash, 'fakehash')
 
697
 
 
698
        self.stubs.Set(nova.virt.fake.FakeConnection, 'agent_update',
 
699
                       fake_driver_agent_update)
 
700
 
 
701
        instance = self._create_fake_instance()
 
702
        self.compute.run_instance(self.context, instance['uuid'])
 
703
        self.compute.agent_update(self.context, instance['uuid'],
 
704
                                  'http://fake/url/', 'fakehash')
 
705
        self.assertTrue(called['agent_update'])
 
706
        self.compute.terminate_instance(self.context, instance['uuid'])
 
707
 
 
708
    def test_snapshot(self):
 
709
        """Ensure instance can be snapshotted"""
 
710
        instance = self._create_fake_instance()
 
711
        instance_uuid = instance['uuid']
 
712
        name = "myfakesnapshot"
 
713
        self.compute.run_instance(self.context, instance_uuid)
 
714
        self.compute.snapshot_instance(self.context, instance_uuid, name)
 
715
        self.compute.terminate_instance(self.context, instance_uuid)
 
716
 
 
717
    def test_snapshot_fails(self):
 
718
        """Ensure task_state is set to None if snapshot fails"""
 
719
        def fake_snapshot(*args, **kwargs):
 
720
            raise test.TestingException()
 
721
 
 
722
        self.stubs.Set(self.compute.driver, 'snapshot', fake_snapshot)
 
723
 
 
724
        instance = self._create_fake_instance()
 
725
        self.compute.run_instance(self.context, instance['uuid'])
 
726
        self.assertRaises(test.TestingException,
 
727
                          self.compute.snapshot_instance,
 
728
                          self.context, instance['uuid'], "failing_snapshot")
 
729
        self._assert_state({'task_state': None})
 
730
        self.compute.terminate_instance(self.context, instance['uuid'])
 
731
 
 
732
    def _assert_state(self, state_dict):
 
733
        """Assert state of VM is equal to state passed as parameter"""
 
734
        instances = db.instance_get_all(context.get_admin_context())
 
735
        self.assertEqual(len(instances), 1)
 
736
 
 
737
        if 'vm_state' in state_dict:
 
738
            self.assertEqual(state_dict['vm_state'], instances[0]['vm_state'])
 
739
        if 'task_state' in state_dict:
 
740
            self.assertEqual(state_dict['task_state'],
 
741
                             instances[0]['task_state'])
 
742
        if 'power_state' in state_dict:
 
743
            self.assertEqual(state_dict['power_state'],
 
744
                             instances[0]['power_state'])
 
745
 
 
746
    def test_console_output(self):
 
747
        """Make sure we can get console output from instance"""
 
748
        instance = self._create_fake_instance()
 
749
        self.compute.run_instance(self.context, instance['uuid'])
 
750
 
 
751
        output = self.compute.get_console_output(self.context,
 
752
                                                  instance['uuid'])
 
753
        self.assertEqual(output, 'FAKE CONSOLE OUTPUT\nANOTHER\nLAST LINE')
 
754
        self.compute.terminate_instance(self.context, instance['uuid'])
 
755
 
 
756
    def test_console_output_tail(self):
 
757
        """Make sure we can get console output from instance"""
 
758
        instance = self._create_fake_instance()
 
759
        self.compute.run_instance(self.context, instance['uuid'])
 
760
 
 
761
        output = self.compute.get_console_output(self.context,
 
762
                                                instance['uuid'],
 
763
                                                tail_length=2)
 
764
        self.assertEqual(output, 'ANOTHER\nLAST LINE')
 
765
        self.compute.terminate_instance(self.context, instance['uuid'])
 
766
 
 
767
    def test_novnc_vnc_console(self):
 
768
        """Make sure we can a vnc console for an instance."""
 
769
        instance = self._create_fake_instance()
 
770
        self.compute.run_instance(self.context, instance['uuid'])
 
771
 
 
772
        console = self.compute.get_vnc_console(self.context,
 
773
                                               instance['uuid'],
 
774
                                               'novnc')
 
775
        self.assert_(console)
 
776
        self.compute.terminate_instance(self.context, instance['uuid'])
 
777
 
 
778
    def test_xvpvnc_vnc_console(self):
 
779
        """Make sure we can a vnc console for an instance."""
 
780
        instance = self._create_fake_instance()
 
781
        self.compute.run_instance(self.context, instance['uuid'])
 
782
 
 
783
        console = self.compute.get_vnc_console(self.context,
 
784
                                               instance['uuid'],
 
785
                                               'xvpvnc')
 
786
        self.assert_(console)
 
787
        self.compute.terminate_instance(self.context, instance['uuid'])
 
788
 
 
789
    def test_invalid_vnc_console_type(self):
 
790
        """Make sure we can a vnc console for an instance."""
 
791
        instance = self._create_fake_instance()
 
792
        self.compute.run_instance(self.context, instance['uuid'])
 
793
 
 
794
        self.assertRaises(exception.ConsoleTypeInvalid,
 
795
                          self.compute.get_vnc_console,
 
796
                          self.context,
 
797
                          instance['uuid'],
 
798
                          'invalid')
 
799
        self.compute.terminate_instance(self.context, instance['uuid'])
 
800
 
 
801
    def test_diagnostics(self):
 
802
        """Make sure we can get diagnostics for an instance."""
 
803
        instance = self._create_fake_instance()
 
804
        self.compute.run_instance(self.context, instance['uuid'])
 
805
 
 
806
        diagnostics = self.compute.get_diagnostics(self.context,
 
807
                                                   instance['uuid'])
 
808
        self.assertEqual(diagnostics, 'FAKE_DIAGNOSTICS')
 
809
        self.compute.terminate_instance(self.context, instance['uuid'])
 
810
 
 
811
    def test_add_fixed_ip_usage_notification(self):
 
812
        def dummy(*args, **kwargs):
 
813
            pass
 
814
 
 
815
        self.stubs.Set(nova.network.API, 'add_fixed_ip_to_instance',
 
816
                       dummy)
 
817
        self.stubs.Set(nova.compute.manager.ComputeManager,
 
818
                       'inject_network_info', dummy)
 
819
        self.stubs.Set(nova.compute.manager.ComputeManager,
 
820
                       'reset_network', dummy)
 
821
 
 
822
        instance = self._create_fake_instance()
 
823
        instance_uuid = instance['uuid']
 
824
 
 
825
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
 
826
        self.compute.add_fixed_ip_to_instance(self.context, instance_uuid, 1)
 
827
 
 
828
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 2)
 
829
        self.compute.terminate_instance(self.context, instance_uuid)
 
830
 
 
831
    def test_remove_fixed_ip_usage_notification(self):
 
832
        def dummy(*args, **kwargs):
 
833
            pass
 
834
 
 
835
        self.stubs.Set(nova.network.API, 'remove_fixed_ip_from_instance',
 
836
                       dummy)
 
837
        self.stubs.Set(nova.compute.manager.ComputeManager,
 
838
                       'inject_network_info', dummy)
 
839
        self.stubs.Set(nova.compute.manager.ComputeManager,
 
840
                       'reset_network', dummy)
 
841
 
 
842
        instance = self._create_fake_instance()
 
843
        instance_uuid = instance['uuid']
 
844
 
 
845
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
 
846
        self.compute.remove_fixed_ip_from_instance(self.context,
 
847
                                                   instance_uuid,
 
848
                                                   1)
 
849
 
 
850
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 2)
 
851
        self.compute.terminate_instance(self.context, instance_uuid)
 
852
 
 
853
    def test_run_instance_usage_notification(self):
 
854
        """Ensure run instance generates apropriate usage notification"""
 
855
        inst_ref = self._create_fake_instance()
 
856
        instance_uuid = inst_ref['uuid']
 
857
        self.compute.run_instance(self.context, instance_uuid)
 
858
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 2)
 
859
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
860
        msg = test_notifier.NOTIFICATIONS[0]
 
861
        self.assertEquals(msg['event_type'], 'compute.instance.create.start')
 
862
        # The last event is the one with the sugar in it.
 
863
        msg = test_notifier.NOTIFICATIONS[1]
 
864
        self.assertEquals(msg['priority'], 'INFO')
 
865
        self.assertEquals(msg['event_type'], 'compute.instance.create.end')
 
866
        payload = msg['payload']
 
867
        self.assertEquals(payload['tenant_id'], self.project_id)
 
868
        self.assertEquals(payload['user_id'], self.user_id)
 
869
        self.assertEquals(payload['instance_id'], inst_ref.uuid)
 
870
        self.assertEquals(payload['instance_type'], 'm1.tiny')
 
871
        type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
 
872
        self.assertEquals(str(payload['instance_type_id']), str(type_id))
 
873
        self.assertEquals(payload['state'], 'active')
 
874
        self.assertTrue('display_name' in payload)
 
875
        self.assertTrue('created_at' in payload)
 
876
        self.assertTrue('launched_at' in payload)
 
877
        self.assertTrue(payload['launched_at'])
 
878
        image_ref_url = utils.generate_image_url(FAKE_IMAGE_REF)
 
879
        self.assertEquals(payload['image_ref_url'], image_ref_url)
 
880
        self.compute.terminate_instance(self.context, instance_uuid)
 
881
 
 
882
    def test_terminate_usage_notification(self):
 
883
        """Ensure terminate_instance generates apropriate usage notification"""
 
884
        old_time = datetime.datetime(2012, 4, 1)
 
885
        cur_time = datetime.datetime(2012, 12, 21, 12, 21)
 
886
        utils.set_time_override(old_time)
 
887
 
 
888
        inst_ref = self._create_fake_instance()
 
889
        self.compute.run_instance(self.context, inst_ref['uuid'])
 
890
        test_notifier.NOTIFICATIONS = []
 
891
        utils.set_time_override(cur_time)
 
892
        self.compute.terminate_instance(self.context, inst_ref['uuid'])
 
893
 
 
894
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 4)
 
895
 
 
896
        msg = test_notifier.NOTIFICATIONS[0]
 
897
        self.assertEquals(msg['priority'], 'INFO')
 
898
        self.assertEquals(msg['event_type'], 'compute.instance.delete.start')
 
899
        msg1 = test_notifier.NOTIFICATIONS[1]
 
900
        self.assertEquals(msg1['event_type'],
 
901
                                            'compute.instance.shutdown.start')
 
902
        msg1 = test_notifier.NOTIFICATIONS[2]
 
903
        self.assertEquals(msg1['event_type'], 'compute.instance.shutdown.end')
 
904
        msg1 = test_notifier.NOTIFICATIONS[3]
 
905
        self.assertEquals(msg1['event_type'], 'compute.instance.delete.end')
 
906
        payload = msg1['payload']
 
907
        self.assertEquals(payload['tenant_id'], self.project_id)
 
908
        self.assertEquals(payload['user_id'], self.user_id)
 
909
        self.assertEquals(payload['instance_id'], inst_ref.uuid)
 
910
        self.assertEquals(payload['instance_type'], 'm1.tiny')
 
911
        type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
 
912
        self.assertEquals(str(payload['instance_type_id']), str(type_id))
 
913
        self.assertTrue('display_name' in payload)
 
914
        self.assertTrue('created_at' in payload)
 
915
        self.assertTrue('launched_at' in payload)
 
916
        self.assertTrue('deleted_at' in payload)
 
917
        self.assertEqual(payload['deleted_at'], str(cur_time))
 
918
        image_ref_url = utils.generate_image_url(FAKE_IMAGE_REF)
 
919
        self.assertEquals(payload['image_ref_url'], image_ref_url)
 
920
 
 
921
    def test_run_instance_existing(self):
 
922
        """Ensure failure when running an instance that already exists"""
 
923
        instance = self._create_fake_instance()
 
924
        self.compute.run_instance(self.context, instance['uuid'])
 
925
        self.assertRaises(exception.Invalid,
 
926
                          self.compute.run_instance,
 
927
                          self.context,
 
928
                          instance['uuid'])
 
929
        self.compute.terminate_instance(self.context, instance['uuid'])
 
930
 
 
931
    def test_instance_set_to_error_on_uncaught_exception(self):
 
932
        """Test that instance is set to error state when exception is raised"""
 
933
        instance = self._create_fake_instance()
 
934
        instance_uuid = instance['uuid']
 
935
 
 
936
        self.mox.StubOutWithMock(self.compute.network_api,
 
937
                                 "allocate_for_instance")
 
938
        self.compute.network_api.allocate_for_instance(
 
939
                mox.IgnoreArg(),
 
940
                mox.IgnoreArg(),
 
941
                requested_networks=None,
 
942
                vpn=False).AndRaise(rpc_common.RemoteError())
 
943
 
 
944
        self.flags(stub_network=False)
 
945
 
 
946
        self.mox.ReplayAll()
 
947
 
 
948
        self.assertRaises(rpc_common.RemoteError,
 
949
                          self.compute.run_instance,
 
950
                          self.context,
 
951
                          instance_uuid)
 
952
 
 
953
        instance = db.instance_get_by_uuid(context.get_admin_context(),
 
954
                                           instance_uuid)
 
955
        self.assertEqual(vm_states.ERROR, instance['vm_state'])
 
956
 
 
957
        self.compute.terminate_instance(self.context, instance['uuid'])
 
958
 
 
959
    def test_instance_termination_exception_sets_error(self):
 
960
        """Test that we handle InstanceTerminationFailure
 
961
        which is propagated up from the underlying driver.
 
962
        """
 
963
        instance = self._create_fake_instance()
 
964
 
 
965
        def fake_delete_instance(context, instance):
 
966
            raise exception.InstanceTerminationFailure(reason='')
 
967
 
 
968
        self.stubs.Set(self.compute, '_delete_instance',
 
969
                       fake_delete_instance)
 
970
 
 
971
        self.compute.terminate_instance(self.context, instance['uuid'])
 
972
        instance = db.instance_get_by_uuid(self.context, instance['uuid'])
 
973
        self.assertEqual(instance['vm_state'], vm_states.ERROR)
 
974
 
 
975
    def test_network_is_deallocated_on_spawn_failure(self):
 
976
        """When a spawn fails the network must be deallocated"""
 
977
        instance = self._create_fake_instance()
 
978
 
 
979
        self.mox.StubOutWithMock(self.compute, "_setup_block_device_mapping")
 
980
        self.compute._setup_block_device_mapping(
 
981
                mox.IgnoreArg(),
 
982
                mox.IgnoreArg()).AndRaise(rpc.common.RemoteError('', '', ''))
 
983
 
 
984
        self.mox.ReplayAll()
 
985
 
 
986
        self.assertRaises(rpc.common.RemoteError,
 
987
                          self.compute.run_instance,
 
988
                          self.context,
 
989
                          instance['uuid'])
 
990
 
 
991
        self.compute.terminate_instance(self.context, instance['uuid'])
 
992
 
 
993
    def test_get_lock(self):
 
994
        instance = self._create_fake_instance()
 
995
        instance_uuid = instance['uuid']
 
996
        self.assertFalse(self.compute.get_lock(self.context, instance_uuid))
 
997
        db.instance_update(self.context, instance_uuid, {'locked': True})
 
998
        self.assertTrue(self.compute.get_lock(self.context, instance_uuid))
 
999
 
 
1000
    def test_lock(self):
 
1001
        """ensure locked instance cannot be changed"""
 
1002
        instance = self._create_fake_instance()
 
1003
        instance_uuid = instance['uuid']
 
1004
        self.compute.run_instance(self.context, instance_uuid)
 
1005
 
 
1006
        non_admin_context = context.RequestContext(None,
 
1007
                                                   None,
 
1008
                                                   is_admin=False)
 
1009
 
 
1010
        # decorator should return False (fail) with locked nonadmin context
 
1011
        self.compute.lock_instance(self.context, instance_uuid)
 
1012
        ret_val = self.compute.reboot_instance(non_admin_context,
 
1013
                                               instance_uuid)
 
1014
        self.assertEqual(ret_val, False)
 
1015
 
 
1016
        # decorator should return None (success) with unlocked nonadmin context
 
1017
        self.compute.unlock_instance(self.context, instance_uuid)
 
1018
        ret_val = self.compute.reboot_instance(non_admin_context,
 
1019
                                               instance_uuid)
 
1020
        self.assertEqual(ret_val, None)
 
1021
 
 
1022
        self.compute.terminate_instance(self.context, instance_uuid)
 
1023
 
 
1024
    def test_finish_resize(self):
 
1025
        """Contrived test to ensure finish_resize doesn't raise anything"""
 
1026
 
 
1027
        def fake(*args, **kwargs):
 
1028
            pass
 
1029
 
 
1030
        self.stubs.Set(self.compute.driver, 'finish_migration', fake)
 
1031
 
 
1032
        context = self.context.elevated()
 
1033
        instance = self._create_fake_instance()
 
1034
        self.compute.prep_resize(context, instance['uuid'], 1, {},
 
1035
                                 filter_properties={})
 
1036
        migration_ref = db.migration_get_by_instance_and_status(context,
 
1037
                instance['uuid'], 'pre-migrating')
 
1038
        self.compute.finish_resize(context, instance['uuid'],
 
1039
                                   int(migration_ref['id']), {}, {})
 
1040
        self.compute.terminate_instance(self.context, instance['uuid'])
 
1041
 
 
1042
    def test_finish_resize_handles_error(self):
 
1043
        """Make sure we don't leave the instance in RESIZE on error"""
 
1044
 
 
1045
        def throw_up(*args, **kwargs):
 
1046
            raise test.TestingException()
 
1047
 
 
1048
        def fake(*args, **kwargs):
 
1049
            pass
 
1050
 
 
1051
        self.stubs.Set(self.compute.driver, 'finish_migration', throw_up)
 
1052
 
 
1053
        context = self.context.elevated()
 
1054
        instance = self._create_fake_instance()
 
1055
        self.compute.prep_resize(context, instance['uuid'], 1, {},
 
1056
                                 filter_properties={})
 
1057
        migration_ref = db.migration_get_by_instance_and_status(context,
 
1058
                instance['uuid'], 'pre-migrating')
 
1059
 
 
1060
        self.assertRaises(test.TestingException, self.compute.finish_resize,
 
1061
                          context, instance['uuid'],
 
1062
                          int(migration_ref['id']), {}, {})
 
1063
 
 
1064
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
1065
        self.assertEqual(instance['vm_state'], vm_states.ERROR)
 
1066
        self.compute.terminate_instance(self.context, instance['uuid'])
 
1067
 
 
1068
    def test_rebuild_instance_notification(self):
 
1069
        """Ensure notifications on instance migrate/resize"""
 
1070
        old_time = datetime.datetime(2012, 4, 1)
 
1071
        cur_time = datetime.datetime(2012, 12, 21, 12, 21)
 
1072
        utils.set_time_override(old_time)
 
1073
        inst_ref = self._create_fake_instance()
 
1074
        instance_uuid = inst_ref['uuid']
 
1075
        self.compute.run_instance(self.context, instance_uuid)
 
1076
        utils.set_time_override(cur_time)
 
1077
 
 
1078
        test_notifier.NOTIFICATIONS = []
 
1079
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
1080
 
 
1081
        image_ref = instance["image_ref"]
 
1082
        new_image_ref = image_ref + '-new_image_ref'
 
1083
        db.instance_update(self.context, instance_uuid,
 
1084
                {'image_ref': new_image_ref})
 
1085
 
 
1086
        password = "new_password"
 
1087
 
 
1088
        self.compute._rebuild_instance(self.context, instance_uuid,
 
1089
                image_ref, new_image_ref, dict(new_pass=password))
 
1090
 
 
1091
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
1092
 
 
1093
        image_ref_url = utils.generate_image_url(image_ref)
 
1094
        new_image_ref_url = utils.generate_image_url(new_image_ref)
 
1095
 
 
1096
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 3)
 
1097
        msg = test_notifier.NOTIFICATIONS[0]
 
1098
        self.assertEquals(msg['event_type'],
 
1099
                          'compute.instance.exists')
 
1100
        self.assertEquals(msg['payload']['image_ref_url'], image_ref_url)
 
1101
        msg = test_notifier.NOTIFICATIONS[1]
 
1102
        self.assertEquals(msg['event_type'],
 
1103
                          'compute.instance.rebuild.start')
 
1104
        self.assertEquals(msg['payload']['image_ref_url'], new_image_ref_url)
 
1105
        msg = test_notifier.NOTIFICATIONS[2]
 
1106
        self.assertEquals(msg['event_type'],
 
1107
                          'compute.instance.rebuild.end')
 
1108
        self.assertEquals(msg['priority'], 'INFO')
 
1109
        payload = msg['payload']
 
1110
        self.assertEquals(payload['tenant_id'], self.project_id)
 
1111
        self.assertEquals(payload['user_id'], self.user_id)
 
1112
        self.assertEquals(payload['instance_id'], instance_uuid)
 
1113
        self.assertEquals(payload['instance_type'], 'm1.tiny')
 
1114
        type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
 
1115
        self.assertEquals(str(payload['instance_type_id']), str(type_id))
 
1116
        self.assertTrue('display_name' in payload)
 
1117
        self.assertTrue('created_at' in payload)
 
1118
        self.assertTrue('launched_at' in payload)
 
1119
        self.assertEqual(payload['launched_at'], str(cur_time))
 
1120
        self.assertEquals(payload['image_ref_url'], new_image_ref_url)
 
1121
        self.compute.terminate_instance(self.context, instance_uuid)
 
1122
 
 
1123
    def test_finish_resize_instance_notification(self):
 
1124
        """Ensure notifications on instance migrate/resize"""
 
1125
        old_time = datetime.datetime(2012, 4, 1)
 
1126
        cur_time = datetime.datetime(2012, 12, 21, 12, 21)
 
1127
        utils.set_time_override(old_time)
 
1128
        instance = self._create_fake_instance()
 
1129
        instance_uuid = instance['uuid']
 
1130
        context = self.context.elevated()
 
1131
        old_type_id = instance_types.get_instance_type_by_name(
 
1132
                                                'm1.tiny')['id']
 
1133
        new_type_id = instance_types.get_instance_type_by_name(
 
1134
                                                'm1.small')['id']
 
1135
        self.compute.run_instance(self.context, instance_uuid)
 
1136
 
 
1137
        db.instance_update(self.context, instance_uuid, {'host': 'foo'})
 
1138
        self.compute.prep_resize(context, instance_uuid, new_type_id, {},
 
1139
                                 filter_properties={})
 
1140
        migration_ref = db.migration_get_by_instance_and_status(context,
 
1141
                                                instance_uuid,
 
1142
                                                'pre-migrating')
 
1143
        self.compute.resize_instance(context, instance_uuid,
 
1144
                                     migration_ref['id'], {})
 
1145
        utils.set_time_override(cur_time)
 
1146
        test_notifier.NOTIFICATIONS = []
 
1147
 
 
1148
        self.compute.finish_resize(context, instance['uuid'],
 
1149
                                   int(migration_ref['id']), {}, {})
 
1150
 
 
1151
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 2)
 
1152
        msg = test_notifier.NOTIFICATIONS[0]
 
1153
        self.assertEquals(msg['event_type'],
 
1154
                          'compute.instance.finish_resize.start')
 
1155
        msg = test_notifier.NOTIFICATIONS[1]
 
1156
        self.assertEquals(msg['event_type'],
 
1157
                          'compute.instance.finish_resize.end')
 
1158
        self.assertEquals(msg['priority'], 'INFO')
 
1159
        payload = msg['payload']
 
1160
        self.assertEquals(payload['tenant_id'], self.project_id)
 
1161
        self.assertEquals(payload['user_id'], self.user_id)
 
1162
        self.assertEquals(payload['instance_id'], instance_uuid)
 
1163
        self.assertEquals(payload['instance_type'], 'm1.small')
 
1164
        self.assertEquals(str(payload['instance_type_id']), str(new_type_id))
 
1165
        self.assertTrue('display_name' in payload)
 
1166
        self.assertTrue('created_at' in payload)
 
1167
        self.assertTrue('launched_at' in payload)
 
1168
        self.assertEqual(payload['launched_at'], str(cur_time))
 
1169
        image_ref_url = utils.generate_image_url(FAKE_IMAGE_REF)
 
1170
        self.assertEquals(payload['image_ref_url'], image_ref_url)
 
1171
        self.compute.terminate_instance(context, instance_uuid)
 
1172
 
 
1173
    def test_resize_instance_notification(self):
 
1174
        """Ensure notifications on instance migrate/resize"""
 
1175
        old_time = datetime.datetime(2012, 4, 1)
 
1176
        cur_time = datetime.datetime(2012, 12, 21, 12, 21)
 
1177
        utils.set_time_override(old_time)
 
1178
        instance = self._create_fake_instance()
 
1179
        instance_uuid = instance['uuid']
 
1180
        context = self.context.elevated()
 
1181
 
 
1182
        self.compute.run_instance(self.context, instance_uuid)
 
1183
        utils.set_time_override(cur_time)
 
1184
        test_notifier.NOTIFICATIONS = []
 
1185
 
 
1186
        db.instance_update(self.context, instance_uuid, {'host': 'foo'})
 
1187
        self.compute.prep_resize(context, instance_uuid, 1, {},
 
1188
                                 filter_properties={})
 
1189
        db.migration_get_by_instance_and_status(context,
 
1190
                                                instance_uuid,
 
1191
                                                'pre-migrating')
 
1192
 
 
1193
        self.assertEquals(len(test_notifier.NOTIFICATIONS), 3)
 
1194
        msg = test_notifier.NOTIFICATIONS[0]
 
1195
        self.assertEquals(msg['event_type'],
 
1196
                          'compute.instance.exists')
 
1197
        msg = test_notifier.NOTIFICATIONS[1]
 
1198
        self.assertEquals(msg['event_type'],
 
1199
                          'compute.instance.resize.prep.start')
 
1200
        msg = test_notifier.NOTIFICATIONS[2]
 
1201
        self.assertEquals(msg['event_type'],
 
1202
                          'compute.instance.resize.prep.end')
 
1203
        self.assertEquals(msg['priority'], 'INFO')
 
1204
        payload = msg['payload']
 
1205
        self.assertEquals(payload['tenant_id'], self.project_id)
 
1206
        self.assertEquals(payload['user_id'], self.user_id)
 
1207
        self.assertEquals(payload['instance_id'], instance_uuid)
 
1208
        self.assertEquals(payload['instance_type'], 'm1.tiny')
 
1209
        type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
 
1210
        self.assertEquals(str(payload['instance_type_id']), str(type_id))
 
1211
        self.assertTrue('display_name' in payload)
 
1212
        self.assertTrue('created_at' in payload)
 
1213
        self.assertTrue('launched_at' in payload)
 
1214
        image_ref_url = utils.generate_image_url(FAKE_IMAGE_REF)
 
1215
        self.assertEquals(payload['image_ref_url'], image_ref_url)
 
1216
        self.compute.terminate_instance(context, instance_uuid)
 
1217
 
 
1218
    def test_prep_resize_instance_migration_error(self):
 
1219
        """Ensure prep_resize raise a migration error"""
 
1220
        self.flags(host="foo", allow_resize_to_same_host=False)
 
1221
 
 
1222
        instance = self._create_fake_instance()
 
1223
        instance_uuid = instance['uuid']
 
1224
        context = self.context.elevated()
 
1225
 
 
1226
        self.compute.run_instance(self.context, instance_uuid)
 
1227
        db.instance_update(self.context, instance_uuid, {'host': 'foo'})
 
1228
 
 
1229
        self.assertRaises(exception.MigrationError, self.compute.prep_resize,
 
1230
                          context, instance_uuid, 1, {})
 
1231
        self.compute.terminate_instance(context, instance_uuid)
 
1232
 
 
1233
    def test_resize_instance_driver_error(self):
 
1234
        """Ensure instance status set to Error on resize error"""
 
1235
 
 
1236
        def throw_up(*args, **kwargs):
 
1237
            raise test.TestingException()
 
1238
 
 
1239
        self.stubs.Set(self.compute.driver, 'migrate_disk_and_power_off',
 
1240
                       throw_up)
 
1241
 
 
1242
        instance = self._create_fake_instance()
 
1243
        instance_uuid = instance['uuid']
 
1244
        context = self.context.elevated()
 
1245
 
 
1246
        self.compute.run_instance(self.context, instance_uuid)
 
1247
        db.instance_update(self.context, instance_uuid, {'host': 'foo'})
 
1248
        self.compute.prep_resize(context, instance_uuid, 1, {},
 
1249
                                 filter_properties={})
 
1250
        migration_ref = db.migration_get_by_instance_and_status(context,
 
1251
                instance_uuid, 'pre-migrating')
 
1252
 
 
1253
        #verify
 
1254
        self.assertRaises(test.TestingException, self.compute.resize_instance,
 
1255
                          context, instance_uuid, migration_ref['id'], {})
 
1256
        instance = db.instance_get_by_uuid(context, instance_uuid)
 
1257
        self.assertEqual(instance['vm_state'], vm_states.ERROR)
 
1258
 
 
1259
        self.compute.terminate_instance(context, instance_uuid)
 
1260
 
 
1261
    def test_resize_instance(self):
 
1262
        """Ensure instance can be migrated/resized"""
 
1263
        instance = self._create_fake_instance()
 
1264
        instance_uuid = instance['uuid']
 
1265
        context = self.context.elevated()
 
1266
 
 
1267
        self.compute.run_instance(self.context, instance_uuid)
 
1268
        db.instance_update(self.context, instance_uuid,
 
1269
                           {'host': 'foo'})
 
1270
        self.compute.prep_resize(context, instance_uuid, 1, {},
 
1271
                                 filter_properties={})
 
1272
        migration_ref = db.migration_get_by_instance_and_status(context,
 
1273
                instance_uuid, 'pre-migrating')
 
1274
        self.compute.resize_instance(context, instance_uuid,
 
1275
                migration_ref['id'], {})
 
1276
        self.compute.terminate_instance(context, instance_uuid)
 
1277
 
 
1278
    def test_finish_revert_resize(self):
 
1279
        """Ensure that the flavor is reverted to the original on revert"""
 
1280
        def fake(*args, **kwargs):
 
1281
            pass
 
1282
 
 
1283
        self.stubs.Set(self.compute.driver, 'finish_migration', fake)
 
1284
        self.stubs.Set(self.compute.driver, 'finish_revert_migration', fake)
 
1285
 
 
1286
        context = self.context.elevated()
 
1287
        instance = self._create_fake_instance()
 
1288
        instance_uuid = instance['uuid']
 
1289
 
 
1290
        self.compute.run_instance(self.context, instance_uuid)
 
1291
 
 
1292
        # Confirm the instance size before the resize starts
 
1293
        inst_ref = db.instance_get_by_uuid(context, instance_uuid)
 
1294
        instance_type_ref = db.instance_type_get(context,
 
1295
                inst_ref['instance_type_id'])
 
1296
        self.assertEqual(instance_type_ref['flavorid'], '1')
 
1297
 
 
1298
        db.instance_update(self.context, instance_uuid, {'host': 'foo'})
 
1299
 
 
1300
        new_instance_type_ref = db.instance_type_get_by_flavor_id(context, 3)
 
1301
        self.compute.prep_resize(context, inst_ref['uuid'],
 
1302
                                 new_instance_type_ref['id'], {},
 
1303
                                 filter_properties={})
 
1304
 
 
1305
        migration_ref = db.migration_get_by_instance_and_status(context,
 
1306
                inst_ref['uuid'], 'pre-migrating')
 
1307
 
 
1308
        self.compute.resize_instance(context, inst_ref['uuid'],
 
1309
                migration_ref['id'], {})
 
1310
        self.compute.finish_resize(context, inst_ref['uuid'],
 
1311
                    int(migration_ref['id']), {}, {})
 
1312
 
 
1313
        # Prove that the instance size is now the new size
 
1314
        inst_ref = db.instance_get_by_uuid(context, instance_uuid)
 
1315
        instance_type_ref = db.instance_type_get(context,
 
1316
                inst_ref['instance_type_id'])
 
1317
        self.assertEqual(instance_type_ref['flavorid'], '3')
 
1318
 
 
1319
        # Finally, revert and confirm the old flavor has been applied
 
1320
        self.compute.revert_resize(context, inst_ref['uuid'],
 
1321
                migration_ref['id'])
 
1322
        self.compute.finish_revert_resize(context, inst_ref['uuid'],
 
1323
                migration_ref['id'])
 
1324
 
 
1325
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
1326
        self.assertEqual(instance['vm_state'], vm_states.ACTIVE)
 
1327
        self.assertEqual(instance['task_state'], None)
 
1328
 
 
1329
        inst_ref = db.instance_get_by_uuid(context, instance_uuid)
 
1330
        instance_type_ref = db.instance_type_get(context,
 
1331
                inst_ref['instance_type_id'])
 
1332
        self.assertEqual(instance_type_ref['flavorid'], '1')
 
1333
        self.assertEqual(inst_ref['host'], migration_ref['source_compute'])
 
1334
 
 
1335
        self.compute.terminate_instance(context, inst_ref['uuid'])
 
1336
 
 
1337
    def test_get_by_flavor_id(self):
 
1338
        type = instance_types.get_instance_type_by_flavor_id(1)
 
1339
        self.assertEqual(type['name'], 'm1.tiny')
 
1340
 
 
1341
    def test_resize_same_source_fails(self):
 
1342
        """Ensure instance fails to migrate when source and destination are
 
1343
        the same host"""
 
1344
        instance = self._create_fake_instance()
 
1345
        self.compute.run_instance(self.context, instance['uuid'])
 
1346
        instance = db.instance_get_by_uuid(self.context, instance['uuid'])
 
1347
        self.assertRaises(exception.MigrationError, self.compute.prep_resize,
 
1348
                self.context, instance['uuid'], 1, {})
 
1349
        self.compute.terminate_instance(self.context, instance['uuid'])
 
1350
 
 
1351
    def test_resize_instance_handles_migration_error(self):
 
1352
        """Ensure vm_state is ERROR when error occurs"""
 
1353
        def raise_migration_failure(*args):
 
1354
            raise test.TestingException()
 
1355
        self.stubs.Set(self.compute.driver,
 
1356
                'migrate_disk_and_power_off',
 
1357
                raise_migration_failure)
 
1358
 
 
1359
        inst_ref = self._create_fake_instance()
 
1360
        context = self.context.elevated()
 
1361
 
 
1362
        self.compute.run_instance(self.context, inst_ref['uuid'])
 
1363
        db.instance_update(self.context, inst_ref['uuid'], {'host': 'foo'})
 
1364
        self.compute.prep_resize(context, inst_ref['uuid'], 1, {},
 
1365
                                 filter_properties={})
 
1366
        migration_ref = db.migration_get_by_instance_and_status(context,
 
1367
                inst_ref['uuid'], 'pre-migrating')
 
1368
        self.assertRaises(test.TestingException, self.compute.resize_instance,
 
1369
                          context, inst_ref['uuid'], migration_ref['id'], {})
 
1370
        inst_ref = db.instance_get_by_uuid(context, inst_ref['uuid'])
 
1371
        self.assertEqual(inst_ref['vm_state'], vm_states.ERROR)
 
1372
        self.compute.terminate_instance(context, inst_ref['uuid'])
 
1373
 
 
1374
    def test_pre_live_migration_instance_has_no_fixed_ip(self):
 
1375
        """Confirm raising exception if instance doesn't have fixed_ip."""
 
1376
        # creating instance testdata
 
1377
        inst_ref = self._create_fake_instance({'host': 'dummy'})
 
1378
        c = context.get_admin_context()
 
1379
 
 
1380
        # start test
 
1381
        self.stubs.Set(time, 'sleep', lambda t: None)
 
1382
        self.assertRaises(exception.FixedIpNotFoundForInstance,
 
1383
                          self.compute.pre_live_migration,
 
1384
                          c, inst_ref['id'])
 
1385
        # cleanup
 
1386
        db.instance_destroy(c, inst_ref['id'])
 
1387
 
 
1388
    def test_pre_live_migration_works_correctly(self):
 
1389
        """Confirm setup_compute_volume is called when volume is mounted."""
 
1390
        def stupid(*args, **kwargs):
 
1391
            return fake_network.fake_get_instance_nw_info(self.stubs,
 
1392
                                                          spectacular=True)
 
1393
        self.stubs.Set(nova.compute.manager.ComputeManager,
 
1394
                       '_get_instance_nw_info', stupid)
 
1395
        # creating instance testdata
 
1396
        inst_ref = self._create_fake_instance({'host': 'dummy'})
 
1397
        c = context.get_admin_context()
 
1398
 
 
1399
        # creating mocks
 
1400
        self.mox.StubOutWithMock(self.compute.driver, 'pre_live_migration')
 
1401
        self.compute.driver.pre_live_migration({'block_device_mapping': []})
 
1402
        nw_info = fake_network.fake_get_instance_nw_info(self.stubs)
 
1403
        self.mox.StubOutWithMock(self.compute.driver, 'plug_vifs')
 
1404
        self.compute.driver.plug_vifs(mox.IsA(inst_ref), nw_info)
 
1405
        self.mox.StubOutWithMock(self.compute.driver,
 
1406
                                 'ensure_filtering_rules_for_instance')
 
1407
        self.compute.driver.ensure_filtering_rules_for_instance(
 
1408
            mox.IsA(inst_ref), nw_info)
 
1409
 
 
1410
        # start test
 
1411
        self.mox.ReplayAll()
 
1412
        ret = self.compute.pre_live_migration(c, inst_ref['id'])
 
1413
        self.assertEqual(ret, None)
 
1414
 
 
1415
        # cleanup
 
1416
        db.instance_destroy(c, inst_ref['id'])
 
1417
 
 
1418
    def test_live_migration_dest_raises_exception(self):
 
1419
        """Confirm exception when pre_live_migration fails."""
 
1420
        # creating instance testdata
 
1421
        inst_ref = self._create_fake_instance({'host': 'dummy'})
 
1422
 
 
1423
        c = context.get_admin_context()
 
1424
        topic = db.queue_get_for(c, FLAGS.compute_topic, inst_ref['host'])
 
1425
 
 
1426
        # creating volume testdata
 
1427
        volume_id = db.volume_create(c, {'size': 1})['id']
 
1428
        values = {'instance_uuid': inst_ref['uuid'], 'device_name': '/dev/vdc',
 
1429
                  'delete_on_termination': False, 'volume_id': volume_id}
 
1430
        db.block_device_mapping_create(c, values)
 
1431
 
 
1432
        # creating mocks
 
1433
        self.mox.StubOutWithMock(rpc, 'call')
 
1434
        rpc.call(c, FLAGS.volume_topic,
 
1435
                 {"method": "check_for_export",
 
1436
                  "args": {'instance_id': inst_ref['id']}})
 
1437
 
 
1438
        self.mox.StubOutWithMock(self.compute.driver, 'get_instance_disk_info')
 
1439
        self.compute.driver.get_instance_disk_info(inst_ref.name)
 
1440
 
 
1441
        rpc.call(c, topic,
 
1442
                 {"method": "pre_live_migration",
 
1443
                  "args": {'instance_id': inst_ref['id'],
 
1444
                           'block_migration': True,
 
1445
                           'disk': None}
 
1446
                 }).AndRaise(rpc.common.RemoteError('', '', ''))
 
1447
 
 
1448
        # mocks for rollback
 
1449
        rpc.call(c, 'network', {'method': 'setup_networks_on_host',
 
1450
                                'args': {'instance_id': inst_ref['id'],
 
1451
                                         'host': self.compute.host,
 
1452
                                         'teardown': False}})
 
1453
        rpc.call(c, topic, {"method": "remove_volume_connection",
 
1454
                            "args": {'instance_id': inst_ref['id'],
 
1455
                                     'volume_id': volume_id}})
 
1456
        rpc.cast(c, topic, {"method": "rollback_live_migration_at_destination",
 
1457
                            "args": {'instance_id': inst_ref['id']}})
 
1458
 
 
1459
        # start test
 
1460
        self.mox.ReplayAll()
 
1461
        self.assertRaises(rpc_common.RemoteError,
 
1462
                          self.compute.live_migration,
 
1463
                          c, inst_ref['id'], inst_ref['host'], True)
 
1464
 
 
1465
        # cleanup
 
1466
        for bdms in db.block_device_mapping_get_all_by_instance(
 
1467
            c, inst_ref['uuid']):
 
1468
            db.block_device_mapping_destroy(c, bdms['id'])
 
1469
        db.volume_destroy(c, volume_id)
 
1470
        db.instance_destroy(c, inst_ref['id'])
 
1471
 
 
1472
    def test_live_migration_works_correctly(self):
 
1473
        """Confirm live_migration() works as expected correctly."""
 
1474
        # creating instance testdata
 
1475
        instance = self._create_fake_instance({'host': 'dummy'})
 
1476
        instance_id = instance['id']
 
1477
        c = context.get_admin_context()
 
1478
        inst_ref = db.instance_get(c, instance_id)
 
1479
        topic = db.queue_get_for(c, FLAGS.compute_topic, inst_ref['host'])
 
1480
 
 
1481
        # create
 
1482
        self.mox.StubOutWithMock(rpc, 'call')
 
1483
        rpc.call(c, topic, {"method": "pre_live_migration",
 
1484
                            "args": {'instance_id': instance_id,
 
1485
                                     'block_migration': False,
 
1486
                                     'disk': None}})
 
1487
 
 
1488
        # start test
 
1489
        self.mox.ReplayAll()
 
1490
        ret = self.compute.live_migration(c, inst_ref['id'], inst_ref['host'])
 
1491
        self.assertEqual(ret, None)
 
1492
 
 
1493
        # cleanup
 
1494
        db.instance_destroy(c, instance_id)
 
1495
 
 
1496
    def test_post_live_migration_working_correctly(self):
 
1497
        """Confirm post_live_migration() works as expected correctly."""
 
1498
        dest = 'desthost'
 
1499
        flo_addr = '1.2.1.2'
 
1500
 
 
1501
        # creating testdata
 
1502
        c = context.get_admin_context()
 
1503
        instance = self._create_fake_instance({
 
1504
                        'state_description': 'migrating',
 
1505
                        'state': power_state.PAUSED})
 
1506
        instance_id = instance['id']
 
1507
        i_ref = db.instance_get(c, instance_id)
 
1508
        db.instance_update(c, i_ref['id'], {'vm_state': vm_states.MIGRATING,
 
1509
                                            'power_state': power_state.PAUSED})
 
1510
        v_ref = db.volume_create(c, {'size': 1, 'instance_id': instance_id})
 
1511
        fix_addr = db.fixed_ip_create(c, {'address': '1.1.1.1',
 
1512
                                          'instance_id': instance_id})
 
1513
        fix_ref = db.fixed_ip_get_by_address(c, fix_addr)
 
1514
        db.floating_ip_create(c, {'address': flo_addr,
 
1515
                                  'fixed_ip_id': fix_ref['id']})
 
1516
 
 
1517
        # creating mocks
 
1518
        self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance')
 
1519
        self.compute.driver.unfilter_instance(i_ref, [])
 
1520
        self.mox.StubOutWithMock(rpc, 'call')
 
1521
        rpc.call(c, db.queue_get_for(c, FLAGS.compute_topic, dest),
 
1522
            {"method": "post_live_migration_at_destination",
 
1523
             "args": {'instance_id': i_ref['id'], 'block_migration': False}})
 
1524
        self.mox.StubOutWithMock(self.compute.driver, 'unplug_vifs')
 
1525
        self.compute.driver.unplug_vifs(i_ref, [])
 
1526
        rpc.call(c, 'network', {'method': 'setup_networks_on_host',
 
1527
                                'args': {'instance_id': instance_id,
 
1528
                                         'host': self.compute.host,
 
1529
                                         'teardown': True}})
 
1530
 
 
1531
        # start test
 
1532
        self.mox.ReplayAll()
 
1533
        self.compute.post_live_migration(c, i_ref, dest)
 
1534
 
 
1535
        # make sure floating ips are rewritten to destinatioin hostname.
 
1536
        flo_refs = db.floating_ip_get_all_by_host(c, dest)
 
1537
        self.assertTrue(flo_refs)
 
1538
        self.assertEqual(flo_refs[0]['address'], flo_addr)
 
1539
 
 
1540
        # cleanup
 
1541
        db.instance_destroy(c, instance_id)
 
1542
        db.volume_destroy(c, v_ref['id'])
 
1543
        db.floating_ip_destroy(c, flo_addr)
 
1544
 
 
1545
    def test_run_kill_vm(self):
 
1546
        """Detect when a vm is terminated behind the scenes"""
 
1547
        self.stubs.Set(compute_manager.ComputeManager,
 
1548
                '_report_driver_status', nop_report_driver_status)
 
1549
 
 
1550
        instance = self._create_fake_instance()
 
1551
 
 
1552
        self.compute.run_instance(self.context, instance['uuid'])
 
1553
 
 
1554
        instances = db.instance_get_all(context.get_admin_context())
 
1555
        LOG.info(_("Running instances: %s"), instances)
 
1556
        self.assertEqual(len(instances), 1)
 
1557
 
 
1558
        instance_name = instances[0].name
 
1559
        self.compute.driver.test_remove_vm(instance_name)
 
1560
 
 
1561
        # Force the compute manager to do its periodic poll
 
1562
        ctxt = context.get_admin_context()
 
1563
        self.compute._sync_power_states(ctxt)
 
1564
 
 
1565
        instances = db.instance_get_all(ctxt)
 
1566
        LOG.info(_("After force-killing instances: %s"), instances)
 
1567
        self.assertEqual(len(instances), 1)
 
1568
        self.assertEqual(power_state.NOSTATE, instances[0]['power_state'])
 
1569
 
 
1570
    def test_add_instance_fault(self):
 
1571
        exc_info = None
 
1572
        instance_uuid = str(utils.gen_uuid())
 
1573
 
 
1574
        def fake_db_fault_create(ctxt, values):
 
1575
            self.assertTrue(values['details'].startswith('test'))
 
1576
            self.assertTrue('raise NotImplementedError' in values['details'])
 
1577
            del values['details']
 
1578
 
 
1579
            expected = {
 
1580
                'code': 500,
 
1581
                'message': 'NotImplementedError',
 
1582
                'instance_uuid': instance_uuid,
 
1583
            }
 
1584
            self.assertEquals(expected, values)
 
1585
 
 
1586
        try:
 
1587
            raise NotImplementedError('test')
 
1588
        except Exception:
 
1589
            exc_info = sys.exc_info()
 
1590
 
 
1591
        self.stubs.Set(nova.db, 'instance_fault_create', fake_db_fault_create)
 
1592
 
 
1593
        ctxt = context.get_admin_context()
 
1594
        self.compute.add_instance_fault_from_exc(ctxt, instance_uuid,
 
1595
                                                 NotImplementedError('test'),
 
1596
                                                 exc_info)
 
1597
 
 
1598
    def test_add_instance_fault_user_error(self):
 
1599
        exc_info = None
 
1600
        instance_uuid = str(utils.gen_uuid())
 
1601
 
 
1602
        def fake_db_fault_create(ctxt, values):
 
1603
 
 
1604
            expected = {
 
1605
                'code': 400,
 
1606
                'message': 'Invalid',
 
1607
                'details': 'fake details',
 
1608
                'instance_uuid': instance_uuid,
 
1609
            }
 
1610
            self.assertEquals(expected, values)
 
1611
 
 
1612
        user_exc = exception.Invalid('fake details', code=400)
 
1613
 
 
1614
        try:
 
1615
            raise user_exc
 
1616
        except Exception:
 
1617
            exc_info = sys.exc_info()
 
1618
 
 
1619
        self.stubs.Set(nova.db, 'instance_fault_create', fake_db_fault_create)
 
1620
 
 
1621
        ctxt = context.get_admin_context()
 
1622
        self.compute.add_instance_fault_from_exc(ctxt, instance_uuid,
 
1623
            user_exc, exc_info)
 
1624
 
 
1625
    def test_add_instance_fault_no_exc_info(self):
 
1626
        instance_uuid = str(utils.gen_uuid())
 
1627
 
 
1628
        def fake_db_fault_create(ctxt, values):
 
1629
            expected = {
 
1630
                'code': 500,
 
1631
                'message': 'NotImplementedError',
 
1632
                'details': 'test',
 
1633
                'instance_uuid': instance_uuid,
 
1634
            }
 
1635
            self.assertEquals(expected, values)
 
1636
 
 
1637
        self.stubs.Set(nova.db, 'instance_fault_create', fake_db_fault_create)
 
1638
 
 
1639
        ctxt = context.get_admin_context()
 
1640
        self.compute.add_instance_fault_from_exc(ctxt, instance_uuid,
 
1641
                                                 NotImplementedError('test'))
 
1642
 
 
1643
    def test_get_additional_capabilities(self):
 
1644
        self.flags(additional_compute_capabilities=['test3=xyzzy',
 
1645
                                                    'test4',
 
1646
                                                    'nothertest=blat'])
 
1647
        caps = compute_manager._get_additional_capabilities()
 
1648
        all_caps = dict(test3='xyzzy',
 
1649
                        test4=True,
 
1650
                        nothertest='blat')
 
1651
        for c, val in all_caps.items():
 
1652
            self.assertTrue(c in caps, c)
 
1653
            self.assertEquals(val, caps[c])
 
1654
 
 
1655
    def test_report_driver_status(self):
 
1656
        test_caps = dict(test1=1024, test2='foo', nothertest='bar')
 
1657
        self.flags(additional_compute_capabilities=['test3=xyzzy',
 
1658
                                                    'test4',
 
1659
                                                    'nothertest=blat'])
 
1660
        self.mox.StubOutWithMock(self.compute.driver, 'get_host_stats')
 
1661
        self.compute.driver.get_host_stats(refresh=True).AndReturn(test_caps)
 
1662
        self.compute._last_host_check = 0
 
1663
        self.mox.ReplayAll()
 
1664
 
 
1665
        self.compute._report_driver_status(context.get_admin_context())
 
1666
        caps = self.compute.last_capabilities
 
1667
        all_caps = dict(test1=1024, test2='foo', test3='xyzzy',
 
1668
                        test4=True, nothertest='bar')
 
1669
        for c, val in all_caps.items():
 
1670
            self.assertTrue(c in caps, c)
 
1671
            self.assertEquals(val, caps[c])
 
1672
 
 
1673
    def test_cleanup_running_deleted_instances(self):
 
1674
        admin_context = context.get_admin_context()
 
1675
        deleted_at = utils.utcnow() - datetime.timedelta(hours=1, minutes=5)
 
1676
        instance = self._create_fake_instance({"deleted_at": deleted_at,
 
1677
                                          "deleted": True})
 
1678
 
 
1679
        self.compute.host = instance['host']
 
1680
 
 
1681
        self.mox.StubOutWithMock(self.compute.driver, 'list_instances')
 
1682
        self.compute.driver.list_instances().AndReturn([instance['name']])
 
1683
        FLAGS.running_deleted_instance_timeout = 3600
 
1684
        FLAGS.running_deleted_instance_action = 'reap'
 
1685
 
 
1686
        self.mox.StubOutWithMock(self.compute.db, "instance_get_all_by_host")
 
1687
        self.compute.db.instance_get_all_by_host(admin_context,
 
1688
                                                 self.compute.host
 
1689
                                                ).AndReturn([instance])
 
1690
 
 
1691
        self.mox.StubOutWithMock(self.compute, "_shutdown_instance")
 
1692
        self.compute._shutdown_instance(admin_context, instance,
 
1693
                                        'Terminating').AndReturn(None)
 
1694
 
 
1695
        self.mox.StubOutWithMock(self.compute, "_cleanup_volumes")
 
1696
        self.compute._cleanup_volumes(admin_context,
 
1697
                                      instance['uuid']).AndReturn(None)
 
1698
 
 
1699
        self.mox.ReplayAll()
 
1700
        self.compute._cleanup_running_deleted_instances(admin_context)
 
1701
 
 
1702
    def test_running_deleted_instances(self):
 
1703
        self.mox.StubOutWithMock(self.compute.driver, 'list_instances')
 
1704
        self.compute.driver.list_instances().AndReturn(['herp', 'derp'])
 
1705
        self.compute.host = 'host'
 
1706
 
 
1707
        instance1 = mox.MockAnything()
 
1708
        instance1.name = 'herp'
 
1709
        instance1.deleted = True
 
1710
        instance1.deleted_at = "sometimeago"
 
1711
 
 
1712
        instance2 = mox.MockAnything()
 
1713
        instance2.name = 'derp'
 
1714
        instance2.deleted = False
 
1715
        instance2.deleted_at = None
 
1716
 
 
1717
        self.mox.StubOutWithMock(utils, 'is_older_than')
 
1718
        utils.is_older_than('sometimeago',
 
1719
                    FLAGS.running_deleted_instance_timeout).AndReturn(True)
 
1720
 
 
1721
        self.mox.StubOutWithMock(self.compute.db, "instance_get_all_by_host")
 
1722
        self.compute.db.instance_get_all_by_host('context',
 
1723
                                                 'host').AndReturn(
 
1724
                                                                [instance1,
 
1725
                                                                 instance2])
 
1726
        self.mox.ReplayAll()
 
1727
        val = self.compute._running_deleted_instances('context')
 
1728
        self.assertEqual(val, [instance1])
 
1729
 
 
1730
    def test_heal_instance_info_cache(self):
 
1731
        # Update on every call for the test
 
1732
        self.flags(heal_instance_info_cache_interval=-1)
 
1733
        ctxt = context.get_admin_context()
 
1734
 
 
1735
        instance_map = {}
 
1736
        instances = []
 
1737
        for x in xrange(5):
 
1738
            uuid = 'fake-uuid-%s' % x
 
1739
            instance_map[uuid] = {'uuid': uuid, 'host': FLAGS.host}
 
1740
            instances.append(instance_map[uuid])
 
1741
 
 
1742
        call_info = {'get_all_by_host': 0, 'get_by_uuid': 0,
 
1743
                'get_nw_info': 0, 'expected_instance': None}
 
1744
 
 
1745
        def fake_instance_get_all_by_host(context, host):
 
1746
            call_info['get_all_by_host'] += 1
 
1747
            return instances[:]
 
1748
 
 
1749
        def fake_instance_get_by_uuid(context, instance_uuid):
 
1750
            if instance_uuid not in instance_map:
 
1751
                raise exception.InstanceNotFound
 
1752
            call_info['get_by_uuid'] += 1
 
1753
            return instance_map[instance_uuid]
 
1754
 
 
1755
        # NOTE(comstud): Override the stub in setUp()
 
1756
        def fake_get_instance_nw_info(context, instance):
 
1757
            # Note that this exception gets caught in compute/manager
 
1758
            # and is ignored.  However, the below increment of
 
1759
            # 'get_nw_info' won't happen, and you'll get an assert
 
1760
            # failure checking it below.
 
1761
            self.assertEqual(instance, call_info['expected_instance'])
 
1762
            call_info['get_nw_info'] += 1
 
1763
 
 
1764
        self.stubs.Set(db, 'instance_get_all_by_host',
 
1765
                fake_instance_get_all_by_host)
 
1766
        self.stubs.Set(db, 'instance_get_by_uuid',
 
1767
                fake_instance_get_by_uuid)
 
1768
        self.stubs.Set(self.compute.network_api, 'get_instance_nw_info',
 
1769
                fake_get_instance_nw_info)
 
1770
 
 
1771
        call_info['expected_instance'] = instances[0]
 
1772
        self.compute._heal_instance_info_cache(ctxt)
 
1773
        self.assertEqual(call_info['get_all_by_host'], 1)
 
1774
        self.assertEqual(call_info['get_by_uuid'], 0)
 
1775
        self.assertEqual(call_info['get_nw_info'], 1)
 
1776
 
 
1777
        call_info['expected_instance'] = instances[1]
 
1778
        self.compute._heal_instance_info_cache(ctxt)
 
1779
        self.assertEqual(call_info['get_all_by_host'], 1)
 
1780
        self.assertEqual(call_info['get_by_uuid'], 1)
 
1781
        self.assertEqual(call_info['get_nw_info'], 2)
 
1782
 
 
1783
        # Make an instance switch hosts
 
1784
        instances[2]['host'] = 'not-me'
 
1785
        # Make an instance disappear
 
1786
        instance_map.pop(instances[3]['uuid'])
 
1787
        # '2' and '3' should be skipped..
 
1788
        call_info['expected_instance'] = instances[4]
 
1789
        self.compute._heal_instance_info_cache(ctxt)
 
1790
        self.assertEqual(call_info['get_all_by_host'], 1)
 
1791
        # Incremented for '2' and '4'.. '3' caused a raise above.
 
1792
        self.assertEqual(call_info['get_by_uuid'], 3)
 
1793
        self.assertEqual(call_info['get_nw_info'], 3)
 
1794
        # Should be no more left.
 
1795
        self.assertEqual(len(self.compute._instance_uuids_to_heal), 0)
 
1796
 
 
1797
        # This should cause a DB query now so we get first instance
 
1798
        # back again
 
1799
        call_info['expected_instance'] = instances[0]
 
1800
        self.compute._heal_instance_info_cache(ctxt)
 
1801
        self.assertEqual(call_info['get_all_by_host'], 2)
 
1802
        # Stays the same, beacuse the instance came from the DB
 
1803
        self.assertEqual(call_info['get_by_uuid'], 3)
 
1804
        self.assertEqual(call_info['get_nw_info'], 4)
 
1805
 
 
1806
    def test_poll_unconfirmed_resizes(self):
 
1807
        instances = [{'uuid': 'fake_uuid1', 'vm_state': vm_states.ACTIVE,
 
1808
                      'task_state': task_states.RESIZE_VERIFY},
 
1809
                     {'uuid': 'noexist'},
 
1810
                     {'uuid': 'fake_uuid2', 'vm_state': vm_states.ERROR,
 
1811
                      'task_state': task_states.RESIZE_VERIFY},
 
1812
                     {'uuid': 'fake_uuid3', 'vm_state': vm_states.ACTIVE,
 
1813
                      'task_state': task_states.REBOOTING},
 
1814
                     {'uuid': 'fake_uuid4', 'vm_state': vm_states.ACTIVE,
 
1815
                      'task_state': task_states.RESIZE_VERIFY},
 
1816
                     {'uuid': 'fake_uuid5', 'vm_state': vm_states.ACTIVE,
 
1817
                      'task_state': task_states.RESIZE_VERIFY}]
 
1818
        expected_migration_status = {'fake_uuid1': 'confirmed',
 
1819
                                     'noexist': 'error',
 
1820
                                     'fake_uuid2': 'error',
 
1821
                                     'fake_uuid3': 'error',
 
1822
                                     'fake_uuid4': None,
 
1823
                                     'fake_uuid5': 'confirmed'}
 
1824
        migrations = []
 
1825
        for i, instance in enumerate(instances, start=1):
 
1826
            migrations.append({'id': i,
 
1827
                               'instance_uuid': instance['uuid'],
 
1828
                               'status': None})
 
1829
 
 
1830
        def fake_instance_get_by_uuid(context, instance_uuid):
 
1831
            # raise InstanceNotFound exception for uuid 'noexist'
 
1832
            if instance_uuid == 'noexist':
 
1833
                raise exception.InstanceNotFound(instance_id=instance_uuid)
 
1834
            for instance in instances:
 
1835
                if instance['uuid'] == instance_uuid:
 
1836
                    return instance
 
1837
 
 
1838
        def fake_migration_get_all_unconfirmed(context, resize_confirm_window):
 
1839
            return migrations
 
1840
 
 
1841
        def fake_migration_update(context, migration_id, values):
 
1842
            for migration in migrations:
 
1843
                if migration['id'] == migration_id and 'status' in values:
 
1844
                    migration['status'] = values['status']
 
1845
 
 
1846
        def fake_confirm_resize(context, instance):
 
1847
            # raise exception for 'fake_uuid4' to check migration status
 
1848
            # does not get set to 'error' on confirm_resize failure.
 
1849
            if instance['uuid'] == 'fake_uuid4':
 
1850
                raise test.TestingException
 
1851
            for migration in migrations:
 
1852
                if migration['instance_uuid'] == instance['uuid']:
 
1853
                    migration['status'] = 'confirmed'
 
1854
 
 
1855
        self.stubs.Set(db, 'instance_get_by_uuid',
 
1856
                fake_instance_get_by_uuid)
 
1857
        self.stubs.Set(db, 'migration_get_all_unconfirmed',
 
1858
                fake_migration_get_all_unconfirmed)
 
1859
        self.stubs.Set(db, 'migration_update',
 
1860
                fake_migration_update)
 
1861
        self.stubs.Set(self.compute.compute_api, 'confirm_resize',
 
1862
                fake_confirm_resize)
 
1863
 
 
1864
        def fetch_instance_migration_status(instance_uuid):
 
1865
            for migration in migrations:
 
1866
                if migration['instance_uuid'] == instance_uuid:
 
1867
                    return migration['status']
 
1868
 
 
1869
        self.flags(resize_confirm_window=60)
 
1870
        ctxt = context.get_admin_context()
 
1871
 
 
1872
        self.compute._poll_unconfirmed_resizes(ctxt)
 
1873
 
 
1874
        for uuid, status in expected_migration_status.iteritems():
 
1875
            self.assertEqual(status, fetch_instance_migration_status(uuid))
 
1876
 
 
1877
    def test_instance_build_timeout_disabled(self):
 
1878
        self.flags(instance_build_timeout=0)
 
1879
        ctxt = context.get_admin_context()
 
1880
        called = {'get_all': False, 'set_error_state': 0}
 
1881
        created_at = utils.utcnow() + datetime.timedelta(seconds=-60)
 
1882
 
 
1883
        def fake_instance_get_all_by_filters(*args, **kwargs):
 
1884
            called['get_all'] = True
 
1885
            return instances[:]
 
1886
 
 
1887
        self.stubs.Set(db, 'instance_get_all_by_filters',
 
1888
                fake_instance_get_all_by_filters)
 
1889
 
 
1890
        def fake_set_instance_error_state(_ctxt, instance_uuid, **kwargs):
 
1891
            called['set_error_state'] += 1
 
1892
 
 
1893
        self.stubs.Set(self.compute, '_set_instance_error_state',
 
1894
                fake_set_instance_error_state)
 
1895
 
 
1896
        instance_map = {}
 
1897
        instances = []
 
1898
        for x in xrange(5):
 
1899
            uuid = 'fake-uuid-%s' % x
 
1900
            instance_map[uuid] = {'uuid': uuid, 'host': FLAGS.host,
 
1901
                    'vm_state': vm_states.BUILDING,
 
1902
                    'created_at': created_at}
 
1903
            instances.append(instance_map[uuid])
 
1904
 
 
1905
        self.compute._check_instance_build_time(ctxt)
 
1906
        self.assertFalse(called['get_all'])
 
1907
        self.assertEqual(called['set_error_state'], 0)
 
1908
 
 
1909
    def test_instance_build_timeout(self):
 
1910
        self.flags(instance_build_timeout=30)
 
1911
        ctxt = context.get_admin_context()
 
1912
        called = {'get_all': False, 'set_error_state': 0}
 
1913
        created_at = utils.utcnow() + datetime.timedelta(seconds=-60)
 
1914
 
 
1915
        def fake_instance_get_all_by_filters(*args, **kwargs):
 
1916
            called['get_all'] = True
 
1917
            return instances[:]
 
1918
 
 
1919
        self.stubs.Set(db, 'instance_get_all_by_filters',
 
1920
                fake_instance_get_all_by_filters)
 
1921
 
 
1922
        def fake_set_instance_error_state(_ctxt, instance_uuid, **kwargs):
 
1923
            called['set_error_state'] += 1
 
1924
 
 
1925
        self.stubs.Set(self.compute, '_set_instance_error_state',
 
1926
                fake_set_instance_error_state)
 
1927
 
 
1928
        instance_map = {}
 
1929
        instances = []
 
1930
        for x in xrange(5):
 
1931
            uuid = 'fake-uuid-%s' % x
 
1932
            instance_map[uuid] = {'uuid': uuid, 'host': FLAGS.host,
 
1933
                    'vm_state': vm_states.BUILDING,
 
1934
                    'created_at': created_at}
 
1935
            instances.append(instance_map[uuid])
 
1936
 
 
1937
        self.compute._check_instance_build_time(ctxt)
 
1938
        self.assertTrue(called['get_all'])
 
1939
        self.assertEqual(called['set_error_state'], 5)
 
1940
 
 
1941
    def test_instance_build_timeout_mixed_instances(self):
 
1942
        self.flags(instance_build_timeout=30)
 
1943
        ctxt = context.get_admin_context()
 
1944
        called = {'get_all': False, 'set_error_state': 0}
 
1945
        created_at = utils.utcnow() + datetime.timedelta(seconds=-60)
 
1946
 
 
1947
        def fake_instance_get_all_by_filters(*args, **kwargs):
 
1948
            called['get_all'] = True
 
1949
            return instances[:]
 
1950
 
 
1951
        self.stubs.Set(db, 'instance_get_all_by_filters',
 
1952
                fake_instance_get_all_by_filters)
 
1953
 
 
1954
        def fake_set_instance_error_state(_ctxt, instance_uuid, **kwargs):
 
1955
            called['set_error_state'] += 1
 
1956
 
 
1957
        self.stubs.Set(self.compute, '_set_instance_error_state',
 
1958
                fake_set_instance_error_state)
 
1959
 
 
1960
        instance_map = {}
 
1961
        instances = []
 
1962
        #expired instances
 
1963
        for x in xrange(4):
 
1964
            uuid = 'fake-uuid-%s' % x
 
1965
            instance_map[uuid] = {'uuid': uuid, 'host': FLAGS.host,
 
1966
                    'vm_state': vm_states.BUILDING,
 
1967
                    'created_at': created_at}
 
1968
            instances.append(instance_map[uuid])
 
1969
 
 
1970
        #not expired
 
1971
        uuid = 'fake-uuid-5'
 
1972
        instance_map[uuid] = {'uuid': uuid, 'host': FLAGS.host,
 
1973
                'vm_state': vm_states.BUILDING,
 
1974
                'created_at': utils.utcnow()}
 
1975
        instances.append(instance_map[uuid])
 
1976
 
 
1977
        self.compute._check_instance_build_time(ctxt)
 
1978
        self.assertTrue(called['get_all'])
 
1979
        self.assertEqual(called['set_error_state'], 4)
 
1980
 
 
1981
 
 
1982
class ComputeAPITestCase(BaseTestCase):
 
1983
 
 
1984
    def setUp(self):
 
1985
        def fake_get_nw_info(cls, ctxt, instance):
 
1986
            self.assertTrue(ctxt.is_admin)
 
1987
            return fake_network.fake_get_instance_nw_info(self.stubs, 1, 1,
 
1988
                                                          spectacular=True)
 
1989
 
 
1990
        super(ComputeAPITestCase, self).setUp()
 
1991
        self.stubs.Set(nova.network.API, 'get_instance_nw_info',
 
1992
                       fake_get_nw_info)
 
1993
        self.compute_api = compute.API()
 
1994
        self.fake_image = {
 
1995
            'id': 1,
 
1996
            'properties': {'kernel_id': 'fake_kernel_id',
 
1997
                           'ramdisk_id': 'fake_ramdisk_id'},
 
1998
        }
 
1999
 
 
2000
    def _run_instance(self):
 
2001
        instance = self._create_fake_instance()
 
2002
        instance_uuid = instance['uuid']
 
2003
        self.compute.run_instance(self.context, instance_uuid)
 
2004
 
 
2005
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2006
        self.assertEqual(instance['task_state'], None)
 
2007
        return instance, instance_uuid
 
2008
 
 
2009
    def test_create_with_too_little_ram(self):
 
2010
        """Test an instance type with too little memory"""
 
2011
 
 
2012
        inst_type = instance_types.get_default_instance_type()
 
2013
        inst_type['memory_mb'] = 1
 
2014
 
 
2015
        def fake_show(*args):
 
2016
            img = copy.copy(self.fake_image)
 
2017
            img['min_ram'] = 2
 
2018
            return img
 
2019
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
2020
 
 
2021
        self.assertRaises(exception.InstanceTypeMemoryTooSmall,
 
2022
            self.compute_api.create, self.context, inst_type, None)
 
2023
 
 
2024
        # Now increase the inst_type memory and make sure all is fine.
 
2025
        inst_type['memory_mb'] = 2
 
2026
        (refs, resv_id) = self.compute_api.create(self.context,
 
2027
                inst_type, None)
 
2028
        db.instance_destroy(self.context, refs[0]['id'])
 
2029
 
 
2030
    def test_create_with_too_little_disk(self):
 
2031
        """Test an instance type with too little disk space"""
 
2032
 
 
2033
        inst_type = instance_types.get_default_instance_type()
 
2034
        inst_type['root_gb'] = 1
 
2035
 
 
2036
        def fake_show(*args):
 
2037
            img = copy.copy(self.fake_image)
 
2038
            img['min_disk'] = 2
 
2039
            return img
 
2040
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
2041
 
 
2042
        self.assertRaises(exception.InstanceTypeDiskTooSmall,
 
2043
            self.compute_api.create, self.context, inst_type, None)
 
2044
 
 
2045
        # Now increase the inst_type disk space and make sure all is fine.
 
2046
        inst_type['root_gb'] = 2
 
2047
        (refs, resv_id) = self.compute_api.create(self.context,
 
2048
                inst_type, None)
 
2049
        db.instance_destroy(self.context, refs[0]['id'])
 
2050
 
 
2051
    def test_create_just_enough_ram_and_disk(self):
 
2052
        """Test an instance type with just enough ram and disk space"""
 
2053
 
 
2054
        inst_type = instance_types.get_default_instance_type()
 
2055
        inst_type['root_gb'] = 2
 
2056
        inst_type['memory_mb'] = 2
 
2057
 
 
2058
        def fake_show(*args):
 
2059
            img = copy.copy(self.fake_image)
 
2060
            img['min_ram'] = 2
 
2061
            img['min_disk'] = 2
 
2062
            return img
 
2063
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
2064
 
 
2065
        (refs, resv_id) = self.compute_api.create(self.context,
 
2066
                inst_type, None)
 
2067
        db.instance_destroy(self.context, refs[0]['id'])
 
2068
 
 
2069
    def test_create_with_no_ram_and_disk_reqs(self):
 
2070
        """Test an instance type with no min_ram or min_disk"""
 
2071
 
 
2072
        inst_type = instance_types.get_default_instance_type()
 
2073
        inst_type['root_gb'] = 1
 
2074
        inst_type['memory_mb'] = 1
 
2075
 
 
2076
        def fake_show(*args):
 
2077
            return copy.copy(self.fake_image)
 
2078
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
2079
 
 
2080
        (refs, resv_id) = self.compute_api.create(self.context,
 
2081
                inst_type, None)
 
2082
        db.instance_destroy(self.context, refs[0]['id'])
 
2083
 
 
2084
    def test_create_instance_defaults_display_name(self):
 
2085
        """Verify that an instance cannot be created without a display_name."""
 
2086
        cases = [dict(), dict(display_name=None)]
 
2087
        for instance in cases:
 
2088
            (ref, resv_id) = self.compute_api.create(self.context,
 
2089
                instance_types.get_default_instance_type(), None, **instance)
 
2090
            try:
 
2091
                self.assertNotEqual(ref[0]['display_name'], None)
 
2092
            finally:
 
2093
                db.instance_destroy(self.context, ref[0]['id'])
 
2094
 
 
2095
    def test_create_instance_sets_system_metadata(self):
 
2096
        """Make sure image properties are copied into system metadata."""
 
2097
        (ref, resv_id) = self.compute_api.create(
 
2098
                self.context,
 
2099
                instance_type=instance_types.get_default_instance_type(),
 
2100
                image_href=None)
 
2101
        try:
 
2102
            sys_metadata = db.instance_system_metadata_get(self.context,
 
2103
                    ref[0]['uuid'])
 
2104
            self.assertEqual(sys_metadata,
 
2105
                    {'image_kernel_id': 'fake_kernel_id',
 
2106
                     'image_ramdisk_id': 'fake_ramdisk_id',
 
2107
                     'image_something_else': 'meow'})
 
2108
        finally:
 
2109
            db.instance_destroy(self.context, ref[0]['id'])
 
2110
 
 
2111
    def test_create_instance_associates_security_groups(self):
 
2112
        """Make sure create associates security groups"""
 
2113
        group = self._create_group()
 
2114
        (ref, resv_id) = self.compute_api.create(
 
2115
                self.context,
 
2116
                instance_type=instance_types.get_default_instance_type(),
 
2117
                image_href=None,
 
2118
                security_group=['testgroup'])
 
2119
        try:
 
2120
            self.assertEqual(len(db.security_group_get_by_instance(
 
2121
                             self.context, ref[0]['id'])), 1)
 
2122
            group = db.security_group_get(self.context, group['id'])
 
2123
            self.assert_(len(group.instances) == 1)
 
2124
        finally:
 
2125
            db.security_group_destroy(self.context, group['id'])
 
2126
            db.instance_destroy(self.context, ref[0]['id'])
 
2127
 
 
2128
    def test_create_instance_with_invalid_security_group_raises(self):
 
2129
        instance_type = instance_types.get_default_instance_type()
 
2130
 
 
2131
        pre_build_len = len(db.instance_get_all(context.get_admin_context()))
 
2132
        self.assertRaises(exception.SecurityGroupNotFoundForProject,
 
2133
                          self.compute_api.create,
 
2134
                          self.context,
 
2135
                          instance_type=instance_type,
 
2136
                          image_href=None,
 
2137
                          security_group=['this_is_a_fake_sec_group'])
 
2138
        self.assertEqual(pre_build_len,
 
2139
                         len(db.instance_get_all(context.get_admin_context())))
 
2140
 
 
2141
    def test_default_hostname_generator(self):
 
2142
        cases = [(None, 'server-1'), ('Hello, Server!', 'hello-server'),
 
2143
                 ('<}\x1fh\x10e\x08l\x02l\x05o\x12!{>', 'hello'),
 
2144
                 ('hello_server', 'hello-server')]
 
2145
        for display_name, hostname in cases:
 
2146
            (ref, resv_id) = self.compute_api.create(self.context,
 
2147
                instance_types.get_default_instance_type(), None,
 
2148
                display_name=display_name)
 
2149
            try:
 
2150
                self.assertEqual(ref[0]['hostname'], hostname)
 
2151
            finally:
 
2152
                db.instance_destroy(self.context, ref[0]['id'])
 
2153
 
 
2154
    def test_destroy_instance_disassociates_security_groups(self):
 
2155
        """Make sure destroying disassociates security groups"""
 
2156
        group = self._create_group()
 
2157
 
 
2158
        (ref, resv_id) = self.compute_api.create(
 
2159
                self.context,
 
2160
                instance_type=instance_types.get_default_instance_type(),
 
2161
                image_href=None,
 
2162
                security_group=['testgroup'])
 
2163
        try:
 
2164
            db.instance_destroy(self.context, ref[0]['id'])
 
2165
            group = db.security_group_get(self.context, group['id'])
 
2166
            self.assert_(len(group.instances) == 0)
 
2167
        finally:
 
2168
            db.security_group_destroy(self.context, group['id'])
 
2169
 
 
2170
    def test_destroy_security_group_disassociates_instances(self):
 
2171
        """Make sure destroying security groups disassociates instances"""
 
2172
        group = self._create_group()
 
2173
 
 
2174
        (ref, resv_id) = self.compute_api.create(
 
2175
                self.context,
 
2176
                instance_type=instance_types.get_default_instance_type(),
 
2177
                image_href=None,
 
2178
                security_group=['testgroup'])
 
2179
 
 
2180
        try:
 
2181
            db.security_group_destroy(self.context, group['id'])
 
2182
            admin_deleted_context = context.get_admin_context(
 
2183
                    read_deleted="only")
 
2184
            group = db.security_group_get(admin_deleted_context, group['id'])
 
2185
            self.assert_(len(group.instances) == 0)
 
2186
        finally:
 
2187
            db.instance_destroy(self.context, ref[0]['id'])
 
2188
 
 
2189
    def test_start(self):
 
2190
        instance = self._create_fake_instance()
 
2191
        instance_uuid = instance['uuid']
 
2192
        self.compute.run_instance(self.context, instance_uuid)
 
2193
 
 
2194
        self.compute.stop_instance(self.context, instance_uuid)
 
2195
 
 
2196
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2197
        self.assertEqual(instance['task_state'], None)
 
2198
 
 
2199
        self.compute_api.start(self.context, instance)
 
2200
 
 
2201
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2202
        self.assertEqual(instance['task_state'], task_states.STARTING)
 
2203
 
 
2204
        db.instance_destroy(self.context, instance['id'])
 
2205
 
 
2206
    def test_stop(self):
 
2207
        instance = self._create_fake_instance()
 
2208
        instance_uuid = instance['uuid']
 
2209
        self.compute.run_instance(self.context, instance_uuid)
 
2210
 
 
2211
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2212
        self.assertEqual(instance['task_state'], None)
 
2213
 
 
2214
        self.compute_api.stop(self.context, instance)
 
2215
 
 
2216
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2217
        self.assertEqual(instance['task_state'], task_states.STOPPING)
 
2218
 
 
2219
        db.instance_destroy(self.context, instance['id'])
 
2220
 
 
2221
    def test_start_shutdown(self):
 
2222
        def check_state(instance_uuid, power_state_, vm_state_, task_state_):
 
2223
            instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2224
            self.assertEqual(instance['power_state'], power_state_)
 
2225
            self.assertEqual(instance['vm_state'], vm_state_)
 
2226
            self.assertEqual(instance['task_state'], task_state_)
 
2227
 
 
2228
        def start_check_state(instance_uuid,
 
2229
                              power_state_, vm_state_, task_state_):
 
2230
            instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2231
            self.compute_api.start(self.context, instance)
 
2232
            check_state(instance_uuid, power_state_, vm_state_, task_state_)
 
2233
 
 
2234
        instance = self._create_fake_instance()
 
2235
        instance_uuid = instance['uuid']
 
2236
        self.compute.run_instance(self.context, instance_uuid)
 
2237
 
 
2238
        check_state(instance_uuid, power_state.RUNNING, vm_states.ACTIVE, None)
 
2239
 
 
2240
        # NOTE(yamahata): emulate compute.manager._sync_power_state() that
 
2241
        # the instance is shutdown by itself
 
2242
        db.instance_update(self.context, instance_uuid,
 
2243
                           {'power_state': power_state.NOSTATE,
 
2244
                            'vm_state': vm_states.SHUTOFF})
 
2245
        check_state(instance_uuid, power_state.NOSTATE, vm_states.SHUTOFF,
 
2246
                    None)
 
2247
 
 
2248
        start_check_state(instance_uuid,
 
2249
                          power_state.NOSTATE, vm_states.SHUTOFF, None)
 
2250
 
 
2251
        db.instance_update(self.context, instance_uuid,
 
2252
                           {'shutdown_terminate': False})
 
2253
        start_check_state(instance_uuid, power_state.NOSTATE,
 
2254
                          vm_states.STOPPED, task_states.STARTING)
 
2255
 
 
2256
        db.instance_destroy(self.context, instance['id'])
 
2257
 
 
2258
    def test_delete(self):
 
2259
        instance, instance_uuid = self._run_instance()
 
2260
 
 
2261
        self.compute_api.delete(self.context, instance)
 
2262
 
 
2263
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2264
        self.assertEqual(instance['task_state'], task_states.DELETING)
 
2265
 
 
2266
        db.instance_destroy(self.context, instance['id'])
 
2267
 
 
2268
    def test_delete_fail(self):
 
2269
        instance, instance_uuid = self._run_instance()
 
2270
 
 
2271
        instance = db.instance_update(self.context, instance_uuid,
 
2272
                                      {'disable_terminate': True})
 
2273
        self.compute_api.delete(self.context, instance)
 
2274
 
 
2275
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2276
        self.assertEqual(instance['task_state'], None)
 
2277
 
 
2278
        db.instance_destroy(self.context, instance['id'])
 
2279
 
 
2280
    def test_delete_soft(self):
 
2281
        instance, instance_uuid = self._run_instance()
 
2282
 
 
2283
        self.compute_api.soft_delete(self.context, instance)
 
2284
 
 
2285
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2286
        self.assertEqual(instance['task_state'], task_states.POWERING_OFF)
 
2287
 
 
2288
        db.instance_destroy(self.context, instance['id'])
 
2289
 
 
2290
    def test_delete_soft_fail(self):
 
2291
        instance, instance_uuid = self._run_instance()
 
2292
 
 
2293
        instance = db.instance_update(self.context, instance_uuid,
 
2294
                                      {'disable_terminate': True})
 
2295
        self.compute_api.soft_delete(self.context, instance)
 
2296
 
 
2297
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2298
        self.assertEqual(instance['task_state'], None)
 
2299
 
 
2300
        db.instance_destroy(self.context, instance['id'])
 
2301
 
 
2302
    def test_force_delete(self):
 
2303
        """Ensure instance can be deleted after a soft delete"""
 
2304
        instance = self._create_fake_instance()
 
2305
        instance_uuid = instance['uuid']
 
2306
        self.compute.run_instance(self.context, instance_uuid)
 
2307
 
 
2308
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2309
        self.compute_api.soft_delete(self.context, instance)
 
2310
 
 
2311
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2312
        self.assertEqual(instance['task_state'], task_states.POWERING_OFF)
 
2313
 
 
2314
        self.compute_api.force_delete(self.context, instance)
 
2315
 
 
2316
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2317
        self.assertEqual(instance['task_state'], task_states.DELETING)
 
2318
 
 
2319
    def test_suspend(self):
 
2320
        """Ensure instance can be suspended"""
 
2321
        instance = self._create_fake_instance()
 
2322
        instance_uuid = instance['uuid']
 
2323
        self.compute.run_instance(self.context, instance_uuid)
 
2324
 
 
2325
        self.assertEqual(instance['task_state'], None)
 
2326
 
 
2327
        self.compute_api.suspend(self.context, instance)
 
2328
 
 
2329
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2330
        self.assertEqual(instance['task_state'], task_states.SUSPENDING)
 
2331
 
 
2332
        db.instance_destroy(self.context, instance['id'])
 
2333
 
 
2334
    def test_resume(self):
 
2335
        """Ensure instance can be resumed (if suspended)"""
 
2336
        instance = self._create_fake_instance()
 
2337
        instance_uuid = instance['uuid']
 
2338
        instance_id = instance['id']
 
2339
        self.compute.run_instance(self.context, instance_uuid)
 
2340
        db.instance_update(self.context, instance_id,
 
2341
                           {'vm_state': vm_states.SUSPENDED})
 
2342
        instance = db.instance_get(self.context, instance_id)
 
2343
 
 
2344
        self.assertEqual(instance['task_state'], None)
 
2345
 
 
2346
        self.compute_api.resume(self.context, instance)
 
2347
 
 
2348
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2349
        self.assertEqual(instance['task_state'], task_states.RESUMING)
 
2350
 
 
2351
        db.instance_destroy(self.context, instance['id'])
 
2352
 
 
2353
    def test_pause(self):
 
2354
        """Ensure instance can be paused"""
 
2355
        instance = self._create_fake_instance()
 
2356
        instance_uuid = instance['uuid']
 
2357
        self.compute.run_instance(self.context, instance_uuid)
 
2358
 
 
2359
        self.assertEqual(instance['task_state'], None)
 
2360
 
 
2361
        self.compute_api.pause(self.context, instance)
 
2362
 
 
2363
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2364
        self.assertEqual(instance['task_state'], task_states.PAUSING)
 
2365
 
 
2366
        db.instance_destroy(self.context, instance['id'])
 
2367
 
 
2368
    def test_unpause(self):
 
2369
        """Ensure instance can be unpaused"""
 
2370
        instance = self._create_fake_instance()
 
2371
        instance_uuid = instance['uuid']
 
2372
        self.compute.run_instance(self.context, instance_uuid)
 
2373
 
 
2374
        self.assertEqual(instance['task_state'], None)
 
2375
 
 
2376
        self.compute.pause_instance(self.context, instance_uuid)
 
2377
        # set the state that the instance gets when pause finishes
 
2378
        db.instance_update(self.context, instance['uuid'],
 
2379
                           {'vm_state': vm_states.PAUSED})
 
2380
        instance = db.instance_get_by_uuid(self.context, instance['uuid'])
 
2381
 
 
2382
        self.compute_api.unpause(self.context, instance)
 
2383
 
 
2384
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2385
        self.assertEqual(instance['task_state'], task_states.UNPAUSING)
 
2386
 
 
2387
        db.instance_destroy(self.context, instance['id'])
 
2388
 
 
2389
    def test_restore(self):
 
2390
        """Ensure instance can be restored from a soft delete"""
 
2391
        instance = self._create_fake_instance()
 
2392
        instance_uuid = instance['uuid']
 
2393
        self.compute.run_instance(self.context, instance_uuid)
 
2394
 
 
2395
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2396
        self.compute_api.soft_delete(self.context, instance)
 
2397
 
 
2398
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2399
        self.assertEqual(instance['task_state'], task_states.POWERING_OFF)
 
2400
 
 
2401
        self.compute_api.restore(self.context, instance)
 
2402
 
 
2403
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2404
        self.assertEqual(instance['task_state'], task_states.POWERING_ON)
 
2405
 
 
2406
        db.instance_destroy(self.context, instance['id'])
 
2407
 
 
2408
    def test_rebuild(self):
 
2409
        inst_ref = self._create_fake_instance()
 
2410
        instance_uuid = inst_ref['uuid']
 
2411
        self.compute.run_instance(self.context, instance_uuid)
 
2412
 
 
2413
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2414
        self.assertEqual(instance['task_state'], None)
 
2415
        # Set some image metadata that should get wiped out and reset
 
2416
        # as well as some other metadata that should be preserved.
 
2417
        db.instance_system_metadata_update(self.context, instance_uuid,
 
2418
                {'image_kernel_id': 'old-data',
 
2419
                 'image_ramdisk_id': 'old_data',
 
2420
                 'image_something_else': 'old-data',
 
2421
                 'image_should_remove': 'bye-bye',
 
2422
                 'preserved': 'preserve this!'},
 
2423
                True)
 
2424
 
 
2425
        # Make sure Compute API updates the image_ref before casting to
 
2426
        # compute manager.
 
2427
        orig_update = self.compute_api.update
 
2428
        info = {'image_ref': None}
 
2429
 
 
2430
        def update_wrapper(*args, **kwargs):
 
2431
            if 'image_ref' in kwargs:
 
2432
                info['image_ref'] = kwargs['image_ref']
 
2433
            return orig_update(*args, **kwargs)
 
2434
 
 
2435
        self.stubs.Set(self.compute_api, 'update', update_wrapper)
 
2436
 
 
2437
        image_ref = instance["image_ref"] + '-new_image_ref'
 
2438
        password = "new_password"
 
2439
        self.compute_api.rebuild(self.context, instance, image_ref, password)
 
2440
        self.assertEqual(info['image_ref'], image_ref)
 
2441
 
 
2442
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2443
        self.assertEqual(instance['vm_state'], vm_states.REBUILDING)
 
2444
        sys_metadata = db.instance_system_metadata_get(self.context,
 
2445
                instance_uuid)
 
2446
        self.assertEqual(sys_metadata,
 
2447
                {'image_kernel_id': 'fake_kernel_id',
 
2448
                 'image_ramdisk_id': 'fake_ramdisk_id',
 
2449
                 'image_something_else': 'meow',
 
2450
                 'preserved': 'preserve this!'})
 
2451
        db.instance_destroy(self.context, instance['id'])
 
2452
 
 
2453
    def test_reboot_soft(self):
 
2454
        """Ensure instance can be soft rebooted"""
 
2455
        inst_ref = self._create_fake_instance()
 
2456
        instance_uuid = inst_ref['uuid']
 
2457
        self.compute.run_instance(self.context, instance_uuid)
 
2458
 
 
2459
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
2460
        self.assertEqual(inst_ref['task_state'], None)
 
2461
 
 
2462
        reboot_type = "SOFT"
 
2463
        self.compute_api.reboot(self.context, inst_ref, reboot_type)
 
2464
 
 
2465
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
2466
        self.assertEqual(inst_ref['task_state'], task_states.REBOOTING)
 
2467
 
 
2468
        db.instance_destroy(self.context, inst_ref['id'])
 
2469
 
 
2470
    def test_reboot_hard(self):
 
2471
        """Ensure instance can be hard rebooted"""
 
2472
        inst_ref = self._create_fake_instance()
 
2473
        instance_uuid = inst_ref['uuid']
 
2474
        self.compute.run_instance(self.context, instance_uuid)
 
2475
 
 
2476
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
2477
        self.assertEqual(inst_ref['task_state'], None)
 
2478
 
 
2479
        reboot_type = "HARD"
 
2480
        self.compute_api.reboot(self.context, inst_ref, reboot_type)
 
2481
 
 
2482
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
2483
        self.assertEqual(inst_ref['task_state'], task_states.REBOOTING_HARD)
 
2484
 
 
2485
        db.instance_destroy(self.context, inst_ref['id'])
 
2486
 
 
2487
    def test_hostname_create(self):
 
2488
        """Ensure instance hostname is set during creation."""
 
2489
        inst_type = instance_types.get_instance_type_by_name('m1.tiny')
 
2490
        (instances, _) = self.compute_api.create(self.context,
 
2491
                                                 inst_type,
 
2492
                                                 None,
 
2493
                                                 display_name='test host')
 
2494
 
 
2495
        self.assertEqual('test-host', instances[0]['hostname'])
 
2496
 
 
2497
    def test_set_admin_password(self):
 
2498
        """Ensure instance can have its admin password set"""
 
2499
        instance = self._create_fake_instance()
 
2500
        instance_uuid = instance['uuid']
 
2501
        self.compute.run_instance(self.context, instance_uuid)
 
2502
 
 
2503
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
2504
        self.assertEqual(inst_ref['vm_state'], vm_states.ACTIVE)
 
2505
        self.assertEqual(inst_ref['task_state'], None)
 
2506
 
 
2507
        self.compute_api.set_admin_password(self.context, inst_ref)
 
2508
 
 
2509
        inst_ref = db.instance_get_by_uuid(self.context, instance_uuid)
 
2510
        self.assertEqual(inst_ref['vm_state'], vm_states.ACTIVE)
 
2511
        self.assertEqual(inst_ref['task_state'], task_states.UPDATING_PASSWORD)
 
2512
 
 
2513
        self.compute.terminate_instance(self.context, instance_uuid)
 
2514
 
 
2515
    def test_rescue_unrescue(self):
 
2516
        instance = self._create_fake_instance()
 
2517
        instance_uuid = instance['uuid']
 
2518
        self.compute.run_instance(self.context, instance_uuid)
 
2519
 
 
2520
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2521
        self.assertEqual(instance['vm_state'], vm_states.ACTIVE)
 
2522
        self.assertEqual(instance['task_state'], None)
 
2523
 
 
2524
        self.compute_api.rescue(self.context, instance)
 
2525
 
 
2526
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2527
        self.assertEqual(instance['vm_state'], vm_states.ACTIVE)
 
2528
        self.assertEqual(instance['task_state'], task_states.RESCUING)
 
2529
 
 
2530
        params = {'vm_state': vm_states.RESCUED, 'task_state': None}
 
2531
        db.instance_update(self.context, instance_uuid, params)
 
2532
 
 
2533
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2534
        self.compute_api.unrescue(self.context, instance)
 
2535
 
 
2536
        instance = db.instance_get_by_uuid(self.context, instance_uuid)
 
2537
        self.assertEqual(instance['vm_state'], vm_states.RESCUED)
 
2538
        self.assertEqual(instance['task_state'], task_states.UNRESCUING)
 
2539
 
 
2540
        self.compute.terminate_instance(self.context, instance_uuid)
 
2541
 
 
2542
    def test_snapshot(self):
 
2543
        """Ensure a snapshot of an instance can be created"""
 
2544
        instance = self._create_fake_instance()
 
2545
        image = self.compute_api.snapshot(self.context, instance, 'snap1',
 
2546
                                        {'extra_param': 'value1'})
 
2547
 
 
2548
        self.assertEqual(image['name'], 'snap1')
 
2549
        properties = image['properties']
 
2550
        self.assertTrue('backup_type' not in properties)
 
2551
        self.assertEqual(properties['image_type'], 'snapshot')
 
2552
        self.assertEqual(properties['instance_uuid'], instance['uuid'])
 
2553
        self.assertEqual(properties['extra_param'], 'value1')
 
2554
 
 
2555
        db.instance_destroy(self.context, instance['id'])
 
2556
 
 
2557
    def test_snapshot_minram_mindisk_VHD(self):
 
2558
        """Ensure a snapshots min_ram and min_disk are correct.
 
2559
 
 
2560
        A snapshot of a non-shrinkable VHD should have min_ram
 
2561
        and min_disk set to that of the original instances flavor.
 
2562
        """
 
2563
 
 
2564
        def fake_show(*args):
 
2565
            img = copy.copy(self.fake_image)
 
2566
            img['disk_format'] = 'vhd'
 
2567
            return img
 
2568
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
2569
 
 
2570
        instance = self._create_fake_instance()
 
2571
        inst_params = {'root_gb': 2, 'memory_mb': 256}
 
2572
        instance['instance_type'].update(inst_params)
 
2573
 
 
2574
        image = self.compute_api.snapshot(self.context, instance, 'snap1',
 
2575
                                        {'extra_param': 'value1'})
 
2576
 
 
2577
        self.assertEqual(image['name'], 'snap1')
 
2578
        self.assertEqual(image['min_ram'], 256)
 
2579
        self.assertEqual(image['min_disk'], 2)
 
2580
        properties = image['properties']
 
2581
        self.assertTrue('backup_type' not in properties)
 
2582
        self.assertEqual(properties['image_type'], 'snapshot')
 
2583
        self.assertEqual(properties['instance_uuid'], instance['uuid'])
 
2584
        self.assertEqual(properties['extra_param'], 'value1')
 
2585
 
 
2586
        db.instance_destroy(self.context, instance['id'])
 
2587
 
 
2588
    def test_snapshot_minram_mindisk(self):
 
2589
        """Ensure a snapshots min_ram and min_disk are correct.
 
2590
 
 
2591
        A snapshot of an instance should have min_ram and min_disk
 
2592
        set to that of the instances original image unless that
 
2593
        image had a disk format of vhd.
 
2594
        """
 
2595
 
 
2596
        def fake_show(*args):
 
2597
            img = copy.copy(self.fake_image)
 
2598
            img['disk_format'] = 'raw'
 
2599
            img['min_ram'] = 512
 
2600
            img['min_disk'] = 1
 
2601
            return img
 
2602
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
2603
 
 
2604
        instance = self._create_fake_instance()
 
2605
 
 
2606
        image = self.compute_api.snapshot(self.context, instance, 'snap1',
 
2607
                                        {'extra_param': 'value1'})
 
2608
 
 
2609
        self.assertEqual(image['name'], 'snap1')
 
2610
        self.assertEqual(image['min_ram'], 512)
 
2611
        self.assertEqual(image['min_disk'], 1)
 
2612
        properties = image['properties']
 
2613
        self.assertTrue('backup_type' not in properties)
 
2614
        self.assertEqual(properties['image_type'], 'snapshot')
 
2615
        self.assertEqual(properties['instance_uuid'], instance['uuid'])
 
2616
        self.assertEqual(properties['extra_param'], 'value1')
 
2617
 
 
2618
        db.instance_destroy(self.context, instance['id'])
 
2619
 
 
2620
    def test_snapshot_minram_mindisk_img_missing_minram(self):
 
2621
        """Ensure a snapshots min_ram and min_disk are correct.
 
2622
 
 
2623
        Do not show an attribute that the orig img did not have.
 
2624
        """
 
2625
 
 
2626
        def fake_show(*args):
 
2627
            img = copy.copy(self.fake_image)
 
2628
            img['disk_format'] = 'raw'
 
2629
            img['min_disk'] = 1
 
2630
            return img
 
2631
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
2632
 
 
2633
        instance = self._create_fake_instance()
 
2634
 
 
2635
        image = self.compute_api.snapshot(self.context, instance, 'snap1',
 
2636
                                        {'extra_param': 'value1'})
 
2637
 
 
2638
        self.assertEqual(image['name'], 'snap1')
 
2639
        self.assertFalse('min_ram' in image)
 
2640
        self.assertEqual(image['min_disk'], 1)
 
2641
        properties = image['properties']
 
2642
        self.assertTrue('backup_type' not in properties)
 
2643
        self.assertEqual(properties['image_type'], 'snapshot')
 
2644
        self.assertEqual(properties['instance_uuid'], instance['uuid'])
 
2645
        self.assertEqual(properties['extra_param'], 'value1')
 
2646
 
 
2647
        db.instance_destroy(self.context, instance['id'])
 
2648
 
 
2649
    def test_snapshot_minram_mindisk_no_image(self):
 
2650
        """Ensure a snapshots min_ram and min_disk are correct.
 
2651
 
 
2652
        A snapshots min_ram and min_disk should be set to default if
 
2653
        an instances original image cannot be found.
 
2654
        """
 
2655
 
 
2656
        def fake_show(*args):
 
2657
            raise exception.ImageNotFound
 
2658
 
 
2659
        self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
 
2660
 
 
2661
        instance = self._create_fake_instance()
 
2662
 
 
2663
        image = self.compute_api.snapshot(self.context, instance, 'snap1',
 
2664
                                        {'extra_param': 'value1'})
 
2665
 
 
2666
        self.assertEqual(image['name'], 'snap1')
 
2667
 
 
2668
        # min_ram and min_disk are not returned when set to default
 
2669
        self.assertFalse('min_ram' in image)
 
2670
        self.assertFalse('min_disk' in image)
 
2671
 
 
2672
        properties = image['properties']
 
2673
        self.assertTrue('backup_type' not in properties)
 
2674
        self.assertEqual(properties['image_type'], 'snapshot')
 
2675
        self.assertEqual(properties['instance_uuid'], instance['uuid'])
 
2676
        self.assertEqual(properties['extra_param'], 'value1')
 
2677
 
 
2678
        db.instance_destroy(self.context, instance['id'])
 
2679
 
 
2680
    def test_backup(self):
 
2681
        """Can't backup an instance which is already being backed up."""
 
2682
        instance = self._create_fake_instance()
 
2683
        image = self.compute_api.backup(self.context, instance,
 
2684
                                        'backup1', 'DAILY', None,
 
2685
                                        {'extra_param': 'value1'})
 
2686
 
 
2687
        self.assertEqual(image['name'], 'backup1')
 
2688
        properties = image['properties']
 
2689
        self.assertEqual(properties['backup_type'], 'DAILY')
 
2690
        self.assertEqual(properties['image_type'], 'backup')
 
2691
        self.assertEqual(properties['instance_uuid'], instance['uuid'])
 
2692
        self.assertEqual(properties['extra_param'], 'value1')
 
2693
 
 
2694
        db.instance_destroy(self.context, instance['id'])
 
2695
 
 
2696
    def test_backup_conflict(self):
 
2697
        """Can't backup an instance which is already being backed up."""
 
2698
        instance = self._create_fake_instance()
 
2699
        instance_uuid = instance['uuid']
 
2700
        instance_values = {'task_state': task_states.IMAGE_BACKUP}
 
2701
        db.instance_update(self.context, instance_uuid, instance_values)
 
2702
        instance = self.compute_api.get(self.context, instance_uuid)
 
2703
 
 
2704
        self.assertRaises(exception.InstanceInvalidState,
 
2705
                          self.compute_api.backup,
 
2706
                          self.context,
 
2707
                          instance,
 
2708
                          None,
 
2709
                          None,
 
2710
                          None)
 
2711
 
 
2712
        db.instance_destroy(self.context, instance['id'])
 
2713
 
 
2714
    def test_snapshot_conflict(self):
 
2715
        """Can't snapshot an instance which is already being snapshotted."""
 
2716
        instance = self._create_fake_instance()
 
2717
        instance_uuid = instance['uuid']
 
2718
        instance_values = {'task_state': task_states.IMAGE_SNAPSHOT}
 
2719
        db.instance_update(self.context, instance_uuid, instance_values)
 
2720
        instance = self.compute_api.get(self.context, instance_uuid)
 
2721
 
 
2722
        self.assertRaises(exception.InstanceInvalidState,
 
2723
                          self.compute_api.snapshot,
 
2724
                          self.context,
 
2725
                          instance,
 
2726
                          None)
 
2727
 
 
2728
        db.instance_destroy(self.context, instance['id'])
 
2729
 
 
2730
    def test_resize_confirm_through_api(self):
 
2731
        instance = self._create_fake_instance()
 
2732
        context = self.context.elevated()
 
2733
        self.compute.run_instance(self.context, instance['uuid'])
 
2734
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2735
        self.compute_api.resize(context, instance, '4')
 
2736
 
 
2737
        # create a fake migration record (manager does this)
 
2738
        db.migration_create(context,
 
2739
                {'instance_uuid': instance['uuid'],
 
2740
                 'status': 'finished'})
 
2741
        # set the state that the instance gets when resize finishes
 
2742
        db.instance_update(self.context, instance['uuid'],
 
2743
                           {'task_state': task_states.RESIZE_VERIFY,
 
2744
                            'vm_state': vm_states.ACTIVE})
 
2745
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2746
 
 
2747
        self.compute_api.confirm_resize(context, instance)
 
2748
        self.compute.terminate_instance(context, instance['uuid'])
 
2749
 
 
2750
    def test_resize_revert_through_api(self):
 
2751
        instance = self._create_fake_instance()
 
2752
        context = self.context.elevated()
 
2753
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2754
        self.compute.run_instance(self.context, instance['uuid'])
 
2755
 
 
2756
        self.compute_api.resize(context, instance, '4')
 
2757
 
 
2758
        # create a fake migration record (manager does this)
 
2759
        db.migration_create(context,
 
2760
                {'instance_uuid': instance['uuid'],
 
2761
                 'status': 'finished'})
 
2762
        # set the state that the instance gets when resize finishes
 
2763
        db.instance_update(self.context, instance['uuid'],
 
2764
                           {'task_state': task_states.RESIZE_VERIFY,
 
2765
                            'vm_state': vm_states.ACTIVE})
 
2766
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2767
 
 
2768
        self.compute_api.revert_resize(context, instance)
 
2769
 
 
2770
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2771
        self.assertEqual(instance['vm_state'], vm_states.RESIZING)
 
2772
        self.assertEqual(instance['task_state'], task_states.RESIZE_REVERTING)
 
2773
 
 
2774
        self.compute.terminate_instance(context, instance['uuid'])
 
2775
 
 
2776
    def test_resize_invalid_flavor_fails(self):
 
2777
        """Ensure invalid flavors raise"""
 
2778
        instance = self._create_fake_instance()
 
2779
        context = self.context.elevated()
 
2780
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2781
        self.compute.run_instance(self.context, instance['uuid'])
 
2782
 
 
2783
        self.assertRaises(exception.NotFound, self.compute_api.resize,
 
2784
                context, instance, 200)
 
2785
 
 
2786
        self.compute.terminate_instance(context, instance['uuid'])
 
2787
 
 
2788
    def test_resize_same_size_fails(self):
 
2789
        """Ensure invalid flavors raise"""
 
2790
        context = self.context.elevated()
 
2791
        instance = self._create_fake_instance()
 
2792
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2793
 
 
2794
        self.compute.run_instance(self.context, instance['uuid'])
 
2795
 
 
2796
        self.assertRaises(exception.CannotResizeToSameSize,
 
2797
                          self.compute_api.resize, context, instance, 1)
 
2798
 
 
2799
        self.compute.terminate_instance(context, instance['uuid'])
 
2800
 
 
2801
    def test_migrate(self):
 
2802
        context = self.context.elevated()
 
2803
        instance = self._create_fake_instance()
 
2804
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2805
        self.compute.run_instance(self.context, instance['uuid'])
 
2806
        # Migrate simply calls resize() without a flavor_id.
 
2807
        self.compute_api.resize(context, instance, None)
 
2808
        self.compute.terminate_instance(context, instance['uuid'])
 
2809
 
 
2810
    def test_resize_request_spec(self):
 
2811
        def _fake_cast(context, topic, msg):
 
2812
            request_spec = msg['args']['request_spec']
 
2813
            filter_properties = msg['args']['filter_properties']
 
2814
            instance_properties = request_spec['instance_properties']
 
2815
            self.assertEqual(instance_properties['host'], 'host2')
 
2816
            self.assertIn('host2', filter_properties['ignore_hosts'])
 
2817
 
 
2818
        self.stubs.Set(rpc, 'cast', _fake_cast)
 
2819
 
 
2820
        context = self.context.elevated()
 
2821
        instance = self._create_fake_instance(dict(host='host2'))
 
2822
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2823
        self.compute.run_instance(self.context, instance['uuid'])
 
2824
        try:
 
2825
            self.compute_api.resize(context, instance, None)
 
2826
        finally:
 
2827
            self.compute.terminate_instance(context, instance['uuid'])
 
2828
 
 
2829
    def test_resize_request_spec_noavoid(self):
 
2830
        def _fake_cast(context, topic, msg):
 
2831
            request_spec = msg['args']['request_spec']
 
2832
            filter_properties = msg['args']['filter_properties']
 
2833
            instance_properties = request_spec['instance_properties']
 
2834
            self.assertEqual(instance_properties['host'], 'host2')
 
2835
            self.assertNotIn('host2', filter_properties['ignore_hosts'])
 
2836
 
 
2837
        self.stubs.Set(rpc, 'cast', _fake_cast)
 
2838
        self.flags(allow_resize_to_same_host=True)
 
2839
 
 
2840
        context = self.context.elevated()
 
2841
        instance = self._create_fake_instance(dict(host='host2'))
 
2842
        instance = db.instance_get_by_uuid(context, instance['uuid'])
 
2843
        self.compute.run_instance(self.context, instance['uuid'])
 
2844
        try:
 
2845
            self.compute_api.resize(context, instance, None)
 
2846
        finally:
 
2847
            self.compute.terminate_instance(context, instance['uuid'])
 
2848
 
 
2849
    def test_associate_floating_ip(self):
 
2850
        """Ensure we can associate a floating ip with an instance"""
 
2851
        called = {'associate': False}
 
2852
 
 
2853
        def fake_associate_ip_network_api(self, ctxt, floating_address,
 
2854
                                          fixed_address):
 
2855
            called['associate'] = True
 
2856
 
 
2857
        self.stubs.Set(nova.network.API, 'associate_floating_ip',
 
2858
                       fake_associate_ip_network_api)
 
2859
 
 
2860
        instance = self._create_fake_instance()
 
2861
        instance_uuid = instance['uuid']
 
2862
        address = '0.1.2.3'
 
2863
 
 
2864
        self.compute.run_instance(self.context, instance_uuid)
 
2865
        self.compute_api.associate_floating_ip(self.context,
 
2866
                                               instance,
 
2867
                                               address)
 
2868
        self.assertTrue(called['associate'])
 
2869
        self.compute.terminate_instance(self.context, instance_uuid)
 
2870
 
 
2871
    def test_associate_floating_ip_no_fixed_ip(self):
 
2872
        """Should fail if instance has no fixed ip."""
 
2873
 
 
2874
        def fake_get_nw_info(self, ctxt, instance):
 
2875
            return []
 
2876
 
 
2877
        self.stubs.Set(nova.network.API, 'get_instance_nw_info',
 
2878
                       fake_get_nw_info)
 
2879
 
 
2880
        instance = self._create_fake_instance()
 
2881
        instance_uuid = instance['uuid']
 
2882
        address = '0.1.2.3'
 
2883
 
 
2884
        self.compute.run_instance(self.context, instance_uuid)
 
2885
        self.assertRaises(exception.FixedIpNotFoundForInstance,
 
2886
                          self.compute_api.associate_floating_ip,
 
2887
                          self.context,
 
2888
                          instance,
 
2889
                          address)
 
2890
        self.compute.terminate_instance(self.context, instance_uuid)
 
2891
 
 
2892
    def test_get(self):
 
2893
        """Test get instance"""
 
2894
        c = context.get_admin_context()
 
2895
        exp_instance = self._create_fake_instance()
 
2896
        expected = dict(exp_instance.iteritems())
 
2897
        expected['name'] = exp_instance['name']
 
2898
 
 
2899
        def fake_db_get(context, instance_uuid):
 
2900
            return exp_instance
 
2901
 
 
2902
        self.stubs.Set(db, 'instance_get_by_uuid', fake_db_get)
 
2903
 
 
2904
        instance = self.compute_api.get(c, exp_instance['uuid'])
 
2905
        self.assertEquals(expected, instance)
 
2906
 
 
2907
    def test_get_with_integer_id(self):
 
2908
        """Test get instance with an integer id"""
 
2909
        c = context.get_admin_context()
 
2910
        exp_instance = self._create_fake_instance()
 
2911
        expected = dict(exp_instance.iteritems())
 
2912
        expected['name'] = exp_instance['name']
 
2913
 
 
2914
        def fake_db_get(context, instance_id):
 
2915
            return exp_instance
 
2916
 
 
2917
        self.stubs.Set(db, 'instance_get', fake_db_get)
 
2918
 
 
2919
        instance = self.compute_api.get(c, exp_instance['id'])
 
2920
        self.assertEquals(expected, instance)
 
2921
 
 
2922
    def test_get_all_by_name_regexp(self):
 
2923
        """Test searching instances by name (display_name)"""
 
2924
        c = context.get_admin_context()
 
2925
        instance1 = self._create_fake_instance({'display_name': 'woot'})
 
2926
        instance2 = self._create_fake_instance({
 
2927
                'display_name': 'woo'})
 
2928
        instance3 = self._create_fake_instance({
 
2929
                'display_name': 'not-woot'})
 
2930
 
 
2931
        instances = self.compute_api.get_all(c,
 
2932
                search_opts={'name': 'woo.*'})
 
2933
        self.assertEqual(len(instances), 2)
 
2934
        instance_uuids = [instance['uuid'] for instance in instances]
 
2935
        self.assertTrue(instance1['uuid'] in instance_uuids)
 
2936
        self.assertTrue(instance2['uuid'] in instance_uuids)
 
2937
 
 
2938
        instances = self.compute_api.get_all(c,
 
2939
                search_opts={'name': 'woot.*'})
 
2940
        instance_uuids = [instance['uuid'] for instance in instances]
 
2941
        self.assertEqual(len(instances), 1)
 
2942
        self.assertTrue(instance1['uuid'] in instance_uuids)
 
2943
 
 
2944
        instances = self.compute_api.get_all(c,
 
2945
                search_opts={'name': '.*oot.*'})
 
2946
        self.assertEqual(len(instances), 2)
 
2947
        instance_uuids = [instance['uuid'] for instance in instances]
 
2948
        self.assertTrue(instance1['uuid'] in instance_uuids)
 
2949
        self.assertTrue(instance3['uuid'] in instance_uuids)
 
2950
 
 
2951
        instances = self.compute_api.get_all(c,
 
2952
                search_opts={'name': 'n.*'})
 
2953
        self.assertEqual(len(instances), 1)
 
2954
        instance_uuids = [instance['uuid'] for instance in instances]
 
2955
        self.assertTrue(instance3['uuid'] in instance_uuids)
 
2956
 
 
2957
        instances = self.compute_api.get_all(c,
 
2958
                search_opts={'name': 'noth.*'})
 
2959
        self.assertEqual(len(instances), 0)
 
2960
 
 
2961
        db.instance_destroy(c, instance1['id'])
 
2962
        db.instance_destroy(c, instance2['id'])
 
2963
        db.instance_destroy(c, instance3['id'])
 
2964
 
 
2965
    def test_get_all_by_instance_name_regexp(self):
 
2966
        """Test searching instances by name"""
 
2967
        self.flags(instance_name_template='instance-%d')
 
2968
 
 
2969
        c = context.get_admin_context()
 
2970
        instance1 = self._create_fake_instance()
 
2971
        instance2 = self._create_fake_instance({'id': 2})
 
2972
        instance3 = self._create_fake_instance({'id': 10})
 
2973
 
 
2974
        instances = self.compute_api.get_all(c,
 
2975
                search_opts={'instance_name': 'instance.*'})
 
2976
        self.assertEqual(len(instances), 3)
 
2977
 
 
2978
        instances = self.compute_api.get_all(c,
 
2979
                search_opts={'instance_name': '.*\-\d$'})
 
2980
        self.assertEqual(len(instances), 2)
 
2981
        instance_uuids = [instance['uuid'] for instance in instances]
 
2982
        self.assertTrue(instance1['uuid'] in instance_uuids)
 
2983
        self.assertTrue(instance2['uuid'] in instance_uuids)
 
2984
 
 
2985
        instances = self.compute_api.get_all(c,
 
2986
                search_opts={'instance_name': 'i.*2'})
 
2987
        self.assertEqual(len(instances), 1)
 
2988
        self.assertEqual(instances[0]['uuid'], instance2['uuid'])
 
2989
 
 
2990
        db.instance_destroy(c, instance1['id'])
 
2991
        db.instance_destroy(c, instance2['id'])
 
2992
        db.instance_destroy(c, instance3['id'])
 
2993
 
 
2994
    def test_get_all_by_multiple_options_at_once(self):
 
2995
        """Test searching by multiple options at once"""
 
2996
        c = context.get_admin_context()
 
2997
        network_manager = fake_network.FakeNetworkManager()
 
2998
        self.stubs.Set(self.compute_api.network_api,
 
2999
                       'get_instance_uuids_by_ip_filter',
 
3000
                       network_manager.get_instance_uuids_by_ip_filter)
 
3001
        self.stubs.Set(network_manager.db,
 
3002
                       'instance_get_id_to_uuid_mapping',
 
3003
                       db.instance_get_id_to_uuid_mapping)
 
3004
 
 
3005
        instance1 = self._create_fake_instance({'display_name': 'woot',
 
3006
                                                'id': 0})
 
3007
        instance2 = self._create_fake_instance({
 
3008
                'display_name': 'woo',
 
3009
                'id': 20})
 
3010
        instance3 = self._create_fake_instance({
 
3011
                'display_name': 'not-woot',
 
3012
                'id': 30})
 
3013
 
 
3014
        # ip ends up matching 2nd octet here.. so all 3 match ip
 
3015
        # but 'name' only matches one
 
3016
        instances = self.compute_api.get_all(c,
 
3017
                search_opts={'ip': '.*\.1', 'name': 'not.*'})
 
3018
        self.assertEqual(len(instances), 1)
 
3019
        self.assertEqual(instances[0]['uuid'], instance3['uuid'])
 
3020
 
 
3021
        # ip ends up matching any ip with a '1' in the last octet..
 
3022
        # so instance 1 and 3.. but name should only match #1
 
3023
        # but 'name' only matches one
 
3024
        instances = self.compute_api.get_all(c,
 
3025
                search_opts={'ip': '.*\.1$', 'name': '^woo.*'})
 
3026
        self.assertEqual(len(instances), 1)
 
3027
        self.assertEqual(instances[0]['uuid'], instance1['uuid'])
 
3028
 
 
3029
        # same as above but no match on name (name matches instance1
 
3030
        # but the ip query doesn't
 
3031
        instances = self.compute_api.get_all(c,
 
3032
                search_opts={'ip': '.*\.2$', 'name': '^woot.*'})
 
3033
        self.assertEqual(len(instances), 0)
 
3034
 
 
3035
        # ip matches all 3... ipv6 matches #2+#3...name matches #3
 
3036
        instances = self.compute_api.get_all(c,
 
3037
                search_opts={'ip': '.*\.1',
 
3038
                             'name': 'not.*',
 
3039
                             'ip6': '^.*12.*34.*'})
 
3040
        self.assertEqual(len(instances), 1)
 
3041
        self.assertEqual(instances[0]['uuid'], instance3['uuid'])
 
3042
 
 
3043
        db.instance_destroy(c, instance1['id'])
 
3044
        db.instance_destroy(c, instance2['id'])
 
3045
        db.instance_destroy(c, instance3['id'])
 
3046
 
 
3047
    def test_get_all_by_image(self):
 
3048
        """Test searching instances by image"""
 
3049
 
 
3050
        c = context.get_admin_context()
 
3051
        instance1 = self._create_fake_instance({'image_ref': '1234'})
 
3052
        instance2 = self._create_fake_instance({'image_ref': '4567'})
 
3053
        instance3 = self._create_fake_instance({'image_ref': '4567'})
 
3054
 
 
3055
        instances = self.compute_api.get_all(c, search_opts={'image': '123'})
 
3056
        self.assertEqual(len(instances), 0)
 
3057
 
 
3058
        instances = self.compute_api.get_all(c, search_opts={'image': '1234'})
 
3059
        self.assertEqual(len(instances), 1)
 
3060
        self.assertEqual(instances[0]['uuid'], instance1['uuid'])
 
3061
 
 
3062
        instances = self.compute_api.get_all(c, search_opts={'image': '4567'})
 
3063
        self.assertEqual(len(instances), 2)
 
3064
        instance_uuids = [instance['uuid'] for instance in instances]
 
3065
        self.assertTrue(instance2['uuid'] in instance_uuids)
 
3066
        self.assertTrue(instance3['uuid'] in instance_uuids)
 
3067
 
 
3068
        # Test passing a list as search arg
 
3069
        instances = self.compute_api.get_all(c,
 
3070
                                    search_opts={'image': ['1234', '4567']})
 
3071
        self.assertEqual(len(instances), 3)
 
3072
 
 
3073
        db.instance_destroy(c, instance1['id'])
 
3074
        db.instance_destroy(c, instance2['id'])
 
3075
        db.instance_destroy(c, instance3['id'])
 
3076
 
 
3077
    def test_get_all_by_flavor(self):
 
3078
        """Test searching instances by image"""
 
3079
 
 
3080
        c = context.get_admin_context()
 
3081
        instance1 = self._create_fake_instance({'instance_type_id': 1})
 
3082
        instance2 = self._create_fake_instance({'instance_type_id': 2})
 
3083
        instance3 = self._create_fake_instance({'instance_type_id': 2})
 
3084
 
 
3085
        # NOTE(comstud): Migrations set up the instance_types table
 
3086
        # for us.  Therefore, we assume the following is true for
 
3087
        # these tests:
 
3088
        # instance_type_id 1 == flavor 3
 
3089
        # instance_type_id 2 == flavor 1
 
3090
        # instance_type_id 3 == flavor 4
 
3091
        # instance_type_id 4 == flavor 5
 
3092
        # instance_type_id 5 == flavor 2
 
3093
 
 
3094
        instances = self.compute_api.get_all(c,
 
3095
                search_opts={'flavor': 5})
 
3096
        self.assertEqual(len(instances), 0)
 
3097
 
 
3098
        # ensure unknown filter maps to an empty list, not an exception
 
3099
        instances = self.compute_api.get_all(c, search_opts={'flavor': 99})
 
3100
        self.assertEqual(instances, [])
 
3101
 
 
3102
        instances = self.compute_api.get_all(c, search_opts={'flavor': 3})
 
3103
        self.assertEqual(len(instances), 1)
 
3104
        self.assertEqual(instances[0]['id'], instance1['id'])
 
3105
 
 
3106
        instances = self.compute_api.get_all(c, search_opts={'flavor': 1})
 
3107
        self.assertEqual(len(instances), 2)
 
3108
        instance_uuids = [instance['uuid'] for instance in instances]
 
3109
        self.assertTrue(instance2['uuid'] in instance_uuids)
 
3110
        self.assertTrue(instance3['uuid'] in instance_uuids)
 
3111
 
 
3112
        db.instance_destroy(c, instance1['id'])
 
3113
        db.instance_destroy(c, instance2['id'])
 
3114
        db.instance_destroy(c, instance3['id'])
 
3115
 
 
3116
    def test_get_all_by_state(self):
 
3117
        """Test searching instances by state"""
 
3118
 
 
3119
        c = context.get_admin_context()
 
3120
        instance1 = self._create_fake_instance({
 
3121
            'power_state': power_state.SHUTDOWN,
 
3122
        })
 
3123
        instance2 = self._create_fake_instance({
 
3124
            'power_state': power_state.RUNNING,
 
3125
        })
 
3126
        instance3 = self._create_fake_instance({
 
3127
            'power_state': power_state.RUNNING,
 
3128
        })
 
3129
 
 
3130
        instances = self.compute_api.get_all(c,
 
3131
                search_opts={'power_state': power_state.SUSPENDED})
 
3132
        self.assertEqual(len(instances), 0)
 
3133
 
 
3134
        instances = self.compute_api.get_all(c,
 
3135
                search_opts={'power_state': power_state.SHUTDOWN})
 
3136
        self.assertEqual(len(instances), 1)
 
3137
        self.assertEqual(instances[0]['uuid'], instance1['uuid'])
 
3138
 
 
3139
        instances = self.compute_api.get_all(c,
 
3140
                search_opts={'power_state': power_state.RUNNING})
 
3141
        self.assertEqual(len(instances), 2)
 
3142
        instance_uuids = [instance['uuid'] for instance in instances]
 
3143
        self.assertTrue(instance2['uuid'] in instance_uuids)
 
3144
        self.assertTrue(instance3['uuid'] in instance_uuids)
 
3145
 
 
3146
        # Test passing a list as search arg
 
3147
        instances = self.compute_api.get_all(c,
 
3148
                search_opts={'power_state': [power_state.SHUTDOWN,
 
3149
                        power_state.RUNNING]})
 
3150
        self.assertEqual(len(instances), 3)
 
3151
 
 
3152
        db.instance_destroy(c, instance1['id'])
 
3153
        db.instance_destroy(c, instance2['id'])
 
3154
        db.instance_destroy(c, instance3['id'])
 
3155
 
 
3156
    def test_get_all_by_metadata(self):
 
3157
        """Test searching instances by metadata"""
 
3158
 
 
3159
        c = context.get_admin_context()
 
3160
        instance0 = self._create_fake_instance()
 
3161
        instance1 = self._create_fake_instance({
 
3162
                'metadata': {'key1': 'value1'}})
 
3163
        instance2 = self._create_fake_instance({
 
3164
                'metadata': {'key2': 'value2'}})
 
3165
        instance3 = self._create_fake_instance({
 
3166
                'metadata': {'key3': 'value3'}})
 
3167
        instance4 = self._create_fake_instance({
 
3168
                'metadata': {'key3': 'value3',
 
3169
                             'key4': 'value4'}})
 
3170
 
 
3171
        # get all instances
 
3172
        instances = self.compute_api.get_all(c,
 
3173
                search_opts={'metadata': {}})
 
3174
        self.assertEqual(len(instances), 5)
 
3175
 
 
3176
        # wrong key/value combination
 
3177
        instances = self.compute_api.get_all(c,
 
3178
                search_opts={'metadata': {'key1': 'value3'}})
 
3179
        self.assertEqual(len(instances), 0)
 
3180
 
 
3181
        # non-existing keys
 
3182
        instances = self.compute_api.get_all(c,
 
3183
                search_opts={'metadata': {'key5': 'value1'}})
 
3184
        self.assertEqual(len(instances), 0)
 
3185
 
 
3186
        # find existing instance
 
3187
        instances = self.compute_api.get_all(c,
 
3188
                search_opts={'metadata': {'key2': 'value2'}})
 
3189
        self.assertEqual(len(instances), 1)
 
3190
        self.assertEqual(instances[0]['uuid'], instance2['uuid'])
 
3191
 
 
3192
        instances = self.compute_api.get_all(c,
 
3193
                search_opts={'metadata': {'key3': 'value3'}})
 
3194
        self.assertEqual(len(instances), 2)
 
3195
        instance_uuids = [instance['uuid'] for instance in instances]
 
3196
        self.assertTrue(instance3['uuid'] in instance_uuids)
 
3197
        self.assertTrue(instance4['uuid'] in instance_uuids)
 
3198
 
 
3199
        # multiple criterias as a dict
 
3200
        instances = self.compute_api.get_all(c,
 
3201
                search_opts={'metadata': {'key3': 'value3',
 
3202
                                          'key4': 'value4'}})
 
3203
        self.assertEqual(len(instances), 1)
 
3204
        self.assertEqual(instances[0]['uuid'], instance4['uuid'])
 
3205
 
 
3206
        # multiple criterias as a list
 
3207
        instances = self.compute_api.get_all(c,
 
3208
                search_opts={'metadata': [{'key4': 'value4'},
 
3209
                                          {'key3': 'value3'}]})
 
3210
        self.assertEqual(len(instances), 1)
 
3211
        self.assertEqual(instances[0]['uuid'], instance4['uuid'])
 
3212
 
 
3213
        db.instance_destroy(c, instance0['id'])
 
3214
        db.instance_destroy(c, instance1['id'])
 
3215
        db.instance_destroy(c, instance2['id'])
 
3216
        db.instance_destroy(c, instance3['id'])
 
3217
        db.instance_destroy(c, instance4['id'])
 
3218
 
 
3219
    def test_instance_metadata(self):
 
3220
        """Test searching instances by state"""
 
3221
        _context = context.get_admin_context()
 
3222
        instance = self._create_fake_instance({'metadata': {'key1': 'value1'}})
 
3223
 
 
3224
        metadata = self.compute_api.get_instance_metadata(_context, instance)
 
3225
        self.assertEqual(metadata, {'key1': 'value1'})
 
3226
 
 
3227
        self.compute_api.update_instance_metadata(_context, instance,
 
3228
                                                  {'key2': 'value2'})
 
3229
        metadata = self.compute_api.get_instance_metadata(_context, instance)
 
3230
        self.assertEqual(metadata, {'key1': 'value1', 'key2': 'value2'})
 
3231
 
 
3232
        new_metadata = {'key2': 'bah', 'key3': 'value3'}
 
3233
        self.compute_api.update_instance_metadata(_context, instance,
 
3234
                                                  new_metadata, delete=True)
 
3235
        metadata = self.compute_api.get_instance_metadata(_context, instance)
 
3236
        self.assertEqual(metadata, new_metadata)
 
3237
 
 
3238
        self.compute_api.delete_instance_metadata(_context, instance, 'key2')
 
3239
        metadata = self.compute_api.get_instance_metadata(_context, instance)
 
3240
        self.assertEqual(metadata, {'key3': 'value3'})
 
3241
 
 
3242
        db.instance_destroy(_context, instance['id'])
 
3243
 
 
3244
    def test_get_instance_faults(self):
 
3245
        """Get an instances latest fault"""
 
3246
        instance = self._create_fake_instance()
 
3247
 
 
3248
        fault_fixture = {
 
3249
                'code': 404,
 
3250
                'instance_uuid': instance['uuid'],
 
3251
                'message': "HTTPNotFound",
 
3252
                'details': "Stock details for test",
 
3253
                'created_at': datetime.datetime(2010, 10, 10, 12, 0, 0),
 
3254
            }
 
3255
 
 
3256
        def return_fault(_ctxt, instance_uuids):
 
3257
            return dict.fromkeys(instance_uuids, [fault_fixture])
 
3258
 
 
3259
        self.stubs.Set(nova.db,
 
3260
                       'instance_fault_get_by_instance_uuids',
 
3261
                       return_fault)
 
3262
 
 
3263
        _context = context.get_admin_context()
 
3264
        output = self.compute_api.get_instance_faults(_context, [instance])
 
3265
        expected = {instance['uuid']: [fault_fixture]}
 
3266
        self.assertEqual(output, expected)
 
3267
 
 
3268
        db.instance_destroy(_context, instance['id'])
 
3269
 
 
3270
    @staticmethod
 
3271
    def _parse_db_block_device_mapping(bdm_ref):
 
3272
        attr_list = ('delete_on_termination', 'device_name', 'no_device',
 
3273
                     'virtual_name', 'volume_id', 'volume_size', 'snapshot_id')
 
3274
        bdm = {}
 
3275
        for attr in attr_list:
 
3276
            val = bdm_ref.get(attr, None)
 
3277
            if val:
 
3278
                bdm[attr] = val
 
3279
 
 
3280
        return bdm
 
3281
 
 
3282
    def test_update_block_device_mapping(self):
 
3283
        swap_size = 1
 
3284
        instance_type = {'swap': swap_size}
 
3285
        instance = self._create_fake_instance()
 
3286
        mappings = [
 
3287
                {'virtual': 'ami', 'device': 'sda1'},
 
3288
                {'virtual': 'root', 'device': '/dev/sda1'},
 
3289
 
 
3290
                {'virtual': 'swap', 'device': 'sdb4'},
 
3291
                {'virtual': 'swap', 'device': 'sdb3'},
 
3292
                {'virtual': 'swap', 'device': 'sdb2'},
 
3293
                {'virtual': 'swap', 'device': 'sdb1'},
 
3294
 
 
3295
                {'virtual': 'ephemeral0', 'device': 'sdc1'},
 
3296
                {'virtual': 'ephemeral1', 'device': 'sdc2'},
 
3297
                {'virtual': 'ephemeral2', 'device': 'sdc3'}]
 
3298
        block_device_mapping = [
 
3299
                # root
 
3300
                {'device_name': '/dev/sda1',
 
3301
                 'snapshot_id': '00000000-aaaa-bbbb-cccc-000000000000',
 
3302
                 'delete_on_termination': False},
 
3303
 
 
3304
 
 
3305
                # overwrite swap
 
3306
                {'device_name': '/dev/sdb2',
 
3307
                 'snapshot_id': '11111111-aaaa-bbbb-cccc-111111111111',
 
3308
                 'delete_on_termination': False},
 
3309
                {'device_name': '/dev/sdb3',
 
3310
                 'snapshot_id': '22222222-aaaa-bbbb-cccc-222222222222'},
 
3311
                {'device_name': '/dev/sdb4',
 
3312
                 'no_device': True},
 
3313
 
 
3314
                # overwrite ephemeral
 
3315
                {'device_name': '/dev/sdc2',
 
3316
                 'snapshot_id': '33333333-aaaa-bbbb-cccc-333333333333',
 
3317
                 'delete_on_termination': False},
 
3318
                {'device_name': '/dev/sdc3',
 
3319
                 'snapshot_id': '44444444-aaaa-bbbb-cccc-444444444444'},
 
3320
                {'device_name': '/dev/sdc4',
 
3321
                 'no_device': True},
 
3322
 
 
3323
                # volume
 
3324
                {'device_name': '/dev/sdd1',
 
3325
                 'snapshot_id': '55555555-aaaa-bbbb-cccc-555555555555',
 
3326
                 'delete_on_termination': False},
 
3327
                {'device_name': '/dev/sdd2',
 
3328
                 'snapshot_id': '66666666-aaaa-bbbb-cccc-666666666666'},
 
3329
                {'device_name': '/dev/sdd3',
 
3330
                 'snapshot_id': '77777777-aaaa-bbbb-cccc-777777777777'},
 
3331
                {'device_name': '/dev/sdd4',
 
3332
                 'no_device': True}]
 
3333
 
 
3334
        self.compute_api._update_image_block_device_mapping(
 
3335
            self.context, instance_type, instance['uuid'], mappings)
 
3336
 
 
3337
        bdms = [self._parse_db_block_device_mapping(bdm_ref)
 
3338
                for bdm_ref in db.block_device_mapping_get_all_by_instance(
 
3339
                    self.context, instance['uuid'])]
 
3340
        expected_result = [
 
3341
            {'virtual_name': 'swap', 'device_name': '/dev/sdb1',
 
3342
             'volume_size': swap_size},
 
3343
            {'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'},
 
3344
 
 
3345
            # NOTE(yamahata): ATM only ephemeral0 is supported.
 
3346
            #                 they're ignored for now
 
3347
            #{'virtual_name': 'ephemeral1', 'device_name': '/dev/sdc2'},
 
3348
            #{'virtual_name': 'ephemeral2', 'device_name': '/dev/sdc3'}
 
3349
            ]
 
3350
        bdms.sort()
 
3351
        expected_result.sort()
 
3352
        self.assertDictListMatch(bdms, expected_result)
 
3353
 
 
3354
        self.compute_api._update_block_device_mapping(
 
3355
            self.context, instance_types.get_default_instance_type(),
 
3356
            instance['uuid'], block_device_mapping)
 
3357
        bdms = [self._parse_db_block_device_mapping(bdm_ref)
 
3358
                for bdm_ref in db.block_device_mapping_get_all_by_instance(
 
3359
                    self.context, instance['uuid'])]
 
3360
        expected_result = [
 
3361
            {'snapshot_id': '00000000-aaaa-bbbb-cccc-000000000000',
 
3362
               'device_name': '/dev/sda1'},
 
3363
 
 
3364
            {'virtual_name': 'swap', 'device_name': '/dev/sdb1',
 
3365
             'volume_size': swap_size},
 
3366
            {'snapshot_id': '11111111-aaaa-bbbb-cccc-111111111111',
 
3367
               'device_name': '/dev/sdb2'},
 
3368
            {'snapshot_id': '22222222-aaaa-bbbb-cccc-222222222222',
 
3369
                'device_name': '/dev/sdb3'},
 
3370
            {'no_device': True, 'device_name': '/dev/sdb4'},
 
3371
 
 
3372
            {'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'},
 
3373
            {'snapshot_id': '33333333-aaaa-bbbb-cccc-333333333333',
 
3374
                'device_name': '/dev/sdc2'},
 
3375
            {'snapshot_id': '44444444-aaaa-bbbb-cccc-444444444444',
 
3376
                'device_name': '/dev/sdc3'},
 
3377
            {'no_device': True, 'device_name': '/dev/sdc4'},
 
3378
 
 
3379
            {'snapshot_id': '55555555-aaaa-bbbb-cccc-555555555555',
 
3380
                'device_name': '/dev/sdd1'},
 
3381
            {'snapshot_id': '66666666-aaaa-bbbb-cccc-666666666666',
 
3382
                'device_name': '/dev/sdd2'},
 
3383
            {'snapshot_id': '77777777-aaaa-bbbb-cccc-777777777777',
 
3384
                'device_name': '/dev/sdd3'},
 
3385
            {'no_device': True, 'device_name': '/dev/sdd4'}]
 
3386
        bdms.sort()
 
3387
        expected_result.sort()
 
3388
        self.assertDictListMatch(bdms, expected_result)
 
3389
 
 
3390
        for bdm in db.block_device_mapping_get_all_by_instance(
 
3391
            self.context, instance['uuid']):
 
3392
            db.block_device_mapping_destroy(self.context, bdm['id'])
 
3393
        instance = db.instance_get_by_uuid(self.context, instance['uuid'])
 
3394
        self.compute.terminate_instance(self.context, instance['uuid'])
 
3395
 
 
3396
    def test_volume_size(self):
 
3397
        ephemeral_size = 2
 
3398
        swap_size = 3
 
3399
        inst_type = {'ephemeral_gb': ephemeral_size, 'swap': swap_size}
 
3400
        self.assertEqual(self.compute_api._volume_size(inst_type,
 
3401
                                                       'ephemeral0'),
 
3402
                         ephemeral_size)
 
3403
        self.assertEqual(self.compute_api._volume_size(inst_type,
 
3404
                                                       'ephemeral1'),
 
3405
                         0)
 
3406
        self.assertEqual(self.compute_api._volume_size(inst_type,
 
3407
                                                       'swap'),
 
3408
                         swap_size)
 
3409
 
 
3410
    def test_reservation_id_one_instance(self):
 
3411
        """Verify building an instance has a reservation_id that
 
3412
        matches return value from create"""
 
3413
        (refs, resv_id) = self.compute_api.create(self.context,
 
3414
                instance_types.get_default_instance_type(), None)
 
3415
        try:
 
3416
            self.assertEqual(len(refs), 1)
 
3417
            self.assertEqual(refs[0]['reservation_id'], resv_id)
 
3418
        finally:
 
3419
            db.instance_destroy(self.context, refs[0]['id'])
 
3420
 
 
3421
    def test_reservation_ids_two_instances(self):
 
3422
        """Verify building 2 instances at once results in a
 
3423
        reservation_id being returned equal to reservation id set
 
3424
        in both instances
 
3425
        """
 
3426
        (refs, resv_id) = self.compute_api.create(self.context,
 
3427
                instance_types.get_default_instance_type(), None,
 
3428
                min_count=2, max_count=2)
 
3429
        try:
 
3430
            self.assertEqual(len(refs), 2)
 
3431
            self.assertNotEqual(resv_id, None)
 
3432
        finally:
 
3433
            for instance in refs:
 
3434
                self.assertEqual(instance['reservation_id'], resv_id)
 
3435
 
 
3436
        db.instance_destroy(self.context, refs[0]['id'])
 
3437
 
 
3438
    def test_instance_name_template(self):
 
3439
        """Test the instance_name template"""
 
3440
        self.flags(instance_name_template='instance-%d')
 
3441
        i_ref = self._create_fake_instance()
 
3442
        self.assertEqual(i_ref['name'], 'instance-%d' % i_ref['id'])
 
3443
        db.instance_destroy(self.context, i_ref['id'])
 
3444
 
 
3445
        self.flags(instance_name_template='instance-%(uuid)s')
 
3446
        i_ref = self._create_fake_instance()
 
3447
        self.assertEqual(i_ref['name'], 'instance-%s' % i_ref['uuid'])
 
3448
        db.instance_destroy(self.context, i_ref['id'])
 
3449
 
 
3450
        self.flags(instance_name_template='%(id)d-%(uuid)s')
 
3451
        i_ref = self._create_fake_instance()
 
3452
        self.assertEqual(i_ref['name'], '%d-%s' %
 
3453
                (i_ref['id'], i_ref['uuid']))
 
3454
        db.instance_destroy(self.context, i_ref['id'])
 
3455
 
 
3456
        # not allowed.. default is uuid
 
3457
        self.flags(instance_name_template='%(name)s')
 
3458
        i_ref = self._create_fake_instance()
 
3459
        self.assertEqual(i_ref['name'], i_ref['uuid'])
 
3460
        db.instance_destroy(self.context, i_ref['id'])
 
3461
 
 
3462
    def test_add_remove_fixed_ip(self):
 
3463
        instance = self._create_fake_instance()
 
3464
        self.compute_api.add_fixed_ip(self.context, instance, '1')
 
3465
        self.compute_api.remove_fixed_ip(self.context, instance, '192.168.1.1')
 
3466
        self.compute_api.delete(self.context, instance)
 
3467
 
 
3468
    def test_attach_volume_invalid(self):
 
3469
        self.assertRaises(exception.InvalidDevicePath,
 
3470
                self.compute_api.attach_volume,
 
3471
                self.context,
 
3472
                None,
 
3473
                None,
 
3474
                '/dev/invalid')
 
3475
 
 
3476
    def test_vnc_console(self):
 
3477
        """Make sure we can a vnc console for an instance."""
 
3478
 
 
3479
        fake_instance = {'uuid': 'fake_uuid',
 
3480
                         'host': 'fake_compute_host'}
 
3481
        fake_console_type = "novnc"
 
3482
        fake_connect_info = {'token': 'fake_token',
 
3483
                             'console_type': fake_console_type,
 
3484
                             'host': 'fake_console_host',
 
3485
                             'port': 'fake_console_port',
 
3486
                             'internal_access_path': 'fake_access_path'}
 
3487
        fake_connect_info2 = copy.deepcopy(fake_connect_info)
 
3488
        fake_connect_info2['access_url'] = 'fake_console_url'
 
3489
 
 
3490
        self.mox.StubOutWithMock(rpc, 'call')
 
3491
 
 
3492
        rpc_msg1 = {'method': 'get_vnc_console',
 
3493
                    'args': {'instance_uuid': fake_instance['uuid'],
 
3494
                             'console_type': fake_console_type},
 
3495
                   'version': compute_rpcapi.ComputeAPI.RPC_API_VERSION}
 
3496
        rpc_msg2 = {'method': 'authorize_console',
 
3497
                    'args': fake_connect_info,
 
3498
                    'version': '1.0'}
 
3499
 
 
3500
        rpc.call(self.context, 'compute.%s' % fake_instance['host'],
 
3501
                rpc_msg1, None).AndReturn(fake_connect_info2)
 
3502
        rpc.call(self.context, FLAGS.consoleauth_topic,
 
3503
                rpc_msg2, None).AndReturn(None)
 
3504
 
 
3505
        self.mox.ReplayAll()
 
3506
 
 
3507
        console = self.compute_api.get_vnc_console(self.context,
 
3508
                fake_instance, fake_console_type)
 
3509
        self.assertEqual(console, {'url': 'fake_console_url'})
 
3510
 
 
3511
    def test_console_output(self):
 
3512
        fake_instance = {'uuid': 'fake_uuid',
 
3513
                         'host': 'fake_compute_host'}
 
3514
        fake_tail_length = 699
 
3515
        fake_console_output = 'fake console output'
 
3516
 
 
3517
        self.mox.StubOutWithMock(rpc, 'call')
 
3518
 
 
3519
        rpc_msg = {'method': 'get_console_output',
 
3520
                   'args': {'instance_uuid': fake_instance['uuid'],
 
3521
                            'tail_length': fake_tail_length},
 
3522
                   'version': compute_rpcapi.ComputeAPI.RPC_API_VERSION}
 
3523
        rpc.call(self.context, 'compute.%s' % fake_instance['host'],
 
3524
                rpc_msg, None).AndReturn(fake_console_output)
 
3525
 
 
3526
        self.mox.ReplayAll()
 
3527
 
 
3528
        output = self.compute_api.get_console_output(self.context,
 
3529
                fake_instance, tail_length=fake_tail_length)
 
3530
        self.assertEqual(output, fake_console_output)
 
3531
 
 
3532
    def test_attach_volume(self):
 
3533
        """Ensure instance can be soft rebooted"""
 
3534
 
 
3535
        def fake_check_attach(*args, **kwargs):
 
3536
            pass
 
3537
 
 
3538
        def fake_reserve_volume(*args, **kwargs):
 
3539
            pass
 
3540
 
 
3541
        def fake_volume_get(self, context, volume_id):
 
3542
            return {'id': volume_id}
 
3543
 
 
3544
        self.stubs.Set(nova.volume.api.API, 'get', fake_volume_get)
 
3545
        self.stubs.Set(nova.volume.api.API, 'check_attach', fake_check_attach)
 
3546
        self.stubs.Set(nova.volume.api.API, 'reserve_volume',
 
3547
                       fake_reserve_volume)
 
3548
        instance = self._create_fake_instance()
 
3549
        self.compute_api.attach_volume(self.context, instance, 1, '/dev/vdb')
 
3550
 
 
3551
    def test_inject_network_info(self):
 
3552
        instance = self._create_fake_instance()
 
3553
        self.compute.run_instance(self.context, instance['uuid'])
 
3554
        instance = self.compute_api.get(self.context, instance['uuid'])
 
3555
        self.compute_api.inject_network_info(self.context, instance)
 
3556
        self.compute_api.delete(self.context, instance)
 
3557
 
 
3558
    def test_reset_network(self):
 
3559
        instance = self._create_fake_instance()
 
3560
        self.compute.run_instance(self.context, instance['uuid'])
 
3561
        instance = self.compute_api.get(self.context, instance['uuid'])
 
3562
        self.compute_api.reset_network(self.context, instance)
 
3563
 
 
3564
    def test_lock(self):
 
3565
        instance = self._create_fake_instance()
 
3566
        self.compute_api.lock(self.context, instance)
 
3567
        self.compute_api.delete(self.context, instance)
 
3568
 
 
3569
    def test_unlock(self):
 
3570
        instance = self._create_fake_instance()
 
3571
        self.compute_api.unlock(self.context, instance)
 
3572
        self.compute_api.delete(self.context, instance)
 
3573
 
 
3574
    def test_get_lock(self):
 
3575
        instance = self._create_fake_instance()
 
3576
        self.assertFalse(self.compute_api.get_lock(self.context, instance))
 
3577
        db.instance_update(self.context, instance['uuid'], {'locked': True})
 
3578
        self.assertTrue(self.compute_api.get_lock(self.context, instance))
 
3579
 
 
3580
    def test_add_remove_security_group(self):
 
3581
        instance = self._create_fake_instance()
 
3582
 
 
3583
        self.compute.run_instance(self.context, instance['uuid'])
 
3584
        instance = self.compute_api.get(self.context, instance['uuid'])
 
3585
        security_group_name = self._create_group()['name']
 
3586
        self.compute_api.add_security_group(self.context,
 
3587
                                            instance,
 
3588
                                            security_group_name)
 
3589
        self.compute_api.remove_security_group(self.context,
 
3590
                                               instance,
 
3591
                                               security_group_name)
 
3592
 
 
3593
    def test_get_diagnostics(self):
 
3594
        instance = self._create_fake_instance()
 
3595
        self.compute_api.get_diagnostics(self.context, instance)
 
3596
        self.compute_api.delete(self.context, instance)
 
3597
 
 
3598
    def test_inject_file(self):
 
3599
        """Ensure we can write a file to an instance"""
 
3600
        instance = self._create_fake_instance()
 
3601
        self.compute_api.inject_file(self.context, instance,
 
3602
                                     "/tmp/test", "File Contents")
 
3603
        db.instance_destroy(self.context, instance['id'])
 
3604
 
 
3605
 
 
3606
def fake_rpc_method(context, topic, msg, do_cast=True):
 
3607
    pass
 
3608
 
 
3609
 
 
3610
def _create_service_entries(context, values={'avail_zone1': ['fake_host1',
 
3611
                                                             'fake_host2'],
 
3612
                                             'avail_zone2': ['fake_host3'], }):
 
3613
    for avail_zone, hosts in values.iteritems():
 
3614
        for host in hosts:
 
3615
            db.service_create(context,
 
3616
                              {'host': host,
 
3617
                               'binary': 'nova-compute',
 
3618
                               'topic': 'compute',
 
3619
                               'report_count': 0,
 
3620
                               'availability_zone': avail_zone})
 
3621
    return values
 
3622
 
 
3623
 
 
3624
class ComputeAPIAggrTestCase(test.TestCase):
 
3625
    """This is for unit coverage of aggregate-related methods
 
3626
    defined in nova.compute.api."""
 
3627
 
 
3628
    def setUp(self):
 
3629
        super(ComputeAPIAggrTestCase, self).setUp()
 
3630
        self.api = compute_api.AggregateAPI()
 
3631
        self.context = context.get_admin_context()
 
3632
        self.stubs.Set(rpc, 'call', fake_rpc_method)
 
3633
        self.stubs.Set(rpc, 'cast', fake_rpc_method)
 
3634
 
 
3635
    def test_create_invalid_availability_zone(self):
 
3636
        """Ensure InvalidAggregateAction is raised with wrong avail_zone."""
 
3637
        self.assertRaises(exception.InvalidAggregateAction,
 
3638
                          self.api.create_aggregate,
 
3639
                          self.context, 'fake_aggr', 'fake_avail_zone')
 
3640
 
 
3641
    def test_update_aggregate_metadata(self):
 
3642
        _create_service_entries(self.context, {'fake_zone': ['fake_host']})
 
3643
        aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
 
3644
                                         'fake_zone')
 
3645
        metadata = {'foo_key1': 'foo_value1',
 
3646
                    'foo_key2': 'foo_value2', }
 
3647
        aggr = self.api.update_aggregate_metadata(self.context, aggr['id'],
 
3648
                                                  metadata)
 
3649
        metadata['foo_key1'] = None
 
3650
        expected = self.api.update_aggregate_metadata(self.context,
 
3651
                                             aggr['id'], metadata)
 
3652
        self.assertDictMatch(expected['metadata'], {'foo_key2': 'foo_value2'})
 
3653
 
 
3654
    def test_delete_aggregate(self):
 
3655
        """Ensure we can delete an aggregate."""
 
3656
        _create_service_entries(self.context, {'fake_zone': ['fake_host']})
 
3657
        aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
 
3658
                                         'fake_zone')
 
3659
        self.api.delete_aggregate(self.context, aggr['id'])
 
3660
        expected = db.aggregate_get(self.context.elevated(read_deleted='yes'),
 
3661
                                    aggr['id'])
 
3662
        self.assertNotEqual(aggr['operational_state'],
 
3663
                            expected['operational_state'])
 
3664
 
 
3665
    def test_delete_non_empty_aggregate(self):
 
3666
        """Ensure InvalidAggregateAction is raised when non empty aggregate."""
 
3667
        _create_service_entries(self.context,
 
3668
                                {'fake_availability_zone': ['fake_host']})
 
3669
        aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
 
3670
                                         'fake_availability_zone')
 
3671
        self.api.add_host_to_aggregate(self.context, aggr['id'], 'fake_host')
 
3672
        self.assertRaises(exception.InvalidAggregateAction,
 
3673
                          self.api.delete_aggregate, self.context, aggr['id'])
 
3674
 
 
3675
    def test_add_host_to_aggregate(self):
 
3676
        """Ensure we can add a host to an aggregate."""
 
3677
        values = _create_service_entries(self.context)
 
3678
        fake_zone = values.keys()[0]
 
3679
        fake_host = values[fake_zone][0]
 
3680
        aggr = self.api.create_aggregate(self.context,
 
3681
                                         'fake_aggregate', fake_zone)
 
3682
        aggr = self.api.add_host_to_aggregate(self.context,
 
3683
                                              aggr['id'], fake_host)
 
3684
        self.assertEqual(aggr['operational_state'], aggregate_states.CHANGING)
 
3685
 
 
3686
    def test_add_host_to_aggregate_multiple(self):
 
3687
        """Ensure we can add multiple hosts to an aggregate."""
 
3688
        values = _create_service_entries(self.context)
 
3689
        fake_zone = values.keys()[0]
 
3690
        aggr = self.api.create_aggregate(self.context,
 
3691
                                         'fake_aggregate', fake_zone)
 
3692
        # let's mock the fact that the aggregate is active already!
 
3693
        status = {'operational_state': aggregate_states.ACTIVE}
 
3694
        db.aggregate_update(self.context, aggr['id'], status)
 
3695
        for host in values[fake_zone]:
 
3696
            aggr = self.api.add_host_to_aggregate(self.context,
 
3697
                                                  aggr['id'], host)
 
3698
        self.assertEqual(len(aggr['hosts']), len(values[fake_zone]))
 
3699
        self.assertEqual(aggr['operational_state'],
 
3700
                         aggregate_states.ACTIVE)
 
3701
 
 
3702
    def test_add_host_to_aggregate_invalid_changing_status(self):
 
3703
        """Ensure InvalidAggregateAction is raised when adding host while
 
3704
        aggregate is not ready."""
 
3705
        values = _create_service_entries(self.context)
 
3706
        fake_zone = values.keys()[0]
 
3707
        fake_host = values[fake_zone][0]
 
3708
        aggr = self.api.create_aggregate(self.context,
 
3709
                                         'fake_aggregate', fake_zone)
 
3710
        aggr = self.api.add_host_to_aggregate(self.context,
 
3711
                                              aggr['id'], fake_host)
 
3712
        self.assertEqual(aggr['operational_state'],
 
3713
                             aggregate_states.CHANGING)
 
3714
        self.assertRaises(exception.InvalidAggregateAction,
 
3715
                          self.api.add_host_to_aggregate, self.context,
 
3716
                          aggr['id'], fake_host)
 
3717
 
 
3718
    def test_add_host_to_aggregate_invalid_dismissed_status(self):
 
3719
        """Ensure InvalidAggregateAction is raised when aggregate is
 
3720
        deleted."""
 
3721
        _create_service_entries(self.context, {'fake_zone': ['fake_host']})
 
3722
        aggr = self.api.create_aggregate(self.context,
 
3723
                                         'fake_aggregate', 'fake_zone')
 
3724
        # let's mock the fact that the aggregate is dismissed!
 
3725
        status = {'operational_state': aggregate_states.DISMISSED}
 
3726
        db.aggregate_update(self.context, aggr['id'], status)
 
3727
        self.assertRaises(exception.InvalidAggregateAction,
 
3728
                          self.api.add_host_to_aggregate, self.context,
 
3729
                          aggr['id'], 'fake_host')
 
3730
 
 
3731
    def test_add_host_to_aggregate_invalid_error_status(self):
 
3732
        """Ensure InvalidAggregateAction is raised when aggregate is
 
3733
        in error."""
 
3734
        _create_service_entries(self.context, {'fake_zone': ['fake_host']})
 
3735
        aggr = self.api.create_aggregate(self.context,
 
3736
                                         'fake_aggregate', 'fake_zone')
 
3737
        # let's mock the fact that the aggregate is in error!
 
3738
        status = {'operational_state': aggregate_states.ERROR}
 
3739
        db.aggregate_update(self.context, aggr['id'], status)
 
3740
        self.assertRaises(exception.InvalidAggregateAction,
 
3741
                          self.api.add_host_to_aggregate, self.context,
 
3742
                          aggr['id'], 'fake_host')
 
3743
 
 
3744
    def test_add_host_to_aggregate_zones_mismatch(self):
 
3745
        """Ensure InvalidAggregateAction is raised when zones don't match."""
 
3746
        _create_service_entries(self.context, {'fake_zoneX': ['fake_host1'],
 
3747
                                               'fake_zoneY': ['fake_host2']})
 
3748
        aggr = self.api.create_aggregate(self.context,
 
3749
                                         'fake_aggregate', 'fake_zoneY')
 
3750
        self.assertRaises(exception.InvalidAggregateAction,
 
3751
                          self.api.add_host_to_aggregate,
 
3752
                          self.context, aggr['id'], 'fake_host1')
 
3753
 
 
3754
    def test_add_host_to_aggregate_raise_not_found(self):
 
3755
        """Ensure ComputeHostNotFound is raised when adding invalid host."""
 
3756
        _create_service_entries(self.context, {'fake_zone': ['fake_host']})
 
3757
        aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
 
3758
                                         'fake_zone')
 
3759
        self.assertRaises(exception.ComputeHostNotFound,
 
3760
                          self.api.add_host_to_aggregate,
 
3761
                          self.context, aggr['id'], 'invalid_host')
 
3762
 
 
3763
    def test_remove_host_from_aggregate_active(self):
 
3764
        """Ensure we can remove a host from an aggregate."""
 
3765
        values = _create_service_entries(self.context)
 
3766
        fake_zone = values.keys()[0]
 
3767
        aggr = self.api.create_aggregate(self.context,
 
3768
                                         'fake_aggregate', fake_zone)
 
3769
        # let's mock the fact that the aggregate is active already!
 
3770
        status = {'operational_state': aggregate_states.ACTIVE}
 
3771
        db.aggregate_update(self.context, aggr['id'], status)
 
3772
        for host in values[fake_zone]:
 
3773
            aggr = self.api.add_host_to_aggregate(self.context,
 
3774
                                                  aggr['id'], host)
 
3775
        expected = self.api.remove_host_from_aggregate(self.context,
 
3776
                                                       aggr['id'],
 
3777
                                                       values[fake_zone][0])
 
3778
        self.assertEqual(len(aggr['hosts']) - 1, len(expected['hosts']))
 
3779
        self.assertEqual(expected['operational_state'],
 
3780
                         aggregate_states.ACTIVE)
 
3781
 
 
3782
    def test_remove_host_from_aggregate_error(self):
 
3783
        """Ensure we can remove a host from an aggregate even if in error."""
 
3784
        values = _create_service_entries(self.context)
 
3785
        fake_zone = values.keys()[0]
 
3786
        aggr = self.api.create_aggregate(self.context,
 
3787
                                         'fake_aggregate', fake_zone)
 
3788
        # let's mock the fact that the aggregate is ready!
 
3789
        status = {'operational_state': aggregate_states.ACTIVE}
 
3790
        db.aggregate_update(self.context, aggr['id'], status)
 
3791
        for host in values[fake_zone]:
 
3792
            aggr = self.api.add_host_to_aggregate(self.context,
 
3793
                                                  aggr['id'], host)
 
3794
        # let's mock the fact that the aggregate is in error!
 
3795
        status = {'operational_state': aggregate_states.ERROR}
 
3796
        expected = self.api.remove_host_from_aggregate(self.context,
 
3797
                                                       aggr['id'],
 
3798
                                                       values[fake_zone][0])
 
3799
        self.assertEqual(len(aggr['hosts']) - 1, len(expected['hosts']))
 
3800
        self.assertEqual(expected['operational_state'],
 
3801
                         aggregate_states.ACTIVE)
 
3802
 
 
3803
    def test_remove_host_from_aggregate_invalid_dismissed_status(self):
 
3804
        """Ensure InvalidAggregateAction is raised when aggregate is
 
3805
        deleted."""
 
3806
        _create_service_entries(self.context, {'fake_zone': ['fake_host']})
 
3807
        aggr = self.api.create_aggregate(self.context,
 
3808
                                         'fake_aggregate', 'fake_zone')
 
3809
        # let's mock the fact that the aggregate is dismissed!
 
3810
        status = {'operational_state': aggregate_states.DISMISSED}
 
3811
        db.aggregate_update(self.context, aggr['id'], status)
 
3812
        self.assertRaises(exception.InvalidAggregateAction,
 
3813
                          self.api.remove_host_from_aggregate, self.context,
 
3814
                          aggr['id'], 'fake_host')
 
3815
 
 
3816
    def test_remove_host_from_aggregate_invalid_changing_status(self):
 
3817
        """Ensure InvalidAggregateAction is raised when aggregate is
 
3818
        changing."""
 
3819
        _create_service_entries(self.context, {'fake_zone': ['fake_host']})
 
3820
        aggr = self.api.create_aggregate(self.context,
 
3821
                                         'fake_aggregate', 'fake_zone')
 
3822
        # let's mock the fact that the aggregate is changing!
 
3823
        status = {'operational_state': aggregate_states.CHANGING}
 
3824
        db.aggregate_update(self.context, aggr['id'], status)
 
3825
        self.assertRaises(exception.InvalidAggregateAction,
 
3826
                          self.api.remove_host_from_aggregate, self.context,
 
3827
                          aggr['id'], 'fake_host')
 
3828
 
 
3829
    def test_remove_host_from_aggregate_raise_not_found(self):
 
3830
        """Ensure ComputeHostNotFound is raised when removing invalid host."""
 
3831
        _create_service_entries(self.context, {'fake_zone': ['fake_host']})
 
3832
        aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
 
3833
                                         'fake_zone')
 
3834
        self.assertRaises(exception.ComputeHostNotFound,
 
3835
                          self.api.remove_host_from_aggregate,
 
3836
                          self.context, aggr['id'], 'invalid_host')
 
3837
 
 
3838
 
 
3839
class ComputeAggrTestCase(BaseTestCase):
 
3840
    """This is for unit coverage of aggregate-related methods
 
3841
    defined in nova.compute.manager."""
 
3842
 
 
3843
    def setUp(self):
 
3844
        super(ComputeAggrTestCase, self).setUp()
 
3845
        self.context = context.get_admin_context()
 
3846
        values = {'name': 'test_aggr',
 
3847
                  'availability_zone': 'test_zone', }
 
3848
        self.aggr = db.aggregate_create(self.context, values)
 
3849
 
 
3850
    def test_add_aggregate_host(self):
 
3851
        def fake_driver_add_to_aggregate(context, aggregate, host):
 
3852
            fake_driver_add_to_aggregate.called = True
 
3853
            return {"foo": "bar"}
 
3854
        self.stubs.Set(self.compute.driver, "add_to_aggregate",
 
3855
                       fake_driver_add_to_aggregate)
 
3856
 
 
3857
        self.compute.add_aggregate_host(self.context, self.aggr.id, "host")
 
3858
        self.assertTrue(fake_driver_add_to_aggregate.called)
 
3859
 
 
3860
    def test_add_aggregate_host_raise_err(self):
 
3861
        """Ensure the undo operation works correctly on add."""
 
3862
        def fake_driver_add_to_aggregate(context, aggregate, host):
 
3863
            raise exception.AggregateError
 
3864
        self.stubs.Set(self.compute.driver, "add_to_aggregate",
 
3865
                       fake_driver_add_to_aggregate)
 
3866
 
 
3867
        state = {'operational_state': aggregate_states.ACTIVE}
 
3868
        db.aggregate_update(self.context, self.aggr.id, state)
 
3869
        db.aggregate_host_add(self.context, self.aggr.id, 'fake_host')
 
3870
 
 
3871
        self.assertRaises(exception.AggregateError,
 
3872
                          self.compute.add_aggregate_host,
 
3873
                          self.context, self.aggr.id, "fake_host")
 
3874
        excepted = db.aggregate_get(self.context, self.aggr.id)
 
3875
        self.assertEqual(excepted.operational_state, aggregate_states.ERROR)
 
3876
        self.assertEqual(excepted.hosts, [])
 
3877
 
 
3878
    def test_remove_aggregate_host(self):
 
3879
        def fake_driver_remove_from_aggregate(context, aggregate, host):
 
3880
            fake_driver_remove_from_aggregate.called = True
 
3881
            self.assertEqual("host", host, "host")
 
3882
            return {"foo": "bar"}
 
3883
        self.stubs.Set(self.compute.driver, "remove_from_aggregate",
 
3884
                       fake_driver_remove_from_aggregate)
 
3885
 
 
3886
        self.compute.remove_aggregate_host(self.context, self.aggr.id, "host")
 
3887
        self.assertTrue(fake_driver_remove_from_aggregate.called)
 
3888
 
 
3889
    def test_remove_aggregate_host_raise_err(self):
 
3890
        """Ensure the undo operation works correctly on remove."""
 
3891
        def fake_driver_remove_from_aggregate(context, aggregate, host):
 
3892
            raise exception.AggregateError
 
3893
        self.stubs.Set(self.compute.driver, "remove_from_aggregate",
 
3894
                       fake_driver_remove_from_aggregate)
 
3895
 
 
3896
        state = {'operational_state': aggregate_states.ACTIVE}
 
3897
        db.aggregate_update(self.context, self.aggr.id, state)
 
3898
 
 
3899
        self.assertRaises(exception.AggregateError,
 
3900
                          self.compute.remove_aggregate_host,
 
3901
                          self.context, self.aggr.id, "fake_host")
 
3902
        excepted = db.aggregate_get(self.context, self.aggr.id)
 
3903
        self.assertEqual(excepted.operational_state, aggregate_states.ERROR)
 
3904
        self.assertEqual(excepted.hosts, ['fake_host'])
 
3905
 
 
3906
 
 
3907
class ComputePolicyTestCase(BaseTestCase):
 
3908
 
 
3909
    def setUp(self):
 
3910
        super(ComputePolicyTestCase, self).setUp()
 
3911
        nova.policy.reset()
 
3912
        nova.policy.init()
 
3913
 
 
3914
        self.compute_api = compute.API()
 
3915
 
 
3916
    def tearDown(self):
 
3917
        super(ComputePolicyTestCase, self).tearDown()
 
3918
        nova.policy.reset()
 
3919
 
 
3920
    def _set_rules(self, rules):
 
3921
        nova.common.policy.set_brain(nova.common.policy.HttpBrain(rules))
 
3922
 
 
3923
    def test_actions_are_prefixed(self):
 
3924
        self.mox.StubOutWithMock(nova.policy, 'enforce')
 
3925
        nova.policy.enforce(self.context, 'compute:reboot', {})
 
3926
        self.mox.ReplayAll()
 
3927
        nova.compute.api.check_policy(self.context, 'reboot', {})
 
3928
 
 
3929
    def test_wrapped_method(self):
 
3930
        instance = self._create_fake_instance()
 
3931
        # Reset this to None for this policy check. If it's set, it
 
3932
        # tries to do a compute_api.update() and we're not testing for
 
3933
        # that here.
 
3934
        instance['host'] = None
 
3935
        self.compute.run_instance(self.context, instance['uuid'])
 
3936
 
 
3937
        # force delete to fail
 
3938
        rules = {"compute:delete": [["false:false"]]}
 
3939
        self._set_rules(rules)
 
3940
 
 
3941
        self.assertRaises(exception.PolicyNotAuthorized,
 
3942
                          self.compute_api.delete, self.context, instance)
 
3943
 
 
3944
        # reset rules to allow deletion
 
3945
        rules = {"compute:delete": []}
 
3946
        self._set_rules(rules)
 
3947
 
 
3948
        self.compute_api.delete(self.context, instance)
 
3949
 
 
3950
    def test_create_fail(self):
 
3951
        rules = {"compute:create": [["false:false"]]}
 
3952
        self._set_rules(rules)
 
3953
 
 
3954
        self.assertRaises(exception.PolicyNotAuthorized,
 
3955
                          self.compute_api.create, self.context, '1', '1')
 
3956
 
 
3957
    def test_create_attach_volume_fail(self):
 
3958
        rules = {
 
3959
            "compute:create": [],
 
3960
            "compute:create:attach_network": [["false:false"]],
 
3961
            "compute:create:attach_volume": [],
 
3962
        }
 
3963
        self._set_rules(rules)
 
3964
 
 
3965
        self.assertRaises(exception.PolicyNotAuthorized,
 
3966
                          self.compute_api.create, self.context, '1', '1',
 
3967
                          requested_networks='blah',
 
3968
                          block_device_mapping='blah')
 
3969
 
 
3970
    def test_create_attach_network_fail(self):
 
3971
        rules = {
 
3972
            "compute:create": [],
 
3973
            "compute:create:attach_network": [],
 
3974
            "compute:create:attach_volume": [["false:false"]],
 
3975
        }
 
3976
        self._set_rules(rules)
 
3977
 
 
3978
        self.assertRaises(exception.PolicyNotAuthorized,
 
3979
                          self.compute_api.create, self.context, '1', '1',
 
3980
                          requested_networks='blah',
 
3981
                          block_device_mapping='blah')
 
3982
 
 
3983
    def test_get_fail(self):
 
3984
        instance = self._create_fake_instance()
 
3985
 
 
3986
        rules = {
 
3987
            "compute:get": [["false:false"]],
 
3988
        }
 
3989
        self._set_rules(rules)
 
3990
 
 
3991
        self.assertRaises(exception.PolicyNotAuthorized,
 
3992
                          self.compute_api.get, self.context, instance['uuid'])
 
3993
 
 
3994
    def test_get_all_fail(self):
 
3995
        rules = {
 
3996
            "compute:get_all": [["false:false"]],
 
3997
        }
 
3998
        self._set_rules(rules)
 
3999
 
 
4000
        self.assertRaises(exception.PolicyNotAuthorized,
 
4001
                          self.compute_api.get_all, self.context)
 
4002
 
 
4003
    def test_get_instance_faults(self):
 
4004
        instance1 = self._create_fake_instance()
 
4005
        instance2 = self._create_fake_instance()
 
4006
        instances = [instance1, instance2]
 
4007
 
 
4008
        rules = {
 
4009
            "compute:get_instance_faults": [["false:false"]],
 
4010
        }
 
4011
        self._set_rules(rules)
 
4012
 
 
4013
        self.assertRaises(exception.PolicyNotAuthorized,
 
4014
                          self.compute_api.get_instance_faults,
 
4015
                          self.context, instances)
 
4016
 
 
4017
 
 
4018
class ComputeHostAPITestCase(BaseTestCase):
 
4019
    def setUp(self):
 
4020
        super(ComputeHostAPITestCase, self).setUp()
 
4021
        self.host_api = compute_api.HostAPI()
 
4022
 
 
4023
    def _rpc_call_stub(self, call_info):
 
4024
        def fake_rpc_call(context, topic, msg, timeout=None):
 
4025
            call_info['context'] = context
 
4026
            call_info['topic'] = topic
 
4027
            call_info['msg'] = msg
 
4028
        self.stubs.Set(rpc, 'call', fake_rpc_call)
 
4029
 
 
4030
    def test_set_host_enabled(self):
 
4031
        ctxt = context.RequestContext('fake', 'fake')
 
4032
        call_info = {}
 
4033
        self._rpc_call_stub(call_info)
 
4034
 
 
4035
        self.host_api.set_host_enabled(ctxt, 'fake_host', 'fake_enabled')
 
4036
        self.assertEqual(call_info['context'], ctxt)
 
4037
        self.assertEqual(call_info['topic'], 'compute.fake_host')
 
4038
        self.assertEqual(call_info['msg'],
 
4039
                {'method': 'set_host_enabled',
 
4040
                 'args': {'enabled': 'fake_enabled'},
 
4041
                 'version': compute_rpcapi.ComputeAPI.RPC_API_VERSION})
 
4042
 
 
4043
    def test_host_power_action(self):
 
4044
        ctxt = context.RequestContext('fake', 'fake')
 
4045
        call_info = {}
 
4046
        self._rpc_call_stub(call_info)
 
4047
        self.host_api.host_power_action(ctxt, 'fake_host', 'fake_action')
 
4048
        self.assertEqual(call_info['context'], ctxt)
 
4049
        self.assertEqual(call_info['topic'], 'compute.fake_host')
 
4050
        self.assertEqual(call_info['msg'],
 
4051
                {'method': 'host_power_action',
 
4052
                 'args': {'action': 'fake_action'},
 
4053
                 'version': compute_rpcapi.ComputeAPI.RPC_API_VERSION})
 
4054
 
 
4055
    def test_set_host_maintenance(self):
 
4056
        ctxt = context.RequestContext('fake', 'fake')
 
4057
        call_info = {}
 
4058
        self._rpc_call_stub(call_info)
 
4059
        self.host_api.set_host_maintenance(ctxt, 'fake_host', 'fake_mode')
 
4060
        self.assertEqual(call_info['context'], ctxt)
 
4061
        self.assertEqual(call_info['topic'], 'compute.fake_host')
 
4062
        self.assertEqual(call_info['msg'],
 
4063
                {'method': 'host_maintenance_mode',
 
4064
                 'args': {'host': 'fake_host', 'mode': 'fake_mode'},
 
4065
                 'version': compute_rpcapi.ComputeAPI.RPC_API_VERSION})
 
4066
 
 
4067
 
 
4068
class KeypairAPITestCase(BaseTestCase):
 
4069
    def setUp(self):
 
4070
        super(KeypairAPITestCase, self).setUp()
 
4071
        self.keypair_api = compute_api.KeypairAPI()
 
4072
        self.ctxt = context.RequestContext('fake', 'fake')
 
4073
        self._keypair_db_call_stubs()
 
4074
        self.pub_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLnVkqJu9WVf' \
 
4075
                  '/5StU3JCrBR2r1s1j8K1tux+5XeSvdqaM8lMFNorzbY5iyoBbRS56gy' \
 
4076
                  '1jmm43QsMPJsrpfUZKcJpRENSe3OxIIwWXRoiapZe78u/a9xKwj0avF' \
 
4077
                  'YMcws9Rk9iAB7W4K1nEJbyCPl5lRBoyqeHBqrnnuXWEgGxJCK0Ah6wc' \
 
4078
                  'OzwlEiVjdf4kxzXrwPHyi7Ea1qvnNXTziF8yYmUlH4C8UXfpTQckwSw' \
 
4079
                  'pDyxZUc63P8q+vPbs3Q2kw+/7vvkCKHJAXVI+oCiyMMfffoTq16M1xf' \
 
4080
                  'V58JstgtTqAXG+ZFpicGajREUE/E3hO5MGgcHmyzIrWHKpe1n3oEGuz'
 
4081
        self.fingerprint = '4e:48:c6:a0:4a:f9:dd:b5:4c:85:54:5a:af:43:47:5a'
 
4082
 
 
4083
    def _keypair_db_call_stubs(self):
 
4084
 
 
4085
        def db_key_pair_get_all_by_user(self, user_id):
 
4086
            return []
 
4087
 
 
4088
        def db_key_pair_create(self, keypair):
 
4089
            pass
 
4090
 
 
4091
        def db_key_pair_destroy(context, user_id, name):
 
4092
            pass
 
4093
 
 
4094
        self.stubs.Set(db, "key_pair_get_all_by_user",
 
4095
                       db_key_pair_get_all_by_user)
 
4096
        self.stubs.Set(db, "key_pair_create",
 
4097
                       db_key_pair_create)
 
4098
        self.stubs.Set(db, "key_pair_destroy",
 
4099
                       db_key_pair_destroy)
 
4100
 
 
4101
    def test_create_keypair(self):
 
4102
        keypair = self.keypair_api.create_key_pair(self.ctxt,
 
4103
                                                   self.ctxt.user_id, 'foo')
 
4104
        self.assertEqual('foo', keypair['name'])
 
4105
 
 
4106
    def test_create_keypair_name_too_long(self):
 
4107
        self.assertRaises(exception.InvalidKeypair,
 
4108
                          self.keypair_api.create_key_pair,
 
4109
                          self.ctxt, self.ctxt.user_id, 'x' * 256)
 
4110
 
 
4111
    def test_create_keypair_invalid_chars(self):
 
4112
        self.assertRaises(exception.InvalidKeypair,
 
4113
                          self.keypair_api.create_key_pair,
 
4114
                          self.ctxt, self.ctxt.user_id, '* BAD CHARACTERS! *')
 
4115
 
 
4116
    def test_create_keypair_already_exists(self):
 
4117
        def db_key_pair_get(context, user_id, name):
 
4118
            pass
 
4119
        self.stubs.Set(db, "key_pair_get",
 
4120
                       db_key_pair_get)
 
4121
        self.assertRaises(exception.KeyPairExists,
 
4122
                          self.keypair_api.create_key_pair,
 
4123
                          self.ctxt, self.ctxt.user_id, 'foo')
 
4124
 
 
4125
    def test_create_keypair_quota_limit(self):
 
4126
        def db_key_pair_count_by_user_max(self, user_id):
 
4127
            return FLAGS.quota_key_pairs
 
4128
        self.stubs.Set(db, "key_pair_count_by_user",
 
4129
                       db_key_pair_count_by_user_max)
 
4130
        self.assertRaises(exception.KeypairLimitExceeded,
 
4131
                          self.keypair_api.create_key_pair,
 
4132
                          self.ctxt, self.ctxt.user_id, 'foo')
 
4133
 
 
4134
    def test_import_keypair(self):
 
4135
        keypair = self.keypair_api.import_key_pair(self.ctxt,
 
4136
                                                   self.ctxt.user_id,
 
4137
                                                   'foo',
 
4138
                                                   self.pub_key)
 
4139
        self.assertEqual('foo', keypair['name'])
 
4140
        self.assertEqual(self.fingerprint, keypair['fingerprint'])
 
4141
        self.assertEqual(self.pub_key, keypair['public_key'])
 
4142
 
 
4143
    def test_import_keypair_bad_public_key(self):
 
4144
        self.assertRaises(exception.InvalidKeypair,
 
4145
                          self.keypair_api.import_key_pair,
 
4146
                          self.ctxt, self.ctxt.user_id, 'foo', 'bad key data')
 
4147
 
 
4148
    def test_import_keypair_name_too_long(self):
 
4149
        self.assertRaises(exception.InvalidKeypair,
 
4150
                          self.keypair_api.import_key_pair,
 
4151
                          self.ctxt, self.ctxt.user_id, 'x' * 256,
 
4152
                          self.pub_key)
 
4153
 
 
4154
    def test_import_keypair_invalid_chars(self):
 
4155
        self.assertRaises(exception.InvalidKeypair,
 
4156
                          self.keypair_api.import_key_pair,
 
4157
                          self.ctxt, self.ctxt.user_id,
 
4158
                          '* BAD CHARACTERS! *', self.pub_key)
 
4159
 
 
4160
    def test_import_keypair_quota_limit(self):
 
4161
        def db_key_pair_count_by_user_max(self, user_id):
 
4162
            return FLAGS.quota_key_pairs
 
4163
        self.stubs.Set(db, "key_pair_count_by_user",
 
4164
                       db_key_pair_count_by_user_max)
 
4165
        self.assertRaises(exception.KeypairLimitExceeded,
 
4166
                          self.keypair_api.import_key_pair,
 
4167
                          self.ctxt, self.ctxt.user_id, 'foo', self.pub_key)