def test_vim_client_with_param(self, connect_mock):
     vim_client = VimClient(auto_sync=False)
     vim_client.connect_userpwd("esx.local", "root", "password")
     connect_mock.assert_called_once_with(host="esx.local",
                                          user="******",
                                          pwd="password",
                                          version="vim.version.version9")
Exemplo n.º 2
0
 def test_update_fail_without_looping(self, connect_mock, update_mock):
     client = VimClient(auto_sync=True, min_interval=1)
     client.connect_userpwd("esx.local", "root", "password")
     update_mock.side_effect = vim.fault.HostConnectFault
     time.sleep(0.5)
     client.disconnect()
     assert_that(update_mock.call_count, less_than(5))  # no crazy loop
Exemplo n.º 3
0
    def test_update_host_cache_in_thread(self, disconnect_mock, connect_mock, spec_mock,
                                         update_mock, prop_collector_mock):
        vm = vim.VirtualMachine("moid", None)
        vm.kind = "enter"
        vm.changeSet = {}
        update = MagicMock()
        update.filterSet = [MagicMock()]
        update.filterSet[0].objectSet = [MagicMock()]
        update.filterSet[0].objectSet[0] = vm

        # Mock the Vim APIs.
        prop_collector_mock.WaitForUpdatesEx = MagicMock()
        prop_collector_mock.WaitForUpdatesEx.return_value = update

        # Create VimClient.
        vim_client = VimClient(min_interval=0.1, auto_sync=True)
        vim_client.connect_userpwd("esx.local", "root", "password")

        # Verify that the update mock is called a few times.
        retry = 0
        while update_mock.call_count < 5 and retry < 10:
            time.sleep(0.2)
            retry += 1
        assert_that(retry, is_not(10), "VimClient.update_mock is not called repeatedly")

        # Disconnect the client and stop the thread.
        vim_client.disconnect()
        assert_that(disconnect_mock.called, is_(True))

        assert_that(update_mock.call_count, is_not(0), "VimClient.update_mock is not called")
 def test_update_fail_without_looping(self, connect_mock, update_mock):
     client = VimClient(auto_sync=True, min_interval=1)
     client.connect_userpwd("esx.local", "root", "password")
     update_mock.side_effect = vim.fault.HostConnectFault
     time.sleep(0.5)
     client.disconnect()
     assert_that(update_mock.call_count, less_than(5))  # no crazy loop
    def test_update_host_cache_in_thread(self, disconnect_mock, connect_mock,
                                         spec_mock, update_mock,
                                         prop_collector_mock):
        vm = vim.VirtualMachine("moid", None)
        vm.kind = "enter"
        vm.changeSet = {}
        update = MagicMock()
        update.filterSet = [MagicMock()]
        update.filterSet[0].objectSet = [MagicMock()]
        update.filterSet[0].objectSet[0] = vm

        # Mock the Vim APIs.
        prop_collector_mock.WaitForUpdatesEx = MagicMock()
        prop_collector_mock.WaitForUpdatesEx.return_value = update

        # Create VimClient.
        vim_client = VimClient(min_interval=0.1, auto_sync=True)
        vim_client.connect_userpwd("esx.local", "root", "password")

        # Verify that the update mock is called a few times.
        retry = 0
        while update_mock.call_count < 5 and retry < 10:
            time.sleep(0.2)
            retry += 1
        assert_that(retry, is_not(10),
                    "VimClient.update_mock is not called repeatedly")

        # Disconnect the client and stop the thread.
        vim_client.disconnect()
        assert_that(disconnect_mock.called, is_(True))

        assert_that(update_mock.call_count, is_not(0),
                    "VimClient.update_mock is not called")
Exemplo n.º 6
0
    def test_poll_update_in_thread(self, disconnect_mock, connect_mock, spec_mock, update_mock):
        vim_client = VimClient(min_interval=0, auto_sync=True)
        vim_client.connect_userpwd("esx.local", "root", "password")
        vim_client._property_collector.WaitForUpdatesEx.return_value = {}

        assert_that(update_mock.called, is_(True))
        retry = 0
        while update_mock.call_count < 5 and retry < 10:
            time.sleep(0.2)
            retry += 1
        assert_that(retry, is_not(10), "VimClient._poll_updates is not called repeatedly")
        vim_client.disconnect()
        assert_that(disconnect_mock.called, is_(True))
    def test_poll_update_in_thread(self, disconnect_mock, connect_mock,
                                   spec_mock, update_mock):
        vim_client = VimClient(min_interval=0, auto_sync=True)
        vim_client.connect_userpwd("esx.local", "root", "password")
        vim_client._property_collector.WaitForUpdatesEx.return_value = {}

        assert_that(update_mock.called, is_(True))
        retry = 0
        while update_mock.call_count < 5 and retry < 10:
            time.sleep(0.2)
            retry += 1
        assert_that(retry, is_not(10),
                    "VimClient._poll_updates is not called repeatedly")
        vim_client.disconnect()
        assert_that(disconnect_mock.called, is_(True))
