def test_acquire_credentials(self, si_method_mock): """The mockery of acquiring local hostd credentials""" local_ticket_mock = MagicMock(name="local_ticket") type(local_ticket_mock).userName = PropertyMock( return_value="local-root") pwd_fd, pwd_path = tempfile.mkstemp() os.write(pwd_fd, "local-root-password") os.close(pwd_fd) type(local_ticket_mock).passwordFilePath = PropertyMock( return_value=pwd_path) session_manager_mock = MagicMock(name="session-manager") session_manager_mock.AcquireLocalTicket.return_value = local_ticket_mock si = MagicMock(name="si") session_manager_property = PropertyMock( return_value=session_manager_mock) type(si.content).sessionManager = session_manager_property si_method_mock.return_value = si vim_client = VimClient(auto_sync=False) (user, password) = vim_client._acquire_local_credentials() os.remove(pwd_path) assert_that(user, equal_to("local-root")) assert_that(password, equal_to("local-root-password"))
def test_update_fail_without_looping(self, connect_mock, update_mock): client = VimClient("esx.local", "root", "password", auto_sync=True, min_interval=1) update_mock.side_effect = vim.fault.HostConnectFault time.sleep(0.5) client.disconnect(wait=True) assert_that(update_mock.call_count, less_than(4)) # 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")
def __init__(self, agent_config): self.logger = logging.getLogger(__name__) # If VimClient's housekeeping thread failed to update its own cache, # call errback to commit suicide. Watchdog will bring up the agent # again. self.vim_client = VimClient(wait_timeout=agent_config.wait_timeout, errback=lambda: suicide()) atexit.register(lambda client: client.disconnect(), self.vim_client) self._uuid = self.vim_client.host_uuid self.set_memory_overcommit(agent_config.memory_overcommit) self.datastore_manager = EsxDatastoreManager( self, agent_config.datastores, agent_config.image_datastores) # datastore manager needs to update the cache when there is a change. self.vim_client.add_update_listener(self.datastore_manager) self.vm_manager = EsxVmManager(self.vim_client, self.datastore_manager) self.disk_manager = EsxDiskManager(self.vim_client, self.datastore_manager) self.image_manager = EsxImageManager(self.vim_client, self.datastore_manager) self.network_manager = EsxNetworkManager(self.vim_client, agent_config.networks) self.system = EsxSystem(self.vim_client) self.image_manager.monitor_for_cleanup() self.image_transferer = HttpNfcTransferer( self.vim_client, self.datastore_manager.image_datastores()) atexit.register(self.image_manager.cleanup)
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")
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"] self.agent_port = config["host_remote_test"].get("agent_port", 8835) if self.host is None or self.pwd is None: raise SkipTest() self.image_datastore = config["host_remote_test"].get( "image_datastore", "datastore1") self._logger = logging.getLogger(__name__) self.vim_client = VimClient(self.host, "root", self.pwd) self.http_transferer = HttpNfcTransferer(self.vim_client, [self.image_datastore], self.host) with tempfile.NamedTemporaryFile(delete=False) as source_file: with open(source_file.name, 'wb') as f: f.write(os.urandom(1024 * 100)) self.random_file = source_file.name self.remote_files_to_delete = []
def test_update_fail_will_suicide(self, sleep_mock, connect_mock, update_mock, update_hosts_mock): killed = threading.Event() def suicide(): killed.set() threading.current_thread().stop() update_cache = MagicMock() update_cache.side_effect = vim.fault.HostConnectFault client = VimClient("esx.local", "root", "password", auto_sync=True, min_interval=1, errback=lambda: suicide()) client.update_cache = update_cache killed.wait(1) client.disconnect(wait=True) # update_cache will be called 5 times before it kill itself assert_that(update_cache.call_count, is_(5)) assert_that(killed.is_set(), is_(True))
def setUp(self, connect, update, creds): creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.vim_client.wait_for_task = MagicMock() self.patcher = patch("host.hypervisor.esx.vm_config.GetEnv") self.patcher.start() self.vm_manager = EsxVmManager(self.vim_client, MagicMock())
def setUp(self, connect, update, creds): creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.vim_client.wait_for_task = MagicMock() self.disk_manager = EsxDiskManager(self.vim_client, []) self.disk_manager._vmdk_mkdir = MagicMock() self.disk_manager._vmdk_rmdir = MagicMock()
def test_update_host_cache_in_thread(self, disconnect_mock, connect_mock, spec_mock, update_mock, update_host_mock, query_spec_mock, perf_manager_mock, prop_collector_mock): # Test Values. counter = MagicMock() counter.groupInfo.key = "mem" counter.nameInfo.key = "consumed" counter.key = 65613 n = 5 statValues = ','.join([str(x) for x in range(1, n + 1)]) statAverage = sum(range(1, n + 1)) / len(range(1, n + 1)) stat = MagicMock() stat.value = [MagicMock()] stat.value[0].id.counterId = 65613 stat.value[0].value = statValues # Mock the Vim APIs. pc_return_mock = MagicMock({'WaitForUpdatesEx.return_value': {}}) summarize_stats = {'QueryPerf.return_value': [stat]} pm_return_mock = MagicMock(perfCounter=[counter], **summarize_stats) # Tie the mocked APIs with VimClient. prop_collector_mock.return_value = pc_return_mock perf_manager_mock.return_value = pm_return_mock # Create VimClient. vim_client = VimClient("esx.local", "root", "password", min_interval=0.1, auto_sync=True, stats_interval=0.2) # 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(wait=True) assert_that(disconnect_mock.called, is_(True)) # Verify that update_host_mock is called atleast once and is called # less number of times than update_mock. assert_that(update_host_mock.call_count, is_not(0), "VimClient.update_host_mock is not called repeatedly") assert_that(update_host_mock.call_count, less_than(update_mock.call_count)) host_stats = update_host_mock.call_args_list for host in host_stats: assert_that(host[0][0]['mem.consumed'], equal_to(statAverage))
def test_check_prefix_len_to_netmask_conversion(self): """Check the conversion from prefix length to netmask""" self.assertEqual(VimClient._prefix_len_to_mask(32), "255.255.255.255") self.assertEqual(VimClient._prefix_len_to_mask(0), "0.0.0.0") self.assertRaises(ValueError, VimClient._prefix_len_to_mask, 33) self.assertEqual(VimClient._prefix_len_to_mask(23), "255.255.254.0") self.assertEqual(VimClient._prefix_len_to_mask(6), "252.0.0.0") self.assertEqual(VimClient._prefix_len_to_mask(32), "255.255.255.255")
def test_update_host_cache_in_thread(self, disconnect_mock, connect_mock, spec_mock, update_mock, update_host_mock, query_spec_mock, perf_manager_mock, prop_collector_mock): # Test Values. counter = MagicMock() counter.groupInfo.key = "mem" counter.nameInfo.key = "consumed" counter.key = 65613 n = 5 statValues = ','.join([str(x) for x in range(1, n+1)]) statAverage = sum(range(1, n+1)) / len(range(1, n+1)) stat = MagicMock() stat.value = [MagicMock()] stat.value[0].id.counterId = 65613 stat.value[0].value = statValues # Mock the Vim APIs. pc_return_mock = MagicMock({'WaitForUpdatesEx.return_value': {}}) summarize_stats = {'QueryPerf.return_value': [stat]} pm_return_mock = MagicMock(perfCounter=[counter], **summarize_stats) # Tie the mocked APIs with VimClient. prop_collector_mock.return_value = pc_return_mock perf_manager_mock.return_value = pm_return_mock # Create VimClient. vim_client = VimClient("esx.local", "root", "password", min_interval=0.1, auto_sync=True, stats_interval=0.2) # 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(wait=True) assert_that(disconnect_mock.called, is_(True)) # Verify that update_host_mock is called atleast once and is called # less number of times than update_mock. assert_that(update_host_mock.call_count, is_not(0), "VimClient.update_host_mock is not called repeatedly") assert_that(update_host_mock.call_count, less_than(update_mock.call_count)) host_stats = update_host_mock.call_args_list for host in host_stats: assert_that(host[0][0]['mem.consumed'], equal_to(statAverage))
def setUp(self, connect, creds): self.shadow_vm_id = SHADOW_VM_NAME_PREFIX + str(uuid.uuid4()) self.image_datastores = ["image_ds", "alt_image_ds"] creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.patcher = patch("host.hypervisor.esx.vm_config.GetEnv") self.patcher.start() services.register(ServiceName.AGENT_CONFIG, MagicMock()) self.http_transferer = HttpNfcTransferer(self.vim_client, self.image_datastores)
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 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 setUp(self): self.vim_client = VimClient(auto_sync=False) self.vim_client._content = MagicMock() self.host = MagicMock(spec=vim.ManagedObject, key=vim.HostSystem("ha-host")) self.host.summary = MagicMock() self.host.summary.quickStats = MagicMock() self.host.summary.hardware = MagicMock() self.host.summary.quickStats.overallCpuUsage = 1024 self.host.summary.hardware.cpuMhz = 1024 self.host.summary.hardware.numCpuCores = 2 self.host.summary.quickStats.overallMemoryUsage = 2 # 2GB self.host.summary.hardware.memorySize = 4 * 1024 * 1024 # 4GB self.vim_client.host_system = MagicMock(return_value=self.host)
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.host, "root", self.pwd) self.vm_manager = EsxVmManager(self.vim_client, []) for vm in self.vim_client.get_vms(): vm.Destroy()
def setUp(self): self.vim_client = VimClient(auto_sync=False) self.vim_client._content = MagicMock() self.vim_client.wait_for_task = MagicMock() self.disk_manager = DiskManager(self.vim_client, []) self.disk_manager._vmdk_mkdir = MagicMock() self.disk_manager._vmdk_rmdir = MagicMock()
def __init__(self, agent_config): self.logger = logging.getLogger(__name__) # If VimClient's housekeeping thread failed to update its own cache, # call errback to commit suicide. Watchdog will bring up the agent # again. errback = lambda: suicide() self.vim_client = VimClient(wait_timeout=agent_config.wait_timeout, errback=errback) atexit.register(lambda client: client.disconnect(), self.vim_client) self._uuid = self.vim_client.host_uuid # Enable/Disable large page support. If this host is removed # from the deployment, large page support will need to be # explicitly updated by the user. disable_large_pages = agent_config.memory_overcommit > 1.0 self.vim_client.set_large_page_support(disable=disable_large_pages) image_datastores = [ds["name"] for ds in agent_config.image_datastores] self.datastore_manager = EsxDatastoreManager( self, agent_config.datastores, image_datastores) # datastore manager needs to update the cache when there is a change. self.vim_client.add_update_listener(self.datastore_manager) self.vm_manager = EsxVmManager(self.vim_client, self.datastore_manager) self.disk_manager = EsxDiskManager(self.vim_client, self.datastore_manager) self.image_manager = EsxImageManager(self.vim_client, self.datastore_manager) self.network_manager = EsxNetworkManager(self.vim_client, agent_config.networks) self.system = EsxSystem(self.vim_client) self.image_manager.monitor_for_cleanup() atexit.register(self.image_manager.cleanup)
def __init__(self, agent_config): self.logger = logging.getLogger(__name__) # If VimClient's housekeeping thread failed to update its own cache, # call errback to commit suicide. Watchdog will bring up the agent # again. errback = lambda: suicide() self.vim_client = VimClient(wait_timeout=agent_config.wait_timeout, errback=errback) atexit.register(lambda client: client.disconnect(), self.vim_client) self._uuid = self.vim_client.host_uuid self.set_memory_overcommit(agent_config.memory_overcommit) image_datastores = [ds["name"] for ds in agent_config.image_datastores] self.datastore_manager = EsxDatastoreManager( self, agent_config.datastores, agent_config.image_datastores) # datastore manager needs to update the cache when there is a change. self.vim_client.add_update_listener(self.datastore_manager) self.vm_manager = EsxVmManager(self.vim_client, self.datastore_manager) self.disk_manager = EsxDiskManager(self.vim_client, self.datastore_manager) self.image_manager = EsxImageManager(self.vim_client, self.datastore_manager) self.network_manager = EsxNetworkManager(self.vim_client, agent_config.networks) self.system = EsxSystem(self.vim_client) self.image_manager.monitor_for_cleanup() self.image_transferer = HttpNfcTransferer(self.vim_client, image_datastores) atexit.register(self.image_manager.cleanup)
class TestEsxDiskManager(unittest.TestCase): @patch.object(VimClient, "acquire_credentials") @patch.object(VimClient, "update_cache") @patch("pysdk.connect.Connect") def setUp(self, connect, update, creds): creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.vim_client.wait_for_task = MagicMock() self.disk_manager = EsxDiskManager(self.vim_client, []) self.disk_manager._vmdk_mkdir = MagicMock() self.disk_manager._vmdk_rmdir = MagicMock() def tearDown(self): self.vim_client.disconnect(wait=True) def test_create_spec(self): """Test that we create a valid disk spec.""" capacity = 2 spec = self.disk_manager._create_spec(capacity) assert_that(spec.capacityKb, equal_to(capacity * (1024 ** 2))) assert_that(spec.adapterType, equal_to(DEFAULT_DISK_ADAPTER_TYPE)) def test_invalid_datastore_path(self): """Test that we propagate InvalidDatastorePath.""" self.vim_client.wait_for_task.side_effect = \ vim.fault.InvalidDatastorePath self.assertRaises(DiskPathException, self.disk_manager.create_disk, "ds1", "foo", 101) def test_disk_not_found(self): """Test that we propagate FileNotFound.""" self.vim_client.wait_for_task.side_effect = vim.fault.FileNotFound self.assertRaises(DiskFileException, self.disk_manager.delete_disk, "ds1", "bar") def test_general_fault(self): """Test general Exception propagation.""" self.vim_client.wait_for_task.side_effect = vim.fault.TaskInProgress self.assertRaises(vim.fault.TaskInProgress, self.disk_manager.move_disk, "ds1", "biz", "ds1", "baz")
class TestEsxDiskManager(unittest.TestCase): @patch.object(VimClient, "acquire_credentials") @patch.object(VimClient, "update_cache") @patch("pysdk.connect.Connect") def setUp(self, connect, update, creds): creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.vim_client.wait_for_task = MagicMock() self.disk_manager = EsxDiskManager(self.vim_client, []) self.disk_manager._vmdk_mkdir = MagicMock() self.disk_manager._vmdk_rmdir = MagicMock() def tearDown(self): self.vim_client.disconnect(wait=True) def test_create_spec(self): """Test that we create a valid disk spec.""" capacity = 2 spec = self.disk_manager._create_spec(capacity) assert_that(spec.capacityKb, equal_to(capacity * (1024**2))) assert_that(spec.adapterType, equal_to(DEFAULT_DISK_ADAPTER_TYPE)) def test_invalid_datastore_path(self): """Test that we propagate InvalidDatastorePath.""" self.vim_client.wait_for_task.side_effect = \ vim.fault.InvalidDatastorePath self.assertRaises(DiskPathException, self.disk_manager.create_disk, "ds1", "foo", 101) def test_disk_not_found(self): """Test that we propagate FileNotFound.""" self.vim_client.wait_for_task.side_effect = vim.fault.FileNotFound self.assertRaises(DiskFileException, self.disk_manager.delete_disk, "ds1", "bar") def test_general_fault(self): """Test general Exception propagation.""" self.vim_client.wait_for_task.side_effect = vim.fault.TaskInProgress self.assertRaises(vim.fault.TaskInProgress, self.disk_manager.move_disk, "ds1", "biz", "ds1", "baz")
def create_host_client(auto_sync=True, errback=None): try: # check whether attache is installed. If not, find_module will throw ImportError. from host.hypervisor.esx.attache_client import AttacheClient return AttacheClient(auto_sync, errback) except ImportError: from host.hypervisor.esx.vim_client import VimClient return VimClient(auto_sync, errback)
def vim_delete_vm(self, vm_id): """ Delete a VM using the vim client """ try: vim_client = VimClient() vim_client.connect_ticket(self.server, self._get_vim_ticket()) vim_vm = vim_client.get_vm(vm_id) if vim_vm.runtime.powerState != 'poweredOff': try: vim_task = vim_vm.PowerOff() vim_client.wait_for_task(vim_task) except: logger.info("Cannot power off vm", exc_info=True) vim_task = vim_vm.Destroy() vim_client.wait_for_task(vim_task) finally: if vim_client: vim_client.disconnect()
def test_acquire_credentials_connection_failure(self, si_method_mock): si = MagicMock(name="si") session_manager_property = PropertyMock( side_effect=HTTPException("hubba")) type(si.content).sessionManager = session_manager_property si_method_mock.return_value = si vim_client = VimClient(auto_sync=False) self.assertRaises(AcquireCredentialsException, vim_client._acquire_local_credentials)
def test_update_cache_in_thread(self, disconnect_mock, connect_mock, spec_mock, update_mock, update_host_mock): vim_client = VimClient("esx.local", "root", "password", min_interval=0, auto_sync=True) 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.update_cache is not " "called repeatedly") vim_client.disconnect(wait=True) assert_that(disconnect_mock.called, is_(True))
def setUp(self, connect, update, creds): # Create VM manager creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.vim_client.wait_for_task = MagicMock() self.patcher = patch("host.hypervisor.esx.vm_config.GetEnv") self.patcher.start() self.vm_manager = EsxVmManager(self.vim_client, MagicMock()) services.register(ServiceName.AGENT_CONFIG, MagicMock()) # Set up test files self.base_dir = os.path.dirname(__file__) self.test_dir = os.path.join(self.base_dir, "../../test_files") self.image_manager = EsxImageManager(MagicMock(), MagicMock()) self.image_scanner = DatastoreImageScanner(self.image_manager, self.vm_manager, self.DATASTORE_ID) self.write_count = 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))
def setUp(self, connect, creds): self.shadow_vm_id = SHADOW_VM_NAME_PREFIX + str(uuid.uuid1()) self.image_datastores = ["image_ds", "alt_image_ds"] creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.patcher = patch("host.hypervisor.esx.vm_config.GetEnv") self.patcher.start() services.register(ServiceName.AGENT_CONFIG, MagicMock()) self.http_transferer = HttpNfcTransferer(self.vim_client, self.image_datastores)
def setUp(self, connect, creds): self.host_uuid = str(uuid.uuid4()) VimClient.host_uuid = self.host_uuid self.image_ds = "image_ds" creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.patcher = patch("host.hypervisor.esx.vm_config.GetEnv") self.patcher.start() services.register(ServiceName.AGENT_CONFIG, MagicMock()) self.http_transferer = HttpNfcTransferer(self.vim_client, self.image_ds)
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))
def _create_remote_vim_client(self, agent_client, host): request = ServiceTicketRequest(service_type=ServiceType.VIM) response = agent_client.get_service_ticket(request) if response.result != ServiceTicketResultCode.OK: self._logger.info("Get service ticket failed. Response = %s" % str(response)) raise ValueError("No ticket") vim_client = VimClient(host=host, ticket=response.vim_ticket, auto_sync=False) return vim_client
def _get_remote_connections(self, host, port): agent_client = DirectClient("Host", Host.Client, host, port) agent_client.connect() request = ServiceTicketRequest(service_type=ServiceType.VIM) response = agent_client.get_service_ticket(request) if response.result != ServiceTicketResultCode.OK: self._logger.info("Get service ticket failed. Response = %s" % str(response)) raise ValueError("No ticket") vim_client = VimClient( host=host, ticket=response.vim_ticket, auto_sync=False) return agent_client, vim_client
def test_vim_client_with_param(self, connect_mock, update_mock): vim_client = VimClient("esx.local", "root", "password", auto_sync=False) assert_that(vim_client.host, is_("esx.local")) assert_that(vim_client.username, is_("root")) assert_that(vim_client.password, is_("password")) connect_mock.assert_called_once_with(host="esx.local", user="******", pwd="password", version="vim.version.version9")
def setUp(self): self.vim_client = VimClient(auto_sync=False) self.vim_client._content = MagicMock() self.host = MagicMock(spec=vim.ManagedObject, key=vim.HostSystem("ha-host")) self.host.summary = MagicMock() self.host.summary.quickStats = MagicMock() self.host.summary.hardware = MagicMock() self.host.summary.quickStats.overallCpuUsage = 1024 self.host.summary.hardware.cpuMhz = 1024 self.host.summary.hardware.numCpuCores = 2 self.host.summary.quickStats.overallMemoryUsage = 2 # 2GB self.host.summary.hardware.memorySize = 4*1024*1024 # 4GB self.vim_client.host_system = MagicMock(return_value=self.host)
def setUp(self): # Create VM manager self.vim_client = VimClient(auto_sync=False) self.vim_client._content = MagicMock() self.vim_client.wait_for_task = MagicMock() self.vm_manager = VmManager(self.vim_client, MagicMock()) services.register(ServiceName.AGENT_CONFIG, MagicMock()) # Set up test files self.base_dir = os.path.dirname(__file__) self.test_dir = os.path.join(self.base_dir, "../test_files") self.image_manager = ImageManager(MagicMock(), MagicMock()) self.image_scanner = DatastoreImageScanner(self.image_manager, self.vm_manager, self.DATASTORE_ID) self.write_count = 0
def test_acquire_credentials(self, si_method_mock): """The mockery of acquiring local hostd credentials""" local_ticket_mock = MagicMock(name="local_ticket") type(local_ticket_mock).userName = PropertyMock(return_value="local-root") pwd_fd, pwd_path = tempfile.mkstemp() os.write(pwd_fd, "local-root-password") os.close(pwd_fd) type(local_ticket_mock).passwordFilePath = PropertyMock(return_value=pwd_path) session_manager_mock = MagicMock(name="session-manager") session_manager_mock.AcquireLocalTicket.return_value = local_ticket_mock si = MagicMock(name="si") session_manager_property = PropertyMock(return_value=session_manager_mock) type(si.content).sessionManager = session_manager_property si_method_mock.return_value = si vim_client = VimClient(auto_sync=False) (user, password) = vim_client._acquire_local_credentials() os.remove(pwd_path) assert_that(user, equal_to("local-root")) assert_that(password, equal_to("local-root-password"))
def __init__(self, agent_config): self.logger = logging.getLogger(__name__) # If VimClient's housekeeping thread failed to update its own cache, # call errback to commit suicide. Watchdog will bring up the agent # again. errback = lambda: suicide() self.vim_client = VimClient(wait_timeout=agent_config.wait_timeout, errback=errback) atexit.register(lambda client: client.disconnect(), self.vim_client) self._uuid = self.vim_client.host_uuid # Enable/Disable large page support. If this host is removed # from the deployment, large page support will need to be # explicitly updated by the user. disable_large_pages = agent_config.memory_overcommit > 1.0 self.vim_client.set_large_page_support(disable=disable_large_pages) image_datastores = [ds["name"] for ds in agent_config.image_datastores] self.datastore_manager = EsxDatastoreManager(self, agent_config.datastores, image_datastores) # datastore manager needs to update the cache when there is a change. self.vim_client.add_update_listener(self.datastore_manager) self.vm_manager = EsxVmManager(self.vim_client, self.datastore_manager) self.disk_manager = EsxDiskManager(self.vim_client, self.datastore_manager) self.image_manager = EsxImageManager(self.vim_client, self.datastore_manager) self.network_manager = EsxNetworkManager(self.vim_client, agent_config.networks) self.system = EsxSystem(self.vim_client) self.image_manager.monitor_for_cleanup() self.image_transferer = HttpNfcTransferer(self.vim_client, image_datastores) atexit.register(self.image_manager.cleanup)
def test_get_nfc_ticket(self, connect_mock): vim_client = VimClient(auto_sync=False) vim_client._find_by_inventory_path = MagicMock(return_value=None) self.assertRaises(DatastoreNotFound, vim_client.get_nfc_ticket_by_ds_name, "no_exist") ds_mock = MagicMock() vim_client._find_by_inventory_path = MagicMock(return_value=ds_mock) nfc_service = MagicMock() type(vim).NfcService = MagicMock() type(vim).NfcService.return_value = nfc_service vim_client._si = MagicMock() vim_client.get_nfc_ticket_by_ds_name("existing_ds") nfc_service.FileManagement.assert_called_once_with(ds_mock)
def test_acquire_credentials(self, password_mock, si_method_mock): """The mockery of acquiring local hostd credentials""" local_ticket_mock = MagicMock(name="local_ticket") user_name_property = PropertyMock(return_value="local-root") type(local_ticket_mock).userName = user_name_property session_manager_mock = MagicMock(name="session-manager") session_manager_mock.AcquireLocalTicket.return_value = \ local_ticket_mock si = MagicMock(name="si") session_manager_property = \ PropertyMock(return_value=session_manager_mock) type(si.content).sessionManager = session_manager_property si_method_mock.return_value = si (user, password) = VimClient.acquire_credentials() assert_that(user, equal_to("local-root"))
def setUp(self, connect, update, creds): # Create VM manager creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.vim_client.wait_for_task = MagicMock() self.patcher = patch("host.hypervisor.esx.vm_config.GetEnv") self.patcher.start() self.vm_manager = EsxVmManager(self.vim_client, MagicMock()) # Set up test files self.base_dir = os.path.dirname(__file__) self.test_dir = os.path.join(self.base_dir, "../../test_files") self.image_manager = EsxImageManager(MagicMock(), MagicMock()) self.image_scanner = DatastoreImageScanner(self.image_manager, self.vm_manager, self.DATASTORE_ID) self.image_scanner._task_runner = MagicMock() self.image_scanner._task_runner.is_stopped.return_value = False self.write_count = 0
def setUp(self): from testconfig import config if "agent_remote_test" not in config: raise SkipTest() # Set the default datastore name self._datastores = None if "datastores" in config["agent_remote_test"]: datastores = config["agent_remote_test"]["datastores"] self._datastores = [d.strip() for d in datastores.split(",")] else: self.fail("datastores not provided for test setUp") # Optionally update the specification of a remote iso file. The file # needs to exist on the remote esx server for this test to succeed. self._remote_iso_file = None self._second_remote_iso_file = None if ("iso_file" in config["agent_remote_test"]): self._remote_iso_file = config["agent_remote_test"]["iso_file"] if ("second_iso_file" in config["agent_remote_test"]): self._second_remote_iso_file = config["agent_remote_test"]["second_iso_file"] server = config["agent_remote_test"]["server"] self.server = server self.generation = int(time.time()) # Connect to server and configure vim_client self.client_connections() self.vim_client = VimClient() self.vim_client.connect_ticket(self.server, self._get_vim_ticket()) connect.SetSi(self.vim_client._si) # Set host mode to normal self.set_host_mode(HostMode.NORMAL) # The first time setup is called the agent will restart. self.provision_hosts() # Reconnect to account for the restart self.client_connections() self.clear()
class VsiTestCase(unittest.TestCase): """ Check hostd rescpu.actav1 value equals to vsi's cpuLoadHistory1MinInPct """ def setUp(self): self.vim_client = VimClient() def tearDown(self): pass def test_hostd_rescpu_actav1_match_vsi_value(self): try: vsi = VsiWrapper() except: return cpu_load_history = vsi.get( "/sched/groups/0/stats" "/cpuStatsDir/cpuLoadHistory" "/cpuLoadHistory1MinInPct") vsi_cpu_load = cpu_load_history["avgActive"] # get average cpu load percentage in past 20 seconds # since hostd takes a sample in every 20 seconds # we use the min 20secs here to get the latest # CPU active average over 1 minute host_stats = copy.copy(self.vim_client.get_perf_manager_stats(20)) rescpu_cpu_load = host_stats['rescpu.actav1'] / 100 check_value = False # vsi gets the current cpu active average over 1 minute. # hostd gets the cpu active average over 1 minute 20 seconds ago. # Thus if there's a CPU active average boost during the # past 20 seconds, the value from hostd's CPU active average # value will be 20 seconds late which will have a large deviation. if (1 if vsi_cpu_load - 7 < 1 else vsi_cpu_load - 7) \ <= rescpu_cpu_load \ <= vsi_cpu_load + 7: check_value = True self.assertEqual(check_value, 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
class VsiTestCase(unittest.TestCase): """ Check hostd rescpu.actav1 value equals to vsi's cpuLoadHistory1MinInPct """ def setUp(self): self.vim_client = VimClient() def tearDown(self): pass def test_hostd_rescpu_actav1_match_vsi_value(self): try: vsi = VsiWrapper() except: return cpu_load_history = vsi.get("/sched/groups/0/stats" "/cpuStatsDir/cpuLoadHistory" "/cpuLoadHistory1MinInPct") vsi_cpu_load = cpu_load_history["avgActive"] # get average cpu load percentage in past 20 seconds # since hostd takes a sample in every 20 seconds # we use the min 20secs here to get the latest # CPU active average over 1 minute host_stats = copy.copy(self.vim_client.get_perf_manager_stats(20)) rescpu_cpu_load = host_stats['rescpu.actav1'] / 100 check_value = False # vsi gets the current cpu active average over 1 minute. # hostd gets the cpu active average over 1 minute 20 seconds ago. # Thus if there's a CPU active average boost during the # past 20 seconds, the value from hostd's CPU active average # value will be 20 seconds late which will have a large deviation. if (1 if vsi_cpu_load - 7 < 1 else vsi_cpu_load - 7) \ <= rescpu_cpu_load \ <= vsi_cpu_load + 7: check_value = True self.assertEqual(check_value, 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
def test_vim_client_errback(self, connect_mock, host_mock): callback = MagicMock() vim_client = VimClient("esx.local", "root", "password", auto_sync=False, errback=callback) 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))
def setUp(self, connect, update, creds): creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) with patch("host.hypervisor.esx.vm_config.GetEnv"): self.vm_config = EsxVmConfig(self.vim_client)
class TestEsxVmConfig(unittest.TestCase): @patch.object(VimClient, "acquire_credentials") @patch.object(VimClient, "update_cache") @patch("pysdk.connect.Connect") def setUp(self, connect, update, creds): creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) with patch("host.hypervisor.esx.vm_config.GetEnv"): self.vm_config = EsxVmConfig(self.vim_client) def tearDown(self): self.vim_client.disconnect(wait=True) def dummy_devices(self): return [ vim.vm.device.VirtualFloppy(key=10), vim.vm.device.VirtualPCIController(key=100), DEFAULT_DISK_CONTROLLER_CLASS(key=1000), vim.vm.device.VirtualSoundCard(key=10000), ] def test_vm_create_spec(self): datastore = "ds1" vm_id = str(uuid.uuid4()) metadata = { "configuration": {"guestOS": "otherLinuxGuest"}, "parameters": [{"name": "key1"}, {"name": "key2"}] } env = { "key1": "value1", "keyUnexpected": "valueNotSet", } spec = self.vm_config.create_spec(vm_id, datastore, 512, 1, metadata, env) assert_that(spec.memoryMB, equal_to(512)) assert_that(spec.numCPUs, equal_to(1)) assert_that(spec.name, equal_to(vm_id)) assert_that(spec.guestId, equal_to("otherLinuxGuest")) expected_metadata = {'guestOS': 'otherLinuxGuest', 'key1': 'value1'} assert_that(spec._metadata, equal_to(expected_metadata)) def test_create_nic_spec(self): net_name = "VM_network" cspec = self.vm_config.update_spec() spec = self.vm_config.add_nic(cspec, net_name) backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo assert_that(spec.deviceChange[0].device.backing.__class__, equal_to(backing)) assert_that(spec.deviceChange[0].device.backing.deviceName, equal_to(net_name)) def test_find_disk_controller(self): devices = self.dummy_devices() device_type = DEFAULT_DISK_CONTROLLER_CLASS disk_controller = self.vm_config.find_device(devices, device_type) assert_that(disk_controller.key, equal_to(1000)) def test_find_nic_controller(self): devices = self.dummy_devices() device_type = vim.vm.device.VirtualPCIController disk_controller = self.vm_config.find_device(devices, device_type) assert_that(disk_controller.key, equal_to(100)) def test_find_virtual_disk(self): spec = vim.vm.ConfigSpec() vm_config = self.vm_config devices = self.dummy_devices() for device in devices: vm_config.add_device(spec, device) cfg_info = FakeConfigInfo() device_type = vim.vm.device.VirtualDisk datastore = "ds1" filename = "folder/foo" path = vmdk_path(datastore, filename) find_disk = vm_config.disk_matcher(datastore, filename) disk = vm_config.find_device(devices, device_type, matcher=find_disk) assert_that(disk, equal_to(None)) vm_config.add_scsi_disk(cfg_info, spec, datastore, "nope") self.assertRaises(DeviceNotFoundException, vm_config.get_device, devices, device_type, matcher=find_disk) vm_config.add_scsi_disk(cfg_info, spec, datastore, filename) device_changes = spec.deviceChange device_list = [] for device_change in device_changes: device_list.append(device_change.device) disk = vm_config.find_device(device_list, device_type, matcher=find_disk) assert_that(disk.backing.fileName, equal_to(path)) def _create_spec_for_disk_test(self, datastore, vm_id): spec = vim.vm.ConfigSpec() devices = self.dummy_devices() for device in devices: self.vm_config.add_device(spec, device) vm_path_name = '[%s] %s/%s' % (datastore, vm_id[0:2], vm_id) spec.files = vim.vm.FileInfo(vmPathName=vm_path_name) spec.name = vm_id return spec def test_create_empty_disk(self): vm_id = str(uuid.uuid4()) datastore = "ds1" spec = self._create_spec_for_disk_test(datastore, vm_id) size_mb = 100 disk_id = str(uuid.uuid4()) self.vm_config.create_empty_disk(spec, datastore, disk_id, size_mb) devs = [change.device for change in spec.deviceChange] device_type = vim.vm.device.VirtualDisk disks = self.vm_config.find_devices(devs, device_type) assert_that(len(disks), equal_to(1)) # verify that uuid to be set on disk to be added matches the # of the disk (modulo some formatting differences) assert_that(disks[0].backing.uuid, equal_to(uuid_to_vmdk_uuid(disk_id))) def test_create_child_disk(self): vm_id = str(uuid.uuid4()) datastore = "ds1" spec = self._create_spec_for_disk_test(datastore, vm_id) disk_id = str(uuid.uuid4()) parent_id = str(uuid.uuid4()) self.vm_config.create_child_disk(spec, datastore, disk_id, parent_id) devs = [change.device for change in spec.deviceChange] device_type = vim.vm.device.VirtualDisk disks = self.vm_config.find_devices(devs, device_type) assert_that(len(disks), equal_to(1)) # verify that disk to be added does not request a specifc uuid assert_that(disks[0].backing.uuid, equal_to(None)) def _get_config_info_with_iso(self, iso_path): devices = self.dummy_devices() cfg_info = FakeConfigInfo() cfg_info.hardware.device = devices cdrom = vim.vm.device.VirtualCdrom() cdrom.key = 1234 cdrom.controllerKey = 100 cdrom.unitNumber = 1 iso_backing = vim.vm.device.VirtualCdrom.IsoBackingInfo() iso_backing.fileName = iso_path cdrom.backing = iso_backing conInfo = vim.vm.device.VirtualDevice.ConnectInfo() conInfo.allowGuestControl = True conInfo.connected = True conInfo.startConnected = True cdrom.connectable = conInfo cfg_info.hardware.device.append(cdrom) return cfg_info def _get_config_info_without_connected(self, is_iso_backing): devices = self.dummy_devices() cfg_info = FakeConfigInfo() cfg_info.hardware.device = devices cdrom = vim.vm.device.VirtualCdrom() cdrom.key = 1234 cdrom.controllerKey = 100 cdrom.unitNumber = 1 if is_iso_backing: iso_backing = vim.vm.device.VirtualCdrom.IsoBackingInfo() cdrom.backing = iso_backing conInfo = vim.vm.device.VirtualDevice.ConnectInfo() conInfo.allowGuestControl = True conInfo.connected = False conInfo.startConnected = True cdrom.connectable = conInfo cfg_info.hardware.device.append(cdrom) return cfg_info def test_add_iso_cdrom(self): virtual_ide_controller = vim.vm.device.VirtualIDEController() cfgOption = vim.vm.ConfigOption() cfgOption.defaultDevice.append(virtual_ide_controller) self.vm_config._cfg_opts = cfgOption # fake iso ds path fake_iso_ds_path = '[ds] vm_fake/fake.iso' # test if no virtual cdrom attached to the VM cfg_info = FakeConfigInfo() cspec = self.vm_config.update_spec() result = self.vm_config.add_iso_cdrom( cspec, fake_iso_ds_path, cfg_info) assert_that(result.__class__, equal_to(bool)) assert_that(result, equal_to(True)) dev = cspec.deviceChange[0].device assert_that(len(cspec.deviceChange), equal_to(1)) assert_that(dev.connectable.connected, equal_to(True)) assert_that(dev.connectable.startConnected, equal_to(True)) assert_that(dev.backing.__class__, equal_to(vim.vm.device.VirtualCdrom.IsoBackingInfo)) # test if virtual cdrom exist and ISO already attached to the VM cspec = self.vm_config.update_spec() cfg_info = self._get_config_info_with_iso(fake_iso_ds_path) result = self.vm_config.add_iso_cdrom( cspec, fake_iso_ds_path, cfg_info) assert_that(result.__class__, equal_to(bool)) assert_that(result, equal_to(False)) # test if virtual cdrom exist and it's iso_backing # and ISO is not attached to the VM cspec = self.vm_config.update_spec() cfg_info = self._get_config_info_without_connected(is_iso_backing=True) result = self.vm_config.add_iso_cdrom( cspec, fake_iso_ds_path, cfg_info) assert_that(result.__class__, equal_to(bool)) assert_that(result, equal_to(True)) dev = cspec.deviceChange[0].device assert_that(len(cspec.deviceChange), equal_to(1)) assert_that(dev.connectable.connected, equal_to(True)) assert_that(dev.connectable.startConnected, equal_to(True)) assert_that(dev.backing.__class__, equal_to(vim.vm.device.VirtualCdrom.IsoBackingInfo)) # test if virtual cdrom exist and it's _not_ iso_backing # and ISO is not attached to the VM cspec = self.vm_config.update_spec() cfg_info = self._get_config_info_without_connected( is_iso_backing=False) self.assertRaises(TypeError, self.vm_config.add_iso_cdrom, cspec, fake_iso_ds_path, cfg_info) def test_disconnect_iso(self): # on vm config with no cdrom devices cfg_info = FakeConfigInfo() cspec = self.vm_config.update_spec() self.assertRaises(DeviceNotFoundException, self.vm_config.disconnect_iso_cdrom, cspec, cfg_info) assert_that(len(cspec.deviceChange), equal_to(0)) # on vm config with no a fake cdrom device fake_iso_ds_path = '[ds] vm_fake/fake.iso' cspec = self.vm_config.update_spec() cfg_info = self._get_config_info_with_iso(fake_iso_ds_path) iso_path = self.vm_config.disconnect_iso_cdrom(cspec, cfg_info) assert_that(len(cspec.deviceChange), equal_to(1)) dev = cspec.deviceChange[0].device assert_that(dev.backing.__class__, equal_to(vim.vm.device.VirtualCdrom.IsoBackingInfo)) assert_that(dev.backing.fileName, equal_to(fake_iso_ds_path)) assert_that(iso_path, equal_to(fake_iso_ds_path)) assert_that(dev.connectable.connected, equal_to(False)) assert_that(dev.connectable.startConnected, equal_to(False)) def test_remove_iso_cdrom_device(self): fake_iso_ds_path = '[ds] vm_fake/fake.iso' cspec = self.vm_config.update_spec() cfg_info = self._get_config_info_with_iso(fake_iso_ds_path) self.vm_config.remove_iso_cdrom(cspec, cfg_info) assert_that(len(cspec.deviceChange), equal_to(1)) assert_that(cspec.deviceChange[0].operation, equal_to('remove')) dev = cspec.deviceChange[0].device assert_that(dev.backing.__class__, equal_to(vim.vm.device.VirtualCdrom.IsoBackingInfo)) assert_that(dev.backing.fileName, equal_to(fake_iso_ds_path)) def test_update_spec(self): cfg_info = FakeConfigInfo() spec = self.vm_config.update_spec() assert_that(len(spec.deviceChange), equal_to(0)) net_name = "VM_Network" self.vm_config.add_nic(spec, net_name) assert_that(len(spec.deviceChange), equal_to(1)) self.vm_config.add_scsi_disk(cfg_info, spec, "ds1", "foo") # One for the controller and one for the disk itself. assert_that(len(spec.deviceChange), equal_to(3)) def test_path_conversion_invalid(self): self.assertRaises(IndexError, datastore_to_os_path, "invalid_ds_path") @parameterized.expand([ ('[foo] a/b/c.vmdk', '/vmfs/volumes/foo/a/b/c.vmdk'), ('[foo] c.vmdk', '/vmfs/volumes/foo/c.vmdk'), ('[foo]a', '/vmfs/volumes/foo/a'), ('/vmfs/volumes/foo/bar.vmdk', '/vmfs/volumes/foo/bar.vmdk'), ('[]/vmfs/volumes/foo/bar.vmdk', '/vmfs/volumes/foo/bar.vmdk'), ('[] /vmfs/volumes/foo/bar.vmdk', '/vmfs/volumes/foo/bar.vmdk') ]) def test_path_conversion(self, ds_path, expected_os_path): path = datastore_to_os_path(ds_path) assert_that(path, equal_to(expected_os_path)) @parameterized.expand([ (['[foo] image_a_b/c.vmdk'], True, False, False), (['[foo] vm_a_b/c.vmdk'], False, True, False), (['[foo] image_a_b/c.vmdk', '[foo] vm/a.vmdk'], False, True, False), (['[foo] disk_a_b/c.vmdk'], False, False, True), (['[foo] image_a/c.vmdk', '[foo] disk/a.vmdk'], False, False, True), ([], False, False, False) ]) def test_is_what_disk(self, disk_files, image, ephemeral, persistent): assert_that(is_image(disk_files), equal_to(image)) assert_that(is_ephemeral_disk(disk_files), equal_to(ephemeral)) assert_that(is_persistent_disk(disk_files), equal_to(persistent)) def test_vmdk_uuid_conversion(self): for id in ['01234567-89ab-cedf-0123-456789abcdef', '01 23456 789ABCEDF0123456789ABCDEF', '01 23 45 67 89 ab ce df-01 23 45 67 89 ab cd ef', '0123456789abcedf0123456789abcdef']: vmdk_uuid = uuid_to_vmdk_uuid(id) assert_that( vmdk_uuid, equal_to('01 23 45 67 89 ab ce df-01 23 45 67 89 ab cd ef')) for id in ['', '01234567-89ab-cedf-0123-456789abcd', '01 23456 789abcedf0123456789abcdefabcd']: self.assertRaises(ValueError, uuid_to_vmdk_uuid, id)
def setUp(self, connect, update, creds): creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.ds_manager = MagicMock() services.register(ServiceName.AGENT_CONFIG, MagicMock()) self.image_manager = EsxImageManager(self.vim_client, self.ds_manager)
class TestEsxImageManager(unittest.TestCase): """Image Manager tests.""" # We can use even more unit test coverage of the image manager here @patch.object(VimClient, "acquire_credentials") @patch.object(VimClient, "update_cache") @patch("pysdk.connect.Connect") def setUp(self, connect, update, creds): creds.return_value = ["username", "password"] self.vim_client = VimClient(auto_sync=False) self.ds_manager = MagicMock() services.register(ServiceName.AGENT_CONFIG, MagicMock()) self.image_manager = EsxImageManager(self.vim_client, self.ds_manager) def tearDown(self): self.vim_client.disconnect(wait=True) @patch("os.path.isdir", return_value=False) @patch("os.makedirs", side_effect=OSError) def test_make_image_dir(self, _makedirs, _isdir): self.assertRaises( OSError, self.image_manager._make_image_dir, "ds", "fake_iid") _isdir.assert_called_once_with("/vmfs/volumes/ds/images/fa/fake_iid") self.assertEqual( _makedirs.call_count, EsxImageManager.NUM_MAKEDIRS_ATTEMPTS) for i in range(0, EsxImageManager.NUM_MAKEDIRS_ATTEMPTS): self.assertEqual(_makedirs.call_args_list[i][0], ("/vmfs/volumes/ds/images/fa/fake_iid",)) @patch( "host.hypervisor.esx.image_manager.EsxImageManager.reap_tmp_images") def test_periodic_reaper(self, mock_reap): """ Test that the we invoke the image reaper periodically """ image_manager = EsxImageManager(self.vim_client, self.ds_manager) image_manager.monitor_for_cleanup(reap_interval=0.1) self.assertFalse(image_manager._image_reaper is None) retry = 0 while mock_reap.call_count < 2 and retry < 10: time.sleep(0.1) retry += 1 image_manager.cleanup() assert_that(mock_reap.call_count, greater_than(1)) assert_that(retry, is_not(10), "reaper cleanup not called repeatedly") @patch("uuid.uuid4", return_value="fake_id") @patch("host.hypervisor.esx.vm_config.os_datastore_path") def test_reap_tmp_images(self, _os_datastore_path, _uuid): """ Test that stray images are found and deleted by the reaper """ def _fake_ds_folder(datastore, folder): return "%s__%s" % (datastore, folder) ds = MagicMock() ds.id = "dsid" ds.type = DatastoreType.EXT3 # In a random transient directory, set up a directory to act as the # tmp images folder and to contain a stray image folder with a file. tmpdir = file_util.mkdtemp(delete=True) tmp_images_folder = _fake_ds_folder(ds.id, TMP_IMAGE_FOLDER_NAME) tmp_images_dir = os.path.join(tmpdir, tmp_images_folder) tmp_image_dir = os.path.join(tmp_images_dir, "stray_image") os.mkdir(tmp_images_dir) os.mkdir(tmp_image_dir) (fd, path) = tempfile.mkstemp(prefix='strayimage_', dir=tmp_image_dir) self.assertTrue(os.path.exists(path)) def _fake_os_datastore_path(datastore, folder): return os.path.join(tmpdir, _fake_ds_folder(datastore, folder)) _os_datastore_path.side_effect = _fake_os_datastore_path ds_manager = MagicMock() ds_manager.get_datastores.return_value = [ds] image_manager = EsxImageManager(self.vim_client, ds_manager) image_manager.reap_tmp_images() # verify stray image is deleted self.assertFalse(os.path.exists(path)) @patch("os.path.isdir") @patch("os.makedirs") def test_vmdk_mkdir_eexist(self, _makedirs, _isdir): eexist = OSError() eexist.errno = errno.EEXIST _makedirs.side_effect = eexist _isdir.side_effect = (False, # dest image dir missing True) # dest image dir is created self.image_manager._make_image_dir("ds", "fake_iid") _isdir.assert_called("/vmfs/volumes/ds/images/fa/fake_iid") @patch("pysdk.task.WaitForTask") @patch("uuid.uuid4", return_value="fake_id") @patch("os.path.exists") @patch("os.makedirs") @patch("shutil.copy") @patch("shutil.rmtree") @patch("shutil.move") @patch.object(EsxImageManager, "_manage_disk") @patch.object(EsxImageManager, "_get_datastore_type", return_value=DatastoreType.EXT3) @patch.object(EsxImageManager, "_check_image_repair", return_value=False) @patch.object(EsxImageManager, "check_and_validate_image", return_value=False) @patch.object(EsxImageManager, "_create_image_timestamp_file") @patch("host.hypervisor.esx.image_manager.FileBackedLock") def test_copy_image(self, _flock, _create_image_timestamp, check_image, _check_image_repair, _get_ds_type, _manage_disk, _mv_dir, _rmtree, _copy, _makedirs, _exists, _uuid, _wait_for_task): _exists.side_effect = (True, # dest image vmdk missing True) # source meta file present self.image_manager.copy_image("ds1", "foo", "ds2", "bar") os_path_prefix1 = '/vmfs/volumes/ds1/images' os_path_prefix2 = '/vmfs/volumes/ds2/images' os_tmp_path_prefix = '/vmfs/volumes/ds2/tmp_images' _copy.assert_called_once_with( '%s/fo/foo/foo.%s' % (os_path_prefix1, METADATA_FILE_EXT), '/vmfs/volumes/ds2/tmp_images/fake_id') ds_path_prefix1 = '[] ' + os_path_prefix1 ds_tmp_path_prefix = '[] ' + os_tmp_path_prefix expected_tmp_disk_ds_path = '%s/fake_id/%s.vmdk' % (ds_tmp_path_prefix, 'bar') _vd_spec = _manage_disk.call_args_list[0][1]['destSpec'] self.assertEqual("thin", _vd_spec.diskType) self.assertEqual("lsiLogic", _vd_spec.adapterType) copy_call = call(vim.VirtualDiskManager.CopyVirtualDisk_Task, sourceName='%s/fo/foo/foo.vmdk' % ds_path_prefix1, destName=expected_tmp_disk_ds_path, destSpec=_vd_spec) expected_vim_calls = [copy_call] self.assertEqual(expected_vim_calls, _manage_disk.call_args_list) _mv_dir.assert_called_once_with('/vmfs/volumes/ds2/tmp_images/fake_id', '%s/ba/bar' % os_path_prefix2) _create_image_timestamp.assert_called_once_with( "/vmfs/volumes/ds2/tmp_images/fake_id") @patch("pysdk.task.WaitForTask") @patch("uuid.uuid4", return_value="fake_id") @patch("os.path.exists") @patch("os.makedirs") @patch("shutil.copy") @patch.object(EsxImageManager, "_manage_disk") @patch.object(EsxImageManager, "_get_datastore_type", return_value=DatastoreType.EXT3) @patch.object(EsxImageManager, "check_image", return_value=False) @patch.object(EsxImageManager, "_create_image_timestamp_file") @patch("host.hypervisor.esx.image_manager.FileBackedLock") def test_create_tmp_image(self, _flock, _create_image_timestamp, check_image, _get_ds_type, _manage_disk, _copy, _makedirs, _exists, _uuid, _wait_for_task): # Common case is the same as the one covered by test_copy_image. # Check that things work when the src metadata file doesn't exist. _exists.side_effect = (False, True) ds_path_prefix1 = '[] /vmfs/volumes/ds1/images' expected_tmp_disk_ds_path = \ "[] /vmfs/volumes/ds2/tmp_images/fake_id/bar.vmdk" self.image_manager._create_tmp_image("ds1", "foo", "ds2", "bar") _flock.assert_called_once_with("/vmfs/volumes/ds2/tmp_images/fake_id", DatastoreType.EXT3) # Verify that we don't copy the metadata file. self.assertFalse(_copy.called) # Verify that we copy the disk correctly _vd_spec = _manage_disk.call_args_list[0][1]['destSpec'] self.assertEqual("thin", _vd_spec.diskType) self.assertEqual("lsiLogic", _vd_spec.adapterType) copy_call = call(vim.VirtualDiskManager.CopyVirtualDisk_Task, sourceName='%s/fo/foo/foo.vmdk' % ds_path_prefix1, destName=expected_tmp_disk_ds_path, destSpec=_vd_spec) expected_vim_calls = [copy_call] self.assertEqual(expected_vim_calls, _manage_disk.call_args_list) # check that we return an IO error if the copy of metadata fails. _copy.side_effect = IOError _exists.side_effect = (True, True) _manage_disk.reset_mock() _flock.reset_mock() self.assertRaises(IOError, self.image_manager._create_tmp_image, "ds1", "foo", "ds2", "bar") self.assertFalse(_manage_disk.called) _flock.assert_called_once_with("/vmfs/volumes/ds2/tmp_images/fake_id", DatastoreType.EXT3) _create_image_timestamp.assert_called_once_with( "/vmfs/volumes/ds2/tmp_images/fake_id") @patch("os.makedirs") @patch("shutil.rmtree") @patch("shutil.move") @patch.object(EsxImageManager, "_get_datastore_type", return_value=DatastoreType.EXT3) @patch.object(EsxImageManager, "_check_image_repair", return_value=True) @patch("host.hypervisor.esx.image_manager.FileBackedLock") @raises(DiskAlreadyExistException) def test_move_image(self, _flock, check_image, _get_ds_type, _mv_dir, _rmtree, _makedirs): # Common case is covered in test_copy_image. # check that if destination image directory exists we don't call move # and just bail after removing the tmp dir _rmtree.reset_mock() _mv_dir.reset_mock() expected_tmp_disk_folder = '/vmfs/volumes/ds2/tmp_images/bar' expected_rm_calls = [call(expected_tmp_disk_folder)] self.image_manager._move_image("foo", "ds1", expected_tmp_disk_folder) self.assertEqual(expected_rm_calls, _rmtree.call_args_list) _makedirs.assert_called_once_with('/vmfs/volumes/ds1/images/fo') _flock.assert_called_once_with('/vmfs/volumes/ds1/images/fo/foo', DatastoreType.EXT3, 3) @parameterized.expand([ (True, ), (False, ) ]) @patch("os.path.exists") @patch.object(EsxImageManager, "_get_datastore_type", return_value=DatastoreType.EXT3) @patch.object(EsxImageManager, "_create_image_timestamp_file") @patch.object(EsxImageManager, "_delete_renamed_image_timestamp_file") @patch("host.hypervisor.esx.image_manager.FileBackedLock") def test_validate_existing_image(self, create, _flock, _delete_renamed_timestamp_file, _create_timestamp_file, _get_ds_type, _path_exists): self._create_image_timestamp_file = create _path_exists.side_effect = self._local_os_path_exists _disk_folder = '/vmfs/volumes/ds1/images/fo/foo' self.image_manager._check_image_repair("foo", "ds1") if create: _create_timestamp_file.assert_called_once_with(_disk_folder) _delete_renamed_timestamp_file.assert_called_once() else: assert not _create_timestamp_file.called assert not _delete_renamed_timestamp_file.called def _local_os_path_exists(self, pathname): if not self._create_image_timestamp_file: return True if pathname.endswith(EsxImageManager.IMAGE_TIMESTAMP_FILE_NAME): return False else: return True @patch.object(EsxImageManager, "_clean_gc_dir") @patch.object(EsxImageManager, "_gc_image_dir") @patch.object(EsxImageManager, "_lock_data_disk") @patch.object(EsxImageManager, "create_image_tombstone") @patch.object(EsxImageManager, "check_image_dir") def test_delete(self, check_image_dir, create_image_tombstone, lock_data_disk, gc_image_dir, clean_gc_dir): # Test successful delete check_image_dir.return_value = True self.image_manager.delete_image("ds1", "foo", 0, False) check_image_dir.assert_called_with("foo", "ds1") create_image_tombstone.assert_called_with("ds1", "foo") # Test successful delete with force option self.image_manager.delete_image("ds1", "foo", 0, True) check_image_dir.assert_called_with("foo", "ds1") create_image_tombstone.assert_called_with("ds1", "foo") lock_data_disk.assert_called_with("ds1", "foo") gc_image_dir.assert_called_with("ds1", "foo") clean_gc_dir.assert_called() # Test image not found check_image_dir.return_value = False self.assertRaises(ImageNotFoundException, self.image_manager.delete_image, "ds1", "foo", 0, False) @patch("host.hypervisor.esx.image_manager.os_vmdk_path") @patch("host.hypervisor.esx.image_manager.os_datastore_path") def test_gc_image_dir(self, dst_path, src_path): """ Test that we move the directory correctly to the GC location """ src_dir = file_util.mkdtemp(delete=True) dst_dir = file_util.mkdtemp(delete=True) src_path.return_value = os.path.join(src_dir, "test.vmdk") dst_path.return_value = dst_dir self.image_manager._gc_image_dir("ds1", "foo") uuid_dir = os.path.join(dst_dir, os.listdir(dst_dir)[0]) # Verify the src directory has been moved into the garbage dir. self.assertEqual(os.listdir(uuid_dir), [os.path.basename(src_dir)]) src_path.assert_called_once_with("ds1", "foo", IMAGE_FOLDER_NAME) dst_path.assert_called_once_with("ds1", GC_IMAGE_FOLDER) def test_image_path(self): image_path = "/vmfs/volumes/ds/images/tt/ttylinux/ttylinux.vmdk" ds = self.image_manager.get_datastore_id_from_path(image_path) image = self.image_manager.get_image_id_from_path(image_path) self.assertEqual(ds, "ds") self.assertEqual(image, "ttylinux") @patch("host.hypervisor.esx.image_manager.os_vmdk_flat_path") @patch("host.hypervisor.esx.image_manager.os.remove") def test_lock_data_disk(self, mock_rm, vmdk_flat_path): """ Test acquisition of the lock on the flat file. """ vmdk_flat_path.return_value = "fake_f_name" self.assertTrue(self.image_manager._lock_data_disk("ds1", "foo")) vmdk_flat_path.assert_called_once_with("ds1", "foo") mock_rm.side_effect = OSError self.assertFalse(self.image_manager._lock_data_disk("ds1", "foo")) @parameterized.expand([ ("CLOUD", "EAGER", ImageType.CLOUD, ImageReplication.EAGER), ("MANAGEMENT", "EAGER", ImageType.MANAGEMENT, ImageReplication.EAGER), ("CLOUD", "ON_DEMAND", ImageType.CLOUD, ImageReplication.ON_DEMAND), ("MANAGEMENT", "ON_DEMAND", ImageType.MANAGEMENT, ImageReplication.ON_DEMAND), ]) def test_image_type(self, type, replication, expected_type, expected_replication): self.ds_manager.image_datastores.return_value = "ds1" with patch("host.hypervisor.esx.image_manager.os_image_manifest_path" "") as manifest_path: tmpdir = file_util.mkdtemp(delete=True) tmpfile = os.path.join(tmpdir, "ds1.manifest") manifest_path.return_value = tmpfile with open(tmpfile, 'w+') as f: f.write('{"imageType":"%s","imageReplication":"%s"}' % ( type, replication)) type, replication = self.image_manager.get_image_manifest( "image_id") self.assertEqual(type, expected_type) self.assertEqual(replication, expected_replication) @patch.object(EsxImageManager, "_move_image") @patch.object(EsxImageManager, "check_image_dir", return_value=False) @patch.object(EsxImageManager, "_create_image_timestamp_file_from_ids") @patch("os.path.exists") def test_create_image(self, _exists, _create_timestamp, check_image_dir, move_image): # Happy path verify move is called with the right args. _exists.side_effect = ([True]) self.image_manager.create_image("ds1", "foo", "img_1") check_image_dir.assert_called_once_with("img_1", "ds1") move_image.assert_called_once_with('img_1', 'ds1', '/vmfs/volumes/ds1/foo') _create_timestamp.assert_called_once_with("ds1", "img_1") # Verify error if tmp image doesn't exist _exists.side_effect = ([False]) move_image.reset_mock() self.assertRaises(ImageNotFoundException, self.image_manager.create_image, "ds1", "foo", "img_1") self.assertFalse(move_image.called) # Verify error if destination image already exists. _exists.side_effect = ([True]) move_image.reset_mock() check_image_dir.return_value = True self.assertRaises(DiskAlreadyExistException, self.image_manager.create_image, "ds1", "foo", "img_1") self.assertFalse(move_image.called) @patch.object(EsxImageManager, "create_image") @patch.object(EsxImageManager, "_manage_disk") @patch("os.path.exists", return_value=True) def test_create_image_with_vm_disk(self, _exists, _manage_disk, _create_image): vm_disk_path = "/vmfs/volumes/dsname/vms/ab/cd.vmdk" self.image_manager.create_image_with_vm_disk( "ds1", "foo", "img_1", vm_disk_path) # Verify that we copy the disk correctly expected_tmp_disk_ds_path = \ "[] /vmfs/volumes/ds1/foo/img_1.vmdk" _vd_spec = _manage_disk.call_args_list[0][1]['destSpec'] self.assertEqual("thin", _vd_spec.diskType) self.assertEqual("lsiLogic", _vd_spec.adapterType) copy_call = call(vim.VirtualDiskManager.CopyVirtualDisk_Task, sourceName='[] %s' % vm_disk_path, destName=expected_tmp_disk_ds_path, destSpec=_vd_spec) expected_vim_calls = [copy_call] self.assertEqual(expected_vim_calls, _manage_disk.call_args_list) _create_image.assert_called_once_with("ds1", "foo", "img_1") @patch("shutil.rmtree") @patch("os.path.exists") def test_delete_tmp_dir(self, _exists, _rmtree): self.image_manager.delete_tmp_dir("ds1", "foo") _exists.assert_called_once("/vmfs/volumes/ds1/foo") _rmtree.assert_called_once("/vmfs/volumes/ds1/foo") _exists.reset_mock() _exists.return_value = False _rmtree.reset_mock() self.assertRaises(DirectoryNotFound, self.image_manager.delete_tmp_dir, "ds1", "foo") _exists.assert_called_once("/vmfs/volumes/ds1/foo") self.assertFalse(_rmtree.called)