Esempio n. 1
0
 def delete_disk(self, path):
     try:
         disk_mgr = self._content.virtualDiskManager
         vim_task = disk_mgr.DeleteVirtualDisk(name=os_to_datastore_path(path))
         self.wait_for_task(vim_task)
     except vim.fault.FileFault, e:
         raise DiskFileException(e.msg)
Esempio n. 2
0
class VimClient():
    """Wrapper class around VIM API calls using Service Instance connection"""
    def __init__(self,
                 auto_sync=True,
                 errback=None,
                 wait_timeout=10,
                 min_interval=1):
        self._logger = logging.getLogger(__name__)
        self._logger.info("VimClient init")
        self._sync_thread = None
        self._auto_sync = auto_sync
        self._errback = errback
        self._wait_timeout = wait_timeout
        self._min_interval = min_interval
        self._update_listeners = set()
        self._lock = threading.Lock()
        self._task_counter = 0
        self._vim_cache = None

    def connect_ticket(self, host, ticket):
        if ticket:
            try:
                stub = connect.SoapStubAdapter(host, HOSTD_PORT, VIM_NAMESPACE)
                self._si = vim.ServiceInstance("ServiceInstance", stub)
                self._si.RetrieveContent().sessionManager.CloneSession(ticket)
                self._post_connect()
            except httplib.HTTPException as http_exception:
                self._logger.info("Failed to login hostd with ticket: %s" %
                                  http_exception)
                raise AcquireCredentialsException(http_exception)

    def connect_userpwd(self, host, user, pwd):
        try:
            self._si = connect.Connect(host=host,
                                       user=user,
                                       pwd=pwd,
                                       version=VIM_VERSION)
            self._post_connect()
        except vim.fault.HostConnectFault as connection_exception:
            self._logger.info("Failed to connect to hostd: %s" %
                              connection_exception)
            raise HostdConnectionFailure(connection_exception)

    def connect_local(self):
        username, password = self._acquire_local_credentials()
        self.connect_userpwd("localhost", username, password)

    def _create_local_service_instance(self):
        stub = connect.SoapStubAdapter("localhost", HOSTD_PORT)
        return vim.ServiceInstance("ServiceInstance", stub)

    def _acquire_local_credentials(self):
        si = self._create_local_service_instance()
        try:
            session_manager = si.content.sessionManager
        except httplib.HTTPException as http_exception:
            self._logger.info("Failed to retrieve credentials from hostd: %s" %
                              http_exception)
            raise AcquireCredentialsException(http_exception)

        local_ticket = session_manager.AcquireLocalTicket(userName="******")
        username = local_ticket.userName
        password = file(local_ticket.passwordFilePath).read()
        return username, password

    def _post_connect(self):
        self._content = self._si.RetrieveContent()
        if self._auto_sync:
            # Start syncing vm cache periodically
            self._start_syncing_cache()

    def disconnect(self):
        """ Disconnect vim client
        :param wait: If wait is true, it waits until the sync thread exit.
        """
        self._logger.info("vimclient disconnect")
        self._stop_syncing_cache()
        try:
            connect.Disconnect(self._si)
        except:
            self._logger.warning("Failed to disconnect vim_client: %s" %
                                 sys.exc_info()[1])

    def _start_syncing_cache(self):
        self._logger.info("Start vim client sync vm cache thread")
        self._vim_cache = VimCache()
        self._vim_cache.poll_updates(self)
        self._sync_thread = SyncVimCacheThread(self, self._vim_cache,
                                               self._wait_timeout,
                                               self._min_interval,
                                               self._errback)
        self._sync_thread.start()

    def _stop_syncing_cache(self):
        if self._sync_thread:
            self._sync_thread.stop()
            self._sync_thread.join()

    @lock_with("_lock")
    def add_update_listener(self, listener):
        # Notify the listener immediately since there might have already been some updates.
        listener.datastores_updated()
        self._update_listeners.add(listener)

    @lock_with("_lock")
    def remove_update_listener(self, listener):
        self._update_listeners.discard(listener)

    @property
    @lock_with("_lock")
    def update_listeners(self):
        return self._update_listeners

    def query_config(self):
        env_browser = invt.GetEnv(si=self._si)
        return env_browser.QueryConfigOption("vmx-10", None)

    @property
    def _property_collector(self):
        return self._content.propertyCollector

    def _root_resource_pool(self):
        """Get the root resource pool for this host.
        :rtype: vim.ResourcePool
        """
        return host.GetRootResourcePool(self._si)

    def _vm_folder(self):
        """Get the default vm folder for this host.
        :rtype: vim.Folder
        """
        return invt.GetVmFolder(si=self._si)

    def host_system(self):
        return host.GetHostSystem(self._si)

    def _find_by_inventory_path(self, *path):
        """
        Finds a managed entity based on its location in the inventory.

        :param path: Inventory path
        :type path: tuple
        :rtype: vim.ManagedEntity
        """
        dc = (HA_DATACENTER_ID, )
        # Convert a tuple of strings to a path for use with `find_by_inventory_path`.
        p = "/".join(p.replace("/", "%2f") for p in dc + path if p)
        return self._content.searchIndex.FindByInventoryPath(p)

    def get_vm(self, vm_id):
        """Get the vm reference on a host.
        :param vm_id: The name of the vm.
        :rtype A vim vm reference.
        """
        vm = self._find_by_inventory_path(VM_FOLDER_NAME, vm_id)
        if not vm:
            raise VmNotFoundException("VM '%s' not found on host." % vm_id)

        return vm

    def get_all_datastores(self):
        """Get all datastores for this host.
        :rtype: list of vim.Datastore
        """
        datastores = []
        for ds in self._find_by_inventory_path(
                DATASTORE_FOLDER_NAME).childEntity:
            datastores.append(VimDatastore(ds))
        return datastores

    def _get_vms(self):
        """ Get VirtualMachine from hostd. Use get_vms_in_cache to have a
        better performance unless you want Vim Object.

        :return: list of vim.VirtualMachine
        """
        PC = vmodl.query.PropertyCollector
        traversal_spec = PC.TraversalSpec(name="folderTraversalSpec",
                                          type=vim.Folder,
                                          path="childEntity",
                                          skip=False)
        property_spec = PC.PropertySpec(
            type=vim.VirtualMachine,
            pathSet=["name", "runtime.powerState", "layout.disk", "config"])
        object_spec = PC.ObjectSpec(obj=self._vm_folder(),
                                    selectSet=[traversal_spec])
        filter_spec = PC.FilterSpec(propSet=[property_spec],
                                    objectSet=[object_spec])

        objects = self._property_collector.RetrieveContents([filter_spec])
        return [object.obj for object in objects]

    def get_vms_in_cache(self):
        """ Get information of all VMs from cache.

        :return: list of VmCache
        """
        return self._vim_cache.get_vms_in_cache()

    def get_vm_in_cache(self, vm_id):
        """ Get information of a VM from cache. The vm state is not
        guaranteed to be up-to-date. Also only name and power_state is
        guaranteed to be not None.

        :return: VmCache for the vm that is found
        :raise VmNotFoundException when vm is not found
        """
        return self._vim_cache.get_vm_in_cache(vm_id)

    def create_vm_spec(self, vm_id, datastore, memoryMB, cpus, metadata, env):
        spec = EsxVmConfigSpec(self.query_config())
        spec.init_for_create(vm_id, datastore, memoryMB, cpus, metadata, env)
        return spec

    def create_vm(self, vm_id, create_spec):
        """Create a new Virtual Maching given a VM create spec.

        :param vm_id: The Vm id
        :type vm_id: string
        :param create_spec: EsxVmConfigSpec
        :type ConfigSpec
        :raise: VmAlreadyExistException
        """
        # sanity check since VIM does not prevent this
        try:
            if self.get_vm_in_cache(vm_id):
                raise VmAlreadyExistException("VM already exists")
        except VmNotFoundException:
            pass

        folder = self._vm_folder()
        resource_pool = self._root_resource_pool()
        spec = create_spec.get_spec()
        # The scenario of the vm creation at ESX where intermediate directory
        # has to be created has not been well exercised and is known to be
        # racy and not informative on failures. So be defensive and proactively
        # create the intermediate directory ("/vmfs/volumes/<dsid>/vm_xy").
        try:
            self.make_directory(spec.files.vmPathName)
        except vim.fault.FileAlreadyExists:
            self._logger.debug(
                "VM directory %s exists, will create VM using it" %
                spec.files.vmPathName)

        task = folder.CreateVm(spec, resource_pool, None)
        self.wait_for_task(task)
        self.wait_for_vm_create(vm_id)

    def get_networks(self):
        return [
            network.name for network in self._find_by_inventory_path(
                NETWORK_FOLDER_NAME).childEntity
        ]

    def create_disk(self, path, size):
        spec = vim.VirtualDiskManager.FileBackedVirtualDiskSpec()
        spec.capacityKb = size * (1024**2)
        spec.diskType = vim.VirtualDiskManager.VirtualDiskType.thin
        spec.adapterType = DEFAULT_DISK_ADAPTER_TYPE

        try:
            disk_mgr = self._content.virtualDiskManager
            vim_task = disk_mgr.CreateVirtualDisk(
                name=os_to_datastore_path(path), spec=spec)
            self.wait_for_task(vim_task)
        except vim.fault.FileAlreadyExists, e:
            raise DiskAlreadyExistException(e.msg)
        except vim.fault.FileFault, e:
            raise DiskFileException(e.msg)