class TestVmManager(unittest.TestCase):
    def setUp(self):
        if "host_remote_test" not in config:
            raise SkipTest()

        self.host = config["host_remote_test"]["server"]
        self.pwd = config["host_remote_test"]["esx_pwd"]

        if self.host is None or self.pwd is None:
            raise SkipTest()

        self._logger = logging.getLogger(__name__)
        self.vim_client = VimClient()
        self.vim_client.connect_userpwd(self.host, "root", self.pwd)
        self.vm_manager = VmManager(self.vim_client, None)
        for vm in self.vim_client._get_vms():
            vm.Destroy()

    def tearDown(self):
        self.vim_client.disconnect()

    @patch('os.path.exists', return_value=True)
    def test_mks_ticket(self, _exists):
        vm_id = self._vm_id()
        flavor = Flavor("vm", [
            QuotaLineItem("vm.cpu", 1, Unit.COUNT),
            QuotaLineItem("vm.memory", 8, Unit.MB)
        ])
        datastore = self.vim_client.get_all_datastores()[0].name
        spec = self.vm_manager.create_vm_spec(vm_id, datastore, flavor)
        try:
            self.vm_manager.create_vm(vm_id, spec)
            self.vm_manager.power_on_vm(vm_id)
            ticket = self.vm_manager.get_mks_ticket(vm_id)
            assert_that(ticket.cfg_file, not_none())
            assert_that(ticket.ticket, not_none())
        finally:
            self.vm_manager.power_off_vm(vm_id)
            self.vm_manager.delete_vm(vm_id)

    def _vm_id(self):
        vm_id = strftime("%Y-%m-%d-%H%M%S-", localtime())
        vm_id += str(random.randint(1, 10000))

        return vm_id

    def _test_port(self):
        return 5907
Exemplo n.º 9
0
class TestVmManager(unittest.TestCase):

    def setUp(self):
        if "host_remote_test" not in config:
            raise SkipTest()

        self.host = config["host_remote_test"]["server"]
        self.pwd = config["host_remote_test"]["esx_pwd"]

        if self.host is None or self.pwd is None:
            raise SkipTest()

        self._logger = logging.getLogger(__name__)
        self.vim_client = VimClient()
        self.vim_client.connect_userpwd(self.host, "root", self.pwd)
        self.vm_manager = VmManager(self.vim_client, None)
        for vm in self.vim_client._get_vms():
            vm.Destroy()

    def tearDown(self):
        self.vim_client.disconnect()

    @patch('os.path.exists', return_value=True)
    def test_mks_ticket(self, _exists):
        vm_id = self._vm_id()
        flavor = Flavor("vm", [QuotaLineItem("vm.cpu", 1, Unit.COUNT),
                               QuotaLineItem("vm.memory", 8, Unit.MB)])
        datastore = self.vim_client.get_all_datastores()[0].name
        spec = self.vm_manager.create_vm_spec(vm_id, datastore, flavor)
        try:
            self.vm_manager.create_vm(vm_id, spec)
            self.vm_manager.power_on_vm(vm_id)
            ticket = self.vm_manager.get_mks_ticket(vm_id)
            assert_that(ticket.cfg_file, not_none())
            assert_that(ticket.ticket, not_none())
        finally:
            self.vm_manager.power_off_vm(vm_id)
            self.vm_manager.delete_vm(vm_id)

    def _vm_id(self):
        vm_id = strftime("%Y-%m-%d-%H%M%S-", localtime())
        vm_id += str(random.randint(1, 10000))

        return vm_id

    def _test_port(self):
        return 5907
Exemplo n.º 10
0
    def test_vim_client_errback(self, connect_mock, host_mock):
        callback = MagicMock()
        vim_client = VimClient(auto_sync=False, errback=callback)
        vim_client.connect_userpwd("esx.local", "root", "password")
        host_mock.side_effect = vim.fault.NotAuthenticated
        vim_client.host_system
        callback.assert_called_once()

        host_mock.side_effect = vim.fault.HostConnectFault
        vim_client.host_system
        assert_that(callback.call_count, is_(2))

        host_mock.side_effect = vim.fault.InvalidLogin
        vim_client.host_system
        assert_that(callback.call_count, is_(3))

        host_mock.side_effect = AcquireCredentialsException
        vim_client.host_system
        assert_that(callback.call_count, is_(4))
Exemplo n.º 11
0
    def test_vim_client_errback(self, connect_mock, host_mock):
        callback = MagicMock()
        vim_client = VimClient(auto_sync=False, errback=callback)
        vim_client.connect_userpwd("esx.local", "root", "password")
        host_mock.side_effect = vim.fault.NotAuthenticated
        vim_client.host_system()
        callback.assert_called_once()

        host_mock.side_effect = vim.fault.HostConnectFault
        vim_client.host_system()
        assert_that(callback.call_count, is_(2))

        host_mock.side_effect = vim.fault.InvalidLogin
        vim_client.host_system()
        assert_that(callback.call_count, is_(3))

        host_mock.side_effect = AcquireCredentialsException
        vim_client.host_system()
        assert_that(callback.call_count, is_(4))
