Add openvixdisklib as an open NBD replacement for VMware VDDK.

VDDK is no longer publicly distributed, so this library reverse-engineers
the vSphere NFC path and exposes ConnectEx, Open, Read, and Write without
the proprietary SDK.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Lucian Petrut
2026-09-07 11:41:01 +00:00
co-authored by Cursor
commit 4ddf0c015d
31 changed files with 4089 additions and 0 deletions
View File
+336
View File
@@ -0,0 +1,336 @@
# Copyright 2026 Cloudbase Solutions Srl
# All Rights Reserved.
"""Test base classes for openvixdisklib integration tests."""
from __future__ import annotations
import ctypes
import os
import time
import unittest
import uuid
from typing import Any, Optional
import yaml
from pyVim.connect import Disconnect
from pyVmomi import vim
from openvixdisklib import nfc_auth
from openvixdisklib.nfc_auth import NfcAuthSession
_REPO_ROOT = os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", ".."))
_CONFIG_PATH = os.path.join(_REPO_ROOT, ".test_config.yaml")
_CONFIG_KEYS = (
"host",
"port",
"username",
"password",
"allow_untrusted",
"datacenter",
"datastore",
)
_VDDK_DIR = os.path.join(_REPO_ROOT, ".vddk")
_VDDK_LIB = os.path.join(_VDDK_DIR, "libvixDiskLib.so")
_DISK_CAPACITY_KB = 10 * 1024 * 1024
_TASK_POLL_S = 0.5
_TASK_TIMEOUT_S = 300
_LAB_VM_PREFIX = "ovdl-test-"
class TestBase(unittest.TestCase):
"""Shared lab vSphere settings for live NFC / VDDK integration tests."""
HOST: str
PORT: int
USERNAME: str
PASSWORD: str
ALLOW_UNTRUSTED: bool
DATACENTER: str
DATASTORE: str
THUMBPRINT: str
VM_MOREF: str
VMX_SPEC: str
DISK_PATH: str
SECTOR_SIZE = 512
SECTOR_AT_1GB = (1024 * 1024 * 1024) // SECTOR_SIZE
VDDK_DIR = _VDDK_DIR
_lab_refcount = 0
_lab_vm_moref: Optional[str] = None
_lab_vm_name: Optional[str] = None
@classmethod
def setUpClass(cls) -> None:
"""Prepare process environment and create a temporary lab VM."""
super().setUpClass()
os.environ.pop("LD_PRELOAD", None)
cls._ensure_vddk_library_path()
TestBase._acquire_lab()
@classmethod
def tearDownClass(cls) -> None:
"""Release the temporary lab VM when the last test class finishes."""
TestBase._release_lab()
super().tearDownClass()
def setUp(self) -> None:
"""Reset per-test state; subclasses may reuse this."""
super().setUp()
@classmethod
def _ensure_vddk_library_path(cls) -> None:
current = os.environ.get("LD_LIBRARY_PATH", "")
parts = [p for p in current.split(":") if p]
if cls.VDDK_DIR not in parts:
os.environ["LD_LIBRARY_PATH"] = (
cls.VDDK_DIR if not current else f"{cls.VDDK_DIR}:{current}")
@classmethod
def require_vddk(cls) -> None:
"""Skip when ``libvixDiskLib`` cannot be loaded from ``.vddk``."""
cls._ensure_vddk_library_path()
try:
ctypes.CDLL(_VDDK_LIB)
except OSError as exc:
raise unittest.SkipTest(
f"VDDK library not available at {_VDDK_LIB}: {exc}") from exc
@classmethod
def _load_test_config(cls) -> None:
"""Load lab settings from the repo-root ``.test_config.yaml``."""
if not os.path.isfile(_CONFIG_PATH):
raise unittest.SkipTest(
"integration tests need .test_config.yaml in the repo "
"root; see README.md for a sample")
with open(_CONFIG_PATH, encoding="utf-8") as config_file:
data = yaml.safe_load(config_file) or {}
missing = [key for key in _CONFIG_KEYS if key not in data]
if missing:
raise RuntimeError(
f"{_CONFIG_PATH} is missing keys: {', '.join(missing)}")
TestBase.HOST = str(data["host"])
TestBase.PORT = int(data["port"])
TestBase.USERNAME = str(data["username"])
TestBase.PASSWORD = str(data["password"])
TestBase.ALLOW_UNTRUSTED = bool(data["allow_untrusted"])
TestBase.DATACENTER = str(data["datacenter"])
TestBase.DATASTORE = str(data["datastore"])
@classmethod
def _connect_vim(cls) -> vim.ServiceInstance:
return nfc_auth.connect_vim(
cls.HOST,
cls.USERNAME,
cls.PASSWORD,
port=cls.PORT,
thumbprint=cls.THUMBPRINT,
allow_untrusted=cls.ALLOW_UNTRUSTED)
@classmethod
def _wait_for_task(cls, task: vim.Task) -> Any:
deadline = time.monotonic() + _TASK_TIMEOUT_S
while task.info.state in (
vim.TaskInfo.State.running, vim.TaskInfo.State.queued):
if time.monotonic() > deadline:
raise TimeoutError(
f"timed out waiting for vSphere task {task}")
time.sleep(_TASK_POLL_S)
if task.info.state != vim.TaskInfo.State.success:
raise RuntimeError(f"vSphere task failed: {task.info.error}")
return task.info.result
@classmethod
def _find_datacenter(
cls, content: vim.ServiceInstanceContent) -> vim.Datacenter:
matches = [
entity for entity in content.rootFolder.childEntity
if isinstance(entity, vim.Datacenter)
and entity.name == cls.DATACENTER]
if not matches:
raise RuntimeError(f"datacenter {cls.DATACENTER!r} not found")
return matches[0]
@classmethod
def _find_datastore(cls, datacenter: vim.Datacenter) -> vim.Datastore:
matches = [
datastore for datastore in datacenter.datastore
if datastore.name == cls.DATASTORE]
if not matches:
raise RuntimeError(
f"datastore {cls.DATASTORE!r} not found in "
f"datacenter {cls.DATACENTER!r}")
return matches[0]
@classmethod
def _bind_lab_fields(cls) -> None:
"""Copy shared lab VM fields onto the active test class."""
cls.HOST = TestBase.HOST
cls.PORT = TestBase.PORT
cls.USERNAME = TestBase.USERNAME
cls.PASSWORD = TestBase.PASSWORD
cls.ALLOW_UNTRUSTED = TestBase.ALLOW_UNTRUSTED
cls.DATACENTER = TestBase.DATACENTER
cls.DATASTORE = TestBase.DATASTORE
cls.THUMBPRINT = TestBase.THUMBPRINT
cls.VM_MOREF = TestBase.VM_MOREF
cls.VMX_SPEC = TestBase.VMX_SPEC
cls.DISK_PATH = TestBase.DISK_PATH
@classmethod
def _acquire_lab(cls) -> None:
if TestBase._lab_refcount == 0:
TestBase._load_test_config()
TestBase.THUMBPRINT = nfc_auth.get_ssl_cert_thumbprint(
TestBase.HOST, TestBase.PORT)
TestBase._create_lab_vm()
TestBase._lab_refcount += 1
cls._bind_lab_fields()
@classmethod
def _release_lab(cls) -> None:
if TestBase._lab_refcount == 0:
return
TestBase._lab_refcount -= 1
if TestBase._lab_refcount == 0:
cls._destroy_lab_vm()
@classmethod
def _create_lab_vm(cls) -> None:
"""Create an empty VM with a 10 GiB thin disk for I/O tests."""
si = cls._connect_vim()
vm = None
try:
content = si.RetrieveContent()
datacenter = cls._find_datacenter(content)
datastore = cls._find_datastore(datacenter)
if not datastore.host:
raise RuntimeError(
f"datastore {cls.DATASTORE!r} is not mounted on any host")
host = datastore.host[0].key
pool = host.parent.resourcePool
vm_name = _LAB_VM_PREFIX + uuid.uuid4().hex[:12]
vm = cls._wait_for_task(
datacenter.vmFolder.CreateVM_Task(
config=cls._vm_config_spec(vm_name, datastore.name),
pool=pool,
host=host))
TestBase._lab_vm_moref = vm._moId
TestBase._lab_vm_name = vm_name
TestBase.VM_MOREF = vm._moId
TestBase.VMX_SPEC = f"moref={vm._moId}"
disks = [
device.backing.fileName
for device in vm.config.hardware.device
if isinstance(device, vim.vm.device.VirtualDisk)]
if not disks:
raise RuntimeError(
f"temporary VM {vm_name!r} has no virtual disks")
TestBase.DISK_PATH = disks[0]
except Exception:
if vm is not None:
try:
cls._wait_for_task(vm.Destroy_Task())
except Exception:
pass
TestBase._lab_vm_moref = None
TestBase._lab_vm_name = None
raise
finally:
Disconnect(si)
@classmethod
def _vm_config_spec(
cls, vm_name: str, datastore_name: str) -> vim.vm.ConfigSpec:
config = vim.vm.ConfigSpec()
config.name = vm_name
config.guestId = "otherGuest64"
config.memoryMB = 128
config.numCPUs = 1
config.files = vim.vm.FileInfo(
vmPathName=f"[{datastore_name}]")
controller = vim.vm.device.ParaVirtualSCSIController()
controller.key = 1000
controller.busNumber = 0
controller.sharedBus = (
vim.vm.device.VirtualSCSIController.Sharing.noSharing)
controller_spec = vim.vm.device.VirtualDeviceSpec()
controller_spec.operation = (
vim.vm.device.VirtualDeviceSpec.Operation.add)
controller_spec.device = controller
backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
backing.diskMode = "persistent"
backing.thinProvisioned = True
backing.fileName = f"[{datastore_name}]"
disk = vim.vm.device.VirtualDisk()
disk.key = 2000
disk.controllerKey = 1000
disk.unitNumber = 0
disk.capacityInKB = _DISK_CAPACITY_KB
disk.backing = backing
disk_spec = vim.vm.device.VirtualDeviceSpec()
disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
disk_spec.fileOperation = (
vim.vm.device.VirtualDeviceSpec.FileOperation.create)
disk_spec.device = disk
config.deviceChange = [controller_spec, disk_spec]
return config
@classmethod
def _destroy_lab_vm(cls) -> None:
"""Power off and delete the temporary lab VM if it still exists."""
moref = TestBase._lab_vm_moref
TestBase._lab_vm_moref = None
TestBase._lab_vm_name = None
if not moref:
return
si = cls._connect_vim()
try:
vm = vim.VirtualMachine(moref, si._stub)
try:
vm.Reload()
except Exception:
return
if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
cls._wait_for_task(vm.PowerOffVM_Task())
cls._wait_for_task(vm.Destroy_Task())
finally:
Disconnect(si)
def authenticate(self, read_only: bool = True) -> NfcAuthSession:
"""Login to the lab vCenter and complete NFC authd for the temp VM."""
return nfc_auth.authenticate(
host=self.HOST,
username=self.USERNAME,
password=self.PASSWORD,
vm_moref=self.VM_MOREF,
thumbprint=self.THUMBPRINT,
allow_untrusted=self.ALLOW_UNTRUSTED,
disk_path=None if read_only else self.DISK_PATH,
read_only=read_only)
def vixdisklib_connect_kwargs(
self, extra: Optional[dict[str, Any]] = None) -> dict[str, Any]:
"""Return common ``VixDiskLib_ConnectEx`` arguments for the temp VM."""
kwargs: dict[str, Any] = {
"server_name": self.HOST,
"port": self.PORT,
"thumbprint": self.THUMBPRINT,
"username": self.USERNAME,
"password": self.PASSWORD,
"vmx_spec": self.VMX_SPEC,
"transport_modes": "nbd",
"read_only": False,
}
if extra:
kwargs.update(extra)
return kwargs
def pattern_bytes(self, length: int, seed: bytes) -> bytes:
"""Return ``length`` bytes by repeating ``seed``."""
if not seed:
raise ValueError("seed must be non-empty")
return (seed * ((length // len(seed)) + 1))[:length]
+94
View File
@@ -0,0 +1,94 @@
# Copyright 2026 Cloudbase Solutions Srl
# All Rights Reserved.
"""Compare writes and reads from VDDK with openvixdisklib."""
from typing import Any, Optional
from openvixdisklib import openvixdisklib as open_vix
from tests.integration import vixdisklib
from tests.integration.base import TestBase
class CrosscheckTest(TestBase):
@classmethod
def setUpClass(cls) -> None:
"""Skip when the bundled VDDK shared library is not present."""
cls.require_vddk()
super().setUpClass()
def _connect_extra(self, module: Any) -> Optional[dict[str, Any]]:
"""Return extra ``connect`` kwargs needed by ``module``."""
if module is open_vix:
return {"allow_untrusted": self.ALLOW_UNTRUSTED}
return None
def _write_sectors(
self,
module: Any,
payloads: dict[int, bytes]) -> None:
"""Write one sector at each index using a vixdisklib-compatible module."""
handle = module.VixDiskLibHandle(
vixdisklib_compatibility_version="8.0",
config_path=None)
buf = module.get_buffer(self.SECTOR_SIZE)
kwargs = self.vixdisklib_connect_kwargs(self._connect_extra(module))
with handle.connect(**kwargs) as conn:
with handle.open(conn, self.DISK_PATH, flags=0) as disk:
for start, data in payloads.items():
buf[:self.SECTOR_SIZE] = data
handle.write(disk, start, 1, buf)
def _read_sectors(
self,
module: Any,
sectors: tuple[int, ...]) -> dict[int, bytes]:
"""Read one sector at each index using a vixdisklib-compatible module."""
handle = module.VixDiskLibHandle(
vixdisklib_compatibility_version="8.0",
config_path=None)
buf = module.get_buffer(self.SECTOR_SIZE)
result: dict[int, bytes] = {}
kwargs = self.vixdisklib_connect_kwargs(self._connect_extra(module))
with handle.connect(**kwargs) as conn:
with handle.open(conn, self.DISK_PATH, flags=0) as disk:
for start in sectors:
buf[:self.SECTOR_SIZE] = b"\xa5" * self.SECTOR_SIZE
handle.read(disk, start, 1, buf)
result[start] = buf.raw[:self.SECTOR_SIZE]
return result
def _assert_both_read(
self,
sectors: tuple[int, ...],
expected: dict[int, bytes]) -> None:
vddk = self._read_sectors(vixdisklib, sectors)
replacement = self._read_sectors(open_vix, sectors)
for start in sectors:
self.assertEqual(
vddk[start], expected[start],
f"VDDK mismatch at sector {start}")
self.assertEqual(
replacement[start], expected[start],
f"openvixdisklib mismatch at sector {start}")
def test_openvixdisklib_matches_vddk_sectors(self) -> None:
"""Writes from either library must be visible to both readers."""
sectors = (0, 1, self.SECTOR_AT_1GB)
vddk_payloads = {
0: self.pattern_bytes(self.SECTOR_SIZE, b"XCHK-VDDK-S0"),
1: self.pattern_bytes(self.SECTOR_SIZE, b"XCHK-VDDK-S1"),
self.SECTOR_AT_1GB: self.pattern_bytes(
self.SECTOR_SIZE, b"XCHK-VDDK-1G"),
}
self._write_sectors(vixdisklib, vddk_payloads)
self._assert_both_read(sectors, vddk_payloads)
ovdl_payloads = {
0: self.pattern_bytes(self.SECTOR_SIZE, b"XCHK-OVDL-S0"),
1: self.pattern_bytes(self.SECTOR_SIZE, b"XCHK-OVDL-S1"),
self.SECTOR_AT_1GB: self.pattern_bytes(
self.SECTOR_SIZE, b"XCHK-OVDL-1G"),
}
self._write_sectors(open_vix, ovdl_payloads)
self._assert_both_read(sectors, ovdl_payloads)
+18
View File
@@ -0,0 +1,18 @@
# Copyright 2026 Cloudbase Solutions Srl
# All Rights Reserved.
"""Exercise VDDK-compatible NFC authentication against the lab vCenter."""
from tests.integration.base import TestBase
class NfcAuthTest(TestBase):
def test_authd_handshake_completes(self) -> None:
"""Complete VIM login and authd PROXY through ``200 Connect``."""
with self.authenticate() as session:
ticket = session.ticket
self.assertTrue(ticket.host)
self.assertTrue(ticket.port)
self.assertTrue(ticket.sessionId)
self.assertTrue(session.authd_sock.version())
self.assertTrue(session.authd_sock.cipher())
+23
View File
@@ -0,0 +1,23 @@
# Copyright 2026 Cloudbase Solutions Srl
# All Rights Reserved.
"""Exercise NFC disk open and a one-sector write/read against the lab."""
from openvixdisklib import nfc_open
from tests.integration.base import TestBase
class NfcOpenTest(TestBase):
def test_open_disk_and_read_first_sector(self) -> None:
"""Open the temp VMDK, write sector 0, and read it back."""
expected = self.pattern_bytes(self.SECTOR_SIZE, b"NFC-OPEN-S0")
with self.authenticate(read_only=False) as session:
with nfc_open.open_disk(
session, self.DISK_PATH, read_only=False) as disk:
self.assertEqual(disk.path, self.DISK_PATH)
self.assertGreater(disk.handle, 0)
self.assertEqual(disk.sector_size, self.SECTOR_SIZE)
disk.write(0, 1, expected)
got = disk.read(0, 1)
self.assertIsNot(got, expected)
self.assertEqual(got, expected)
+54
View File
@@ -0,0 +1,54 @@
# Copyright 2026 Cloudbase Solutions Srl
# All Rights Reserved.
"""Exercise NFC sector writes and reads against the lab vCenter."""
from openvixdisklib import nfc_open
from tests.integration.base import TestBase
class NfcReadWriteTest(TestBase):
def test_sector_writes_and_reads(self) -> None:
"""Write known patterns and read them back at several ranges."""
ranges = [
(0, 1),
(0, 2),
(1, 1),
(8, 8),
(0, 128),
(0, 129),
(256, 64),
]
with self.authenticate(read_only=False) as session:
with nfc_open.open_disk(
session, self.DISK_PATH, read_only=False) as disk:
for start, n_sectors in ranges:
length = n_sectors * self.SECTOR_SIZE
seed = f"NFC-R{start}:{n_sectors}-".encode()
to_write = self.pattern_bytes(length, seed)
disk.write(start, n_sectors, to_write)
got = disk.read(start, n_sectors)
self.assertIsNot(got, to_write)
self.assertEqual(len(got), length)
self.assertEqual(got, to_write)
two_seed = b"NFC-TWO-SECTOR"
two_to_write = self.pattern_bytes(
2 * self.SECTOR_SIZE, two_seed)
disk.write(0, 2, two_to_write)
two_got = disk.read(0, 2)
self.assertIsNot(two_got, two_to_write)
self.assertEqual(two_got, two_to_write)
self.assertEqual(
disk.read(1, 1), two_to_write[self.SECTOR_SIZE:])
big_seed = b"NFC-129-SECTOR-WRITE"
big_to_write = self.pattern_bytes(
129 * self.SECTOR_SIZE, big_seed)
disk.write(0, 129, big_to_write)
big_got = disk.read(0, 129)
self.assertIsNot(big_got, big_to_write)
self.assertEqual(big_got, big_to_write)
self.assertEqual(
big_got[self.SECTOR_SIZE:2 * self.SECTOR_SIZE],
big_to_write[self.SECTOR_SIZE:2 * self.SECTOR_SIZE])
+33
View File
@@ -0,0 +1,33 @@
# Copyright 2026 Cloudbase Solutions Srl
# All Rights Reserved.
"""Exercise the VDDK-compatible openvixdisklib handle against the lab."""
from openvixdisklib import openvixdisklib as vixdisklib
from tests.integration.base import TestBase
class OpenVixDiskLibTest(TestBase):
def test_write_and_read_sector_zero_and_one_gib(self) -> None:
"""Write then read sector 0 and the sector at a 1 GiB offset."""
handle = vixdisklib.VixDiskLibHandle(
vixdisklib_compatibility_version="8.0",
config_path=None)
write_buf = vixdisklib.get_buffer(self.SECTOR_SIZE)
read_buf = vixdisklib.get_buffer(self.SECTOR_SIZE)
connect_kwargs = self.vixdisklib_connect_kwargs({
"allow_untrusted": self.ALLOW_UNTRUSTED,
})
patterns = {
0: self.pattern_bytes(self.SECTOR_SIZE, b"OVDL-S0"),
self.SECTOR_AT_1GB: self.pattern_bytes(
self.SECTOR_SIZE, b"OVDL-1GB"),
}
with handle.connect(**connect_kwargs) as conn:
with handle.open(conn, self.DISK_PATH, flags=0) as disk:
for start, expected in patterns.items():
write_buf[:self.SECTOR_SIZE] = expected
handle.write(disk, start, 1, write_buf)
read_buf[:self.SECTOR_SIZE] = b"\xa5" * self.SECTOR_SIZE
handle.read(disk, start, 1, read_buf)
self.assertEqual(read_buf.raw[:self.SECTOR_SIZE], expected)
+31
View File
@@ -0,0 +1,31 @@
# Copyright 2026 Cloudbase Solutions Srl
# All Rights Reserved.
"""Exercise native VDDK via tests.integration.vixdisklib against the lab."""
from tests.integration import vixdisklib
from tests.integration.base import TestBase
class VddkTest(TestBase):
@classmethod
def setUpClass(cls) -> None:
"""Skip when the bundled VDDK shared library is not present."""
cls.require_vddk()
super().setUpClass()
def test_write_and_read_first_sector(self) -> None:
"""Open the temp VMDK with VDDK, write sector 0, and read it back."""
handle = vixdisklib.VixDiskLibHandle(
vixdisklib_compatibility_version="8.0",
config_path=None)
write_buf = vixdisklib.get_buffer(self.SECTOR_SIZE)
read_buf = vixdisklib.get_buffer(self.SECTOR_SIZE)
expected = self.pattern_bytes(self.SECTOR_SIZE, b"VDDK-S0")
write_buf[:self.SECTOR_SIZE] = expected
with handle.connect(**self.vixdisklib_connect_kwargs()) as conn:
with handle.open(conn, self.DISK_PATH, flags=0) as disk:
handle.write(disk, 0, 1, write_buf)
read_buf[:self.SECTOR_SIZE] = b"\xa5" * self.SECTOR_SIZE
handle.read(disk, 0, 1, read_buf)
self.assertEqual(read_buf.raw[:self.SECTOR_SIZE], expected)
+538
View File
@@ -0,0 +1,538 @@
# Copyright 2019 Cloudbase Solutions Srl
# All Rights Reserved.
# Generated from vixDiskLib 6.7.0-8535999 from:
# $VIX_ROOT/doc/errors/errors.html
VIX_OK = 0
VIX_E_FAIL = 1
VIX_E_OUT_OF_MEMORY = 2
VIX_E_INVALID_ARG = 3
VIX_E_FILE_NOT_FOUND = 4
VIX_E_OBJECT_IS_BUSY = 5
VIX_E_NOT_SUPPORTED = 6
VIX_E_FILE_ERROR = 7
VIX_E_DISK_FULL = 8
VIX_E_INCORRECT_FILE_TYPE = 9
VIX_E_CANCELLED = 10
VIX_E_FILE_READ_ONLY = 11
VIX_E_FILE_ALREADY_EXISTS = 12
VIX_E_FILE_ACCESS_ERROR = 13
VIX_E_REQUIRES_LARGE_FILES = 14
VIX_E_FILE_ALREADY_LOCKED = 15
VIX_E_VMDB = 16
VIX_E_NOT_SUPPORTED_ON_REMOTE_OBJECT = 20
VIX_E_FILE_TOO_BIG = 21
VIX_E_FILE_NAME_INVALID = 22
VIX_E_ALREADY_EXISTS = 23
VIX_E_BUFFER_TOOSMALL = 24
VIX_E_OBJECT_NOT_FOUND = 25
VIX_E_HOST_NOT_CONNECTED = 26
VIX_E_INVALID_UTF = 8
VIX_E_OPERATION_ALREADY_IN_PROGRESS = 31
VIX_E_UNFINISHED_JOB = 29
VIX_E_NEED_KEY = 30
VIX_E_LICENSE = 32
VIX_E_VM_HOST_DISCONNECTED = 34
VIX_E_AUTHENTICATION_FAIL = 35
VIX_E_HOST_CONNECTION_LOST = 36
VIX_E_DUPLICATE_NAME = 41
VIX_E_ARGUMENT_TOO_BIG = 44
VIX_E_INVALID_HANDLE = 1000
VIX_E_NOT_SUPPORTED_ON_HANDLE_TYPE = 1001
VIX_E_TOO_MANY_HANDLES = 1002
VIX_E_NOT_FOUND = 2000
VIX_E_TYPE_MISMATCH = 2001
VIX_E_INVALID_XML = 2002
VIX_E_TIMEOUT_WAITING_FOR_TOOLS = 3000
VIX_E_UNRECOGNIZED_COMMAND = 3001
VIX_E_OP_NOT_SUPPORTED_ON_GUEST = 3003
VIX_E_PROGRAM_NOT_STARTED = 3004
VIX_E_CANNOT_START_READ_ONLY_VM = 3005
VIX_E_VM_NOT_RUNNING = 3006
VIX_E_VM_IS_RUNNING = 3007
VIX_E_CANNOT_CONNECT_TO_VM = 3008
VIX_E_POWEROP_SCRIPTS_NOT_AVAILABLE = 3009
VIX_E_NO_GUEST_OS_INSTALLED = 3010
VIX_E_VM_INSUFFICIENT_HOST_MEMORY = 3011
VIX_E_SUSPEND_ERROR = 3012
VIX_E_VM_NOT_ENOUGH_CPUS = 3013
VIX_E_HOST_USER_PERMISSIONS = 3014
VIX_E_GUEST_USER_PERMISSIONS = 3015
VIX_E_TOOLS_NOT_RUNNING = 3016
VIX_E_GUEST_OPERATIONS_PROHIBITED = 3017
VIX_E_ANON_GUEST_OPERATIONS_PROHIBITED = 3018
VIX_E_ROOT_GUEST_OPERATIONS_PROHIBITED = 3019
VIX_E_MISSING_ANON_GUEST_ACCOUNT = 3023
VIX_E_CANNOT_AUTHENTICATE_WITH_GUEST = 3024
VIX_E_UNRECOGNIZED_COMMAND_IN_GUEST = 3025
VIX_E_CONSOLE_GUEST_OPERATIONS_PROHIBITED = 3026
VIX_E_MUST_BE_CONSOLE_USER = 3027
VIX_E_VMX_MSG_DIALOG_AND_NO_UI = 3028
VIX_E_OPERATION_NOT_ALLOWED_FOR_LOGIN_TYPE = 3031
VIX_E_LOGIN_TYPE_NOT_SUPPORTED = 3032
VIX_E_EMPTY_PASSWORD_NOT_ALLOWED_IN_GUEST = 3033
VIX_E_INTERACTIVE_SESSION_NOT_PRESENT = 3034
VIX_E_INTERACTIVE_SESSION_USER_MISMATCH = 3035
VIX_E_CANNOT_POWER_ON_VM = 3041
VIX_E_NO_DISPLAY_SERVER = 3043
VIX_E_TOO_MANY_LOGONS = 3046
VIX_E_INVALID_AUTHENTICATION_SESSION = 3047
VIX_E_VM_NOT_FOUND = 4000
VIX_E_NOT_SUPPORTED_FOR_VM_VERSION = 4001
VIX_E_CANNOT_READ_VM_CONFIG = 4002
VIX_E_TEMPLATE_VM = 4003
VIX_E_VM_ALREADY_LOADED = 4004
VIX_E_VM_ALREADY_UP_TO_DATE = 4006
VIX_E_VM_UNSUPPORTED_GUEST = 4011
VIX_E_UNRECOGNIZED_PROPERTY = 6000
VIX_E_INVALID_PROPERTY_VALUE = 6001
VIX_E_READ_ONLY_PROPERTY = 6002
VIX_E_MISSING_REQUIRED_PROPERTY = 6003
VIX_E_INVALID_SERIALIZED_DATA = 6004
VIX_E_PROPERTY_TYPE_MISMATCH = 6005
VIX_E_BAD_VM_INDEX = 8000
VIX_E_INVALID_MESSAGE_HEADER = 10000
VIX_E_INVALID_MESSAGE_BODY = 10001
VIX_E_SNAPSHOT_INVAL = 13000
VIX_E_SNAPSHOT_DUMPER = 13001
VIX_E_SNAPSHOT_DISKLIB = 13002
VIX_E_SNAPSHOT_NOTFOUND = 13003
VIX_E_SNAPSHOT_EXISTS = 13004
VIX_E_SNAPSHOT_VERSION = 13005
VIX_E_SNAPSHOT_NOPERM = 13006
VIX_E_SNAPSHOT_CONFIG = 13007
VIX_E_SNAPSHOT_NOCHANGE = 13008
VIX_E_SNAPSHOT_CHECKPOINT = 13009
VIX_E_SNAPSHOT_LOCKED = 13010
VIX_E_SNAPSHOT_INCONSISTENT = 13011
VIX_E_SNAPSHOT_NAMETOOLONG = 13012
VIX_E_SNAPSHOT_VIXFILE = 13013
VIX_E_SNAPSHOT_DISKLOCKED = 13014
VIX_E_SNAPSHOT_DUPLICATEDDISK = 13015
VIX_E_SNAPSHOT_INDEPENDENTDISK = 13016
VIX_E_SNAPSHOT_NONUNIQUE_NAME = 13017
VIX_E_SNAPSHOT_MEMORY_ON_INDEPENDENT_DISK = 13018
VIX_E_SNAPSHOT_MAXSNAPSHOTS = 13019
VIX_E_SNAPSHOT_MIN_FREE_SPACE = 13020
VIX_E_SNAPSHOT_HIERARCHY_TOODEEP = 13021
VIX_E_SNAPSHOT_NOT_REVERTABLE = 13024
VIX_E_HOST_DISK_INVALID_VALUE = 14003
VIX_E_HOST_DISK_SECTORSIZE = 14004
VIX_E_HOST_FILE_ERROR_EOF = 14005
VIX_E_HOST_NETBLKDEV_HANDSHAKE = 14006
VIX_E_HOST_SOCKET_CREATION_ERROR = 14007
VIX_E_HOST_SERVER_NOT_FOUND = 14008
VIX_E_HOST_NETWORK_CONN_REFUSED = 14009
VIX_E_HOST_TCP_SOCKET_ERROR = 14010
VIX_E_HOST_TCP_CONN_LOST = 14011
VIX_E_HOST_NBD_HASHFILE_VOLUME = 14012
VIX_E_HOST_NBD_HASHFILE_INIT = 14013
VIX_E_DISK_INVAL = 16000
VIX_E_DISK_NOINIT = 16001
VIX_E_DISK_NOIO = 16002
VIX_E_DISK_PARTIALCHAIN = 16003
VIX_E_DISK_NEEDSREPAIR = 16006
VIX_E_DISK_OUTOFRANGE = 16007
VIX_E_DISK_CID_MISMATCH = 16008
VIX_E_DISK_CANTSHRINK = 16009
VIX_E_DISK_PARTMISMATCH = 16010
VIX_E_DISK_UNSUPPORTEDDISKVERSION = 16011
VIX_E_DISK_OPENPARENT = 16012
VIX_E_DISK_NOTSUPPORTED = 16013
VIX_E_DISK_NEEDKEY = 16014
VIX_E_DISK_NOKEYOVERRIDE = 16015
VIX_E_DISK_NOTENCRYPTED = 16016
VIX_E_DISK_NOKEY = 16017
VIX_E_DISK_INVALIDPARTITIONTABLE = 16018
VIX_E_DISK_NOTNORMAL = 16019
VIX_E_DISK_NOTENCDESC = 16020
VIX_E_DISK_NEEDVMFS = 16022
VIX_E_DISK_RAWTOOBIG = 16024
VIX_E_DISK_TOOMANYOPENFILES = 16027
VIX_E_DISK_TOOMANYREDO = 16028
VIX_E_DISK_RAWTOOSMALL = 16029
VIX_E_DISK_INVALIDCHAIN = 16030
VIX_E_DISK_KEY_NOTFOUND = 16052
VIX_E_DISK_SUBSYSTEM_INIT_FAIL = 16053
VIX_E_DISK_INVALID_CONNECTION = 16054
VIX_E_DISK_ENCODING = 16061
VIX_E_DISK_CANTREPAIR = 16062
VIX_E_DISK_INVALIDDISK = 16063
VIX_E_DISK_NOLICENSE = 16064
VIX_E_DISK_NODEVICE = 16065
VIX_E_DISK_UNSUPPORTEDDEVICE = 16066
VIX_E_DISK_CAPACITY_MISMATCH = 16067
VIX_E_DISK_PARENT_NOTALLOWED = 16068
VIX_E_DISK_ATTACH_ROOTLINK = 16069
VIX_E_CRYPTO_UNKNOWN_ALGORITHM = 17000
VIX_E_CRYPTO_BAD_BUFFER_SIZE = 17001
VIX_E_CRYPTO_INVALID_OPERATION = 17002
VIX_E_CRYPTO_RANDOM_DEVICE = 17003
VIX_E_CRYPTO_NEED_PASSWORD = 17004
VIX_E_CRYPTO_BAD_PASSWORD = 17005
VIX_E_CRYPTO_NOT_IN_DICTIONARY = 17006
VIX_E_CRYPTO_NO_CRYPTO = 17007
VIX_E_CRYPTO_ERROR = 17008
VIX_E_CRYPTO_BAD_FORMAT = 17009
VIX_E_CRYPTO_LOCKED = 17010
VIX_E_CRYPTO_EMPTY = 17011
VIX_E_CRYPTO_KEYSAFE_LOCATOR = 17012
VIX_E_CANNOT_CONNECT_TO_HOST = 18000
VIX_E_NOT_FOR_REMOTE_HOST = 18001
VIX_E_INVALID_HOSTNAME_SPECIFICATION = 18002
VIX_E_SCREEN_CAPTURE_ERROR = 19000
VIX_E_SCREEN_CAPTURE_BAD_FORMAT = 19001
VIX_E_SCREEN_CAPTURE_COMPRESSION_FAIL = 19002
VIX_E_SCREEN_CAPTURE_LARGE_DATA = 19003
VIX_E_GUEST_VOLUMES_NOT_FROZEN = 20000
VIX_E_NOT_A_FILE = 20001
VIX_E_NOT_A_DIRECTORY = 20002
VIX_E_NO_SUCH_PROCESS = 20003
VIX_E_FILE_NAME_TOO_LONG = 20004
VIX_E_OPERATION_DISABLED = 20005
VIX_E_TOOLS_INSTALL_NO_IMAGE = 21000
VIX_E_TOOLS_INSTALL_IMAGE_INACCESIBLE = 21001
VIX_E_TOOLS_INSTALL_NO_DEVICE = 21002
VIX_E_TOOLS_INSTALL_DEVICE_NOT_CONNECTED = 21003
VIX_E_TOOLS_INSTALL_CANCELLED = 21004
VIX_E_TOOLS_INSTALL_INIT_FAILED = 21005
VIX_E_TOOLS_INSTALL_AUTO_NOT_SUPPORTED = 21006
VIX_E_TOOLS_INSTALL_GUEST_NOT_READY = 21007
VIX_E_TOOLS_INSTALL_SIG_CHECK_FAILED = 21008
VIX_E_TOOLS_INSTALL_ERROR = 21009
VIX_E_TOOLS_INSTALL_ALREADY_UP_TO_DATE = 21010
VIX_E_TOOLS_INSTALL_IN_PROGRESS = 21011
VIX_E_TOOLS_INSTALL_IMAGE_COPY_FAILED = 21012
VIX_E_WRAPPER_WORKSTATION_NOT_INSTALLED = 22001
VIX_E_WRAPPER_VERSION_NOT_FOUND = 22002
VIX_E_WRAPPER_SERVICEPROVIDER_NOT_FOUND = 22003
VIX_E_WRAPPER_PLAYER_NOT_INSTALLED = 22004
VIX_E_WRAPPER_RUNTIME_NOT_INSTALLED = 22005
VIX_E_WRAPPER_MULTIPLE_SERVICEPROVIDERS = 22006
VIX_E_MNTAPI_MOUNTPT_NOT_FOUND = 24000
VIX_E_MNTAPI_MOUNTPT_IN_USE = 24001
VIX_E_MNTAPI_DISK_NOT_FOUND = 24002
VIX_E_MNTAPI_DISK_NOT_MOUNTED = 24003
VIX_E_MNTAPI_DISK_IS_MOUNTED = 24004
VIX_E_MNTAPI_DISK_NOT_SAFE = 24005
VIX_E_MNTAPI_DISK_CANT_OPEN = 24006
VIX_E_MNTAPI_CANT_READ_PARTS = 24007
VIX_E_MNTAPI_UMOUNT_APP_NOT_FOUND = 24008
VIX_E_MNTAPI_UMOUNT = 24009
VIX_E_MNTAPI_NO_MOUNTABLE_PARTITONS = 24010
VIX_E_MNTAPI_PARTITION_RANGE = 24011
VIX_E_MNTAPI_PERM = 24012
VIX_E_MNTAPI_DICT = 24013
VIX_E_MNTAPI_DICT_LOCKED = 24014
VIX_E_MNTAPI_OPEN_HANDLES = 24015
VIX_E_MNTAPI_CANT_MAKE_VAR_DIR = 24016
VIX_E_MNTAPI_NO_ROOT = 24017
VIX_E_MNTAPI_LOOP_FAILED = 24018
VIX_E_MNTAPI_DAEMON = 24019
VIX_E_MNTAPI_INTERNAL = 24020
VIX_E_MNTAPI_SYSTEM = 24021
VIX_E_MNTAPI_NO_CONNECTION_DETAILS = 24022
VIX_E_MNTAPI_INCOMPATIBLE_VERSION = 24300
VIX_E_MNTAPI_OS_ERROR = 24301
VIX_E_MNTAPI_DRIVE_LETTER_IN_USE = 24302
VIX_E_MNTAPI_DRIVE_LETTER_ALREADY_ASSIGNED = 24303
VIX_E_MNTAPI_VOLUME_NOT_MOUNTED = 24304
VIX_E_MNTAPI_VOLUME_ALREADY_MOUNTED = 24305
VIX_E_MNTAPI_FORMAT_FAILURE = 24306
VIX_E_MNTAPI_NO_DRIVER = 24307
VIX_E_MNTAPI_ALREADY_OPENED = 24308
VIX_E_MNTAPI_ITEM_NOT_FOUND = 24309
VIX_E_MNTAPI_UNSUPPROTED_BOOT_LOADER = 24310
VIX_E_MNTAPI_UNSUPPROTED_OS = 24311
VIX_E_MNTAPI_CODECONVERSION = 24312
VIX_E_MNTAPI_REGWRITE_ERROR = 24313
VIX_E_MNTAPI_UNSUPPORTED_FT_VOLUME = 24314
VIX_E_MNTAPI_PARTITION_NOT_FOUND = 24315
VIX_E_MNTAPI_PUTFILE_ERROR = 24316
VIX_E_MNTAPI_GETFILE_ERROR = 24317
VIX_E_MNTAPI_REG_NOT_OPENED = 24318
VIX_E_MNTAPI_REGDELKEY_ERROR = 24319
VIX_E_MNTAPI_CREATE_PARTITIONTABLE_ERROR = 24320
VIX_E_MNTAPI_OPEN_FAILURE = 24321
VIX_E_MNTAPI_VOLUME_NOT_WRITABLE = 24322
VIX_E_ASYNC_MIXEDMODE_UNSUPPORTED = 26000
VIX_E_NET_HTTP_UNSUPPORTED_PROTOCOL = 30001
VIX_E_NET_HTTP_URL_MALFORMAT = 30003
VIX_E_NET_HTTP_COULDNT_RESOLVE_PROXY = 30005
VIX_E_NET_HTTP_COULDNT_RESOLVE_HOST = 30006
VIX_E_NET_HTTP_COULDNT_CONNECT = 30007
VIX_E_NET_HTTP_HTTP_RETURNED_ERROR = 30022
VIX_E_NET_HTTP_OPERATION_TIMEDOUT = 30028
VIX_E_NET_HTTP_SSL_CONNECT_ERROR = 30035
VIX_E_NET_HTTP_TOO_MANY_REDIRECTS = 30047
VIX_E_NET_HTTP_TRANSFER = 30200
VIX_E_NET_HTTP_SSL_SECURITY = 30201
VIX_E_NET_HTTP_GENERIC = 30202
VIX_ERROR_CODE_MAP = {
VIX_OK: "The operation was successful.",
VIX_E_FAIL: "Unknown error.",
VIX_E_OUT_OF_MEMORY: "Memory allocation failed. Out of memory.",
VIX_E_INVALID_ARG: "One of the parameters was invalid.",
VIX_E_FILE_NOT_FOUND: "A file was not found.",
VIX_E_OBJECT_IS_BUSY: "This function cannot be performed because the handle is executing another function.",
VIX_E_NOT_SUPPORTED: "The operation is not supported.",
VIX_E_FILE_ERROR: "A file access error occurred on the host or guest operating system.",
VIX_E_DISK_FULL: "An error occurred while writing a file; the disk is full. Data has not been saved. Free some disk space and try again.",
VIX_E_INCORRECT_FILE_TYPE: "An error occurred while accessing a file: wrong file type.",
VIX_E_CANCELLED: "The operation was canceled.",
VIX_E_FILE_READ_ONLY: "The file is write-protected.",
VIX_E_FILE_ALREADY_EXISTS: "The file already exists.",
VIX_E_FILE_ACCESS_ERROR: "You do not have access rights to this file.",
VIX_E_REQUIRES_LARGE_FILES: "The file system does not support large files.",
VIX_E_FILE_ALREADY_LOCKED: "The file is already in use.",
VIX_E_VMDB: "The system returned an error. Communication with the virtual machine might have been interrupted.",
VIX_E_NOT_SUPPORTED_ON_REMOTE_OBJECT: "The command is not supported on remote objects.",
VIX_E_FILE_TOO_BIG: "The file is too large for the file system.",
VIX_E_FILE_NAME_INVALID: "The file name is not valid.",
VIX_E_ALREADY_EXISTS: "Already exists.",
VIX_E_BUFFER_TOOSMALL: "Buffer is too small.",
VIX_E_OBJECT_NOT_FOUND: "The request refers to an object that does not exist.",
VIX_E_HOST_NOT_CONNECTED: "Unable to connect to the host.",
VIX_E_INVALID_UTF: "The string parameter has incorrect encoding.",
VIX_E_OPERATION_ALREADY_IN_PROGRESS: "The operation is already in progress.",
VIX_E_UNFINISHED_JOB: "The job has not finished.",
VIX_E_NEED_KEY: "A decryption key is required to perform the operation.",
VIX_E_LICENSE: "This operation is not supported with the current license.",
VIX_E_VM_HOST_DISCONNECTED: "Unable to communicate with the virtual machine's host because it is disconnected.",
VIX_E_AUTHENTICATION_FAIL: "Authentication for encrypted virtual machine failed.",
VIX_E_HOST_CONNECTION_LOST: "The connection to the host was lost.",
VIX_E_DUPLICATE_NAME: "Another object is using this name.",
VIX_E_ARGUMENT_TOO_BIG: "One of the specified arguments is too large.",
VIX_E_INVALID_HANDLE: "The handle is not a valid VIX object.",
VIX_E_NOT_SUPPORTED_ON_HANDLE_TYPE: "The operation is not supported on this type of handle.",
VIX_E_TOO_MANY_HANDLES: "Too many handles are open.",
VIX_E_NOT_FOUND: "Invalid file. A required section of the file is missing.",
VIX_E_TYPE_MISMATCH: "Invalid file. An object has the wrong type.",
VIX_E_INVALID_XML: "Invalid file. The contents might be corrupt.",
VIX_E_TIMEOUT_WAITING_FOR_TOOLS: "A timeout error occurred while waiting for .",
VIX_E_UNRECOGNIZED_COMMAND: "The command is not recognized by the virtual machine.",
VIX_E_OP_NOT_SUPPORTED_ON_GUEST: "The requested operation is not supported on this guest operating system.",
VIX_E_PROGRAM_NOT_STARTED: "A program could not run on the guest operating system.",
VIX_E_CANNOT_START_READ_ONLY_VM: "Cannot power on a read-only virtual machine.",
VIX_E_VM_NOT_RUNNING: "The virtual machine needs to be powered on.",
VIX_E_VM_IS_RUNNING: "The virtual machine should not be powered on. It is already running.",
VIX_E_CANNOT_CONNECT_TO_VM: "Cannot connect to the virtual machine.",
VIX_E_POWEROP_SCRIPTS_NOT_AVAILABLE: "Cannot execute scripts.",
VIX_E_NO_GUEST_OS_INSTALLED: "There is no operating system installed in the virtual machine.",
VIX_E_VM_INSUFFICIENT_HOST_MEMORY: "Not enough physical memory is available to power on this virtual machine.",
VIX_E_SUSPEND_ERROR: "An error occurred while suspending the virtual machine.",
VIX_E_VM_NOT_ENOUGH_CPUS: "This virtual machine is configured to run with 2 CPUs, but the host has only 1 CPU. The virtual machine cannot be powered on.",
VIX_E_HOST_USER_PERMISSIONS: "Insufficient permissions in the host operating system.",
VIX_E_GUEST_USER_PERMISSIONS: "Authentication failure or insufficient permissions in guest operating system.",
VIX_E_TOOLS_NOT_RUNNING: " are not running in the guest.",
VIX_E_GUEST_OPERATIONS_PROHIBITED: "Guest operations are not allowed on this virtual machine.",
VIX_E_ANON_GUEST_OPERATIONS_PROHIBITED: "Anonymous guest operations are not allowed on this virtual machine. You must call VixVM_LoginInGuest before performing guest operations.",
VIX_E_ROOT_GUEST_OPERATIONS_PROHIBITED: "Guest operations are not allowed for the administrative user on this virtual machine.",
VIX_E_MISSING_ANON_GUEST_ACCOUNT: "The virtual machine configuration must specify the guest account name to be used for anonymous guest operations.",
VIX_E_CANNOT_AUTHENTICATE_WITH_GUEST: "The virtual machine cannot authenticate users with guest.",
VIX_E_UNRECOGNIZED_COMMAND_IN_GUEST: "The command is not recognized by .",
VIX_E_CONSOLE_GUEST_OPERATIONS_PROHIBITED: "Guest operations are not allowed for console users on this virtual machine.",
VIX_E_MUST_BE_CONSOLE_USER: "Only the console user can run the command.",
VIX_E_VMX_MSG_DIALOG_AND_NO_UI: "The virtual machine is blocked waiting for a user operation.",
VIX_E_OPERATION_NOT_ALLOWED_FOR_LOGIN_TYPE: "The command is not allowed by this login type.",
VIX_E_LOGIN_TYPE_NOT_SUPPORTED: "This login type is not supported.",
VIX_E_EMPTY_PASSWORD_NOT_ALLOWED_IN_GUEST: "The guest OS does not support empty passwords.",
VIX_E_INTERACTIVE_SESSION_NOT_PRESENT: "The specified guest user must be logged in interactively to perform this operation.",
VIX_E_INTERACTIVE_SESSION_USER_MISMATCH: "The specified guest user does not match the user currently logged in interactively.",
VIX_E_CANNOT_POWER_ON_VM: "The virtual machine could not start.",
VIX_E_NO_DISPLAY_SERVER: "Cannot launch the UI because no display server is present in the current environment.",
VIX_E_TOO_MANY_LOGONS: "The supported number of active authentication sessions has been exceeded.",
VIX_E_INVALID_AUTHENTICATION_SESSION: "The authenticaton session provided does not exist.",
VIX_E_VM_NOT_FOUND: "The virtual machine cannot be found.",
VIX_E_NOT_SUPPORTED_FOR_VM_VERSION: "The operation is not supported for this virtual machine version.",
VIX_E_CANNOT_READ_VM_CONFIG: "Cannot read the virtual machine configuration file.",
VIX_E_TEMPLATE_VM: "Cannot perform this operation on a template virtual machine.",
VIX_E_VM_ALREADY_LOADED: "The virtual machine has already been loaded.",
VIX_E_VM_ALREADY_UP_TO_DATE: "The virtual machine is already up-to-date.",
VIX_E_VM_UNSUPPORTED_GUEST: "The specified guest operating system is not supported on the host that is the target of the operation.",
VIX_E_UNRECOGNIZED_PROPERTY: "Unrecognized handle property identifier.",
VIX_E_INVALID_PROPERTY_VALUE: "Invalid property value.",
VIX_E_READ_ONLY_PROPERTY: "Cannot change a read-only property.",
VIX_E_MISSING_REQUIRED_PROPERTY: "This handle is missing a required property.",
VIX_E_INVALID_SERIALIZED_DATA: "A serialized object is invalid and cannot be deserialized.",
VIX_E_PROPERTY_TYPE_MISMATCH: "The data provided does not match the property type.",
VIX_E_BAD_VM_INDEX: "The index parameter does not correspond to a result set.",
VIX_E_INVALID_MESSAGE_HEADER: "A message header was corrupted or has the incorrect version.",
VIX_E_INVALID_MESSAGE_BODY: "A message body was corrupted or is missing.",
VIX_E_SNAPSHOT_INVAL: "A snapshot-related error has occurred.",
VIX_E_SNAPSHOT_DUMPER: "Unable to open the snapshot file.",
VIX_E_SNAPSHOT_DISKLIB: "Disk error.",
VIX_E_SNAPSHOT_NOTFOUND: "The snapshot does not exist.",
VIX_E_SNAPSHOT_EXISTS: "The snapshot already exists.",
VIX_E_SNAPSHOT_VERSION: "Snapshots are not allowed on this virtual machine.",
VIX_E_SNAPSHOT_NOPERM: "Insufficient permissions.",
VIX_E_SNAPSHOT_CONFIG: "There is an error in the configuration file.",
VIX_E_SNAPSHOT_NOCHANGE: "The state of the virtual machine has not changed since the last snapshot operation.",
VIX_E_SNAPSHOT_CHECKPOINT: "Unable to save the snapshot file.",
VIX_E_SNAPSHOT_LOCKED: "A snapshot operation is already in progress.",
VIX_E_SNAPSHOT_INCONSISTENT: "The snapshot files are in an inconsistent state.",
VIX_E_SNAPSHOT_NAMETOOLONG: "The filename is too long.",
VIX_E_SNAPSHOT_VIXFILE: "Cannot snapshot all metadata files.",
VIX_E_SNAPSHOT_DISKLOCKED: "One or more of the disks are busy.",
VIX_E_SNAPSHOT_DUPLICATEDDISK: "The virtual disk is used multiple times.",
VIX_E_SNAPSHOT_INDEPENDENTDISK: "Cannot take snapshots of powered on virtual machines with independent disks.",
VIX_E_SNAPSHOT_NONUNIQUE_NAME: "The name does not uniquely identify one snapshot.",
VIX_E_SNAPSHOT_MEMORY_ON_INDEPENDENT_DISK: "Failed to take a memory snapshot because the virtual machine is configured with independent disks.",
VIX_E_SNAPSHOT_MAXSNAPSHOTS: "Exceeded the maximum number of permitted snapshots.",
VIX_E_SNAPSHOT_MIN_FREE_SPACE: "Available free space is less than the configured minimum free space.",
VIX_E_SNAPSHOT_HIERARCHY_TOODEEP: "Snapshot hierarchy is too deep.",
VIX_E_SNAPSHOT_NOT_REVERTABLE: "Cannot revert. The snapshot is .",
VIX_E_HOST_DISK_INVALID_VALUE: "The specified device is not a valid physical disk device.",
VIX_E_HOST_DISK_SECTORSIZE: "The disk sector size check failed.",
VIX_E_HOST_FILE_ERROR_EOF: "Read beyond the end of file.",
VIX_E_HOST_NETBLKDEV_HANDSHAKE: "Error in protocol.",
VIX_E_HOST_SOCKET_CREATION_ERROR: "Unable to create a socket.",
VIX_E_HOST_SERVER_NOT_FOUND: "The specified server could not be contacted.",
VIX_E_HOST_NETWORK_CONN_REFUSED: "The server refused connection.",
VIX_E_HOST_TCP_SOCKET_ERROR: "There was an error in communication.",
VIX_E_HOST_TCP_CONN_LOST: "The connection was lost.",
VIX_E_HOST_NBD_HASHFILE_VOLUME: "NBD_ERR_HASHFILE_VOLUME.",
VIX_E_HOST_NBD_HASHFILE_INIT: "NBD_ERR_HASHFILE_INIT.",
VIX_E_DISK_INVAL: "One of the parameters supplied is invalid.",
VIX_E_DISK_NOINIT: "The disk library has not been initialized.",
VIX_E_DISK_NOIO: "The called function requires the virtual disk to be opened for I/O.",
VIX_E_DISK_PARTIALCHAIN: "The called function cannot be performed on partial chains. Open the parent virtual disk.",
VIX_E_DISK_NEEDSREPAIR: "The specified virtual disk needs repair.",
VIX_E_DISK_OUTOFRANGE: "You have requested access to an area of the virtual disk that is out of bounds.",
VIX_E_DISK_CID_MISMATCH: "The parent virtual disk has been modified since the child was created. Parent virutal disk's content ID does not match with the parent content ID in the child.",
VIX_E_DISK_CANTSHRINK: "The specified virtual disk cannot be shrunk because it is not the parent disk.",
VIX_E_DISK_PARTMISMATCH: "The partition table on the physical disk has changed since the disk was created. Remove the physical disk from the virtual machine, then add it again.",
VIX_E_DISK_UNSUPPORTEDDISKVERSION: "The version of the virtual disk is newer than the version supported by this program.",
VIX_E_DISK_OPENPARENT: "The parent of this virtual disk could not be opened.",
VIX_E_DISK_NOTSUPPORTED: "The specified feature is not supported by this version.",
VIX_E_DISK_NEEDKEY: "One or more required keys were not provided.",
VIX_E_DISK_NOKEYOVERRIDE: "Will not create an unencrypted child of an encrypted disk without explicit request.",
VIX_E_DISK_NOTENCRYPTED: "Not an encrypted disk.",
VIX_E_DISK_NOKEY: "No keys were supplied for encrypting the disk.",
VIX_E_DISK_INVALIDPARTITIONTABLE: "The partition table is invalid.",
VIX_E_DISK_NOTNORMAL: "Only sparse extents with embedded descriptors can be encrypted.",
VIX_E_DISK_NOTENCDESC: "Not an encrypted descriptor file.",
VIX_E_DISK_NEEDVMFS: "The file system is not VMFS.",
VIX_E_DISK_RAWTOOBIG: "The physical disk is too big.",
VIX_E_DISK_TOOMANYOPENFILES: "The host's limit for open files has been exceeded.",
VIX_E_DISK_TOOMANYREDO: "Too many levels of redo logs.",
VIX_E_DISK_RAWTOOSMALL: "The physical disk is too small.",
VIX_E_DISK_INVALIDCHAIN: "Invalid disk chain: cannot mix hosted and managed style disks in the same chain.",
VIX_E_DISK_KEY_NOTFOUND: "The specified key is not found in the disk database.",
VIX_E_DISK_SUBSYSTEM_INIT_FAIL: "One or more required subsystems failed to initialize.",
VIX_E_DISK_INVALID_CONNECTION: "Invalid connection handle.",
VIX_E_DISK_ENCODING: "Disk encoding error.",
VIX_E_DISK_CANTREPAIR: "The disk is corrupted and unrepairable.",
VIX_E_DISK_INVALIDDISK: "The specified file is not a virtual disk.",
VIX_E_DISK_NOLICENSE: "The host is not licensed for this feature.",
VIX_E_DISK_NODEVICE: "The device does not exist.",
VIX_E_DISK_UNSUPPORTEDDEVICE: "The operation is not supported on this type of device.",
VIX_E_DISK_CAPACITY_MISMATCH: "The parent virtual disk's capacity is not the same as child's capacity.",
VIX_E_DISK_PARENT_NOTALLOWED: "Disk type cannot be allowed as parent.",
VIX_E_DISK_ATTACH_ROOTLINK: "Both parent and child virtual disks are root links.",
VIX_E_CRYPTO_UNKNOWN_ALGORITHM: "Security library error.",
VIX_E_CRYPTO_BAD_BUFFER_SIZE: "Security library error.",
VIX_E_CRYPTO_INVALID_OPERATION: "Security library error.",
VIX_E_CRYPTO_RANDOM_DEVICE: "Security library error.",
VIX_E_CRYPTO_NEED_PASSWORD: "A password is required for this operation.",
VIX_E_CRYPTO_BAD_PASSWORD: "Incorrect password.",
VIX_E_CRYPTO_NOT_IN_DICTIONARY: "Security library error.",
VIX_E_CRYPTO_NO_CRYPTO: "Security library error.",
VIX_E_CRYPTO_ERROR: "Security library error.",
VIX_E_CRYPTO_BAD_FORMAT: "Security library error.",
VIX_E_CRYPTO_LOCKED: "Security library error.",
VIX_E_CRYPTO_EMPTY: "Security library error.",
VIX_E_CRYPTO_KEYSAFE_LOCATOR: "Security library error.",
VIX_E_CANNOT_CONNECT_TO_HOST: "Cannot connect to the host.",
VIX_E_NOT_FOR_REMOTE_HOST: "Only a local host can support this feature.",
VIX_E_INVALID_HOSTNAME_SPECIFICATION: "Malformed hostname parameter. For the given service provider, the hostname must be a URL in the form https://<hostname>:<port>/sdk.",
VIX_E_SCREEN_CAPTURE_ERROR: "Could not capture screen.",
VIX_E_SCREEN_CAPTURE_BAD_FORMAT: "Requested unsupported format.",
VIX_E_SCREEN_CAPTURE_COMPRESSION_FAIL: "Could not compress the screen capture.",
VIX_E_SCREEN_CAPTURE_LARGE_DATA: "The screen capture data is larger than the maximum size.",
VIX_E_GUEST_VOLUMES_NOT_FROZEN: "The drives are not frozen.",
VIX_E_NOT_A_FILE: "The object is not a file.",
VIX_E_NOT_A_DIRECTORY: "The object is not a directory.",
VIX_E_NO_SUCH_PROCESS: "No such process.",
VIX_E_FILE_NAME_TOO_LONG: "File name too long.",
VIX_E_OPERATION_DISABLED: "The operation has been disabled by the guest operating system.",
VIX_E_TOOLS_INSTALL_NO_IMAGE: "No .",
VIX_E_TOOLS_INSTALL_IMAGE_INACCESIBLE: "The .",
VIX_E_TOOLS_INSTALL_NO_DEVICE: "The guest operating system does not have a device configured for the .",
VIX_E_TOOLS_INSTALL_DEVICE_NOT_CONNECTED: "The guest operating system device used for installation of .",
VIX_E_TOOLS_INSTALL_CANCELLED: "The .",
VIX_E_TOOLS_INSTALL_INIT_FAILED: "The .",
VIX_E_TOOLS_INSTALL_AUTO_NOT_SUPPORTED: "The .",
VIX_E_TOOLS_INSTALL_GUEST_NOT_READY: " are not running in the guest OS. Automatic upgrade is not possible.",
VIX_E_TOOLS_INSTALL_SIG_CHECK_FAILED: "The .",
VIX_E_TOOLS_INSTALL_ERROR: "The .",
VIX_E_TOOLS_INSTALL_ALREADY_UP_TO_DATE: " are already up to date.",
VIX_E_TOOLS_INSTALL_IN_PROGRESS: "A .",
VIX_E_TOOLS_INSTALL_IMAGE_COPY_FAILED: "Could not copy .",
VIX_E_WRAPPER_WORKSTATION_NOT_INSTALLED: "Service type VIX_SERVICEPROVIDER_VMWARE_WORKSTATION was specified but not installed.",
VIX_E_WRAPPER_VERSION_NOT_FOUND: "The specified version was not found.",
VIX_E_WRAPPER_SERVICEPROVIDER_NOT_FOUND: "The specified service provider was not found.",
VIX_E_WRAPPER_PLAYER_NOT_INSTALLED: "Service type VIX_SERVICEPROVIDER_VMWARE_PLAYER was specified but not installed.",
VIX_E_WRAPPER_RUNTIME_NOT_INSTALLED: "Cannot find support libraries; VIX appears to have not been installed.",
VIX_E_WRAPPER_MULTIPLE_SERVICEPROVIDERS: "Cannot connect with multiple service providers.",
VIX_E_MNTAPI_MOUNTPT_NOT_FOUND: "Could not find the specified mountpoint.",
VIX_E_MNTAPI_MOUNTPT_IN_USE: "The mountpoint is already in use.",
VIX_E_MNTAPI_DISK_NOT_FOUND: "Could not find the specified virtual disk.",
VIX_E_MNTAPI_DISK_NOT_MOUNTED: "The specified disk is not mounted.",
VIX_E_MNTAPI_DISK_IS_MOUNTED: "The specified disk is already mounted.",
VIX_E_MNTAPI_DISK_NOT_SAFE: "It is not safe to mount the virtual disk. It might be attached to a suspended or powered-on virtual machine, or it may be inside a snapshot chain.",
VIX_E_MNTAPI_DISK_CANT_OPEN: "Cannot open the virtual disk.",
VIX_E_MNTAPI_CANT_READ_PARTS: "Cannot read or parse the partition table on the virtual disk.",
VIX_E_MNTAPI_UMOUNT_APP_NOT_FOUND: "Could not find the umount application in a standard system directory such as /bin, /usr/bin, or /sbin.",
VIX_E_MNTAPI_UMOUNT: "The umount command failed.",
VIX_E_MNTAPI_NO_MOUNTABLE_PARTITONS: "The virtual disk does not have any partitions that the host system knows how to mount.",
VIX_E_MNTAPI_PARTITION_RANGE: "An invalid partition number was specified.",
VIX_E_MNTAPI_PERM: "Insufficient permissions to perform this operation.",
VIX_E_MNTAPI_DICT: "Error accessing metadata. You might not have sufficient permission to access this disk or the metadata may be corrupted.",
VIX_E_MNTAPI_DICT_LOCKED: "The metadata for this disk is locked. Check for other running virtual disk mounter applications.",
VIX_E_MNTAPI_OPEN_HANDLES: "Another process is performing an operation on this mounted virtual disk.",
VIX_E_MNTAPI_CANT_MAKE_VAR_DIR: "Cannot create directory '/var/run/vmware/fuse'.",
VIX_E_MNTAPI_NO_ROOT: "This application must be run setuid root.",
VIX_E_MNTAPI_LOOP_FAILED: "A loop device operation failed.",
VIX_E_MNTAPI_DAEMON: "The VMware fuse daemon failed to start.",
VIX_E_MNTAPI_INTERNAL: "An internal error has occurred. Contact VMware support.",
VIX_E_MNTAPI_SYSTEM: "A system call has failed.",
VIX_E_MNTAPI_NO_CONNECTION_DETAILS: "Unable to get vixDiskLib connection details.",
VIX_E_MNTAPI_INCOMPATIBLE_VERSION: "The product version number is lower than the expected version number.",
VIX_E_MNTAPI_OS_ERROR: "There was an operating system error.",
VIX_E_MNTAPI_DRIVE_LETTER_IN_USE: "The specified drive letter is already in use.",
VIX_E_MNTAPI_DRIVE_LETTER_ALREADY_ASSIGNED: "The specified drive letter is already assigned.",
VIX_E_MNTAPI_VOLUME_NOT_MOUNTED: "The specified volume is not mounted.",
VIX_E_MNTAPI_VOLUME_ALREADY_MOUNTED: "The specified volume is already mounted.",
VIX_E_MNTAPI_FORMAT_FAILURE: "Unable to format volume.",
VIX_E_MNTAPI_NO_DRIVER: "Driver not found.",
VIX_E_MNTAPI_ALREADY_OPENED: "A handle to the Volume or DiskSet is already open.",
VIX_E_MNTAPI_ITEM_NOT_FOUND: "Invalid file. A required section of the file is missing.",
VIX_E_MNTAPI_UNSUPPROTED_BOOT_LOADER: "Boot loader not supported.",
VIX_E_MNTAPI_UNSUPPROTED_OS: "The current operating system is not supported.",
VIX_E_MNTAPI_CODECONVERSION: "An error occurred while converting the string.",
VIX_E_MNTAPI_REGWRITE_ERROR: "There was an error writing to the registry.",
VIX_E_MNTAPI_UNSUPPORTED_FT_VOLUME: "Windows NT4 Fault Tolerant volume type is not supported.",
VIX_E_MNTAPI_PARTITION_NOT_FOUND: "The specified partition was not found.",
VIX_E_MNTAPI_PUTFILE_ERROR: "Putfile error.",
VIX_E_MNTAPI_GETFILE_ERROR: "Getfile error.",
VIX_E_MNTAPI_REG_NOT_OPENED: "Unable to open registry key.",
VIX_E_MNTAPI_REGDELKEY_ERROR: "There was an error deleting the registry key.",
VIX_E_MNTAPI_CREATE_PARTITIONTABLE_ERROR: "An error occurred while creating the partition table.",
VIX_E_MNTAPI_OPEN_FAILURE: "Failed to open DiskSet.",
VIX_E_MNTAPI_VOLUME_NOT_WRITABLE: "The volume is write-protected.",
VIX_E_ASYNC_MIXEDMODE_UNSUPPORTED: "Synchronous and asynchronous I/O on the same disk handle is not allowed.",
VIX_E_NET_HTTP_UNSUPPORTED_PROTOCOL: "The URL provided uses an unsupported protocol.",
VIX_E_NET_HTTP_URL_MALFORMAT: "The URL was not properly formatted.",
VIX_E_NET_HTTP_COULDNT_RESOLVE_PROXY: "Failed to resolve proxy.",
VIX_E_NET_HTTP_COULDNT_RESOLVE_HOST: "Failed to resolve host.",
VIX_E_NET_HTTP_COULDNT_CONNECT: "Failed to connect to host or proxy.",
VIX_E_NET_HTTP_HTTP_RETURNED_ERROR: "Server returned HTTP error code >= 400.",
VIX_E_NET_HTTP_OPERATION_TIMEDOUT: "Network operation timed out.",
VIX_E_NET_HTTP_SSL_CONNECT_ERROR: "A problem occurred during the SSL/TLS handshake.",
VIX_E_NET_HTTP_TOO_MANY_REDIRECTS: "Reached the maximum number of redirects.",
VIX_E_NET_HTTP_TRANSFER: "Failure sending/receiving network data.",
VIX_E_NET_HTTP_SSL_SECURITY: "An SSL error occurred.",
VIX_E_NET_HTTP_GENERIC: "A generic HTTP error occurred."
}
+324
View File
@@ -0,0 +1,324 @@
# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.
"""Python bindings for the VDDK vixdisklib library. Superseded by the
openvixdisklib, which avoids the proprietary VDDK SDK.
This module is used by the integration tests in order to cross-check the
openvixdisklib library. ctypes layouts follow `.vddk/vixDiskLib.h`.
"""
import contextlib
import ctypes
import logging
import os
import traceback
from tests.integration import vix_disklib_errors
LOG = logging.getLogger(__name__)
VIXDISKLIB_VERSION_MAJOR = 8
VIXDISKLIB_VERSION_MINOR = 0
VIXDISKLIB_SECTOR_SIZE = 512
VIXDISKLIB_CRED_UID = 1
VIXDISKLIB_FLAG_OPEN_UNBUFFERED = 1
VIXDISKLIB_FLAG_OPEN_SINGLE_LINK = 2
VIXDISKLIB_FLAG_OPEN_READ_ONLY = 4
# NBD compression flags
VIXDISKLIB_FLAG_OPEN_COMPRESSION_ZLIB = 16
VIXDISKLIB_FLAG_OPEN_COMPRESSION_FASTLZ = 32
VIXDISKLIB_FLAG_OPEN_COMPRESSION_SKIPZ = 64
VIX_SUPPORTED_COMPATIBILITY_MODES = [
"6.0", "6.5", "6.7", "7.0", "8.0"]
class VixDiskLibUidPasswdCreds(ctypes.Structure):
_fields_ = [
("userName", ctypes.c_char_p),
("password", ctypes.c_char_p),
]
class VixDiskLibSessionIdCreds(ctypes.Structure):
_fields_ = [
("cookie", ctypes.c_char_p),
("userName", ctypes.c_char_p),
("key", ctypes.c_char_p),
]
class VixDiskLibCreds(ctypes.Union):
_fields_ = [
("uid", VixDiskLibUidPasswdCreds),
("sessionId", VixDiskLibSessionIdCreds),
]
class VixDiskLibConnectParams(ctypes.Structure):
_fields_ = [
("vmxSpec", ctypes.c_char_p),
("serverName", ctypes.c_char_p),
("thumbPrint", ctypes.c_char_p),
# Note: this is 32bit on Windows
("privateUse", ctypes.c_longlong),
("credType", ctypes.c_uint32),
("creds", VixDiskLibCreds),
("port", ctypes.c_uint32),
("nfcHostPort", ctypes.c_uint32),
("vimApiVer", ctypes.c_char_p),
]
class VixDiskLibConnection(ctypes.Structure):
_fields_ = []
def get_buffer(size):
return ctypes.create_string_buffer(size)
class VixDiskLibHandle(object):
""" Class which acts as a proxy for vixDiskLib-related operations:
"""
def __init__(
self, config_path=None, vixdisklib_compatibility_version=None):
self._vix_disklib = ctypes.cdll.LoadLibrary(
self.get_vix_disklib_name())
self._setup_vix_disklib()
if config_path:
config_path = config_path.encode()
target_versions = VIX_SUPPORTED_COMPATIBILITY_MODES
if vixdisklib_compatibility_version:
target_versions = [vixdisklib_compatibility_version]
LOG.debug("vixDiskLib versions targeted: %s", target_versions)
# NOTE: iterate through all versions and try to initialize using each:
version_used = None
for version in reversed(target_versions):
major_ver = None
minor_ver = None
try:
major_ver, minor_ver = version.split(".")
major_ver = int(major_ver)
minor_ver = int(minor_ver)
except ValueError as ex:
raise ValueError(
"Unsupported vixDiskLib version format '%s'. vixDiskLib "
"compatibility mode must be of the form "
"'$major.$minor'" % version) from ex
try:
self._check_err(self._vix_disklib.VixDiskLib_InitEx(
major_ver, minor_ver, None, None, None, None, config_path))
version_used = version
break
except Exception:
LOG.debug(
"Failed to initialize vixDiskLib using compatibility "
"version '%s'. Trying next version. Error trace: %s",
version, traceback.format_exc())
if not version_used:
raise Exception(
"Could not initialize vixDiskLib with any of the following "
"versions: %s" % target_versions)
LOG.info(
"Successfully initialized vixDiskLib with target version '%s'",
version_used)
@classmethod
def get_vix_disklib_name(cls):
vixDiskLibName = None
if os.name == 'nt':
vixDiskLibName = 'vixDiskLib.dll'
else:
vixDiskLibName = 'libvixDiskLib.so'
return vixDiskLibName
def _setup_vix_disklib(self):
self._vix_disklib.VixDiskLib_InitEx.argtypes = [
ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p,
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
self._vix_disklib.VixDiskLib_InitEx.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_GetErrorText.argtypes = [
ctypes.c_uint64, ctypes.c_char_p]
self._vix_disklib.VixDiskLib_GetErrorText.restype = ctypes.c_void_p
self._vix_disklib.VixDiskLib_FreeErrorText.arg_types = [
ctypes.c_char_p]
self._vix_disklib.VixDiskLib_FreeErrorText.restype = None
self._vix_disklib.VixDiskLib_ListTransportModes.argtypes = []
self._vix_disklib.VixDiskLib_ListTransportModes.restype = (
ctypes.c_char_p)
self._vix_disklib.VixDiskLib_GetTransportMode.argtypes = [
ctypes.c_void_p]
self._vix_disklib.VixDiskLib_GetTransportMode.restype = (
ctypes.c_char_p)
self._vix_disklib.VixDiskLib_ConnectEx.argtypes = [
ctypes.POINTER(VixDiskLibConnectParams), ctypes.c_char,
ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p)]
self._vix_disklib.VixDiskLib_ConnectEx.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_Open.argtypes = [
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_void_p)]
self._vix_disklib.VixDiskLib_Open.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_Read.argtypes = [
ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_char_p]
self._vix_disklib.VixDiskLib_Read.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_Write.argtypes = [
ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_char_p]
self._vix_disklib.VixDiskLib_Write.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_GetMetadataKeys.argtypes = [
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint64,
ctypes.POINTER(ctypes.c_uint64)]
self._vix_disklib.VixDiskLib_GetMetadataKeys.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_ReadMetadata.argtypes = [
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint64,
ctypes.POINTER(ctypes.c_uint64)]
self._vix_disklib.VixDiskLib_ReadMetadata.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_Close.argtypes = [ctypes.c_void_p]
self._vix_disklib.VixDiskLib_Close.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_Disconnect.argtypes = [ctypes.c_void_p]
self._vix_disklib.VixDiskLib_Disconnect.restype = ctypes.c_uint64
self._vix_disklib.VixDiskLib_Exit.argtypes = []
self._vix_disklib.VixDiskLib_Exit.restype = None
def _check_err(self, err, allowed_values=[vix_disklib_errors.VIX_OK]):
if err not in allowed_values:
err_msg = self._vix_disklib.VixDiskLib_GetErrorText(err, None)
err_msg_copy = str(ctypes.cast(
err_msg, ctypes.c_char_p).value.decode())
self._vix_disklib.VixDiskLib_FreeErrorText(
ctypes.cast(err_msg, ctypes.c_char_p))
msg = None
if err == vix_disklib_errors.VIX_E_OUT_OF_MEMORY:
msg = (
"The ESXi host performing the CBT export ran out of RAM. "
"The host performing the export is automatically chosen "
"by vCenter, so enough RAM to run the export is required "
"on all hosts. To force the export from the specific host "
"the VM is on, create a Coriolis endpoint with the DNS "
"name/IP address of that host.")
if err == vix_disklib_errors.VIX_E_HOST_NETWORK_CONN_REFUSED:
msg = (
"The ESXi host performing the CBT export refused "
"connection. The host is chosen automatically by vCenter, "
"so please ensure that the Coriolis deployment "
"can dial TCP/902 on all of the ESXi hosts of a vSphere, "
"and that DNS name resolution and firewalls are setup to "
"facilitate this. Alternatively, try connecting Coriolis "
"directly to the specific ESXi host which is running the "
"VM(s) to be migrated by creating a Coriolis endpoint "
"using the DNS name/IP address of the host itself.")
if err == vix_disklib_errors.VIX_E_CANNOT_CONNECT_TO_HOST:
msg = (
"Coriolis lost connection to the ESXi host performing the "
"CBT export. If the Coriolis Endpoint connects to a "
"vSphere host, please try connecting Coriolis to the ESXi "
"host directly. If problem persists, try re-enabling CBT "
"on the VM, or moving it to another ESXi host.")
err_msg = err_msg_copy
if msg:
LOG.debug("Original vixDiskLib error message: %s", err_msg_copy)
err_msg = msg
raise Exception(err_msg)
def get_transport_modes(self):
transport_modes = self._vix_disklib.VixDiskLib_ListTransportModes()
return transport_modes.decode().split(':')
def get_transport_mode(self, disk_handle):
t_mode = self._vix_disklib.VixDiskLib_GetTransportMode(disk_handle)
return t_mode.decode()
@contextlib.contextmanager
def connect(
self, server_name, thumbprint, username, password,
vmx_spec=None, snapshot_ref=None, read_only=True,
transport_modes=None, port=443):
LOG.debug("Connecting VixDiskLib: %s", server_name)
connectParams = VixDiskLibConnectParams()
connectParams.serverName = server_name.encode()
if vmx_spec:
connectParams.vmxSpec = vmx_spec.encode()
if thumbprint:
connectParams.thumbPrint = thumbprint.encode()
connectParams.credType = VIXDISKLIB_CRED_UID
connectParams.creds.uid.userName = username.encode()
connectParams.creds.uid.password = password.encode()
connectParams.port = port
if transport_modes:
transport_modes = transport_modes.encode()
if snapshot_ref:
snapshot_ref = snapshot_ref.encode()
conn = ctypes.c_void_p()
self._check_err(self._vix_disklib.VixDiskLib_ConnectEx(
connectParams, read_only, snapshot_ref, transport_modes,
ctypes.byref(conn)))
try:
yield conn
finally:
self.disconnect(conn)
@contextlib.contextmanager
def open(self, conn, disk_path, flags=VIXDISKLIB_FLAG_OPEN_READ_ONLY):
LOG.debug("Openning VixDiskLib disk: %s", disk_path)
disk_handle = ctypes.c_void_p()
self._check_err(self._vix_disklib.VixDiskLib_Open(
conn, disk_path.encode(), flags, ctypes.byref(disk_handle)))
try:
yield disk_handle
finally:
self.close(disk_handle)
def read(self, disk_handle, start_sector, num_sectors, buf):
self._check_err(self._vix_disklib.VixDiskLib_Read(
disk_handle, start_sector, num_sectors, buf))
def write(self, disk_handle, start_sector, num_sectors, buf):
"""Write ``num_sectors`` from ``buf`` starting at ``start_sector``."""
self._check_err(self._vix_disklib.VixDiskLib_Write(
disk_handle, start_sector, num_sectors, buf))
def close(self, disk_handle):
LOG.debug("Closing VixDiskLib disk handle: %s", disk_handle)
self._check_err(self._vix_disklib.VixDiskLib_Close(disk_handle))
def disconnect(self, conn):
LOG.debug("Disconnecting VixDiskLib")
self._check_err(self._vix_disklib.VixDiskLib_Disconnect(conn))
def exit(self):
self._vix_disklib.VixDiskLib_Exit()