~ubuntu-branches/ubuntu/quantal/nova/quantal-proposed

« back to all changes in this revision

Viewing changes to nova/tests/test_xenapi.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-08-16 14:04:11 UTC
  • mto: This revision was merged to the branch mainline in revision 84.
  • Revision ID: package-import@ubuntu.com-20120816140411-0mr4n241wmk30t9l
Tags: upstream-2012.2~f3
ImportĀ upstreamĀ versionĀ 2012.2~f3

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""Test suite for XenAPI."""
18
18
 
19
19
import ast
 
20
import base64
20
21
import contextlib
 
22
import cPickle as pickle
21
23
import functools
22
24
import os
23
25
import re
24
26
 
25
 
from nova.compute import aggregate_states
 
27
from nova.compute import api as compute_api
26
28
from nova.compute import instance_types
27
29
from nova.compute import power_state
28
30
from nova import context
30
32
from nova import exception
31
33
from nova import flags
32
34
from nova.openstack.common import importutils
 
35
from nova.openstack.common import jsonutils
33
36
from nova.openstack.common import log as logging
34
37
from nova.openstack.common import timeutils
35
38
from nova import test
38
41
from nova.tests import fake_utils
39
42
import nova.tests.image.fake as fake_image
40
43
from nova.tests.xenapi import stubs
41
 
from nova.virt.xenapi import connection as xenapi_conn
 
44
from nova.virt.xenapi import agent
 
45
from nova.virt.xenapi import driver as xenapi_conn
42
46
from nova.virt.xenapi import fake as xenapi_fake
 
47
from nova.virt.xenapi import pool_states
43
48
from nova.virt.xenapi import vm_utils
44
49
from nova.virt.xenapi import vmops
45
50
from nova.virt.xenapi import volume_utils
92
97
 
93
98
def set_image_fixtures():
94
99
    image_service = fake_image.FakeImageService()
95
 
    image_service.delete_all()
 
100
    image_service.images.clear()
96
101
    for image_id, image_meta in IMAGE_FIXTURES.items():
97
102
        image_meta = image_meta['image_meta']
98
103
        image_meta['id'] = image_id
134
139
    return decorated_function
135
140
 
136
141
 
137
 
class XenAPIVolumeTestCase(test.TestCase):
 
142
class XenAPIVolumeTestCase(stubs.XenAPITestBase):
138
143
    """Unit tests for Volume operations."""
139
144
    def setUp(self):
140
145
        super(XenAPIVolumeTestCase, self).setUp()
141
146
        self.user_id = 'fake'
142
147
        self.project_id = 'fake'
143
148
        self.context = context.RequestContext(self.user_id, self.project_id)
144
 
        self.flags(target_host='127.0.0.1',
145
 
                xenapi_connection_url='test_url',
146
 
                xenapi_connection_password='test_pass',
147
 
                firewall_driver='nova.virt.xenapi.firewall.'
148
 
                                'Dom0IptablesFirewallDriver')
 
149
        self.flags(xenapi_connection_url='test_url',
 
150
                   xenapi_connection_password='test_pass',
 
151
                   firewall_driver='nova.virt.xenapi.firewall.'
 
152
                                   'Dom0IptablesFirewallDriver')
149
153
        db_fakes.stub_out_db_instance_api(self.stubs)
150
 
        xenapi_fake.reset()
151
154
        self.instance_values = {'id': 1,
152
155
                  'project_id': self.user_id,
153
156
                  'user_id': 'fake',
252
255
                          '/dev/sdc')
253
256
 
254
257
 
255
 
class XenAPIVMTestCase(test.TestCase):
 
258
class XenAPIVMTestCase(stubs.XenAPITestBase):
256
259
    """Unit tests for VM operations."""
257
260
    def setUp(self):
258
261
        super(XenAPIVMTestCase, self).setUp()
262
265
                   instance_name_template='%d',
263
266
                   firewall_driver='nova.virt.xenapi.firewall.'
264
267
                                   'Dom0IptablesFirewallDriver')
265
 
        xenapi_fake.reset()
266
268
        xenapi_fake.create_local_srs()
267
269
        xenapi_fake.create_local_pifs()
268
270
        db_fakes.stub_out_db_instance_api(self.stubs)
282
284
        stubs.stubout_image_service_download(self.stubs)
283
285
        stubs.stubout_stream_disk(self.stubs)
284
286
 
 
287
        def fake_inject_instance_metadata(self, instance, vm):
 
288
            pass
 
289
        self.stubs.Set(vmops.VMOps, 'inject_instance_metadata',
 
290
                       fake_inject_instance_metadata)
 
291
 
 
292
        def fake_safe_copy_vdi(session, sr_ref, instance, vdi_to_copy_ref):
 
293
            name_label = "fakenamelabel"
 
294
            disk_type = "fakedisktype"
 
295
            virtual_size = 777
 
296
            return vm_utils.create_vdi(
 
297
                    session, sr_ref, instance, name_label, disk_type,
 
298
                    virtual_size)
 
299
        self.stubs.Set(vm_utils, '_safe_copy_vdi', fake_safe_copy_vdi)
 
300
 
285
301
    def tearDown(self):
286
302
        super(XenAPIVMTestCase, self).tearDown()
287
303
        fake_image.FakeImageService_reset()
288
304
 
289
305
    def test_init_host(self):
290
306
        session = xenapi_conn.XenAPISession('test_url', 'root', 'test_pass')
291
 
        vm = vm_utils.get_this_vm_ref(session)
 
307
        vm = vm_utils._get_this_vm_ref(session)
292
308
        # Local root disk
293
309
        vdi0 = xenapi_fake.create_vdi('compute', None)
294
310
        vbd0 = xenapi_fake.create_vbd(vm, vdi0)
309
325
 
310
326
    def test_get_rrd_server(self):
311
327
        self.flags(xenapi_connection_url='myscheme://myaddress/')
312
 
        server_info = vm_utils.get_rrd_server()
 
328
        server_info = vm_utils._get_rrd_server()
313
329
        self.assertEqual(server_info[0], 'myscheme')
314
330
        self.assertEqual(server_info[1], 'myaddress')
315
331
 
317
333
        def fake_get_rrd(host, vm_uuid):
318
334
            with open('xenapi/vm_rrd.xml') as f:
319
335
                return re.sub(r'\s', '', f.read())
320
 
        self.stubs.Set(vm_utils, 'get_rrd', fake_get_rrd)
 
336
        self.stubs.Set(vm_utils, '_get_rrd', fake_get_rrd)
321
337
 
322
338
        fake_diagnostics = {
323
339
            'vbd_xvdb_write': '0.0',
355
371
        stubs.stubout_firewall_driver(self.stubs, self.conn)
356
372
        instance = self._create_instance()
357
373
 
358
 
        name = "MySnapshot"
 
374
        image_id = "my_snapshot_id"
359
375
        self.assertRaises(exception.NovaException, self.conn.snapshot,
360
 
                          self.context, instance, name)
 
376
                          self.context, instance, image_id)
361
377
 
362
378
    def test_instance_snapshot(self):
363
379
        stubs.stubout_instance_snapshot(self.stubs)
367
383
        stubs.stubout_firewall_driver(self.stubs, self.conn)
368
384
        instance = self._create_instance()
369
385
 
370
 
        name = "MySnapshot"
371
 
        template_vm_ref = self.conn.snapshot(self.context, instance, name)
 
386
        image_id = "my_snapshot_id"
 
387
        self.conn.snapshot(self.context, instance, image_id)
372
388
 
373
389
        # Ensure VM was torn down
374
390
        vm_labels = []
435
451
            tcpip_data = ast.literal_eval(xenstore_value)
436
452
            self.assertEquals(tcpip_data,
437
453
                              {'broadcast': '192.168.1.255',
438
 
                               'dns': ['192.168.1.3', '192.168.1.4'],
 
454
                               'dns': ['192.168.1.4', '192.168.1.3'],
439
455
                               'gateway': '192.168.1.1',
440
456
                               'gateway_v6': 'fe80::def',
441
457
                               'ip6s': [{'enabled': '1',
507
523
    def _test_spawn(self, image_ref, kernel_id, ramdisk_id,
508
524
                    instance_type_id="3", os_type="linux",
509
525
                    hostname="test", architecture="x86-64", instance_id=1,
510
 
                    check_injection=False,
 
526
                    injected_files=None, check_injection=False,
511
527
                    create_record=True, empty_dns=False):
 
528
        if injected_files is None:
 
529
            injected_files = []
 
530
 
 
531
        # Fake out inject_instance_metadata
 
532
        def fake_inject_instance_metadata(self, instance, vm):
 
533
            pass
 
534
        self.stubs.Set(vmops.VMOps, 'inject_instance_metadata',
 
535
                       fake_inject_instance_metadata)
 
536
 
512
537
        if create_record:
513
538
            instance_values = {'id': instance_id,
514
539
                      'project_id': self.project_id,
531
556
            # NOTE(tr3buchet): this is a terrible way to do this...
532
557
            network_info[0]['network']['subnets'][0]['dns'] = []
533
558
 
534
 
        # admin_pass isn't part of the DB model, but it does get set as
535
 
        # an attribute for spawn to use
536
 
        instance.admin_pass = 'herp'
537
559
        image_meta = {'id': IMAGE_VHD,
538
560
                      'disk_format': 'vhd'}
539
 
        self.conn.spawn(self.context, instance, image_meta, network_info)
 
561
        self.conn.spawn(self.context, instance, image_meta, injected_files,
 
562
                        'herp', network_info)
540
563
        self.create_vm_record(self.conn, os_type, instance['name'])
541
564
        self.check_vm_record(self.conn, check_injection)
542
565
        self.assertTrue(instance.os_type)
656
679
            self._tee_executed = True
657
680
            return '', ''
658
681
 
 
682
        def _readlink_handler(cmd_parts, **kwargs):
 
683
            return os.path.realpath(cmd_parts[2]), ''
 
684
 
659
685
        fake_utils.fake_execute_set_repliers([
660
686
            # Capture the tee .../etc/network/interfaces command
661
687
            (r'tee.*interfaces', _tee_handler),
 
688
            (r'readlink -nm.*', _readlink_handler),
662
689
        ])
663
690
        self._test_spawn(IMAGE_MACHINE,
664
691
                         IMAGE_KERNEL,
729
756
 
730
757
        self.network.allocate_for_instance(ctxt,
731
758
                          instance_id=2,
732
 
                          instance_uuid="00000000-0000-0000-0000-000000000000",
 
759
                          instance_uuid='00000000-0000-0000-0000-000000000002',
733
760
                          host=FLAGS.host,
734
761
                          vpn=None,
735
762
                          rxtx_factor=3,
751
778
            self.assertEquals(vif_rec['qos_algorithm_params']['kbps'],
752
779
                              str(3 * 10 * 1024))
753
780
 
 
781
    def test_spawn_injected_files(self):
 
782
        """Test spawning with injected_files"""
 
783
        actual_injected_files = []
 
784
 
 
785
        def fake_inject_file(self, method, args):
 
786
            path = base64.b64decode(args['b64_path'])
 
787
            contents = base64.b64decode(args['b64_contents'])
 
788
            actual_injected_files.append((path, contents))
 
789
            return jsonutils.dumps({'returncode': '0', 'message': 'success'})
 
790
        self.stubs.Set(stubs.FakeSessionForVMTests,
 
791
                       '_plugin_agent_inject_file', fake_inject_file)
 
792
 
 
793
        injected_files = [('/tmp/foo', 'foobar')]
 
794
        self._test_spawn(IMAGE_VHD, None, None,
 
795
                         os_type="linux", architecture="x86-64",
 
796
                         injected_files=injected_files)
 
797
        self.check_vm_params_for_linux()
 
798
        self.assertEquals(actual_injected_files, injected_files)
 
799
 
754
800
    def test_rescue(self):
755
801
        instance = self._create_instance()
756
802
        session = xenapi_conn.XenAPISession('test_url', 'root', 'test_pass')
757
803
        vm_ref = vm_utils.lookup(session, instance.name)
758
804
 
759
 
        xenapi_fake.create_vbd(vm_ref, "swap", userdevice=1)
760
 
        xenapi_fake.create_vbd(vm_ref, "rootfs", userdevice=0)
 
805
        swap_vdi_ref = xenapi_fake.create_vdi('swap', None)
 
806
        root_vdi_ref = xenapi_fake.create_vdi('root', None)
 
807
 
 
808
        xenapi_fake.create_vbd(vm_ref, swap_vdi_ref, userdevice=1)
 
809
        xenapi_fake.create_vbd(vm_ref, root_vdi_ref, userdevice=0)
761
810
 
762
811
        conn = xenapi_conn.XenAPIDriver(False)
763
812
        image_meta = {'id': IMAGE_VHD,
764
813
                      'disk_format': 'vhd'}
765
 
        conn.rescue(self.context, instance, [], image_meta)
 
814
        conn.rescue(self.context, instance, [], image_meta, '')
766
815
 
767
816
        vm = xenapi_fake.get_record('VM', vm_ref)
768
817
        rescue_name = "%s-rescue" % vm["name_label"]
805
854
        conn.finish_revert_migration(instance, None)
806
855
        self.assertTrue(conn._vmops.finish_revert_migration_called)
807
856
 
 
857
    def test_reboot_hard(self):
 
858
        instance = self._create_instance()
 
859
        conn = xenapi_conn.XenAPIDriver(False)
 
860
        conn.reboot(instance, None, "HARD")
 
861
 
 
862
    def test_reboot_soft(self):
 
863
        instance = self._create_instance()
 
864
        conn = xenapi_conn.XenAPIDriver(False)
 
865
        conn.reboot(instance, None, "SOFT")
 
866
 
 
867
    def test_reboot_halted(self):
 
868
        session = xenapi_conn.XenAPISession('test_url', 'root', 'test_pass')
 
869
        instance = self._create_instance(spawn=False)
 
870
        conn = xenapi_conn.XenAPIDriver(False)
 
871
        xenapi_fake.create_vm(instance.name, 'Halted')
 
872
        conn.reboot(instance, None, "SOFT")
 
873
        vm_ref = vm_utils.lookup(session, instance.name)
 
874
        vm = xenapi_fake.get_record('VM', vm_ref)
 
875
        self.assertEquals(vm['power_state'], 'Running')
 
876
 
 
877
    def test_reboot_unknown_state(self):
 
878
        instance = self._create_instance(spawn=False)
 
879
        conn = xenapi_conn.XenAPIDriver(False)
 
880
        xenapi_fake.create_vm(instance.name, 'Unknown')
 
881
        self.assertRaises(xenapi_fake.Failure, conn.reboot, instance,
 
882
                None, "SOFT")
 
883
 
808
884
    def _create_instance(self, instance_id=1, spawn=True):
809
885
        """Creates and spawns a test instance."""
810
886
        instance_values = {
811
887
            'id': instance_id,
 
888
            'uuid': '00000000-0000-0000-0000-00000000000%d' % instance_id,
812
889
            'project_id': self.project_id,
813
890
            'user_id': self.user_id,
814
891
            'image_ref': 1,
817
894
            'root_gb': 20,
818
895
            'instance_type_id': '3',  # m1.large
819
896
            'os_type': 'linux',
 
897
            'vm_mode': 'hvm',
820
898
            'architecture': 'x86-64'}
821
899
        instance = db.instance_create(self.context, instance_values)
822
900
        network_info = fake_network.fake_get_instance_nw_info(self.stubs,
824
902
        image_meta = {'id': IMAGE_VHD,
825
903
                      'disk_format': 'vhd'}
826
904
        if spawn:
827
 
            instance.admin_pass = 'herp'
828
 
            self.conn.spawn(self.context, instance, image_meta, network_info)
 
905
            self.conn.spawn(self.context, instance, image_meta, [], 'herp',
 
906
                            network_info)
829
907
        return instance
830
908
 
831
909
 
833
911
    """Unit tests for Diffie-Hellman code."""
834
912
    def setUp(self):
835
913
        super(XenAPIDiffieHellmanTestCase, self).setUp()
836
 
        self.alice = vmops.SimpleDH()
837
 
        self.bob = vmops.SimpleDH()
 
914
        self.alice = agent.SimpleDH()
 
915
        self.bob = agent.SimpleDH()
838
916
 
839
917
    def test_shared(self):
840
918
        alice_pub = self.alice.get_public()
868
946
        self._test_encryption(''.join(['abcd' for i in xrange(1024)]))
869
947
 
870
948
 
871
 
class XenAPIMigrateInstance(test.TestCase):
 
949
class XenAPIMigrateInstance(stubs.XenAPITestBase):
872
950
    """Unit test for verifying migration-related actions."""
873
951
 
874
952
    def setUp(self):
875
953
        super(XenAPIMigrateInstance, self).setUp()
876
 
        self.flags(target_host='127.0.0.1',
877
 
                xenapi_connection_url='test_url',
878
 
                xenapi_connection_password='test_pass',
879
 
                firewall_driver='nova.virt.xenapi.firewall.'
880
 
                                'Dom0IptablesFirewallDriver')
 
954
        self.flags(xenapi_connection_url='test_url',
 
955
                   xenapi_connection_password='test_pass',
 
956
                   firewall_driver='nova.virt.xenapi.firewall.'
 
957
                                   'Dom0IptablesFirewallDriver')
881
958
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
882
959
        db_fakes.stub_out_db_instance_api(self.stubs)
883
 
        xenapi_fake.reset()
884
960
        xenapi_fake.create_network('fake', FLAGS.flat_network_bridge)
885
961
        self.user_id = 'fake'
886
962
        self.project_id = 'fake'
912
988
        stubs.stub_out_migration_methods(self.stubs)
913
989
        stubs.stubout_get_this_vm_uuid(self.stubs)
914
990
 
 
991
        def fake_inject_instance_metadata(self, instance, vm):
 
992
            pass
 
993
        self.stubs.Set(vmops.VMOps, 'inject_instance_metadata',
 
994
                       fake_inject_instance_metadata)
 
995
 
915
996
    def test_resize_xenserver_6(self):
916
997
        instance = db.instance_create(self.context, self.instance_values)
917
998
        called = {'resize': False}
922
1003
        self.stubs.Set(stubs.FakeSessionForVMTests,
923
1004
                       "VDI_resize", fake_vdi_resize)
924
1005
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests,
925
 
                              product_version=(6, 0, 0))
926
 
        conn = xenapi_conn.XenAPIDriver(False)
927
 
        vdi_ref = xenapi_fake.create_vdi('hurr', 'fake')
928
 
        vdi_uuid = xenapi_fake.get_record('VDI', vdi_ref)['uuid']
929
 
        conn._vmops._resize_instance(instance,
930
 
                                     {'uuid': vdi_uuid, 'ref': vdi_ref})
931
 
        self.assertEqual(called['resize'], True)
 
1006
                              product_version=(6, 0, 0),
 
1007
                              product_brand='XenServer')
 
1008
        conn = xenapi_conn.XenAPIDriver(False)
 
1009
        vdi_ref = xenapi_fake.create_vdi('hurr', 'fake')
 
1010
        vdi_uuid = xenapi_fake.get_record('VDI', vdi_ref)['uuid']
 
1011
        conn._vmops._resize_instance(instance,
 
1012
                                     {'uuid': vdi_uuid, 'ref': vdi_ref})
 
1013
        self.assertEqual(called['resize'], True)
 
1014
 
 
1015
    def test_resize_xcp(self):
 
1016
        instance = db.instance_create(self.context, self.instance_values)
 
1017
        called = {'resize': False}
 
1018
 
 
1019
        def fake_vdi_resize(*args, **kwargs):
 
1020
            called['resize'] = True
 
1021
 
 
1022
        self.stubs.Set(stubs.FakeSessionForVMTests,
 
1023
                       "VDI_resize", fake_vdi_resize)
 
1024
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests,
 
1025
                              product_version=(1, 4, 99),
 
1026
                              product_brand='XCP')
 
1027
        conn = xenapi_conn.XenAPIDriver(False)
 
1028
        vdi_ref = xenapi_fake.create_vdi('hurr', 'fake')
 
1029
        vdi_uuid = xenapi_fake.get_record('VDI', vdi_ref)['uuid']
 
1030
        conn._vmops._resize_instance(instance,
 
1031
                                     {'uuid': vdi_uuid, 'ref': vdi_ref})
 
1032
        self.assertEqual(called['resize'], True)
 
1033
 
 
1034
    def test_migrate_disk_and_power_off(self):
 
1035
        instance = db.instance_create(self.context, self.instance_values)
 
1036
        xenapi_fake.create_vm(instance.name, 'Running')
 
1037
        instance_type = db.instance_type_get_by_name(self.context, 'm1.large')
 
1038
        conn = xenapi_conn.XenAPIDriver(False)
 
1039
        conn.migrate_disk_and_power_off(self.context, instance,
 
1040
                                        '127.0.0.1', instance_type, None)
932
1041
 
933
1042
    def test_migrate_disk_and_power_off(self):
934
1043
        instance = db.instance_create(self.context, self.instance_values)
973
1082
        self.stubs.Set(vmops.VMOps, '_start', fake_vm_start)
974
1083
        self.stubs.Set(vmops.VMOps, 'finish_revert_migration',
975
1084
                       fake_finish_revert_migration)
 
1085
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests,
 
1086
                              product_version=(4, 0, 0),
 
1087
                              product_brand='XenServer')
976
1088
 
977
1089
        conn = xenapi_conn.XenAPIDriver(False)
978
1090
        network_info = fake_network.fake_get_instance_nw_info(self.stubs,
1005
1117
        self.stubs.Set(vmops.VMOps, '_start', fake_vm_start)
1006
1118
        self.stubs.Set(stubs.FakeSessionForVMTests,
1007
1119
                       "VDI_resize_online", fake_vdi_resize)
 
1120
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests,
 
1121
                              product_version=(4, 0, 0),
 
1122
                              product_brand='XenServer')
1008
1123
 
1009
1124
        conn = xenapi_conn.XenAPIDriver(False)
1010
1125
        network_info = fake_network.fake_get_instance_nw_info(self.stubs,
1072
1187
 
1073
1188
class XenAPIDetermineDiskImageTestCase(test.TestCase):
1074
1189
    """Unit tests for code that detects the ImageType."""
1075
 
    def setUp(self):
1076
 
        super(XenAPIDetermineDiskImageTestCase, self).setUp()
1077
 
 
1078
 
        class FakeInstance(object):
1079
 
            pass
1080
 
 
1081
 
        self.fake_instance = FakeInstance()
1082
 
        self.fake_instance.id = 42
1083
 
        self.fake_instance.os_type = 'linux'
1084
 
        self.fake_instance.architecture = 'x86-64'
1085
 
 
1086
1190
    def assert_disk_type(self, image_meta, expected_disk_type):
1087
1191
        actual = vm_utils.determine_disk_image_type(image_meta)
1088
1192
        self.assertEqual(expected_disk_type, actual)
1122
1226
        self.assertTrue(vmops.cmp_version('1.2.3', '1.2.3.4') < 0)
1123
1227
 
1124
1228
 
1125
 
class XenAPIHostTestCase(test.TestCase):
 
1229
class XenAPIHostTestCase(stubs.XenAPITestBase):
1126
1230
    """Tests HostState, which holds metrics from XenServer that get