Exemplo n.º 12
0
    def test_update_fail_will_suicide(self, sleep_mock, connect_mock, update_mock):
        killed = threading.Event()

        def suicide():
            killed.set()
            threading.current_thread().stop()

        poll_updates = MagicMock()
        poll_updates.side_effect = vim.fault.HostConnectFault

        client = VimClient(auto_sync=True, min_interval=1, errback=lambda: suicide())
        client.connect_userpwd("esx.local", "root", "password")
        client._vim_cache.poll_updates = poll_updates

        killed.wait(1)
        client.disconnect()

        # poll_updates will be called 5 times before it kill itself
        assert_that(poll_updates.call_count, is_(5))
        assert_that(killed.is_set(), is_(True))
Exemplo n.º 13
0
    def test_update_fail_will_suicide(self, sleep_mock, connect_mock,
                                      update_mock):
        killed = threading.Event()

        def suicide():
            killed.set()
            threading.current_thread().stop()

        poll_updates = MagicMock()
        poll_updates.side_effect = vim.fault.HostConnectFault

        client = VimClient(auto_sync=True,
                           min_interval=1,
                           errback=lambda: suicide())
        client.connect_userpwd("esx.local", "root", "password")
        client._vim_cache.poll_updates = poll_updates

        killed.wait(1)
        client.disconnect()

        # poll_updates will be called 5 times before it kill itself
        assert_that(poll_updates.call_count, is_(5))
        assert_that(killed.is_set(), is_(True))
Exemplo n.º 14
0
 def test_vim_client_with_param(self, connect_mock):
     vim_client = VimClient(auto_sync=False)
     vim_client.connect_userpwd("esx.local", "root", "password")
     connect_mock.assert_called_once_with(host="esx.local", user="******", pwd="password",
                                          version="vim.version.version9")