Esempio n. 3
0
        vd_spec.adapterType = str(
            vim.VirtualDiskManager.VirtualDiskAdapterType.lsiLogic)

        try:
            disk_mgr = self._content.virtualDiskManager
            vim_task = disk_mgr.CopyVirtualDisk(
                sourceName=os_to_datastore_path(src),
                destName=os_to_datastore_path(dst),
                destSpec=vd_spec)
            self.wait_for_task(vim_task)
        except vim.fault.FileAlreadyExists, e:
            raise DiskAlreadyExistException(e.msg)
        except vim.fault.FileLocked, e:
            raise DeviceBusyException(e.msg)
        except vim.fault.FileFault, e:
            raise DiskFileException(e.msg)
        except vim.fault.InvalidDatastore, e:
            raise DiskPathException(e.msg)

    def move_disk(self, src, dst):
        try:
            disk_mgr = self._content.virtualDiskManager
            vim_task = disk_mgr.MoveVirtualDisk(
                sourceName=os_to_datastore_path(src),
                destName=os_to_datastore_path(dst))
            self.wait_for_task(vim_task)
        except vim.fault.FileAlreadyExists, e:
            raise DiskAlreadyExistException(e.msg)
        except vim.fault.FileFault, e:
            raise DiskFileException(e.msg)
        except vim.fault.InvalidDatastore, e:
Esempio n. 4
0
 def query_disk_uuid(self, path):
     try:
         disk_mgr = self._content.virtualDiskManager
         return disk_mgr.QueryVirtualDiskUuid(name=os_to_datastore_path(path))
     except vim.fault.FileFault, e:
         raise DiskFileException(e.msg)
Esempio n. 5
0
 def set_disk_uuid(self, path, uuid):
     try:
         disk_mgr = self._content.virtualDiskManager
         disk_mgr.SetVirtualDiskUuid(name=os_to_datastore_path(path), uuid=uuid_to_vmdk_uuid(uuid))
     except vim.fault.FileFault, e:
         raise DiskFileException(e.msg)
Esempio n. 6
0
class VimClient(HostClient):
    """Wrapper class around VIM API calls using Service Instance connection"""

    ALLOC_LARGE_PAGES = "Mem.AllocGuestLargePage"
    metric_names = [
        "cpu.totalmhz",
        "cpu.usage",
        "cpu.usagemhz",
        "cpu.swapwait",
        "mem.usage",
        "mem.totalmb",
        "mem.sysUsage",
        "mem.swapout",
        "mem.swapin",
        "mem.swapused",
        "mem.heapfree",
        "net.usage",
        "net.packetsRx",
        "net.packetsTx",
        "net.droppedRx",
        "net.droppedTx",
        "net.errorsRx",
        "net.errorsTx",
        "net.bytesRx",
        "net.bytesTx",
        "net.transmitted",
        "disk.usage",
        "disk.maxTotalLatency",
        "disk.numberRead",
        "disk.numberWrite",
        "disk.commandsAborted",
        "disk.busResets",
        "disk.kernelReadLatency",
        "disk.kernelWriteLatency",
        "datastore.numberReadAveraged",
        "datastore.numberWriteAveraged",
        "storageAdapter.numberReadAveraged",
        "storageAdapter.numberWriteAveraged"
    ]
    host_cpu_usage_metric_name = "cpu.cpuUsagePercentage"
    host_mem_usage_metric_name = "mem.memoryUsagePercentage"

    def __init__(self, auto_sync=True, errback=None, wait_timeout=10, min_interval=1):
        self._logger = logging.getLogger(__name__)
        self._logger.info("VimClient init")
        self._sync_thread = None
        self._auto_sync = auto_sync
        self._errback = errback
        self._wait_timeout = wait_timeout
        self._min_interval = min_interval
        self._update_listeners = set()
        self._lock = threading.Lock()
        self._task_counter = 0
        self._vim_cache = None

    def connect_ticket(self, host, ticket):
        if ticket:
            try:
                stub = connect.SoapStubAdapter(host, HOSTD_PORT, VIM_NAMESPACE)
                self._si = vim.ServiceInstance("ServiceInstance", stub)
                self._si.RetrieveContent().sessionManager.CloneSession(ticket)
                self._post_connect()
            except httplib.HTTPException as http_exception:
                self._logger.info("Failed to login hostd with ticket: %s" % http_exception)
                raise AcquireCredentialsException(http_exception)

    def connect_userpwd(self, host, user, pwd):
        try:
            self._si = connect.Connect(host=host, user=user, pwd=pwd, version=VIM_VERSION)
            self._post_connect()
        except vim.fault.HostConnectFault as connection_exception:
            self._logger.info("Failed to connect to hostd: %s" % connection_exception)
            raise HostdConnectionFailure(connection_exception)

    def connect_local(self):
        username, password = self._acquire_local_credentials()
        self.connect_userpwd("localhost", username, password)

    def _create_local_service_instance(self):
        stub = connect.SoapStubAdapter("localhost", HOSTD_PORT)
        return vim.ServiceInstance("ServiceInstance", stub)

    def _acquire_local_credentials(self):
        si = self._create_local_service_instance()
        try:
            session_manager = si.content.sessionManager
        except httplib.HTTPException as http_exception:
            self._logger.info("Failed to retrieve credentials from hostd: %s" % http_exception)
            raise AcquireCredentialsException(http_exception)

        local_ticket = session_manager.AcquireLocalTicket(userName="******")
        username = local_ticket.userName
        password = file(local_ticket.passwordFilePath).read()
        return username, password

    def _post_connect(self):
        self._content = self._si.RetrieveContent()
        if self._auto_sync:
            # Start syncing vm cache periodically
            self._start_syncing_cache()

    def disconnect(self):
        """ Disconnect vim client
        :param wait: If wait is true, it waits until the sync thread exit.
        """
        self._logger.info("vimclient disconnect")
        self._stop_syncing_cache()
        try:
            connect.Disconnect(self._si)
        except:
            self._logger.warning("Failed to disconnect vim_client: %s" % sys.exc_info()[1])

    def _start_syncing_cache(self):
        self._logger.info("Start vim client sync vm cache thread")
        self._vim_cache = VimCache()
        self._vim_cache.poll_updates(self)
        self._sync_thread = SyncVimCacheThread(self, self._vim_cache, self._wait_timeout,
                                               self._min_interval, self._errback)
        self._sync_thread.start()

    def _stop_syncing_cache(self):
        if self._sync_thread:
            self._sync_thread.stop()
            self._sync_thread.join()

    def _get_timestamps(self, sample_info_csv):
        # extract timestamps from sampleInfoCSV
        # format is '20,2015-12-03T18:39:20Z,20,2015-12-03T18:39:40Z...'
        # Note: timegm() returns seconds since epoch without adjusting for
        # local timezone, which is how we want timestamp interpreted.
        timestamps = sample_info_csv.split(',')[1::2]
        return [timegm(datetime.strptime(dt, '%Y-%m-%dT%H:%M:%SZ').timetuple()) for dt in timestamps]

    @lock_with("_lock")
    def add_update_listener(self, listener):
        # Notify the listener immediately since there might have already been some updates.
        listener.datastores_updated()
        self._update_listeners.add(listener)

    @lock_with("_lock")
    def remove_update_listener(self, listener):
        self._update_listeners.discard(listener)

    @property
    @lock_with("_lock")
    def update_listeners(self):
        return self._update_listeners

    def query_config(self):
        env_browser = invt.GetEnv(si=self._si)
        return env_browser.QueryConfigOption("vmx-10", None)

    @hostd_error_handler
    def query_stats(self, start_time, end_time=None):
        """ Returns the host statistics by querying the perf manager on the
            host for the passed-in metric_names.
        """
        metric_id_objs = []
        counter_to_metric_map = {}
        host = self.host_system()

        for c in self._perf_manager.perfCounter:
            metric_name = "%s.%s" % (c.groupInfo.key, c.nameInfo.key)
            if metric_name in self.metric_names:
                counter_to_metric_map[c.key] = metric_name
                metric_id_objs.append(
                    vim.PerformanceManager.MetricId(
                        counterId=c.key,
                        instance="*"
                    ))

        # Stats are sampled by the performance manager every 20
        # seconds. Hostd keeps 180 samples at the rate of 1 sample
        # per 20 seconds, which results in samples that span an hour.
        query_spec = [vim.PerformanceManager.QuerySpec(
            entity=host,
            intervalId=20,
            format='csv',
            metricId=metric_id_objs,
            startTime=start_time,
            endTime=end_time)]

        results = {}
        stats = self._perf_manager.QueryPerf(query_spec)
        if stats:
            for stat in stats:
                timestamps = self._get_timestamps(stat.sampleInfoCSV)
                values = stat.value
                for value in values:
                    id = value.id.counterId
                    counter_values = [float(i) for i in value.value.split(',')]
                    if id in counter_to_metric_map:
                        metric_name = counter_to_metric_map[id]
                        results[metric_name] = zip(timestamps, counter_values)
        else:
            self._logger.debug("No metrics collected")

        # Get remaining Host Stats for CPU and Memory Usage.
        timestamp = int(time.mktime(datetime.now().timetuple()))
        results[self.host_cpu_usage_metric_name] = [(timestamp, self._host_cpu_usage(host))]
        results[self.host_mem_usage_metric_name] = [(timestamp, self._host_mem_usage(host))]
        return results

    def _host_cpu_usage(self, host):
        overall_cpu_usage = host.summary.quickStats.overallCpuUsage
        total_cpu = host.summary.hardware.cpuMhz * host.summary.hardware.numCpuCores
        if total_cpu > 0:
            return (overall_cpu_usage * 100) / float(total_cpu)
        return 0.0

    def _host_mem_usage(self, host):
        overall_memory_usage = host.summary.quickStats.overallMemoryUsage
        total_memory = host.summary.hardware.memorySize / 1024 / 1024
        if total_memory > 0:
            return (overall_memory_usage * 100) / float(total_memory)
        return 0.0

    @property
    @hostd_error_handler
    def _perf_manager(self):
        return self._content.perfManager

    @property
    @hostd_error_handler
    def _property_collector(self):
        return self._content.propertyCollector

    @hostd_error_handler
    def _root_resource_pool(self):
        """Get the root resource pool for this host.
        :rtype: vim.ResourcePool
        """
        return host.GetRootResourcePool(self._si)

    @hostd_error_handler
    def _vm_folder(self):
        """Get the default vm folder for this host.
        :rtype: vim.Folder
        """
        return invt.GetVmFolder(si=self._si)

    @hostd_error_handler
    def host_system(self):
        return host.GetHostSystem(self._si)

    @property
    @hostd_error_handler
    def host_version(self):
        return self.host_system().config.product.version

    @property
    @hostd_error_handler
    def memory_usage_mb(self):
        return self._vim_cache.get_memory_usage()

    @property
    @hostd_error_handler
    def total_vmusable_memory_mb(self):
        return self.host_system().summary.hardware.memorySize >> 20

    @property
    @hostd_error_handler
    def num_physical_cpus(self):
        """
        Returns the number of pCPUs on the host. 1 pCPU is one hyper
        thread, if HT is enabled.
        :rtype: number of pCPUs
        """
        return self.host_system().summary.hardware.numCpuThreads

    @hostd_error_handler
    def get_nfc_ticket_by_ds_name(self, datastore):
        """
        :param datastore: str, datastore name
        :rtype: vim.HostServiceTicket
        """
        ds = self._find_by_inventory_path(DATASTORE_FOLDER_NAME, datastore)
        if not ds:
            raise DatastoreNotFound('Datastore %s not found' % datastore)
        nfc_service = vim.NfcService('ha-nfc-service', self._si._stub)
        return nfc_service.FileManagement(ds)

    @hostd_error_handler
    def get_vim_ticket(self):
        """
        acquire a clone ticket of current session, that can be used to login as
        current user.
        :return: str, ticket
        """
        return self._content.sessionManager.AcquireCloneTicket()

    @hostd_error_handler
    def _find_by_inventory_path(self, *path):
        """
        Finds a managed entity based on its location in the inventory.

        :param path: Inventory path
        :type path: tuple
        :rtype: vim.ManagedEntity
        """
        dc = (HA_DATACENTER_ID,)
        # Convert a tuple of strings to a path for use with `find_by_inventory_path`.
        p = "/".join(p.replace("/", "%2f") for p in dc + path if p)
        return self._content.searchIndex.FindByInventoryPath(p)

    @hostd_error_handler
    def get_vm(self, vm_id):
        """Get the vm reference on a host.
        :param vm_id: The name of the vm.
        :rtype A vim vm reference.
        """
        vm = self._find_by_inventory_path(VM_FOLDER_NAME, vm_id)
        if not vm:
            raise VmNotFoundException("VM '%s' not found on host." % vm_id)

        return vm

    @hostd_error_handler
    def get_datastore_in_cache(self, name):
        """Get a datastore network for this host.
        :param name: datastore name
        :type name: str
        :rtype: vim.Datastore
        """
        ds = self._find_by_inventory_path(DATASTORE_FOLDER_NAME, name)
        return VimDatastore(ds)

    @hostd_error_handler
    def get_all_datastores(self):
        """Get all datastores for this host.
        :rtype: list of vim.Datastore
        """
        datastores = []
        for ds in self._find_by_inventory_path(DATASTORE_FOLDER_NAME).childEntity:
            datastores.append(VimDatastore(ds))
        return datastores

    @hostd_error_handler
    def _get_vms(self):
        """ Get VirtualMachine from hostd. Use get_vms_in_cache to have a
        better performance unless you want Vim Object.

        :return: list of vim.VirtualMachine
        """
        PC = vmodl.query.PropertyCollector
        traversal_spec = PC.TraversalSpec(name="folderTraversalSpec", type=vim.Folder, path="childEntity", skip=False)
        property_spec = PC.PropertySpec(type=vim.VirtualMachine,
                                        pathSet=["name", "runtime.powerState", "layout.disk", "config"])
        object_spec = PC.ObjectSpec(obj=self._vm_folder(), selectSet=[traversal_spec])
        filter_spec = PC.FilterSpec(propSet=[property_spec], objectSet=[object_spec])

        objects = self._property_collector.RetrieveContents([filter_spec])
        return [object.obj for object in objects]

    def get_vms_in_cache(self):
        """ Get information of all VMs from cache.

        :return: list of VmCache
        """
        return self._vim_cache.get_vms_in_cache()

    def get_vm_in_cache(self, vm_id):
        """ Get information of a VM from cache. The vm state is not
        guaranteed to be up-to-date. Also only name and power_state is
        guaranteed to be not None.

        :return: VmCache for the vm that is found
        :raise VmNotFoundException when vm is not found
        """
        return self._vim_cache.get_vm_in_cache(vm_id)

    @hostd_error_handler
    def get_vm_resource_ids(self):
        return self._vim_cache.get_vm_ids_in_cache()

    def create_vm_spec(self, vm_id, datastore, memoryMB, cpus, metadata, env):
        spec = EsxVmConfigSpec(self.query_config())
        spec.init_for_create(vm_id, datastore, memoryMB, cpus, metadata, env)
        return spec

    @log_duration
    @hostd_error_handler
    def create_vm(self, vm_id, create_spec):
        """Create a new Virtual Maching given a VM create spec.

        :param vm_id: The Vm id
        :type vm_id: string
        :param create_spec: EsxVmConfigSpec
        :type ConfigSpec
        :raise: VmAlreadyExistException
        """
        # sanity check since VIM does not prevent this
        try:
            if self.get_vm_in_cache(vm_id):
                raise VmAlreadyExistException("VM already exists")
        except VmNotFoundException:
            pass

        folder = self._vm_folder()
        resource_pool = self._root_resource_pool()
        spec = create_spec.get_spec()
        # The scenario of the vm creation at ESX where intermediate directory
        # has to be created has not been well exercised and is known to be
        # racy and not informative on failures. So be defensive and proactively
        # create the intermediate directory ("/vmfs/volumes/<dsid>/vm_xy").
        try:
            self.make_directory(spec.files.vmPathName)
        except vim.fault.FileAlreadyExists:
            self._logger.debug("VM directory %s exists, will create VM using it" % spec.files.vmPathName)

        task = folder.CreateVm(spec, resource_pool, None)
        self.wait_for_task(task)
        self.wait_for_vm_create(vm_id)

    @hostd_error_handler
    def get_networks(self):
        return [network.name for network in
                self._find_by_inventory_path(NETWORK_FOLDER_NAME).childEntity]

    @hostd_error_handler
    def create_disk(self, path, size):
        spec = vim.VirtualDiskManager.FileBackedVirtualDiskSpec()
        spec.capacityKb = size * (1024 ** 2)
        spec.diskType = vim.VirtualDiskManager.VirtualDiskType.thin
        spec.adapterType = DEFAULT_DISK_ADAPTER_TYPE

        try:
            disk_mgr = self._content.virtualDiskManager
            vim_task = disk_mgr.CreateVirtualDisk(name=os_to_datastore_path(path), spec=spec)
            self.wait_for_task(vim_task)
        except vim.fault.FileAlreadyExists, e:
            raise DiskAlreadyExistException(e.msg)
        except vim.fault.FileFault, e:
            raise DiskFileException(e.msg)