1127
1231
    reported back to the Schedulers."""
1128
1232
 
1131
1235
        self.flags(xenapi_connection_url='test_url',
1132
1236
                   xenapi_connection_password='test_pass')
1133
1237
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
1134
 
        xenapi_fake.reset()
1135
1238
        xenapi_fake.create_local_srs()
1136
1239
        self.conn = xenapi_conn.XenAPIDriver(False)
1137
1240
 
1174
1277
    def test_set_enable_host_disable(self):
1175
1278
        self._test_host_action(self.conn.set_host_enabled, False, 'disabled')
1176
1279
 
1177
 
 
1178
 
class XenAPIAutoDiskConfigTestCase(test.TestCase):
 
1280
    def test_get_host_uptime(self):
 
1281
        result = self.conn.get_host_uptime('host')
 
1282
        self.assertEqual(result, 'fake uptime')
 
1283
 
 
1284
 
 
1285
class XenAPIAutoDiskConfigTestCase(stubs.XenAPITestBase):
1179
1286
    def setUp(self):
1180
1287
        super(XenAPIAutoDiskConfigTestCase, self).setUp()
1181
 
        self.flags(target_host='127.0.0.1',
1182
 
                   xenapi_connection_url='test_url',
 
1288
        self.flags(xenapi_connection_url='test_url',
1183
1289
                   xenapi_connection_password='test_pass',
1184
1290
                   firewall_driver='nova.virt.xenapi.firewall.'
1185
1291
                                   'Dom0IptablesFirewallDriver')
1186
1292
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
1187
 
        xenapi_fake.reset()
1188
1293
        self.conn = xenapi_conn.XenAPIDriver(False)
1189
1294
 
1190
1295
        self.user_id = 'fake'
1228
1333
        vdi_uuid = session.call_xenapi('VDI.get_record', vdi_ref)['uuid']
1229
1334
        vdis = {'root': {'uuid': vdi_uuid, 'ref': vdi_ref}}
1230
1335
 
1231
 
        self.conn._vmops._attach_disks(instance, disk_image_type, vm_ref, vdis)
 
1336
        self.conn._vmops._attach_disks(instance, vm_ref, instance['name'],
 
1337
                                       disk_image_type, vdis)
1232
1338
 
1233
1339
        self.assertEqual(marker["partition_called"], called)
1234
1340
 
1266
1372
        self.assertIsPartitionCalled(True)
1267
1373
 
1268
1374
 
1269
 
class XenAPIGenerateLocal(test.TestCase):
 
1375
class XenAPIGenerateLocal(stubs.XenAPITestBase):
1270
1376
    """Test generating of local disks, like swap and ephemeral"""
1271
1377
    def setUp(self):
1272
1378
        super(XenAPIGenerateLocal, self).setUp()
1273
 
        self.flags(target_host='127.0.0.1',
1274
 
                   xenapi_connection_url='test_url',
 
1379
        self.flags(xenapi_connection_url='test_url',
1275
1380
                   xenapi_connection_password='test_pass',
1276
1381
                   xenapi_generate_swap=True,
1277
1382
                   firewall_driver='nova.virt.xenapi.firewall.'
1278
1383
                                   'Dom0IptablesFirewallDriver')
1279
1384
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
1280
1385
        db_fakes.stub_out_db_instance_api(self.stubs)
1281
 
        xenapi_fake.reset()
1282
1386
        self.conn = xenapi_conn.XenAPIDriver(False)
1283
1387
 
1284
1388
        self.user_id = 'fake'
1315
1419
        vdis = {'root': {'uuid': vdi_uuid, 'ref': vdi_ref}}
1316
1420
 
1317
1421
        self.called = False
1318
 
        self.conn._vmops._attach_disks(instance, disk_image_type, vm_ref, vdis)
 
1422
        self.conn._vmops._attach_disks(instance, vm_ref, instance['name'],
 
1423
                                       disk_image_type, vdis)
1319
1424
        self.assertTrue(self.called)
1320
1425
 
1321
1426
    def test_generate_swap(self):
1343
1448
        self.assertCalled(instance)
1344
1449
 
1345
1450
 
1346
 
class XenAPIBWUsageTestCase(test.TestCase):
 
1451
class XenAPIBWUsageTestCase(stubs.XenAPITestBase):
1347
1452
    def setUp(self):
1348
1453
        super(XenAPIBWUsageTestCase, self).setUp()
1349
1454
        self.stubs.Set(vm_utils, 'compile_metrics',
1350
1455
                       XenAPIBWUsageTestCase._fake_compile_metrics)
1351
 
        self.flags(target_host='127.0.0.1',
1352
 
                   xenapi_connection_url='test_url',
 
1456
        self.flags(xenapi_connection_url='test_url',
1353
1457
                   xenapi_connection_password='test_pass',
1354
1458
                   firewall_driver='nova.virt.xenapi.firewall.'
1355
1459
                                   'Dom0IptablesFirewallDriver')
1356
1460
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
1357
 
        xenapi_fake.reset()
1358
1461
        self.conn = xenapi_conn.XenAPIDriver(False)
1359
1462
 
1360
1463
    @classmethod
1378
1481
# TODO(salvatore-orlando): this class and
1379
1482
# nova.tests.test_libvirt.IPTablesFirewallDriverTestCase share a lot of code.
1380
1483
# Consider abstracting common code in a base class for firewall driver testing.
1381
 
class XenAPIDom0IptablesFirewallTestCase(test.TestCase):
 
1484
class XenAPIDom0IptablesFirewallTestCase(stubs.XenAPITestBase):
1382
1485
 
1383
1486
    _in_nat_rules = [
1384
1487
      '# Generated by iptables-save v1.4.10 on Sat Feb 19 00:03:19 2011',
1396
1499
      ':FORWARD ACCEPT [0:0]',
1397
1500
      ':OUTPUT ACCEPT [915599:63811649]',
1398
1501
      ':nova-block-ipv4 - [0:0]',
1399
 
      '-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT ',
1400
 
      '-A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED'
 
1502
      '[0:0] -A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT ',
 
1503
      '[0:0] -A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED'
1401
1504
      ',ESTABLISHED -j ACCEPT ',
1402
 
      '-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT ',
1403
 
      '-A FORWARD -i virbr0 -o virbr0 -j ACCEPT ',
1404
 
      '-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable ',
1405
 
      '-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable ',
 
1505
      '[0:0] -A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT ',
 
1506
      '[0:0] -A FORWARD -i virbr0 -o virbr0 -j ACCEPT ',
 
1507
      '[0:0] -A FORWARD -o virbr0 -j REJECT '
 
1508
      '--reject-with icmp-port-unreachable ',
 
1509
      '[0:0] -A FORWARD -i virbr0 -j REJECT '
 
1510
      '--reject-with icmp-port-unreachable ',
1406
1511
      'COMMIT',
1407
1512
      '# Completed on Mon Dec  6 11:54:13 2010',
1408
1513
    ]
1424
1529
                   instance_name_template='%d',
1425
1530
                   firewall_driver='nova.virt.xenapi.firewall.'
1426
1531
                                   'Dom0IptablesFirewallDriver')
1427
 
        xenapi_fake.reset()
1428
1532
        xenapi_fake.create_local_srs()
1429
1533
        xenapi_fake.create_local_pifs()
1430
1534
        self.user_id = 'mappin'
1496
1600
        self.assertTrue(security_group_chain,
1497
1601
                        "The security group chain wasn't added")
1498
1602
 
1499
 
        regex = re.compile('-A .* -j ACCEPT -p icmp -s 192.168.11.0/24')
 
1603
        regex = re.compile('\[0\:0\] -A .* -j ACCEPT -p icmp'
 
1604
                           ' -s 192.168.11.0/24')
1500
1605
        self.assertTrue(len(filter(regex.match, self._out_rules)) > 0,
1501
1606
                        "ICMP acceptance rule wasn't added")
1502
1607
 
1503
 
        regex = re.compile('-A .* -j ACCEPT -p icmp -m icmp --icmp-type 8'
1504
 
                           ' -s 192.168.11.0/24')
 
1608
        regex = re.compile('\[0\:0\] -A .* -j ACCEPT -p icmp -m icmp'
 
1609
                           ' --icmp-type 8 -s 192.168.11.0/24')
1505
1610
        self.assertTrue(len(filter(regex.match, self._out_rules)) > 0,
1506
1611
                        "ICMP Echo Request acceptance rule wasn't added")
1507
1612
 
1508
 
        regex = re.compile('-A .* -j ACCEPT -p tcp --dport 80:81'
 
1613
        regex = re.compile('\[0\:0\] -A .* -j ACCEPT -p tcp --dport 80:81'
1509
1614
                           ' -s 192.168.10.0/24')
1510
1615
        self.assertTrue(len(filter(regex.match, self._out_rules)) > 0,
1511
1616
                        "TCP port 80/81 acceptance rule wasn't added")
1550
1655
        for ip in network_model.fixed_ips():
1551
1656
            if ip['version'] != 4:
1552
1657
                continue
1553
 
            regex = re.compile('-A .* -j ACCEPT -p tcp'
 
1658
            regex = re.compile('\[0\:0\] -A .* -j ACCEPT -p tcp'
1554
1659
                               ' --dport 80:81 -s %s' % ip['address'])
1555
1660
            self.assertTrue(len(filter(regex.match, self._out_rules)) > 0,
1556
1661
                            "TCP port 80/81 acceptance rule wasn't added")
1615
1720
                                       'cidr': '192.168.99.0/24'})
1616
1721
        #validate the extra rule
1617
1722
        self.fw.refresh_security_group_rules(secgroup)
1618
 
        regex = re.compile('-A .* -j ACCEPT -p udp --dport 200:299'
 
1723
        regex = re.compile('\[0\:0\] -A .* -j ACCEPT -p udp --dport 200:299'
1619
1724
                           ' -s 192.168.99.0/24')
1620
1725
        self.assertTrue(len(filter(regex.match, self._out_rules)) > 0,
1621
1726
                        "Rules were not updated properly."
1679
1784
        self.assertEqual(1, len(rules))
1680
1785
 
1681
1786
 
1682
 
class XenAPISRSelectionTestCase(test.TestCase):
 
1787
class XenAPISRSelectionTestCase(stubs.XenAPITestBase):
1683
1788
    """Unit tests for testing we find the right SR."""
1684
 
    def setUp(self):
1685
 
        super(XenAPISRSelectionTestCase, self).setUp()
1686
 
        xenapi_fake.reset()
1687
 
 
1688
1789
    def test_safe_find_sr_raise_exception(self):
1689
1790
        """Ensure StorageRepositoryNotFound is raise when wrong filter."""
1690
1791
        self.flags(sr_matching_filter='yadayadayada')
1733
1834
                         expected)
1734
1835
 
1735
1836
 
1736
 
class XenAPIAggregateTestCase(test.TestCase):
 
1837
def _create_service_entries(context, values={'avail_zone1': ['fake_host1',
 
1838
                                                         'fake_host2'],
 
1839
                                         'avail_zone2': ['fake_host3'], }):
 
1840
    for avail_zone, hosts in values.iteritems():
 
1841
        for host in hosts:
 
1842
            db.service_create(context,
 
1843
                              {'host': host,
 
1844
                               'binary': 'nova-compute',
 
1845
                               'topic': 'compute',
 
1846
                               'report_count': 0,
 
1847
                               'availability_zone': avail_zone})
 
1848
    return values
 
1849
 
 
1850
 
 
1851
class XenAPIAggregateTestCase(stubs.XenAPITestBase):
1737
1852
    """Unit tests for aggregate operations."""
1738
1853
    def setUp(self):
1739
1854
        super(XenAPIAggregateTestCase, self).setUp()
1743
1858
                   instance_name_template='%d',
1744
1859
                   firewall_driver='nova.virt.xenapi.firewall.'
1745
1860
                                   'Dom0IptablesFirewallDriver',
1746
 
                   host='host')
1747
 
        xenapi_fake.reset()
 
1861
                   host='host',
 
1862
                   connection_type='xenapi',
 
1863
                   compute_driver='nova.virt.xenapi.driver.XenAPIDriver')
1748
1864
        host_ref = xenapi_fake.get_all('host')[0]
1749
1865
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
1750
1866
        self.context = context.get_admin_context()
1751
1867
        self.conn = xenapi_conn.XenAPIDriver(False)
1752
 
        self.fake_metadata = {'master_compute': 'host',
 
1868
        self.compute = importutils.import_object(FLAGS.compute_manager)
 
1869
        self.api = compute_api.AggregateAPI()
 
1870
        values = {'name': 'test_aggr',
 
1871
                  'availability_zone': 'test_zone',
 
1872
                  'metadata': {pool_states.POOL_FLAG: 'XenAPI'}}
 
1873
        self.aggr = db.aggregate_create(self.context, values)
 
1874
        self.fake_metadata = {pool_states.POOL_FLAG: 'XenAPI',
 
1875
                              'master_compute': 'host',
 
1876
                              pool_states.KEY: pool_states.ACTIVE,
1753
1877
                              'host': xenapi_fake.get_record('host',
1754
1878
                                                             host_ref)['uuid']}
1755
1879
 
1773
1897
        result = db.aggregate_get(self.context, aggregate.id)
1774
1898
        self.assertTrue(fake_init_pool.called)
1775
1899
        self.assertDictMatch(self.fake_metadata, result.metadetails)
1776
 
        self.assertEqual(aggregate_states.ACTIVE, result.operational_state)
1777
1900
 
1778
1901
    def test_join_slave(self):
1779
1902
        """Ensure join_slave gets called when the request gets to master."""
1801
1924
        values = {"name": 'fake_aggregate',
1802
1925
                  "availability_zone": 'fake_zone'}
1803
1926
        result = db.aggregate_create(self.context, values)
 
1927
        metadata = {pool_states.POOL_FLAG: "XenAPI",
 
1928
                    pool_states.KEY: pool_states.CREATED}
 
1929
        db.aggregate_metadata_add(self.context, result.id, metadata)
 
1930
 
1804
1931
        db.aggregate_host_add(self.context, result.id, "host")
1805
1932
        aggregate = db.aggregate_get(self.context, result.id)
1806
1933
        self.assertEqual(["host"], aggregate.hosts)
1807
 
        self.assertEqual({}, aggregate.metadetails)
 
1934
        self.assertEqual(metadata, aggregate.metadetails)
1808
1935
 
1809
1936
        self.conn._pool.add_to_aggregate(self.context, aggregate, "host")
1810
1937
        self.assertTrue(fake_pool_set_name_label.called)
1820
1947
        self.assertTrue(fake_remove_from_aggregate.called)
1821
1948
 
1822
1949
    def test_remove_from_empty_aggregate(self):
1823
 
        values = {"name": 'fake_aggregate',
1824
 
                  "availability_zone": 'fake_zone'}
1825
 
        result = db.aggregate_create(self.context, values)
1826
 
        self.assertRaises(exception.AggregateError,
 
1950
        result = self._aggregate_setup()
 
1951
        self.assertRaises(exception.InvalidAggregateAction,
1827
1952
                          self.conn._pool.remove_from_aggregate,
1828
 
                          None, result, "test_host")
 
1953
                          self.context, result, "test_host")
1829
1954
 
1830
1955
    def test_remove_slave(self):
1831
1956
        """Ensure eject slave gets called."""
1835
1960
 
1836
1961
        self.fake_metadata['host2'] = 'fake_host2_uuid'
1837
1962
        aggregate = self._aggregate_setup(hosts=['host', 'host2'],
1838
 
                                          metadata=self.fake_metadata)
 
1963
                metadata=self.fake_metadata, aggr_state=pool_states.ACTIVE)
1839
1964
        self.conn._pool.remove_from_aggregate(self.context, aggregate, "host2")
1840
1965
        self.assertTrue(fake_eject_slave.called)
1841
1966
 
1845
1970
            fake_clear_pool.called = True
1846
1971
        self.stubs.Set(self.conn._pool, "_clear_pool", fake_clear_pool)
1847
1972
 
1848
 
        aggregate = self._aggregate_setup(aggr_state=aggregate_states.ACTIVE,
1849
 
                                          metadata=self.fake_metadata)
 
1973
        aggregate = self._aggregate_setup(metadata=self.fake_metadata)
1850
1974
        self.conn._pool.remove_from_aggregate(self.context, aggregate, "host")
1851
1975
        result = db.aggregate_get(self.context, aggregate.id)
1852
1976
        self.assertTrue(fake_clear_pool.called)
1853
 
        self.assertDictMatch({}, result.metadetails)
1854
 
        self.assertEqual(aggregate_states.ACTIVE, result.operational_state)
 
1977
        self.assertDictMatch({pool_states.POOL_FLAG: 'XenAPI',
 
1978
                pool_states.KEY: pool_states.ACTIVE}, result.metadetails)
1855
1979
 
1856
1980
    def test_remote_master_non_empty_pool(self):
1857
1981
        """Ensure AggregateError is raised if removing the master."""
1858
 
        aggregate = self._aggregate_setup(aggr_state=aggregate_states.ACTIVE,
1859
 
                                          hosts=['host', 'host2'],
 
1982
        aggregate = self._aggregate_setup(hosts=['host', 'host2'],
1860
1983
                                          metadata=self.fake_metadata)
 
1984
 
1861
1985
        self.assertRaises(exception.InvalidAggregateAction,
1862
1986
                          self.conn._pool.remove_from_aggregate,
1863
1987
                          self.context, aggregate, "host")
1864
1988
 
1865
1989
    def _aggregate_setup(self, aggr_name='fake_aggregate',
1866
1990
                         aggr_zone='fake_zone',
1867
 
                         aggr_state=aggregate_states.CREATED,
 
1991
                         aggr_state=pool_states.CREATED,
1868
1992
                         hosts=['host'], metadata=None):
1869
1993
        values = {"name": aggr_name,
1870
 
                  "availability_zone": aggr_zone,
1871
 
                  "operational_state": aggr_state, }
 
1994
                  "availability_zone": aggr_zone}
1872
1995
        result = db.aggregate_create(self.context, values)
 
1996
        pool_flag = {pool_states.POOL_FLAG: "XenAPI",
 
1997
                    pool_states.KEY: aggr_state}
 
1998
        db.aggregate_metadata_add(self.context, result.id, pool_flag)
 
1999
 
1873
2000
        for host in hosts:
1874
2001
            db.aggregate_host_add(self.context, result.id, host)
1875
2002
        if metadata:
1876
2003
            db.aggregate_metadata_add(self.context, result.id, metadata)
1877
2004
        return db.aggregate_get(self.context, result.id)
 
2005
 
 
2006
    def test_add_host_to_aggregate_invalid_changing_status(self):
 
2007
        """Ensure InvalidAggregateAction is raised when adding host while
 