Exemplo n.º 15
0
class TestVimClient(unittest.TestCase):
    def setUp(self):
        if "host_remote_test" not in config:
            raise SkipTest()

        self.host = config["host_remote_test"]["server"]
        self.pwd = config["host_remote_test"]["esx_pwd"]

        if self.host is None or self.pwd is None:
            raise SkipTest()

        self.vim_client = VimClient(auto_sync=True)
        self.vim_client.connect_userpwd(self.host, "root", self.pwd)
        self._logger = logging.getLogger(__name__)

    def tearDown(self):
        self.vim_client.disconnect()

    def test_memory_usage(self):
        used_memory = self.vim_client.memory_usage_mb
        assert_that(used_memory > 0, is_(True))

    def test_total_memory(self):
        total_memory = self.vim_client.total_vmusable_memory_mb
        assert_that(total_memory > 0, is_(True))

    def test_total_cpus(self):
        num_cpus = self.vim_client.num_physical_cpus
        assert_that(num_cpus > 0, is_(True))

    def _create_test_vm(self, suffix="host-integ"):
        # Create VM
        vm_id = "vm_%s-%s-%s" % (time.strftime("%Y-%m-%d-%H%M%S",
                                               time.localtime()),
                                 str(random.randint(100000, 1000000)), suffix)

        datastore = self.vim_client.get_all_datastores()[0].name
        disk_path = "[%s] %s/disk.vmdk" % (datastore, vm_id)
        create_spec = self.get_create_spec(datastore, vm_id, disk_path)
        self.vim_client.create_vm(vm_id, create_spec)
        vm = self.vim_client.get_vm(vm_id)
        return (vm_id, vm, datastore, disk_path)

    def test_get_cached_vm(self):
        vm_id, vm, datastore, disk_path = self._create_test_vm("vm-cache-test")

        # Verify VM is in cache
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms), is_(1))
        assert_that(found_vms[0].name, is_(vm_id))
        assert_that(found_vms[0].power_state, is_(VmPowerState.STOPPED))
        assert_that(found_vms[0].memory_mb, is_(64))
        assert_that(found_vms[0].path, starts_with("[%s]" % datastore))
        assert_that(len(found_vms[0].disks), is_(1))
        assert_that(found_vms[0].disks[0], is_(disk_path))

        # Make sure get_vm_in_cache works
        vm_from_cache = self.vim_client.get_vm_in_cache(vm_id)
        assert_that(vm_from_cache.name, is_(vm_id))
        self.assertRaises(VmNotFoundException, self.vim_client.get_vm_in_cache,
                          "missing")

        # Add disk
        disk2_path = "[%s] %s/disk2.vmdk" % (datastore, vm_id)
        update_spec = self.get_update_spec(vm, disk2_path)
        task = vm.ReconfigVM_Task(update_spec.get_spec())
        self.vim_client.wait_for_task(task)

        # For the ReconfigVM task to remove disk, the hostd could update
        # task status to success before updating VM status. Thus when
        # wait_for_task returns, the vm_cache is possible to be still in old
        # state, though eventually it converges to consistent state. It only
        # happens in this task AFAIK. It should be fine for this task, because
        # rarely there is other operation that depends on this task.
        self._wait_vm_has_disk(vm_id, 2)

        # Verify disk added
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms[0].disks), is_(2))
        assert_that(found_vms[0].disks,
                    contains_inanyorder(disk_path, disk2_path))

        # Remove disk
        vm = self.vim_client.get_vm(vm_id)
        remove_spec = self.get_remove_spec(vm, disk2_path)
        task = vm.ReconfigVM_Task(remove_spec.get_spec())
        self.vim_client.wait_for_task(task)

        # Same as before when disk is added
        self._wait_vm_has_disk(vm_id, 1)

        # Verify disk removed
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms), is_(1))
        assert_that(len(found_vms[0].disks), is_(1),
                    "disk2 in " + str(found_vms[0].disks))
        assert_that(found_vms[0].disks, contains_inanyorder(disk_path))

        # Power on vm
        task = vm.PowerOn()
        self.vim_client.wait_for_task(task)

        # Wait until it disappears from the cache
        self._wait_vm_power_status(vm_id, VmPowerState.STARTED)

        # Verify VM state in cache is updated
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms), is_(1))
        assert_that(found_vms[0].power_state, is_(VmPowerState.STARTED))
        assert_that(found_vms[0].name, is_(vm_id))
        assert_that(found_vms[0].memory_mb, is_(64))
        assert_that(found_vms[0].path, starts_with("[%s]" % datastore))
        assert_that(len(found_vms[0].disks), is_(1))
        assert_that(found_vms[0].disks[0], is_(disk_path))

        # Destroy VM
        task = vm.PowerOff()
        self.vim_client.wait_for_task(task)
        task = vm.Destroy()
        self.vim_client.wait_for_task(task)

        # Verify VM is deleted from cache
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms), is_(0))

    def test_no_datastore_update(self):
        """ Test datastore update is no longer triggered on VM creates/deletes
        """
        class UpdateListener(object):
            def __init__(self):
                self._ds_update_count = 0

            def datastores_updated(self):
                self._ds_update_count += 1

        listener = UpdateListener()
        self.vim_client.add_update_listener(listener)
        # listener always gets updated once on add
        assert_that(listener._ds_update_count, is_(1))

        mock_apply = MagicMock(
            wraps=self.vim_client._vim_cache._update_ds_cache)
        self.vim_client._vim_cache._update_ds_cache = mock_apply

        _, vm, _, _ = self._create_test_vm("ds-update-test")
        task = vm.Destroy()
        self.vim_client.wait_for_task(task)

        # expect to get a datastore property update (unfortunately) ...
        for _ in xrange(50):
            if mock_apply.call_count > 0:
                break
            time.sleep(0.1)
        # ... but that additional datastore updated notifications are sent out
        # as a result
        assert_that(listener._ds_update_count, is_(1))

    def get_create_spec(self, datastore, vm_id, disk_path):
        create_spec = EsxVmConfigSpec(None)
        create_spec.init_for_create(vm_id, datastore, 64, 2)
        create_spec._cfg_spec.files = vim.vm.FileInfo(vmPathName="[%s] /" %
                                                      datastore)
        controller = vim.vm.device.VirtualLsiLogicController(
            key=1,
            sharedBus=vim.vm.device.VirtualSCSIController.Sharing.noSharing,
            busNumber=2,
            unitNumber=-1)
        create_spec._add_device(controller)
        backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo(
            fileName=disk_path,
            diskMode=vim.vm.device.VirtualDiskOption.DiskMode.persistent)
        disk = vim.vm.device.VirtualDisk(
            controllerKey=1,
            key=-1,
            unitNumber=-1,
            backing=backing,
            capacityInKB=1024,
        )
        create_spec._create_device(disk)
        return create_spec

    def get_update_spec(self, vm_info, disk_path):
        update_spec = EsxVmConfigSpec(None)
        update_spec.init_for_update()
        backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo(
            fileName=disk_path,
            diskMode=vim.vm.device.VirtualDiskOption.DiskMode.persistent)
        controller = update_spec._find_scsi_controller(vm_info.config)
        disk = vim.vm.device.VirtualDisk(
            controllerKey=controller.key,
            key=-1,
            unitNumber=-1,
            backing=backing,
            capacityInKB=1024,
        )
        update_spec._create_device(disk)
        return update_spec

    def get_remove_spec(self, vm_info, disk_path):
        remove_spec = EsxVmConfigSpec(None)
        remove_spec.init_for_update()
        devices = remove_spec._get_devices_by_type(vm_info.config,
                                                   vim.vm.device.VirtualDisk)
        found_device = None
        for device in devices:
            if device.backing.fileName.endswith(disk_path):
                found_device = device
        remove_spec._remove_device(found_device)
        return remove_spec

    def test_clone_ticket(self):
        ticket = self.vim_client.get_vim_ticket()
        vim_client2 = VimClient()
        vim_client2.connect_ticket(self.host, ticket)
        vim_client2.host_system()

    def _wait_vm_has_disk(self, vm_id, disk_num):
        """Wait until the vm has disk number of the vm becomes disk_num
        """
        now = time.time()
        for _ in xrange(50):
            vm_in_cache = self.vim_client.get_vm_in_cache(vm_id)
            if len(vm_in_cache.disks) == disk_num:
                self._logger.info("VmCache disk number synced in %.2f second" %
                                  (time.time() - now))
                break
            time.sleep(0.1)

    def _wait_vm_power_status(self, vm_id, power_state):
        """Wait until the vm has power_state
        """
        now = time.time()
        for _ in xrange(50):
            vm_in_cache = self.vim_client.get_vm_in_cache(vm_id)
            if vm_in_cache.power_state == power_state:
                self._logger.info("VmCache power_state synced in %.2f second" %
                                  (time.time() - now))
                break
            time.sleep(0.1)
