mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-27 13:52:20 +00:00
esx: Add domain snapshot support
Fix invalid code generating in esx_vi_generator.py regarding deep copy types that contain enum properties. Add strptime and timegm to bootstrap.conf. Both are used to convert a xsd:dateTime to calendar time. Add a testcase of the xsd:dateTime conversion.
This commit is contained in:
parent
1787fdff57
commit
1aaa909116
@ -52,9 +52,11 @@ stpcpy
|
|||||||
strchrnul
|
strchrnul
|
||||||
strndup
|
strndup
|
||||||
strerror
|
strerror
|
||||||
|
strptime
|
||||||
strsep
|
strsep
|
||||||
sys_stat
|
sys_stat
|
||||||
time_r
|
time_r
|
||||||
|
timegm
|
||||||
useless-if-before-free
|
useless-if-before-free
|
||||||
vasprintf
|
vasprintf
|
||||||
verify
|
verify
|
||||||
|
@ -563,6 +563,7 @@ esxClose(virConnectPtr conn)
|
|||||||
esxVI_Logout(priv->host) < 0) {
|
esxVI_Logout(priv->host) < 0) {
|
||||||
result = -1;
|
result = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
esxVI_Context_Free(&priv->host);
|
esxVI_Context_Free(&priv->host);
|
||||||
|
|
||||||
if (priv->vCenter != NULL) {
|
if (priv->vCenter != NULL) {
|
||||||
@ -570,6 +571,7 @@ esxClose(virConnectPtr conn)
|
|||||||
esxVI_Logout(priv->vCenter) < 0) {
|
esxVI_Logout(priv->vCenter) < 0) {
|
||||||
result = -1;
|
result = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
esxVI_Context_Free(&priv->vCenter);
|
esxVI_Context_Free(&priv->vCenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1742,23 +1744,8 @@ esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
|
|||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (powerState) {
|
info->state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
|
||||||
case esxVI_VirtualMachinePowerState_PoweredOff:
|
(powerState);
|
||||||
info->state = VIR_DOMAIN_SHUTOFF;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case esxVI_VirtualMachinePowerState_PoweredOn:
|
|
||||||
info->state = VIR_DOMAIN_RUNNING;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case esxVI_VirtualMachinePowerState_Suspended:
|
|
||||||
info->state = VIR_DOMAIN_PAUSED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
info->state = VIR_DOMAIN_NOSTATE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
|
} else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
|
||||||
if (esxVI_AnyType_ExpectType(dynamicProperty->val,
|
if (esxVI_AnyType_ExpectType(dynamicProperty->val,
|
||||||
esxVI_Type_Int) < 0) {
|
esxVI_Type_Int) < 0) {
|
||||||
@ -2329,7 +2316,6 @@ esxListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
|
|||||||
count = -1;
|
count = -1;
|
||||||
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3308,6 +3294,425 @@ esxDomainIsPersistent(virDomainPtr domain ATTRIBUTE_UNUSED)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static virDomainSnapshotPtr
|
||||||
|
esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
esxPrivate *priv = domain->conn->privateData;
|
||||||
|
virDomainSnapshotDefPtr def = NULL;
|
||||||
|
esxVI_ObjectContent *virtualMachine = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
|
||||||
|
esxVI_ManagedObjectReference *task = NULL;
|
||||||
|
esxVI_TaskInfoState taskInfoState;
|
||||||
|
virDomainSnapshotPtr snapshot = NULL;
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
def = virDomainSnapshotDefParseString(xmlDesc, 1);
|
||||||
|
|
||||||
|
if (def == NULL) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
|
||||||
|
(priv->host, domain->uuid, NULL, &virtualMachine,
|
||||||
|
priv->autoAnswer) < 0 ||
|
||||||
|
esxVI_LookupRootSnapshotTreeList(priv->host, domain->uuid,
|
||||||
|
&rootSnapshotList) < 0 ||
|
||||||
|
esxVI_GetSnapshotTreeByName(rootSnapshotList, def->name,
|
||||||
|
&snapshotTree, &snapshotTreeParent,
|
||||||
|
esxVI_Occurrence_OptionalItem) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshotTree != NULL) {
|
||||||
|
ESX_ERROR(VIR_ERR_OPERATION_INVALID,
|
||||||
|
_("Snapshot '%s' already exists"), def->name);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_CreateSnapshot_Task(priv->host, virtualMachine->obj,
|
||||||
|
def->name, def->description,
|
||||||
|
esxVI_Boolean_True,
|
||||||
|
esxVI_Boolean_False, &task) < 0 ||
|
||||||
|
esxVI_WaitForTaskCompletion(priv->host, task, domain->uuid,
|
||||||
|
priv->autoAnswer, &taskInfoState) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taskInfoState != esxVI_TaskInfoState_Success) {
|
||||||
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create snapshot"));
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot = virGetDomainSnapshot(domain, def->name);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virDomainSnapshotDefFree(def);
|
||||||
|
esxVI_ObjectContent_Free(&virtualMachine);
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
|
||||||
|
esxVI_ManagedObjectReference_Free(&task);
|
||||||
|
|
||||||
|
return snapshot;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
domain = NULL;
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
esxDomainSnapshotDumpXML(virDomainSnapshotPtr snapshot,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
esxPrivate *priv = snapshot->domain->conn->privateData;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
|
||||||
|
virDomainSnapshotDef def;
|
||||||
|
char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
|
||||||
|
char *xml = NULL;
|
||||||
|
|
||||||
|
memset(&def, 0, sizeof (virDomainSnapshotDef));
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupRootSnapshotTreeList(priv->host, snapshot->domain->uuid,
|
||||||
|
&rootSnapshotList) < 0 ||
|
||||||
|
esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
|
||||||
|
&snapshotTree, &snapshotTreeParent,
|
||||||
|
esxVI_Occurrence_RequiredItem) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
def.name = snapshot->name;
|
||||||
|
def.description = snapshotTree->description;
|
||||||
|
def.parent = snapshotTreeParent != NULL ? snapshotTreeParent->name : NULL;
|
||||||
|
|
||||||
|
if (esxVI_DateTime_ConvertToCalendarTime(snapshotTree->createTime,
|
||||||
|
&def.creationTime) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
def.state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
|
||||||
|
(snapshotTree->state);
|
||||||
|
|
||||||
|
virUUIDFormat(snapshot->domain->uuid, uuid_string);
|
||||||
|
|
||||||
|
xml = virDomainSnapshotDefFormat(uuid_string, &def, 0);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
VIR_FREE(xml);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
esxDomainSnapshotNum(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
esxPrivate *priv = domain->conn->privateData;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupRootSnapshotTreeList(priv->host, domain->uuid,
|
||||||
|
&rootSnapshotTreeList) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = esxVI_GetNumberOfSnapshotTrees(rootSnapshotTreeList);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
esxDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
esxPrivate *priv = domain->conn->privateData;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
|
||||||
|
|
||||||
|
if (names == NULL || nameslen < 0) {
|
||||||
|
ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameslen == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupRootSnapshotTreeList(priv->host, domain->uuid,
|
||||||
|
&rootSnapshotTreeList) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = esxVI_GetSnapshotTreeNames(rootSnapshotTreeList, names, nameslen);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static virDomainSnapshotPtr
|
||||||
|
esxDomainSnapshotLookupByName(virDomainPtr domain, const char *name,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
esxPrivate *priv = domain->conn->privateData;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
|
||||||
|
virDomainSnapshotPtr snapshot = NULL;
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupRootSnapshotTreeList(priv->host, domain->uuid,
|
||||||
|
&rootSnapshotTreeList) < 0 ||
|
||||||
|
esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, name, &snapshotTree,
|
||||||
|
&snapshotTreeParent,
|
||||||
|
esxVI_Occurrence_RequiredItem) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot = virGetDomainSnapshot(domain, name);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
|
||||||
|
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
esxDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
esxPrivate *priv = domain->conn->privateData;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
|
||||||
|
|
||||||
|
if (flags != 0) {
|
||||||
|
ESX_ERROR(VIR_ERR_INVALID_ARG,
|
||||||
|
_("Unsupported flags (0x%x) passed to %s"),
|
||||||
|
flags, __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupCurrentSnapshotTree(priv->host, domain->uuid,
|
||||||
|
¤tSnapshotTree,
|
||||||
|
esxVI_Occurrence_OptionalItem) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSnapshotTree != NULL) {
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(¤tSnapshotTree);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static virDomainSnapshotPtr
|
||||||
|
esxDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
|
||||||
|
{
|
||||||
|
virDomainSnapshotPtr snapshot = NULL;
|
||||||
|
esxPrivate *priv = domain->conn->privateData;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
|
||||||
|
|
||||||
|
if (flags != 0) {
|
||||||
|
ESX_ERROR(VIR_ERR_INVALID_ARG,
|
||||||
|
_("Unsupported flags (0x%x) passed to %s"),
|
||||||
|
flags, __FUNCTION__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupCurrentSnapshotTree(priv->host, domain->uuid,
|
||||||
|
¤tSnapshotTree,
|
||||||
|
esxVI_Occurrence_RequiredItem) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot = virGetDomainSnapshot(domain, currentSnapshotTree->name);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(¤tSnapshotTree);
|
||||||
|
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
esxPrivate *priv = snapshot->domain->conn->privateData;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
|
||||||
|
esxVI_ManagedObjectReference *task = NULL;
|
||||||
|
esxVI_TaskInfoState taskInfoState;
|
||||||
|
|
||||||
|
if (flags != 0) {
|
||||||
|
ESX_ERROR(VIR_ERR_INVALID_ARG,
|
||||||
|
_("Unsupported flags (0x%x) passed to %s"),
|
||||||
|
flags, __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupRootSnapshotTreeList(priv->host, snapshot->domain->uuid,
|
||||||
|
&rootSnapshotList) < 0 ||
|
||||||
|
esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
|
||||||
|
&snapshotTree, &snapshotTreeParent,
|
||||||
|
esxVI_Occurrence_RequiredItem) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_RevertToSnapshot_Task(priv->host, snapshotTree->snapshot, NULL,
|
||||||
|
&task) < 0 ||
|
||||||
|
esxVI_WaitForTaskCompletion(priv->host, task, snapshot->domain->uuid,
|
||||||
|
priv->autoAnswer, &taskInfoState) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taskInfoState != esxVI_TaskInfoState_Success) {
|
||||||
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Could not revert to snapshot '%s'"), snapshot->name);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
|
||||||
|
esxVI_ManagedObjectReference_Free(&task);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
esxPrivate *priv = snapshot->domain->conn->privateData;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
|
||||||
|
esxVI_Boolean removeChildren = esxVI_Boolean_False;
|
||||||
|
esxVI_ManagedObjectReference *task = NULL;
|
||||||
|
esxVI_TaskInfoState taskInfoState;
|
||||||
|
|
||||||
|
if (esxVI_EnsureSession(priv->host) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) {
|
||||||
|
removeChildren = esxVI_Boolean_True;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_LookupRootSnapshotTreeList(priv->host, snapshot->domain->uuid,
|
||||||
|
&rootSnapshotList) < 0 ||
|
||||||
|
esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
|
||||||
|
&snapshotTree, &snapshotTreeParent,
|
||||||
|
esxVI_Occurrence_RequiredItem) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_RemoveSnapshot_Task(priv->host, snapshotTree->snapshot,
|
||||||
|
removeChildren, &task) < 0 ||
|
||||||
|
esxVI_WaitForTaskCompletion(priv->host, task, snapshot->domain->uuid,
|
||||||
|
priv->autoAnswer, &taskInfoState) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taskInfoState != esxVI_TaskInfoState_Success) {
|
||||||
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Could not delete snapshot '%s'"), snapshot->name);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
|
||||||
|
esxVI_ManagedObjectReference_Free(&task);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static virDriver esxDriver = {
|
static virDriver esxDriver = {
|
||||||
VIR_DRV_ESX,
|
VIR_DRV_ESX,
|
||||||
"ESX",
|
"ESX",
|
||||||
@ -3388,23 +3793,23 @@ static virDriver esxDriver = {
|
|||||||
esxDomainIsPersistent, /* domainIsPersistent */
|
esxDomainIsPersistent, /* domainIsPersistent */
|
||||||
NULL, /* cpuCompare */
|
NULL, /* cpuCompare */
|
||||||
NULL, /* cpuBaseline */
|
NULL, /* cpuBaseline */
|
||||||
NULL, /* domainGetJobInfo */
|
NULL, /* domainGetJobInfo */
|
||||||
NULL, /* domainAbortJob */
|
NULL, /* domainAbortJob */
|
||||||
NULL, /* domainMigrateSetMaxDowntime */
|
NULL, /* domainMigrateSetMaxDowntime */
|
||||||
NULL, /* domainEventRegisterAny */
|
NULL, /* domainEventRegisterAny */
|
||||||
NULL, /* domainEventDeregisterAny */
|
NULL, /* domainEventDeregisterAny */
|
||||||
NULL, /* domainManagedSave */
|
NULL, /* domainManagedSave */
|
||||||
NULL, /* domainHasManagedSaveImage */
|
NULL, /* domainHasManagedSaveImage */
|
||||||
NULL, /* domainManagedSaveRemove */
|
NULL, /* domainManagedSaveRemove */
|
||||||
NULL, /* domainSnapshotCreateXML */
|
esxDomainSnapshotCreateXML, /* domainSnapshotCreateXML */
|
||||||
NULL, /* domainSnapshotDumpXML */
|
esxDomainSnapshotDumpXML, /* domainSnapshotDumpXML */
|
||||||
NULL, /* domainSnapshotNum */
|
esxDomainSnapshotNum, /* domainSnapshotNum */
|
||||||
NULL, /* domainSnapshotListNames */
|
esxDomainSnapshotListNames, /* domainSnapshotListNames */
|
||||||
NULL, /* domainSnapshotLookupByName */
|
esxDomainSnapshotLookupByName, /* domainSnapshotLookupByName */
|
||||||
NULL, /* domainHasCurrentSnapshot */
|
esxDomainHasCurrentSnapshot, /* domainHasCurrentSnapshot */
|
||||||
NULL, /* domainSnapshotCurrent */
|
esxDomainSnapshotCurrent, /* domainSnapshotCurrent */
|
||||||
NULL, /* domainRevertToSnapshot */
|
esxDomainRevertToSnapshot, /* domainRevertToSnapshot */
|
||||||
NULL, /* domainSnapshotDelete */
|
esxDomainSnapshotDelete, /* domainSnapshotDelete */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
293
src/esx/esx_vi.c
293
src/esx/esx_vi.c
@ -1718,6 +1718,152 @@ esxVI_GetVirtualMachineIdentity(esxVI_ObjectContent *virtualMachine,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
esxVI_GetNumberOfSnapshotTrees
|
||||||
|
(esxVI_VirtualMachineSnapshotTree *snapshotTreeList)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTree;
|
||||||
|
|
||||||
|
for (snapshotTree = snapshotTreeList; snapshotTree != NULL;
|
||||||
|
snapshotTree = snapshotTree->_next) {
|
||||||
|
count += 1 + esxVI_GetNumberOfSnapshotTrees
|
||||||
|
(snapshotTree->childSnapshotList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
esxVI_GetSnapshotTreeNames(esxVI_VirtualMachineSnapshotTree *snapshotTreeList,
|
||||||
|
char **names, int nameslen)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
int result;
|
||||||
|
int i;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTree;
|
||||||
|
|
||||||
|
for (snapshotTree = snapshotTreeList;
|
||||||
|
snapshotTree != NULL && count < nameslen;
|
||||||
|
snapshotTree = snapshotTree->_next) {
|
||||||
|
names[count] = strdup(snapshotTree->name);
|
||||||
|
|
||||||
|
if (names[count] == NULL) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count >= nameslen) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = esxVI_GetSnapshotTreeNames(snapshotTree->childSnapshotList,
|
||||||
|
names + count, nameslen - count);
|
||||||
|
|
||||||
|
if (result < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
count += result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
VIR_FREE(names[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
esxVI_GetSnapshotTreeByName
|
||||||
|
(esxVI_VirtualMachineSnapshotTree *snapshotTreeList, const char *name,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **snapshotTree,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **snapshotTreeParent,
|
||||||
|
esxVI_Occurrence occurrence)
|
||||||
|
{
|
||||||
|
esxVI_VirtualMachineSnapshotTree *candidate;
|
||||||
|
|
||||||
|
if (snapshotTree == NULL || *snapshotTree != NULL ||
|
||||||
|
snapshotTreeParent == NULL || *snapshotTreeParent != NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (candidate = snapshotTreeList; candidate != NULL;
|
||||||
|
candidate = candidate->_next) {
|
||||||
|
if (STREQ(candidate->name, name)) {
|
||||||
|
*snapshotTree = candidate;
|
||||||
|
*snapshotTreeParent = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_GetSnapshotTreeByName(candidate->childSnapshotList, name,
|
||||||
|
snapshotTree, snapshotTreeParent,
|
||||||
|
occurrence) > 0) {
|
||||||
|
if (*snapshotTreeParent == NULL) {
|
||||||
|
*snapshotTreeParent = candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (occurrence == esxVI_Occurrence_OptionalItem) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_NO_DOMAIN_SNAPSHOT,
|
||||||
|
_("Could not find snapshot with name '%s'"), name);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
esxVI_GetSnapshotTreeBySnapshot
|
||||||
|
(esxVI_VirtualMachineSnapshotTree *snapshotTreeList,
|
||||||
|
esxVI_ManagedObjectReference *snapshot,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **snapshotTree)
|
||||||
|
{
|
||||||
|
esxVI_VirtualMachineSnapshotTree *candidate;
|
||||||
|
|
||||||
|
if (snapshotTree == NULL || *snapshotTree != NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (candidate = snapshotTreeList; candidate != NULL;
|
||||||
|
candidate = candidate->_next) {
|
||||||
|
if (STREQ(candidate->snapshot->value, snapshot->value)) {
|
||||||
|
*snapshotTree = candidate;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_GetSnapshotTreeBySnapshot(candidate->childSnapshotList,
|
||||||
|
snapshot, snapshotTree) >= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ESX_VI_ERROR(VIR_ERR_NO_DOMAIN_SNAPSHOT,
|
||||||
|
_("Could not find domain snapshot with internal name '%s'"),
|
||||||
|
snapshot->value);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
esxVI_LookupResourcePoolByHostSystem
|
esxVI_LookupResourcePoolByHostSystem
|
||||||
(esxVI_Context *ctx, esxVI_ObjectContent *hostSystem,
|
(esxVI_Context *ctx, esxVI_ObjectContent *hostSystem,
|
||||||
@ -2335,6 +2481,149 @@ esxVI_LookupAndHandleVirtualMachineQuestion(esxVI_Context *ctx,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
esxVI_LookupRootSnapshotTreeList
|
||||||
|
(esxVI_Context *ctx, const unsigned char *virtualMachineUuid,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **rootSnapshotTreeList)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
esxVI_String *propertyNameList = NULL;
|
||||||
|
esxVI_ObjectContent *virtualMachine = NULL;
|
||||||
|
esxVI_DynamicProperty *dynamicProperty = NULL;
|
||||||
|
|
||||||
|
if (rootSnapshotTreeList == NULL || *rootSnapshotTreeList != NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_String_AppendValueToList(&propertyNameList,
|
||||||
|
"snapshot.rootSnapshotList") < 0 ||
|
||||||
|
esxVI_LookupVirtualMachineByUuid(ctx, virtualMachineUuid,
|
||||||
|
propertyNameList, &virtualMachine,
|
||||||
|
esxVI_Occurrence_RequiredItem) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
|
||||||
|
dynamicProperty = dynamicProperty->_next) {
|
||||||
|
if (STREQ(dynamicProperty->name, "snapshot.rootSnapshotList")) {
|
||||||
|
if (esxVI_VirtualMachineSnapshotTree_CastListFromAnyType
|
||||||
|
(dynamicProperty->val, rootSnapshotTreeList) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*rootSnapshotTreeList == NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("Could not lookup root snapshot list"));
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_String_Free(&propertyNameList);
|
||||||
|
esxVI_ObjectContent_Free(&virtualMachine);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(rootSnapshotTreeList);
|
||||||
|
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
esxVI_LookupCurrentSnapshotTree
|
||||||
|
(esxVI_Context *ctx, const unsigned char *virtualMachineUuid,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **currentSnapshotTree,
|
||||||
|
esxVI_Occurrence occurrence)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
esxVI_String *propertyNameList = NULL;
|
||||||
|
esxVI_ObjectContent *virtualMachine = NULL;
|
||||||
|
esxVI_DynamicProperty *dynamicProperty = NULL;
|
||||||
|
esxVI_ManagedObjectReference *currentSnapshot = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
|
||||||
|
esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
|
||||||
|
|
||||||
|
if (currentSnapshotTree == NULL || *currentSnapshotTree != NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_String_AppendValueListToList(&propertyNameList,
|
||||||
|
"snapshot.currentSnapshot\0"
|
||||||
|
"snapshot.rootSnapshotList\0") < 0 ||
|
||||||
|
esxVI_LookupVirtualMachineByUuid(ctx, virtualMachineUuid,
|
||||||
|
propertyNameList, &virtualMachine,
|
||||||
|
esxVI_Occurrence_RequiredItem) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
|
||||||
|
dynamicProperty = dynamicProperty->_next) {
|
||||||
|
if (STREQ(dynamicProperty->name, "snapshot.currentSnapshot")) {
|
||||||
|
if (esxVI_ManagedObjectReference_CastFromAnyType
|
||||||
|
(dynamicProperty->val, ¤tSnapshot) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
} else if (STREQ(dynamicProperty->name, "snapshot.rootSnapshotList")) {
|
||||||
|
if (esxVI_VirtualMachineSnapshotTree_CastListFromAnyType
|
||||||
|
(dynamicProperty->val, &rootSnapshotTreeList) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSnapshot == NULL) {
|
||||||
|
if (occurrence == esxVI_Occurrence_OptionalItem) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
|
||||||
|
_("Domain has no current snapshot"));
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootSnapshotTreeList == NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("Could not lookup root snapshot list"));
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esxVI_GetSnapshotTreeBySnapshot(rootSnapshotTreeList, currentSnapshot,
|
||||||
|
&snapshotTree) < 0 ||
|
||||||
|
esxVI_VirtualMachineSnapshotTree_DeepCopy(currentSnapshotTree,
|
||||||
|
snapshotTree) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esxVI_String_Free(&propertyNameList);
|
||||||
|
esxVI_ObjectContent_Free(&virtualMachine);
|
||||||
|
esxVI_ManagedObjectReference_Free(¤tSnapshot);
|
||||||
|
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
esxVI_HandleVirtualMachineQuestion
|
esxVI_HandleVirtualMachineQuestion
|
||||||
(esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachine,
|
(esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachine,
|
||||||
@ -2422,9 +2711,7 @@ esxVI_HandleVirtualMachineQuestion
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
failure:
|
failure:
|
||||||
if (possibleAnswers == NULL) {
|
virBufferFreeAndReset(&buffer);
|
||||||
possibleAnswers = virBufferContentAndReset(&buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = -1;
|
result = -1;
|
||||||
|
|
||||||
|
@ -233,6 +233,24 @@ int esxVI_LookupNumberOfDomainsByPowerState
|
|||||||
int esxVI_GetVirtualMachineIdentity(esxVI_ObjectContent *virtualMachine,
|
int esxVI_GetVirtualMachineIdentity(esxVI_ObjectContent *virtualMachine,
|
||||||
int *id, char **name, unsigned char *uuid);
|
int *id, char **name, unsigned char *uuid);
|
||||||
|
|
||||||
|
int esxVI_GetNumberOfSnapshotTrees
|
||||||
|
(esxVI_VirtualMachineSnapshotTree *snapshotTreeList);
|
||||||
|
|
||||||
|
int esxVI_GetSnapshotTreeNames
|
||||||
|
(esxVI_VirtualMachineSnapshotTree *snapshotTreeList, char **names,
|
||||||
|
int nameslen);
|
||||||
|
|
||||||
|
int esxVI_GetSnapshotTreeByName
|
||||||
|
(esxVI_VirtualMachineSnapshotTree *snapshotTreeList, const char *name,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **snapshotTree,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **snapshotTreeParent,
|
||||||
|
esxVI_Occurrence occurrence);
|
||||||
|
|
||||||
|
int esxVI_GetSnapshotTreeBySnapshot
|
||||||
|
(esxVI_VirtualMachineSnapshotTree *snapshotTreeList,
|
||||||
|
esxVI_ManagedObjectReference *snapshot,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **snapshotTree);
|
||||||
|
|
||||||
int esxVI_LookupResourcePoolByHostSystem
|
int esxVI_LookupResourcePoolByHostSystem
|
||||||
(esxVI_Context *ctx, esxVI_ObjectContent *hostSystem,
|
(esxVI_Context *ctx, esxVI_ObjectContent *hostSystem,
|
||||||
esxVI_ManagedObjectReference **resourcePool);
|
esxVI_ManagedObjectReference **resourcePool);
|
||||||
@ -274,6 +292,15 @@ int esxVI_LookupAndHandleVirtualMachineQuestion(esxVI_Context *ctx,
|
|||||||
const unsigned char *uuid,
|
const unsigned char *uuid,
|
||||||
esxVI_Boolean autoAnswer);
|
esxVI_Boolean autoAnswer);
|
||||||
|
|
||||||
|
int esxVI_LookupRootSnapshotTreeList
|
||||||
|
(esxVI_Context *ctx, const unsigned char *virtualMachineUuid,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **rootSnapshotTreeList);
|
||||||
|
|
||||||
|
int esxVI_LookupCurrentSnapshotTree
|
||||||
|
(esxVI_Context *ctx, const unsigned char *virtualMachineUuid,
|
||||||
|
esxVI_VirtualMachineSnapshotTree **currentSnapshotTree,
|
||||||
|
esxVI_Occurrence occurrence);
|
||||||
|
|
||||||
int esxVI_HandleVirtualMachineQuestion
|
int esxVI_HandleVirtualMachineQuestion
|
||||||
(esxVI_Context *ctx,
|
(esxVI_Context *ctx,
|
||||||
esxVI_ManagedObjectReference *virtualMachine,
|
esxVI_ManagedObjectReference *virtualMachine,
|
||||||
|
@ -424,3 +424,15 @@ object VirtualMachineQuestionInfo
|
|||||||
ChoiceOption choice r
|
ChoiceOption choice r
|
||||||
VirtualMachineMessage message i
|
VirtualMachineMessage message i
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
object VirtualMachineSnapshotTree
|
||||||
|
ManagedObjectReference snapshot r
|
||||||
|
ManagedObjectReference vm r
|
||||||
|
String name r
|
||||||
|
String description r
|
||||||
|
DateTime createTime r
|
||||||
|
VirtualMachinePowerState state r
|
||||||
|
Boolean quiesced r
|
||||||
|
VirtualMachineSnapshotTree childSnapshotList ol
|
||||||
|
end
|
||||||
|
@ -95,6 +95,8 @@ class Property:
|
|||||||
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_LIST(%s, %s)\n" % (self.type, self.name)
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_LIST(%s, %s)\n" % (self.type, self.name)
|
||||||
elif self.type == "String":
|
elif self.type == "String":
|
||||||
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_VALUE(String, %s)\n" % self.name
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_VALUE(String, %s)\n" % self.name
|
||||||
|
elif self.is_enum():
|
||||||
|
return " (*dest)->%s = src->%s;\n" % (self.name, self.name)
|
||||||
else:
|
else:
|
||||||
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY(%s, %s)\n" % (self.type, self.name)
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY(%s, %s)\n" % (self.type, self.name)
|
||||||
|
|
||||||
@ -841,17 +843,19 @@ additional_object_features = { "Event" : Object.FEATURE__LI
|
|||||||
"SharesInfo" : Object.FEATURE__ANY_TYPE,
|
"SharesInfo" : Object.FEATURE__ANY_TYPE,
|
||||||
"TaskInfo" : Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST,
|
"TaskInfo" : Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST,
|
||||||
"UserSession" : Object.FEATURE__ANY_TYPE,
|
"UserSession" : Object.FEATURE__ANY_TYPE,
|
||||||
"VirtualMachineQuestionInfo" : Object.FEATURE__ANY_TYPE }
|
"VirtualMachineQuestionInfo" : Object.FEATURE__ANY_TYPE,
|
||||||
|
"VirtualMachineSnapshotTree" : Object.FEATURE__DEEP_COPY | Object.FEATURE__ANY_TYPE }
|
||||||
|
|
||||||
|
|
||||||
removed_object_features = { "DynamicProperty" : Object.FEATURE__SERIALIZE,
|
removed_object_features = { "DynamicProperty" : Object.FEATURE__SERIALIZE,
|
||||||
"ObjectContent" : Object.FEATURE__SERIALIZE,
|
"ObjectContent" : Object.FEATURE__SERIALIZE,
|
||||||
"ObjectUpdate" : Object.FEATURE__SERIALIZE,
|
"ObjectUpdate" : Object.FEATURE__SERIALIZE,
|
||||||
"PropertyChange" : Object.FEATURE__SERIALIZE,
|
"PropertyChange" : Object.FEATURE__SERIALIZE,
|
||||||
"PropertyFilterUpdate" : Object.FEATURE__SERIALIZE,
|
"PropertyFilterUpdate" : Object.FEATURE__SERIALIZE,
|
||||||
"TaskInfo" : Object.FEATURE__SERIALIZE,
|
"TaskInfo" : Object.FEATURE__SERIALIZE,
|
||||||
"UpdateSet" : Object.FEATURE__SERIALIZE,
|
"UpdateSet" : Object.FEATURE__SERIALIZE,
|
||||||
"VirtualMachineConfigInfo" : Object.FEATURE__SERIALIZE }
|
"VirtualMachineConfigInfo" : Object.FEATURE__SERIALIZE,
|
||||||
|
"VirtualMachineSnapshotTree" : Object.FEATURE__SERIALIZE }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -948,7 +952,8 @@ for obj in objects_by_name.values():
|
|||||||
if obj.features & Object.FEATURE__DEEP_COPY:
|
if obj.features & Object.FEATURE__DEEP_COPY:
|
||||||
for property in obj.properties:
|
for property in obj.properties:
|
||||||
if property.occurrence != Property.OCCURRENCE__IGNORED and \
|
if property.occurrence != Property.OCCURRENCE__IGNORED and \
|
||||||
property.type not in predefined_objects:
|
property.type not in predefined_objects and \
|
||||||
|
property.type in objects_by_name:
|
||||||
objects_by_name[property.type].features |= Object.FEATURE__DEEP_COPY
|
objects_by_name[property.type].features |= Object.FEATURE__DEEP_COPY
|
||||||
|
|
||||||
# detect extended_by relation
|
# detect extended_by relation
|
||||||
|
@ -491,6 +491,92 @@ ESX_VI__METHOD(RegisterVM_Task,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* esxVI_CreateSnapshot_Task */
|
||||||
|
ESX_VI__METHOD(CreateSnapshot_Task,
|
||||||
|
(esxVI_Context *ctx,
|
||||||
|
esxVI_ManagedObjectReference *virtualMachine,
|
||||||
|
const char *name, const char *description,
|
||||||
|
esxVI_Boolean memory, esxVI_Boolean quiesce,
|
||||||
|
esxVI_ManagedObjectReference **task),
|
||||||
|
RequiredItem,
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__CHECK_OUTPUT(task)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__REQUIRE_THIS(virtualMachine)
|
||||||
|
ESX_VI__METHOD__PARAMETER__REQUIRE(name)
|
||||||
|
ESX_VI__METHOD__PARAMETER__REQUIRE(memory)
|
||||||
|
ESX_VI__METHOD__PARAMETER__REQUIRE(quiesce)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE_THIS(ManagedObjectReference,
|
||||||
|
virtualMachine)
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE_VALUE(String, name)
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE_VALUE(String, description)
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE(Boolean, memory)
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE(Boolean, quiesce)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if (esxVI_ManagedObjectReference_Deserialize(response->node, task) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* esxVI_RevertToSnapshot_Task */
|
||||||
|
ESX_VI__METHOD(RevertToSnapshot_Task,
|
||||||
|
(esxVI_Context *ctx,
|
||||||
|
esxVI_ManagedObjectReference *virtualMachineSnapshot,
|
||||||
|
esxVI_ManagedObjectReference *host,
|
||||||
|
esxVI_ManagedObjectReference **task),
|
||||||
|
RequiredItem,
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__CHECK_OUTPUT(task)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__REQUIRE_THIS(virtualMachineSnapshot)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE_THIS(ManagedObjectReference,
|
||||||
|
virtualMachineSnapshot)
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE(ManagedObjectReference, host)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if (esxVI_ManagedObjectReference_Deserialize(response->node, task) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* esxVI_RemoveSnapshot_Task */
|
||||||
|
ESX_VI__METHOD(RemoveSnapshot_Task,
|
||||||
|
(esxVI_Context *ctx,
|
||||||
|
esxVI_ManagedObjectReference *virtualMachineSnapshot,
|
||||||
|
esxVI_Boolean removeChildren,
|
||||||
|
esxVI_ManagedObjectReference **task),
|
||||||
|
RequiredItem,
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__CHECK_OUTPUT(task)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__REQUIRE_THIS(virtualMachineSnapshot)
|
||||||
|
ESX_VI__METHOD__PARAMETER__REQUIRE(removeChildren)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE_THIS(ManagedObjectReference,
|
||||||
|
virtualMachineSnapshot)
|
||||||
|
ESX_VI__METHOD__PARAMETER__SERIALIZE(Boolean, removeChildren)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if (esxVI_ManagedObjectReference_Deserialize(response->node, task) < 0) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* esxVI_CancelTask */
|
/* esxVI_CancelTask */
|
||||||
ESX_VI__METHOD(CancelTask,
|
ESX_VI__METHOD(CancelTask,
|
||||||
(esxVI_Context *ctx,
|
(esxVI_Context *ctx,
|
||||||
|
@ -80,6 +80,20 @@ int esxVI_RegisterVM_Task(esxVI_Context *ctx,
|
|||||||
esxVI_ManagedObjectReference *host,
|
esxVI_ManagedObjectReference *host,
|
||||||
esxVI_ManagedObjectReference **task);
|
esxVI_ManagedObjectReference **task);
|
||||||
|
|
||||||
|
int esxVI_CreateSnapshot_Task(esxVI_Context *ctx,
|
||||||
|
esxVI_ManagedObjectReference *virtualMachine,
|
||||||
|
const char *name, const char *description,
|
||||||
|
esxVI_Boolean memory, esxVI_Boolean quiesce,
|
||||||
|
esxVI_ManagedObjectReference **task);
|
||||||
|
|
||||||
|
int esxVI_RevertToSnapshot_Task
|
||||||
|
(esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachineSnapshot,
|
||||||
|
esxVI_ManagedObjectReference *host, esxVI_ManagedObjectReference **task);
|
||||||
|
|
||||||
|
int esxVI_RemoveSnapshot_Task
|
||||||
|
(esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachineSnapshot,
|
||||||
|
esxVI_Boolean removeChildren, esxVI_ManagedObjectReference **task);
|
||||||
|
|
||||||
int esxVI_CancelTask(esxVI_Context *ctx, esxVI_ManagedObjectReference *task);
|
int esxVI_CancelTask(esxVI_Context *ctx, esxVI_ManagedObjectReference *task);
|
||||||
|
|
||||||
int esxVI_UnregisterVM(esxVI_Context *ctx,
|
int esxVI_UnregisterVM(esxVI_Context *ctx,
|
||||||
|
@ -1177,6 +1177,12 @@ ESX_VI__TEMPLATE__VALIDATE(DateTime,
|
|||||||
ESX_VI__TEMPLATE__PROPERTY__REQUIRE(value);
|
ESX_VI__TEMPLATE__PROPERTY__REQUIRE(value);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/* esxVI_DateTime_DeepCopy */
|
||||||
|
ESX_VI__TEMPLATE__DEEP_COPY(DateTime,
|
||||||
|
{
|
||||||
|
ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_VALUE(String, value)
|
||||||
|
})
|
||||||
|
|
||||||
/* esxVI_DateTime_Serialize */
|
/* esxVI_DateTime_Serialize */
|
||||||
ESX_VI__TEMPLATE__SERIALIZE(DateTime,
|
ESX_VI__TEMPLATE__SERIALIZE(DateTime,
|
||||||
{
|
{
|
||||||
@ -1213,6 +1219,104 @@ esxVI_DateTime_Deserialize(xmlNodePtr node, esxVI_DateTime **dateTime)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
esxVI_DateTime_ConvertToCalendarTime(esxVI_DateTime *dateTime,
|
||||||
|
time_t *secondsSinceEpoch)
|
||||||
|
{
|
||||||
|
char value[64] = "";
|
||||||
|
char *tmp;
|
||||||
|
struct tm tm;
|
||||||
|
int milliseconds;
|
||||||
|
char sign;
|
||||||
|
int tz_hours;
|
||||||
|
int tz_minutes;
|
||||||
|
int tz_offset = 0;
|
||||||
|
|
||||||
|
if (dateTime == NULL || secondsSinceEpoch == NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virStrcpyStatic(value, dateTime->value) == NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("xsd:dateTime value '%s' too long for destination"),
|
||||||
|
dateTime->value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* expected format: [-]CCYY-MM-DDTHH:MM:SS[.ssssss][((+|-)HH:MM|Z)]
|
||||||
|
* typical example: 2010-04-05T12:13:55.316789+02:00
|
||||||
|
*
|
||||||
|
* see http://www.w3.org/TR/xmlschema-2/#dateTime
|
||||||
|
*
|
||||||
|
* map negative years to 0, since the base for time_t is the year 1970.
|
||||||
|
*/
|
||||||
|
if (*value == '-') {
|
||||||
|
*secondsSinceEpoch = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = strptime(value, "%Y-%m-%dT%H:%M:%S", &tm);
|
||||||
|
|
||||||
|
if (tmp == NULL) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("xsd:dateTime value '%s' has unexpected format"),
|
||||||
|
dateTime->value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*tmp != '\0') {
|
||||||
|
/* skip .ssssss part if present */
|
||||||
|
if (*tmp == '.' &&
|
||||||
|
virStrToLong_i(tmp + 1, &tmp, 10, &milliseconds) < 0) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("xsd:dateTime value '%s' has unexpected format"),
|
||||||
|
dateTime->value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse timezone offset if present. if missing assume UTC */
|
||||||
|
if (*tmp == '+' || *tmp == '-') {
|
||||||
|
sign = *tmp;
|
||||||
|
|
||||||
|
if (virStrToLong_i(tmp + 1, &tmp, 10, &tz_hours) < 0 ||
|
||||||
|
*tmp != ':' ||
|
||||||
|
virStrToLong_i(tmp + 1, NULL, 10, &tz_minutes) < 0) {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("xsd:dateTime value '%s' has unexpected format"),
|
||||||
|
dateTime->value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tz_offset = tz_hours * 60 * 60 + tz_minutes * 60;
|
||||||
|
|
||||||
|
if (sign == '-') {
|
||||||
|
tz_offset = -tz_offset;
|
||||||
|
}
|
||||||
|
} else if (STREQ(tmp, "Z")) {
|
||||||
|
/* Z refers to UTC. tz_offset is already initialized to zero */
|
||||||
|
} else {
|
||||||
|
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("xsd:dateTime value '%s' has unexpected format"),
|
||||||
|
dateTime->value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* xsd:dateTime represents local time relative to the optional timezone
|
||||||
|
* given as offset. pretend the local time is in UTC and use timegm in
|
||||||
|
* order to avoid interference with the timezone to this computer.
|
||||||
|
* apply timezone correction afterwards, because it's simpler than
|
||||||
|
* handling all the possible over- and underflows when trying to apply
|
||||||
|
* it to the tm struct.
|
||||||
|
*/
|
||||||
|
*secondsSinceEpoch = timegm(&tm) - tz_offset;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
@ -1344,4 +1448,31 @@ esxVI_ManagedObjectReference_Deserialize
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "esx_vi_types.generated.c"
|
#include "esx_vi_types.generated.c"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* VI Enum: VirtualMachinePowerState (Additions)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
esxVI_VirtualMachinePowerState_ConvertToLibvirt
|
||||||
|
(esxVI_VirtualMachinePowerState powerState)
|
||||||
|
{
|
||||||
|
switch (powerState) {
|
||||||
|
case esxVI_VirtualMachinePowerState_PoweredOff:
|
||||||
|
return VIR_DOMAIN_SHUTOFF;
|
||||||
|
|
||||||
|
case esxVI_VirtualMachinePowerState_PoweredOn:
|
||||||
|
return VIR_DOMAIN_RUNNING;
|
||||||
|
|
||||||
|
case esxVI_VirtualMachinePowerState_Suspended:
|
||||||
|
return VIR_DOMAIN_PAUSED;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return VIR_DOMAIN_NOSTATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -230,9 +230,12 @@ struct _esxVI_DateTime {
|
|||||||
int esxVI_DateTime_Alloc(esxVI_DateTime **dateTime);
|
int esxVI_DateTime_Alloc(esxVI_DateTime **dateTime);
|
||||||
void esxVI_DateTime_Free(esxVI_DateTime **dateTime);
|
void esxVI_DateTime_Free(esxVI_DateTime **dateTime);
|
||||||
int esxVI_DateTime_Validate(esxVI_DateTime *dateTime);
|
int esxVI_DateTime_Validate(esxVI_DateTime *dateTime);
|
||||||
|
int esxVI_DateTime_DeepCopy(esxVI_DateTime **dest, esxVI_DateTime *src);
|
||||||
int esxVI_DateTime_Serialize(esxVI_DateTime *dateTime, const char *element,
|
int esxVI_DateTime_Serialize(esxVI_DateTime *dateTime, const char *element,
|
||||||
virBufferPtr output);
|
virBufferPtr output);
|
||||||
int esxVI_DateTime_Deserialize(xmlNodePtr node, esxVI_DateTime **dateTime);
|
int esxVI_DateTime_Deserialize(xmlNodePtr node, esxVI_DateTime **dateTime);
|
||||||
|
int esxVI_DateTime_ConvertToCalendarTime(esxVI_DateTime *dateTime,
|
||||||
|
time_t *secondsSinceEpoch);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -295,4 +298,13 @@ int esxVI_ManagedObjectReference_Deserialize
|
|||||||
|
|
||||||
# include "esx_vi_types.generated.h"
|
# include "esx_vi_types.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* VI Enum: VirtualMachinePowerState (Additions)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int esxVI_VirtualMachinePowerState_ConvertToLibvirt
|
||||||
|
(esxVI_VirtualMachinePowerState powerState);
|
||||||
|
|
||||||
#endif /* __ESX_VI_TYPES_H__ */
|
#endif /* __ESX_VI_TYPES_H__ */
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# include "testutils.h"
|
# include "testutils.h"
|
||||||
# include "util.h"
|
# include "util.h"
|
||||||
# include "esx/esx_util.h"
|
# include "esx/esx_util.h"
|
||||||
|
# include "esx/esx_vi_types.h"
|
||||||
|
|
||||||
static char *progname;
|
static char *progname;
|
||||||
|
|
||||||
@ -164,6 +165,64 @@ testParseDatastoreRelatedPath(const void *data ATTRIBUTE_UNUSED)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct testDateTime {
|
||||||
|
const char *dateTime;
|
||||||
|
time_t calendarTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct testDateTime times[] = {
|
||||||
|
/* different timezones */
|
||||||
|
{ "2010-04-08T05:45:11-07:00", 1270730711 },
|
||||||
|
{ "2010-04-08T07:45:11-05:00", 1270730711 },
|
||||||
|
{ "2010-04-08T12:45:11+00:00", 1270730711 },
|
||||||
|
{ "2010-04-08T14:45:11+02:00", 1270730711 },
|
||||||
|
{ "2010-04-08T22:15:11+09:30", 1270730711 },
|
||||||
|
{ "2010-04-09T01:30:11+12:45", 1270730711 },
|
||||||
|
|
||||||
|
/* optional parts */
|
||||||
|
{ "2010-04-08T12:45:11Z", 1270730711 },
|
||||||
|
{ "2010-04-08T12:45:11", 1270730711 },
|
||||||
|
{ "-2010-04-08T14:45:11+02:00", 0 },
|
||||||
|
{ "2010-04-08T14:45:11.529576+02:00", 1270730711 },
|
||||||
|
|
||||||
|
/* borders */
|
||||||
|
{ "1970-01-01T00:00:00+00:00", 0 },
|
||||||
|
{ "2038-01-19T03:14:07+00:00", 2147483647 },
|
||||||
|
|
||||||
|
/* random */
|
||||||
|
{ "1999-08-02T01:19:55+02:00", 933549595 },
|
||||||
|
{ "2004-03-07T23:23:55+02:00", 1078694635 },
|
||||||
|
{ "1984-10-27T14:33:45+02:00", 467728425 },
|
||||||
|
{ "1970-01-12T16:11:04+02:00", 1001464 },
|
||||||
|
{ "2014-07-20T13:35:38+02:00", 1405856138 },
|
||||||
|
{ "2032-06-24T17:04:49+02:00", 1971702289 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
testConvertDateTimeToCalendarTime(const void *data ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
esxVI_DateTime dateTime;
|
||||||
|
time_t calendarTime;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_CARDINALITY(times); ++i) {
|
||||||
|
dateTime.value = (char *)times[i].dateTime;
|
||||||
|
|
||||||
|
if (esxVI_DateTime_ConvertToCalendarTime(&dateTime,
|
||||||
|
&calendarTime) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (times[i].calendarTime != calendarTime) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mymain(int argc, char **argv)
|
mymain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -194,6 +253,7 @@ mymain(int argc, char **argv)
|
|||||||
DO_TEST(IndexToDiskName);
|
DO_TEST(IndexToDiskName);
|
||||||
DO_TEST(DiskNameToIndex);
|
DO_TEST(DiskNameToIndex);
|
||||||
DO_TEST(ParseDatastoreRelatedPath);
|
DO_TEST(ParseDatastoreRelatedPath);
|
||||||
|
DO_TEST(ConvertDateTimeToCalendarTime);
|
||||||
|
|
||||||
return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user