2008
        aggregate is not ready."""
 
2009
        aggregate = self._aggregate_setup(aggr_state=pool_states.CHANGING)
 
2010
        self.assertRaises(exception.InvalidAggregateAction,
 
2011
                          self.conn.add_to_aggregate, self.context,
 
2012
                          aggregate, 'host')
 
2013
 
 
2014
    def test_add_host_to_aggregate_invalid_dismissed_status(self):
 
2015
        """Ensure InvalidAggregateAction is raised when aggregate is
 
2016
        deleted."""
 
2017
        aggregate = self._aggregate_setup(aggr_state=pool_states.DISMISSED)
 
2018
        self.assertRaises(exception.InvalidAggregateAction,
 
2019
                          self.conn.add_to_aggregate, self.context,
 
2020
                          aggregate, 'fake_host')
 
2021
 
 
2022
    def test_add_host_to_aggregate_invalid_error_status(self):
 
2023
        """Ensure InvalidAggregateAction is raised when aggregate is
 
2024
        in error."""
 
2025
        aggregate = self._aggregate_setup(aggr_state=pool_states.ERROR)
 
2026
        self.assertRaises(exception.InvalidAggregateAction,
 
2027
                          self.conn.add_to_aggregate, self.context,
 
2028
                          aggregate, 'fake_host')
 
2029
 
 
2030
    def test_remove_host_from_aggregate_error(self):
 
2031
        """Ensure we can remove a host from an aggregate even if in error."""
 
2032
        values = _create_service_entries(self.context)
 
2033
        fake_zone = values.keys()[0]
 
2034
        aggr = self.api.create_aggregate(self.context,
 
2035
                                         'fake_aggregate', fake_zone)
 
2036
        # let's mock the fact that the aggregate is ready!
 
2037
        metadata = {pool_states.POOL_FLAG: "XenAPI",
 
2038
                    pool_states.KEY: pool_states.ACTIVE}
 
2039
        db.aggregate_metadata_add(self.context, aggr['id'], metadata)
 
2040
        for host in values[fake_zone]:
 
2041
            aggr = self.api.add_host_to_aggregate(self.context,
 
2042
                                                  aggr['id'], host)
 
2043
        # let's mock the fact that the aggregate is in error!
 
2044
        status = {'operational_state': pool_states.ERROR}
 
2045
        expected = self.api.remove_host_from_aggregate(self.context,
 
2046
                                                       aggr['id'],
 
2047
                                                       values[fake_zone][0])
 
2048
        self.assertEqual(len(aggr['hosts']) - 1, len(expected['hosts']))
 
2049
        self.assertEqual(expected['metadata'][pool_states.KEY],
 
2050
                         pool_states.ACTIVE)
 
2051
 
 
2052
    def test_remove_host_from_aggregate_invalid_dismissed_status(self):
 
2053
        """Ensure InvalidAggregateAction is raised when aggregate is
 