Exemplo n.º 16
0
    def test_update_cache(self, connect_mock, spec_mock):
        vim_client = VimClient(auto_sync=False)
        vim_client.connect_userpwd("esx.local", "root", "password")
        vim_client._property_collector.WaitForUpdatesEx.return_value = {}
        vim_client._vim_cache = VimCache()

        # Test enter
        update = vmodl.query.PropertyCollector.UpdateSet(version="1")
        filter = vmodl.query.PropertyCollector.FilterUpdate()
        update.filterSet.append(filter)
        object_update = vmodl.query.PropertyCollector.ObjectUpdate(
            kind="enter",
            obj=vim.VirtualMachine("vim.VirtualMachine:9"),
        )
        filter.objectSet.append(object_update)
        object_update.changeSet.append(
            vmodl.query.PropertyCollector.Change(name="name",
                                                 op="assign",
                                                 val="agent4"))
        object_update.changeSet.append(
            vmodl.query.PropertyCollector.Change(name="runtime.powerState",
                                                 op="assign",
                                                 val="poweredOff"))
        object_update.changeSet.append(
            vmodl.query.PropertyCollector.Change(
                name="config",
                op="assign",
                val=vim.vm.ConfigInfo(
                    files=vim.vm.FileInfo(
                        vmPathName="[datastore2] agent4/agent4.vmx"),
                    hardware=vim.vm.VirtualHardware(memoryMB=4096),
                    locationId="location1"),
            ))
        disk_list = vim.vm.FileLayout.DiskLayout.Array()
        disk_list.append(vim.vm.FileLayout.DiskLayout(diskFile=["disk1"]))
        disk_list.append(vim.vm.FileLayout.DiskLayout(diskFile=["disk2"]))
        object_update.changeSet.append(
            vmodl.query.PropertyCollector.Change(name="layout.disk",
                                                 op="assign",
                                                 val=disk_list))

        vim_client._property_collector.WaitForUpdatesEx.return_value = update
        assert_that(len(vim_client.get_vms_in_cache()), is_(0))
        vim_client._vim_cache.poll_updates(vim_client)
        vim_client._property_collector.WaitForUpdatesEx.assert_called()

        vms = vim_client.get_vms_in_cache()
        assert_that(vim_client._vim_cache._current_version, is_("1"))
        assert_that(len(vms), 1)
        assert_that(vms[0].memory_mb, is_(4096))
        assert_that(vms[0].path, is_("[datastore2] agent4/agent4.vmx"))
        assert_that(vms[0].name, is_("agent4"))
        assert_that(vms[0].power_state, is_(VmPowerState.STOPPED))
        assert_that(len(vms[0].disks), is_(2))
        assert_that(vms[0].disks, contains_inanyorder("disk1", "disk2"))
        assert_that(vms[0].location_id, is_("location1"))

        # Test Modify
        update.version = "2"
        object_update = vmodl.query.PropertyCollector.ObjectUpdate(
            kind="modify",
            obj=vim.VirtualMachine("vim.VirtualMachine:9"),
        )
        filter.objectSet[0] = object_update
        object_update.changeSet.append(
            vmodl.query.PropertyCollector.Change(name="runtime.powerState",
                                                 op="assign",
                                                 val="poweredOn"))
        object_update.changeSet.append(
            vmodl.query.PropertyCollector.Change(name="runtime.powerState",
                                                 op="assign",
                                                 val="poweredOn"))
        disk_list = vim.vm.FileLayout.DiskLayout.Array()
        disk_list.append(
            vim.vm.FileLayout.DiskLayout(diskFile=["disk3", "disk4"]))
        object_update.changeSet.append(
            vmodl.query.PropertyCollector.Change(name="layout.disk",
                                                 op="assign",
                                                 val=disk_list))

        vim_client._vim_cache.poll_updates(vim_client)
        vms = vim_client.get_vms_in_cache()
        assert_that(vim_client._vim_cache._current_version, is_("2"))
        assert_that(len(vms), is_(1))
        assert_that(vms[0].memory_mb, is_(4096))
        assert_that(vms[0].path, is_("[datastore2] agent4/agent4.vmx"))
        assert_that(vms[0].name, is_("agent4"))
        assert_that(vms[0].power_state, is_(VmPowerState.STARTED))
        assert_that(len(vms[0].disks), is_(2))
        assert_that(vms[0].disks, contains_inanyorder("disk3", "disk4"))

        # Test leave
        update.version = "3"
        object_update = vmodl.query.PropertyCollector.ObjectUpdate(
            kind="leave",
            obj=vim.VirtualMachine("vim.VirtualMachine:9"),
        )
        filter.objectSet[0] = object_update
        vim_client._vim_cache.poll_updates(vim_client)
        vms = vim_client.get_vms_in_cache()
        assert_that(vim_client._vim_cache._current_version, is_("3"))
        assert_that(len(vms), is_(0))
Exemplo n.º 17
0
    def test_update_cache(self, connect_mock, spec_mock):
        vim_client = VimClient(auto_sync=False)
        vim_client.connect_userpwd("esx.local", "root", "password")
        vim_client._property_collector.WaitForUpdatesEx.return_value = {}
        vim_client._vim_cache = VimCache()

        # Test enter
        update = vmodl.query.PropertyCollector.UpdateSet(version="1")
        filter = vmodl.query.PropertyCollector.FilterUpdate()
        update.filterSet.append(filter)
        object_update = vmodl.query.PropertyCollector.ObjectUpdate(
            kind="enter",
            obj=vim.VirtualMachine("vim.VirtualMachine:9"),
        )
        filter.objectSet.append(object_update)
        object_update.changeSet.append(
                vmodl.query.PropertyCollector.Change(name="name", op="assign", val="agent4"))
        object_update.changeSet.append(
                vmodl.query.PropertyCollector.Change(name="runtime.powerState", op="assign", val="poweredOff"))
        object_update.changeSet.append(
            vmodl.query.PropertyCollector.Change(name="config", op="assign", val=vim.vm.ConfigInfo(
                files=vim.vm.FileInfo(vmPathName="[datastore2] agent4/agent4.vmx"),
                hardware=vim.vm.VirtualHardware(memoryMB=4096),
                locationId="location1"),
            ))
        disk_list = vim.vm.FileLayout.DiskLayout.Array()
        disk_list.append(vim.vm.FileLayout.DiskLayout(diskFile=["disk1"]))
        disk_list.append(vim.vm.FileLayout.DiskLayout(diskFile=["disk2"]))
        object_update.changeSet.append(
                vmodl.query.PropertyCollector.Change(name="layout.disk", op="assign", val=disk_list))

        vim_client._property_collector.WaitForUpdatesEx.return_value = update
        assert_that(len(vim_client.get_vms_in_cache()), is_(0))
        vim_client._vim_cache.poll_updates(vim_client)
        vim_client._property_collector.WaitForUpdatesEx.assert_called()

        vms = vim_client.get_vms_in_cache()
        assert_that(vim_client._vim_cache._current_version, is_("1"))
        assert_that(len(vms), 1)
        assert_that(vms[0].memory_mb, is_(4096))
        assert_that(vms[0].path, is_("[datastore2] agent4/agent4.vmx"))
        assert_that(vms[0].name, is_("agent4"))
        assert_that(vms[0].power_state, is_(VmPowerState.STOPPED))
        assert_that(len(vms[0].disks), is_(2))
        assert_that(vms[0].disks, contains_inanyorder("disk1", "disk2"))
        assert_that(vms[0].location_id, is_("location1"))

        # Test Modify
        update.version = "2"
        object_update = vmodl.query.PropertyCollector.ObjectUpdate(
            kind="modify",
            obj=vim.VirtualMachine("vim.VirtualMachine:9"),
        )
        filter.objectSet[0] = object_update
        object_update.changeSet.append(
                vmodl.query.PropertyCollector.Change(name="runtime.powerState", op="assign", val="poweredOn"))
        object_update.changeSet.append(
                vmodl.query.PropertyCollector.Change(name="runtime.powerState", op="assign", val="poweredOn"))
        disk_list = vim.vm.FileLayout.DiskLayout.Array()
        disk_list.append(vim.vm.FileLayout.DiskLayout(diskFile=["disk3", "disk4"]))
        object_update.changeSet.append(
                vmodl.query.PropertyCollector.Change(name="layout.disk", op="assign", val=disk_list))

        vim_client._vim_cache.poll_updates(vim_client)
        vms = vim_client.get_vms_in_cache()
        assert_that(vim_client._vim_cache._current_version, is_("2"))
        assert_that(len(vms), is_(1))
        assert_that(vms[0].memory_mb, is_(4096))
        assert_that(vms[0].path, is_("[datastore2] agent4/agent4.vmx"))
        assert_that(vms[0].name, is_("agent4"))
        assert_that(vms[0].power_state, is_(VmPowerState.STARTED))
        assert_that(len(vms[0].disks), is_(2))
        assert_that(vms[0].disks, contains_inanyorder("disk3", "disk4"))

        # Test leave
        update.version = "3"
        object_update = vmodl.query.PropertyCollector.ObjectUpdate(
            kind="leave",
            obj=vim.VirtualMachine("vim.VirtualMachine:9"),
        )
        filter.objectSet[0] = object_update
        vim_client._vim_cache.poll_updates(vim_client)
        vms = vim_client.get_vms_in_cache()
        assert_that(vim_client._vim_cache._current_version, is_("3"))
        assert_that(len(vms), is_(0))