2054
        deleted."""
 
2055
        aggregate = self._aggregate_setup(aggr_state=pool_states.DISMISSED)
 
2056
        self.assertRaises(exception.InvalidAggregateAction,
 
2057
                          self.conn.remove_from_aggregate, self.context,
 
2058
                          aggregate, 'fake_host')
 
2059
 
 
2060
    def test_remove_host_from_aggregate_invalid_changing_status(self):
 
2061
        """Ensure InvalidAggregateAction is raised when aggregate is
 
2062
        changing."""
 
2063
        aggregate = self._aggregate_setup(aggr_state=pool_states.CHANGING)
 
2064
        self.assertRaises(exception.InvalidAggregateAction,
 
2065
                          self.conn.remove_from_aggregate, self.context,
 
2066
                          aggregate, 'fake_host')
 
2067
 
 
2068
    def test_add_aggregate_host_raise_err(self):
 
2069
        """Ensure the undo operation works correctly on add."""
 
2070
        def fake_driver_add_to_aggregate(context, aggregate, host):
 
2071
            raise exception.AggregateError
 
2072
        self.stubs.Set(self.compute.driver, "add_to_aggregate",
 
2073
                       fake_driver_add_to_aggregate)
 
2074
        metadata = {pool_states.POOL_FLAG: "XenAPI",
 
2075
                    pool_states.KEY: pool_states.ACTIVE}
 
2076
        db.aggregate_metadata_add(self.context, self.aggr.id, metadata)
 
2077
        db.aggregate_host_add(self.context, self.aggr.id, 'fake_host')
 
2078
 
 
2079
        self.assertRaises(exception.AggregateError,
 
2080
                          self.compute.add_aggregate_host,
 
2081
                          self.context, self.aggr.id, "fake_host")
 
2082
        excepted = db.aggregate_get(self.context, self.aggr.id)
 
2083
        self.assertEqual(excepted.metadetails[pool_states.KEY],
 
2084
                pool_states.ERROR)
 
2085
        self.assertEqual(excepted.hosts, [])
 
2086
 
 
2087
 
 
2088
class VmUtilsTestCase(test.TestCase):
 
2089
    """Unit tests for xenapi utils."""
 
2090
 
 
2091
    def test_upload_image(self):
 
2092
        """Ensure image properties include instance system metadata
 
2093
           as well as few local settings."""
 
2094
 
 
2095
        def fake_instance_system_metadata_get(context, uuid):
 
2096
            return dict(image_a=1, image_b=2, image_c='c', d='d')
 
2097
 
 
2098
        def fake_get_sr_path(session):
 
2099
            return "foo"
 
2100
 
 
2101
        class FakeInstance(dict):
 
2102
            def __init__(self):
 
2103
                super(FakeInstance, self).__init__({
 
2104
                        'auto_disk_config': 'auto disk config',
 
2105
                        'os_type': 'os type'})
 
2106
 
 
2107
            def __missing__(self, item):
 
2108
                return "whatever"
 
2109
 
 
2110
        class FakeSession(object):
 
2111
            def call_plugin(session_self, service, command, kwargs):
 
2112
                self.kwargs = kwargs
 
2113
 
 
2114
        def fake_dumps(thing):
 
2115
            return thing
 
2116
 
 
2117
        self.stubs.Set(db, "instance_system_metadata_get",
 
2118
                                             fake_instance_system_metadata_get)
 
2119
        self.stubs.Set(vm_utils, "get_sr_path", fake_get_sr_path)
 
2120
        self.stubs.Set(pickle, "dumps", fake_dumps)
 
2121
 
 
2122
        ctx = context.get_admin_context()
 
2123
 
 
2124
        instance = FakeInstance()
 
2125
        session = FakeSession()
 
2126
        vm_utils.upload_image(ctx, session, instance, "vmi uuids", "image id")
 
2127
 
 
2128
        actual = self.kwargs['params']['properties']
 
2129
        expected = dict(a=1, b=2, c='c', d='d',
 
2130
                        auto_disk_config='auto disk config',
 
2131
                        os_type='os type')
 
2132
        self.assertEquals(expected, actual)
 
2133
 
 
2134
 
 
2135
class XenAPILiveMigrateTestCase(stubs.XenAPITestBase):
 
2136
    """Unit tests for live_migration."""
 
2137
    def setUp(self):
 
2138
        super(XenAPILiveMigrateTestCase, self).setUp()
 
2139
        self.flags(xenapi_connection_url='test_url',
 
2140
                   xenapi_connection_password='test_pass',
 
2141
                   firewall_driver='nova.virt.xenapi.firewall.'
 
2142
                                   'Dom0IptablesFirewallDriver',
 
2143
                   host='host')
 
2144
        db_fakes.stub_out_db_instance_api(self.stubs)
 
2145
        self.context = context.get_admin_context()
 
2146
        xenapi_fake.create_local_pifs()
 
2147
 
 
2148
    def test_live_migration_calls_vmops(self):
 
2149
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2150
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2151
 
 
2152
        def fake_live_migrate(context, instance_ref, dest, post_method,
 
2153
                              recover_method, block_migration, migrate_data):
 
2154
            fake_live_migrate.called = True
 
2155
 
 
2156
        self.stubs.Set(self.conn._vmops, "live_migrate", fake_live_migrate)
 
2157
 
 
2158
        self.conn.live_migration(None, None, None, None, None)
 
2159
        self.assertTrue(fake_live_migrate.called)
 
2160
 
 
2161
    def test_pre_live_migration(self):
 
2162
        # ensure method is present
 
2163
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2164
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2165
        self.conn.pre_live_migration(None, None, None, None)
 
2166
 
 
2167
    def test_post_live_migration_at_destination(self):
 
2168
        # ensure method is present
 
2169
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2170
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2171
        self.conn.post_live_migration_at_destination(None, None, None, None)
 
2172
 
 
2173
    def test_check_can_live_migrate_destination_with_block_migration(self):
 
2174
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2175
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2176
        expected = {'block_migration': True,
 
2177
                    'migrate_data': {'xenops': '',
 
2178
                                     'host': '',
 
2179
                                     'master': '',
 
2180
                                     'session_id': '',
 
2181
                                     'SM': ''}
 
2182
                    }
 
2183
        fake_data = self.conn.check_can_live_migrate_destination(self.context,
 
2184
                              {'host': 'host'}, True, False)
 
2185
        self.assertEqual(expected.keys(), fake_data.keys())
 
2186
        self.assertEqual(expected['migrate_data'].keys(),
 
2187
                         fake_data['migrate_data'].keys())
 
2188
 
 
2189
    def test_check_can_live_migrate_destination_block_migration_fails(self):
 
2190
        stubs.stubout_session(self.stubs,
 
2191
                              stubs.FakeSessionForFailedMigrateTests)
 
2192
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2193
        self.assertRaises(exception.MigrationError,
 
2194
                          self.conn.check_can_live_migrate_destination,
 
2195
                          self.context, {'host': 'host'}, True, False)
 
2196
 
 
2197
    def test_check_can_live_migrate_source_with_block_migrate(self):
 
2198
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2199
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2200
 
 
2201
        def fake_get_vm_opaque_ref(instance):
 
2202
            return "fake_vm"
 
2203
 
 
2204
        self.stubs.Set(self.conn._vmops, "_get_vm_opaque_ref",
 
2205
                       fake_get_vm_opaque_ref)
 
2206
        dest_check_data = {'block_migration': True,
 
2207
                           'migrate_data': {}}
 
2208
        self.assertNotRaises(None,
 
2209
                             self.conn.check_can_live_migrate_source,
 
2210
                             self.context,
 
2211
                             {'host': 'host'},
 
2212
                             dest_check_data)
 
2213
 
 
2214
    def test_check_can_live_migrate_source_with_block_migrate_fails(self):
 
2215
        def fake_get_vm_opaque_ref(instance):
 
2216
            return "fake_vm"
 
2217
        stubs.stubout_session(self.stubs,
 
2218
                              stubs.FakeSessionForFailedMigrateTests)
 
2219
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2220
        self.stubs.Set(self.conn._vmops, "_get_vm_opaque_ref",
 
2221
                       fake_get_vm_opaque_ref)
 
2222
 
 
2223
        dest_check_data = {'block_migration': True,
 
2224
                           'migrate_data': {}}
 
2225
        self.assertRaises(exception.MigrationError,
 
2226
                          self.conn.check_can_live_migrate_source,
 
2227
                          self.context,
 
2228
                          {'host': 'host'},
 
2229
                          dest_check_data)
 
2230
 
 
2231
    def test_check_can_live_migrate_works(self):
 
2232
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2233
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2234
 
 
2235
        class fake_aggregate:
 
2236
            def __init__(self):
 
2237
                self.metadetails = {"host": "test_host_uuid"}
 
2238
 
 
2239
        def fake_aggregate_get_by_host(context, host, key=None):
 
2240
            self.assertEqual(FLAGS.host, host)
 
2241
            return [fake_aggregate()]
 
2242
 
 
2243
        self.stubs.Set(db, "aggregate_get_by_host",
 
2244
                fake_aggregate_get_by_host)
 
2245
        self.conn.check_can_live_migrate_destination(self.context,
 
2246
                {'host': 'host'}, False, False)
 
2247
 
 
2248
    def test_check_can_live_migrate_fails(self):
 
2249
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2250
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2251
 
 
2252
        class fake_aggregate:
 
2253
            def __init__(self):
 
2254
                self.metadetails = {"dest_other": "test_host_uuid"}
 
2255
 
 
2256
        def fake_aggregate_get_by_host(context, host, key=None):
 
2257
            self.assertEqual(FLAGS.host, host)
 
2258
            return [fake_aggregate()]
 
2259
 
 
2260
        self.stubs.Set(db, "aggregate_get_by_host",
 
2261
                      fake_aggregate_get_by_host)
 
2262
        self.assertRaises(exception.MigrationError,
 
2263
                          self.conn.check_can_live_migrate_destination,
 
2264
                          self.context, {'host': 'host'}, None, None)
 
2265
 
 
2266
    def test_live_migration(self):
 
2267
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2268
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2269
 
 
2270
        def fake_get_vm_opaque_ref(instance):
 
2271
            return "fake_vm"
 
2272
        self.stubs.Set(self.conn._vmops, "_get_vm_opaque_ref",
 
2273
                       fake_get_vm_opaque_ref)
 
2274
 
 
2275
        def fake_get_host_opaque_ref(context, destination_hostname):
 
2276
            return "fake_host"
 
2277
        self.stubs.Set(self.conn._vmops, "_get_host_opaque_ref",
 
2278
                       fake_get_host_opaque_ref)
 
2279
 
 
2280
        def post_method(context, instance, destination_hostname,
 
2281
                        block_migration):
 
2282
            post_method.called = True
 
2283
 
 
2284
        self.conn.live_migration(self.conn, None, None, post_method, None)
 
2285
 
 
2286
        self.assertTrue(post_method.called, "post_method.called")
 
2287
 
 
2288
    def test_live_migration_on_failure(self):
 
2289
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2290
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2291
 
 
2292
        def fake_get_vm_opaque_ref(instance):
 
2293
            return "fake_vm"
 
2294
        self.stubs.Set(self.conn._vmops, "_get_vm_opaque_ref",
 
2295
                       fake_get_vm_opaque_ref)
 
2296
 
 
2297
        def fake_get_host_opaque_ref(context, destination_hostname):
 
2298
            return "fake_host"
 
2299
        self.stubs.Set(self.conn._vmops, "_get_host_opaque_ref",
 
2300
                       fake_get_host_opaque_ref)
 
2301
 
 
2302
        def fake_call_xenapi(*args):
 
2303
            raise NotImplementedError()
 
2304
        self.stubs.Set(self.conn._vmops._session, "call_xenapi",
 
2305
                       fake_call_xenapi)
 
2306
 
 
2307
        def recover_method(context, instance, destination_hostname,
 
2308
                        block_migration):
 
2309
            recover_method.called = True
 
2310
 
 
2311
        self.assertRaises(NotImplementedError, self.conn.live_migration,
 
2312
                          self.conn, None, None, None, recover_method)
 
2313
        self.assertTrue(recover_method.called, "recover_method.called")
 
2314
 
 
2315
    def test_live_migration_with_block_migration(self):
 
2316
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2317
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2318
 
 
2319
        def fake_get_vm_opaque_ref(instance):
 
2320
            return "fake_vm"
 
2321
        self.stubs.Set(self.conn._vmops, "_get_vm_opaque_ref",
 
2322
                       fake_get_vm_opaque_ref)
 
2323
 
 
2324
        def post_method(context, instance, destination_hostname,
 
2325
                        block_migration):
 
2326
            post_method.called = True
 
2327
 
 
2328
        # pass block_migration = True and migrate data
 
2329
        migrate_data = {"test": "data"}
 
2330
        self.conn.live_migration(self.conn, None, None, post_method, None,
 
2331
                                 True, migrate_data)
 
2332
        self.assertTrue(post_method.called, "post_method.called")
 
2333
 
 
2334
    def test_live_migration_with_block_migration_raises_invalid_param(self):
 
2335
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2336
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2337
 
 
2338
        def fake_get_vm_opaque_ref(instance):
 
2339
            return "fake_vm"
 
2340
        self.stubs.Set(self.conn._vmops, "_get_vm_opaque_ref",
 
2341
                       fake_get_vm_opaque_ref)
 
2342
 
 
2343
        def recover_method(context, instance, destination_hostname,
 
2344
                           block_migration):
 
2345
            recover_method.called = True
 
2346
        # pass block_migration = True and no migrate data
 
2347
        self.assertRaises(exception.InvalidParameterValue,
 
2348
                          self.conn.live_migration, self.conn,
 
2349
                          None, None, None, recover_method, True, None)
 
2350
        self.assertTrue(recover_method.called, "recover_method.called")
 
2351
 
 
2352
    def test_live_migration_with_block_migration_fails_migrate_send(self):
 
2353
        stubs.stubout_session(self.stubs,
 
2354
                              stubs.FakeSessionForFailedMigrateTests)
 
2355
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2356
 
 
2357
        def fake_get_vm_opaque_ref(instance):
 
2358
            return "fake_vm"
 
2359
        self.stubs.Set(self.conn._vmops, "_get_vm_opaque_ref",
 
2360
                       fake_get_vm_opaque_ref)
 
2361
 
 
2362
        def recover_method(context, instance, destination_hostname,
 
2363
                           block_migration):
 
2364
            recover_method.called = True
 
2365
        # pass block_migration = True and migrate data
 
2366
        migrate_data = {"test": "data"}
 
2367
        self.assertRaises(exception.MigrationError,
 
2368
                          self.conn.live_migration, self.conn,
 
2369
                          None, None, None, recover_method, True, migrate_data)
 
2370
        self.assertTrue(recover_method.called, "recover_method.called")
 
2371
 
 
2372
 
 
2373
class XenAPIInjectMetadataTestCase(stubs.XenAPITestBase):
 
2374
    def setUp(self):
 
2375
        super(XenAPIInjectMetadataTestCase, self).setUp()
 
2376
        self.flags(xenapi_connection_url='test_url',
 
2377
                   xenapi_connection_password='test_pass',
 
2378
                   firewall_driver='nova.virt.xenapi.firewall.'
 
2379
                                   'Dom0IptablesFirewallDriver')
 
2380
        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 
2381
        self.conn = xenapi_conn.XenAPIDriver(False)
 
2382
 
 
2383
        self.xenstore = dict(persist={}, ephem={})
 
2384
 
 
2385
        def fake_get_vm_opaque_ref(inst, instance):
 
2386
            self.assertEqual(instance, 'instance')
 
2387
            return 'vm_ref'
 
2388
 
 
2389
        def fake_add_to_param_xenstore(inst, vm_ref, key, val):
 
2390
            self.assertEqual(vm_ref, 'vm_ref')
 
2391
            self.xenstore['persist'][key] = val
 
2392
 
 
2393
        def fake_remove_from_param_xenstore(inst, vm_ref, key):
 
2394
            self.assertEqual(vm_ref, 'vm_ref')
 
2395
            if key in self.xenstore['persist']:
 
2396
                del self.xenstore['persist'][key]
 
2397
 
 
2398
        def fake_write_to_xenstore(inst, instance, path, value, vm_ref=None):
 
2399
            self.assertEqual(instance, 'instance')
 
2400
            self.assertEqual(vm_ref, 'vm_ref')
 
2401
            self.xenstore['ephem'][path] = jsonutils.dumps(value)
 
2402
 
 
2403
        def fake_delete_from_xenstore(inst, instance, path, vm_ref=None):
 
2404
            self.assertEqual(instance, 'instance')
 
2405
            self.assertEqual(vm_ref, 'vm_ref')
 
2406
            if path in self.xenstore['ephem']:
 
2407
                del self.xenstore['ephem'][path]
 
2408
 
 
2409
        self.stubs.Set(vmops.VMOps, '_get_vm_opaque_ref',
 
2410
                       fake_get_vm_opaque_ref)
 
2411
        self.stubs.Set(vmops.VMOps, '_add_to_param_xenstore',
 
2412
                       fake_add_to_param_xenstore)
 
2413
        self.stubs.Set(vmops.VMOps, '_remove_from_param_xenstore',
 
2414
                       fake_remove_from_param_xenstore)
 
2415
        self.stubs.Set(vmops.VMOps, '_write_to_xenstore',
 
2416
                       fake_write_to_xenstore)
 
2417
        self.stubs.Set(vmops.VMOps, '_delete_from_xenstore',
 
2418
                       fake_delete_from_xenstore)
 
2419
 
 
2420
    def test_inject_instance_metadata(self):
 
2421
 
 
2422
        # Add some system_metadata to ensure it doesn't get added
 
2423
        # to xenstore
 
2424
        instance = dict(metadata=[{'key': 'a', 'value': 1},
 
2425
                                  {'key': 'b', 'value': 2},
 
2426
                                  {'key': 'c', 'value': 3},
 
2427
                                  # Check xenstore key sanitizing
 
2428
                                  {'key': 'hi.there', 'value': 4},
 
2429
                                  {'key': 'hi!t.e/e', 'value': 5}],
 
2430
                                  # Check xenstore key sanitizing
 
2431
                        system_metadata=[{'key': 'sys_a', 'value': 1},
 
2432
                                         {'key': 'sys_b', 'value': 2},
 
2433
                                         {'key': 'sys_c', 'value': 3}])
 
2434
        self.conn._vmops.inject_instance_metadata(instance, 'vm_ref')
 
2435
 
 
2436
        self.assertEqual(self.xenstore, {
 
2437
                'persist': {
 
2438
                    'vm-data/user-metadata/a': '1',
 
2439
                    'vm-data/user-metadata/b': '2',
 
2440
                    'vm-data/user-metadata/c': '3',
 
2441
                    'vm-data/user-metadata/hi_there': '4',
 
2442
                    'vm-data/user-metadata/hi_t_e_e': '5',
 
2443
                    },
 
2444
                'ephem': {},
 
2445
                })
 
2446
 
 
2447
    def test_change_instance_metadata_add(self):
 
2448
        # Test XenStore key sanitizing here, too.
 
2449
        diff = {'test.key': ['+', 4]}
 
2450
        self.xenstore = {
 
2451
            'persist': {
 
2452
                'vm-data/user-metadata/a': '1',
 
2453
                'vm-data/user-metadata/b': '2',
 
2454
                'vm-data/user-metadata/c': '3',
 
2455
                },
 
2456
            'ephem': {
 
2457
                'vm-data/user-metadata/a': '1',
 
2458
                'vm-data/user-metadata/b': '2',
 
2459
                'vm-data/user-metadata/c': '3',
 
2460
                },
 
2461
            }
 
2462
 
 
2463
        self.conn._vmops.change_instance_metadata('instance', diff)
 
2464
 
 
2465
        self.assertEqual(self.xenstore, {
 
2466
                'persist': {
 
2467
                    'vm-data/user-metadata/a': '1',
 
2468
                    'vm-data/user-metadata/b': '2',
 
2469
                    'vm-data/user-metadata/c': '3',
 
2470
                    'vm-data/user-metadata/test_key': '4',
 
2471
                    },
 
2472
                'ephem': {
 
2473
                    'vm-data/user-metadata/a': '1',
 
2474
                    'vm-data/user-metadata/b': '2',
 
2475
                    'vm-data/user-metadata/c': '3',
 
2476
                    'vm-data/user-metadata/test_key': '4',
 
2477
                    },
 
2478
                })
 
2479
 
 
2480
    def test_change_instance_metadata_update(self):
 
2481
        diff = dict(b=['+', 4])
 
2482
        self.xenstore = {
 
2483
            'persist': {
 
2484
                'vm-data/user-metadata/a': '1',
 
2485
                'vm-data/user-metadata/b': '2',
 
2486
                'vm-data/user-metadata/c': '3',
 
2487
                },
 
2488
            'ephem': {
 
2489
                'vm-data/user-metadata/a': '1',
 
2490
                'vm-data/user-metadata/b': '2',
 
2491
                'vm-data/user-metadata/c': '3',
 
2492
                },
 
2493
            }
 
2494
 
 
2495
        self.conn._vmops.change_instance_metadata('instance', diff)
 
2496
 
 
2497
        self.assertEqual(self.xenstore, {
 
2498
                'persist': {
 
2499
                    'vm-data/user-metadata/a': '1',
 
2500
                    'vm-data/user-metadata/b': '4',
 
2501
                    'vm-data/user-metadata/c': '3',
 
2502
                    },
 
2503
                'ephem': {
 
2504
                    'vm-data/user-metadata/a': '1',
 
2505
                    'vm-data/user-metadata/b': '4',
 
2506
                    'vm-data/user-metadata/c': '3',
 
2507
                    },
 
2508
                })
 
2509
 
 
2510
    def test_change_instance_metadata_delete(self):
 
2511
        diff = dict(b=['-'])
 
2512
        self.xenstore = {
 
2513
            'persist': {
 
2514
                'vm-data/user-metadata/a': '1',
 
2515
                'vm-data/user-metadata/b': '2',
 
2516
                'vm-data/user-metadata/c': '3',
 
2517
                },
 
2518
            'ephem': {
 
2519
                'vm-data/user-metadata/a': '1',
 
2520
                'vm-data/user-metadata/b': '2',
 
2521
                'vm-data/user-metadata/c': '3',
 
2522
                },
 
2523
            }
 
2524
 
 
2525
        self.conn._vmops.change_instance_metadata('instance', diff)
 
2526
 
 
2527
        self.assertEqual(self.xenstore, {
 
2528
                'persist': {
 
2529
                    'vm-data/user-metadata/a': '1',
 
2530
                    'vm-data/user-metadata/c': '3',
 
2531
                    },
 
2532
                'ephem': {
 
2533
                    'vm-data/user-metadata/a': '1',
 
2534
                    'vm-data/user-metadata/c': '3',
 
2535
                    },
 
2536
                })