Exemplo n.º 18
0
class TestVimClient(unittest.TestCase):
    def setUp(self):
        if "host_remote_test" not in config:
            raise SkipTest()

        self.host = config["host_remote_test"]["server"]
        self.pwd = config["host_remote_test"]["esx_pwd"]

        if self.host is None or self.pwd is None:
            raise SkipTest()

        self.vim_client = VimClient(auto_sync=True)
        self.vim_client.connect_userpwd(self.host, "root", self.pwd)
        self._logger = logging.getLogger(__name__)

    def tearDown(self):
        self.vim_client.disconnect()

    def test_memory_usage(self):
        used_memory = self.vim_client.memory_usage_mb
        assert_that(used_memory > 0, is_(True))

    def test_total_memory(self):
        total_memory = self.vim_client.total_vmusable_memory_mb
        assert_that(total_memory > 0, is_(True))

    def test_total_cpus(self):
        num_cpus = self.vim_client.num_physical_cpus
        assert_that(num_cpus > 0, is_(True))

    def _create_test_vm(self, suffix="host-integ"):
        # Create VM
        vm_id = "vm_%s-%s-%s" % (
            time.strftime("%Y-%m-%d-%H%M%S", time.localtime()),
            str(random.randint(100000, 1000000)),
            suffix)

        datastore = self.vim_client.get_all_datastores()[0].name
        disk_path = "[%s] %s/disk.vmdk" % (datastore, vm_id)
        create_spec = self.get_create_spec(datastore, vm_id, disk_path)
        self.vim_client.create_vm(vm_id, create_spec)
        vm = self.vim_client.get_vm(vm_id)
        return (vm_id, vm, datastore, disk_path)

    def test_get_cached_vm(self):
        vm_id, vm, datastore, disk_path = self._create_test_vm("vm-cache-test")

        # Verify VM is in cache
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms), is_(1))
        assert_that(found_vms[0].name, is_(vm_id))
        assert_that(found_vms[0].power_state, is_(VmPowerState.STOPPED))
        assert_that(found_vms[0].memory_mb, is_(64))
        assert_that(found_vms[0].path, starts_with("[%s]" % datastore))
        assert_that(len(found_vms[0].disks), is_(1))
        assert_that(found_vms[0].disks[0], is_(disk_path))

        # Make sure get_vm_in_cache works
        vm_from_cache = self.vim_client.get_vm_in_cache(vm_id)
        assert_that(vm_from_cache.name, is_(vm_id))
        self.assertRaises(VmNotFoundException,
                          self.vim_client.get_vm_in_cache, "missing")

        # Add disk
        disk2_path = "[%s] %s/disk2.vmdk" % (datastore, vm_id)
        update_spec = self.get_update_spec(vm, disk2_path)
        task = vm.ReconfigVM_Task(update_spec.get_spec())
        self.vim_client.wait_for_task(task)

        # For the ReconfigVM task to remove disk, the hostd could update
        # task status to success before updating VM status. Thus when
        # wait_for_task returns, the vm_cache is possible to be still in old
        # state, though eventually it converges to consistent state. It only
        # happens in this task AFAIK. It should be fine for this task, because
        # rarely there is other operation that depends on this task.
        self._wait_vm_has_disk(vm_id, 2)

        # Verify disk added
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms[0].disks), is_(2))
        assert_that(found_vms[0].disks,
                    contains_inanyorder(disk_path, disk2_path))

        # Remove disk
        vm = self.vim_client.get_vm(vm_id)
        remove_spec = self.get_remove_spec(vm, disk2_path)
        task = vm.ReconfigVM_Task(remove_spec.get_spec())
        self.vim_client.wait_for_task(task)

        # Same as before when disk is added
        self._wait_vm_has_disk(vm_id, 1)

        # Verify disk removed
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms), is_(1))
        assert_that(len(found_vms[0].disks), is_(1), "disk2 in " +
                                                     str(found_vms[0].disks))
        assert_that(found_vms[0].disks,
                    contains_inanyorder(disk_path))

        # Power on vm
        task = vm.PowerOn()
        self.vim_client.wait_for_task(task)

        # Wait until it disappears from the cache
        self._wait_vm_power_status(vm_id, VmPowerState.STARTED)

        # Verify VM state in cache is updated
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms), is_(1))
        assert_that(found_vms[0].power_state, is_(VmPowerState.STARTED))
        assert_that(found_vms[0].name, is_(vm_id))
        assert_that(found_vms[0].memory_mb, is_(64))
        assert_that(found_vms[0].path, starts_with("[%s]" % datastore))
        assert_that(len(found_vms[0].disks), is_(1))
        assert_that(found_vms[0].disks[0], is_(disk_path))

        # Destroy VM
        task = vm.PowerOff()
        self.vim_client.wait_for_task(task)
        task = vm.Destroy()
        self.vim_client.wait_for_task(task)

        # Verify VM is deleted from cache
        vms = self.vim_client.get_vms_in_cache()
        found_vms = [v for v in vms if v.name == vm_id]
        assert_that(len(found_vms), is_(0))

    def test_no_datastore_update(self):
        """ Test datastore update is no longer triggered on VM creates/deletes
        """

        class UpdateListener(object):
            def __init__(self):
                self._ds_update_count = 0

            def datastores_updated(self):
                self._ds_update_count += 1

        listener = UpdateListener()
        self.vim_client.add_update_listener(listener)
        # listener always gets updated once on add
        assert_that(listener._ds_update_count, is_(1))

        mock_apply = MagicMock(wraps=self.vim_client._vim_cache._update_ds_cache)
        self.vim_client._vim_cache._update_ds_cache = mock_apply

        _, vm, _, _ = self._create_test_vm("ds-update-test")
        task = vm.Destroy()
        self.vim_client.wait_for_task(task)

        # expect to get a datastore property update (unfortunately) ...
        for _ in xrange(50):
            if mock_apply.call_count > 0:
                break
            time.sleep(0.1)
        # ... but that additional datastore updated notifications are sent out
        # as a result
        assert_that(listener._ds_update_count, is_(1))

    def get_create_spec(self, datastore, vm_id, disk_path):
        create_spec = EsxVmConfigSpec(None)
        create_spec.init_for_create(vm_id, datastore, 64, 2)
        create_spec._cfg_spec.files = vim.vm.FileInfo(vmPathName="[%s] /" % datastore)
        controller = vim.vm.device.VirtualLsiLogicController(
            key=1,
            sharedBus=vim.vm.device.VirtualSCSIController.Sharing.noSharing,
            busNumber=2,
            unitNumber=-1)
        create_spec._add_device(controller)
        backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo(
            fileName=disk_path,
            diskMode=vim.vm.device.VirtualDiskOption.DiskMode.persistent
        )
        disk = vim.vm.device.VirtualDisk(
            controllerKey=1,
            key=-1,
            unitNumber=-1,
            backing=backing,
            capacityInKB=1024,
        )
        create_spec._create_device(disk)
        return create_spec

    def get_update_spec(self, vm_info, disk_path):
        update_spec = EsxVmConfigSpec(None)
        update_spec.init_for_update()
        backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo(
            fileName=disk_path,
            diskMode=vim.vm.device.VirtualDiskOption.DiskMode.persistent
        )
        controller = update_spec._find_scsi_controller(vm_info.config)
        disk = vim.vm.device.VirtualDisk(
            controllerKey=controller.key,
            key=-1,
            unitNumber=-1,
            backing=backing,
            capacityInKB=1024,
        )
        update_spec._create_device(disk)
        return update_spec

    def get_remove_spec(self, vm_info, disk_path):
        remove_spec = EsxVmConfigSpec(None)
        remove_spec.init_for_update()
        devices = remove_spec._get_devices_by_type(vm_info.config, vim.vm.device.VirtualDisk)
        found_device = None
        for device in devices:
            if device.backing.fileName.endswith(disk_path):
                found_device = device
        remove_spec._remove_device(found_device)
        return remove_spec

    def test_clone_ticket(self):
        ticket = self.vim_client.get_vim_ticket()
        vim_client2 = VimClient()
        vim_client2.connect_ticket(self.host, ticket)
        vim_client2.host_system()

    def _wait_vm_has_disk(self, vm_id, disk_num):
        """Wait until the vm has disk number of the vm becomes disk_num
        """
        now = time.time()
        for _ in xrange(50):
            vm_in_cache = self.vim_client.get_vm_in_cache(vm_id)
            if len(vm_in_cache.disks) == disk_num:
                self._logger.info("VmCache disk number synced in %.2f second" %
                                  (time.time() - now))
                break
            time.sleep(0.1)

    def _wait_vm_power_status(self, vm_id, power_state):
        """Wait until the vm has power_state
        """
        now = time.time()
        for _ in xrange(50):
            vm_in_cache = self.vim_client.get_vm_in_cache(vm_id)
            if vm_in_cache.power_state == power_state:
                self._logger.info("VmCache power_state synced in %.2f second" %
                                  (time.time() - now))
                break
            time.sleep(0.1)