[libvirt] [PATCH 2/2] ESX: Implement virDomainScreenshot

Dawid Zamirski dzamirski at dattobackup.com
Thu Mar 27 22:24:24 UTC 2014


This patch implements virDomainScreenshot support for ESX versions newer
than 4.0. It adds CreateScreenshot_Task (apiVersion 4.0) and
DeleteDatastoreFile_Task (v2.5) then uses those to implement
esxDomainScreenshot function. The DeleteDatastoreFile_Task is used to
remove the screenshot file that is left on the server after invoking
CreateScreenshot_Task call.
---
 src/esx/esx_driver.c           | 173 +++++++++++++++++++++++++++++++++++++++++
 src/esx/esx_vi_generator.input |  19 ++++-
 2 files changed, 190 insertions(+), 2 deletions(-)

diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index ff44881..e825aaf 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -22,6 +22,7 @@
  */
 
 #include <config.h>
+#include <fcntl.h>
 
 #include "internal.h"
 #include "domain_conf.h"
@@ -44,6 +45,8 @@
 #include "esx_vi.h"
 #include "esx_vi_methods.h"
 #include "esx_util.h"
+#include "configmake.h"
+#include "fdstream.h"
 #include "virstring.h"
 #include "viruri.h"
 
@@ -2501,6 +2504,175 @@ esxDomainGetState(virDomainPtr domain,
 
 
 
+static char *
+esxDomainScreenshot(virDomainPtr domain,
+                    virStreamPtr st ATTRIBUTE_UNUSED,
+                    unsigned int screen ATTRIBUTE_UNUSED,
+                    unsigned int flags)
+{
+    esxPrivate *priv = domain->conn->privateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *virtualMachine = NULL;
+    esxVI_VirtualMachinePowerState powerState;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+    char *taskInfoErrorMessage = NULL;
+    esxVI_TaskInfo *taskInfo = NULL;
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    char *screenshotPath = NULL;
+    char *dataStoreName = NULL;
+    char *directoryName = NULL;
+    char *directoryAndFileName = NULL;
+    char *url = NULL;
+    char *screenData = NULL;
+    unsigned long long screenSize = 0;
+    char *tmp = NULL;
+    char *tmpdir = NULL;
+    int tmp_fd = -1;
+    char *ret = NULL;
+    bool unlink_tmp = false;
+
+    virCheckFlags(0, NULL);
+
+    if (esxVI_EnsureSession(priv->primary) < 0) {
+        return NULL;
+    }
+
+    if (priv->primary->apiVersion < esxVI_APIVersion_40) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+                       _("Operation not supported in VI API version %s, "
+                         "minimum version is 4.0"),
+                         priv->primary->service->about->apiVersion);
+    }
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+                                       "runtime.powerState") < 0 ||
+        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
+           priv->parsedUri->autoAnswer) < 0 ||
+        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
+        goto cleanup;
+    }
+
+    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("Domain is not powered on"));
+        goto cleanup;
+    }
+
+    if (esxVI_CreateScreenshot_Task(priv->primary, virtualMachine->obj,
+                                    &task) < 0 ||
+        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
+                                    esxVI_Occurrence_RequiredItem,
+                                    priv->parsedUri->autoAnswer, &taskInfoState,
+                                    &taskInfoErrorMessage) < 0) {
+        goto cleanup;
+    }
+
+    if (taskInfoState != esxVI_TaskInfoState_Success) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create screenshot: %s"),
+                       taskInfoErrorMessage);
+        goto cleanup;
+    }
+
+    if (esxVI_LookupTaskInfoByTask(priv->primary, task, &taskInfo) < 0 ||
+        esxVI_String_CastValueFromAnyType(taskInfo->result, &screenshotPath)) {
+        goto cleanup;
+    }
+
+    if (esxUtil_ParseDatastorePath(screenshotPath, &dataStoreName,
+                                   &directoryName, &directoryAndFileName) < 0) {
+        goto cleanup;
+    }
+
+    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
+                     domain->conn->uri->server, domain->conn->uri->port);
+    virBufferURIEncodeString(&buffer, directoryAndFileName);
+    virBufferAddLit(&buffer, "?dcPath=");
+    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
+    virBufferAddLit(&buffer, "&dsName=");
+    virBufferURIEncodeString(&buffer, dataStoreName);
+
+    if (virBufferError(&buffer)) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    url = virBufferContentAndReset(&buffer);
+
+    if (esxVI_CURL_Download(priv->primary->curl, url, &screenData, 0,
+        &screenSize) < 0) {
+        goto cleanup;
+    }
+
+    tmpdir = virGetEnvBlockSUID("TMPDIR");
+    if (!tmpdir) tmpdir = "/tmp";
+
+    if (virAsprintf(&tmp, "%s/esx.screendump.XXXXXX",
+        tmpdir) < 0) {
+        goto cleanup;
+    }
+
+    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
+        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
+        goto endjob;
+    }
+    unlink_tmp = true;
+
+    if (safewrite(tmp_fd, screenData, screenSize) < 0) {
+        virReportSystemError(errno, _("unable to write data to '%s'"), tmp);
+        goto endjob;
+    }
+
+    if (VIR_CLOSE(tmp_fd) < 0) {
+        virReportSystemError(errno, _("unable to close %s"), tmp);
+        goto endjob;
+    }
+
+    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("unable to open stream"));
+        goto endjob;
+    }
+
+    if (VIR_STRDUP(ret, "image/png") < 0) {
+       goto endjob;
+    }
+
+    esxVI_ManagedObjectReference_Free(&task);
+    esxVI_DeleteDatastoreFile_Task(priv->primary, screenshotPath,
+                                   priv->primary->datacenter->_reference, &task);
+
+ endjob:
+    VIR_FORCE_CLOSE(tmp_fd);
+
+    if (unlink_tmp)
+        unlink(tmp);
+
+    VIR_FREE(tmp);
+
+ cleanup:
+    if (!url) {
+        virBufferFreeAndReset(&buffer);
+    }
+
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&virtualMachine);
+    esxVI_ManagedObjectReference_Free(&task);
+    esxVI_TaskInfo_Free(&taskInfo);
+    VIR_FREE(taskInfoErrorMessage);
+    VIR_FREE(screenshotPath);
+    VIR_FREE(screenData);
+    VIR_FREE(dataStoreName);
+    VIR_FREE(directoryName);
+    VIR_FREE(directoryAndFileName);
+    VIR_FREE(url);
+
+    return ret;
+}
+
+
+
 static int
 esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
                        unsigned int flags)
@@ -5221,6 +5393,7 @@ static virDriver esxDriver = {
     .domainGetMemoryParameters = esxDomainGetMemoryParameters, /* 0.8.6 */
     .domainGetInfo = esxDomainGetInfo, /* 0.7.0 */
     .domainGetState = esxDomainGetState, /* 0.9.2 */
+    .domainScreenshot = esxDomainScreenshot, /* 1.2.3 */
     .domainSetVcpus = esxDomainSetVcpus, /* 0.7.0 */
     .domainSetVcpusFlags = esxDomainSetVcpusFlags, /* 0.8.5 */
     .domainGetVcpusFlags = esxDomainGetVcpusFlags, /* 0.8.5 */
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 22c114e..ebc718a 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -1,5 +1,5 @@
 #
-# Definitions of vSphere API 2.5 enumeration and objects types used as input
+# Definitions of vSphere API enumeration and objects types used as input
 # for the esx_vi_generator.py script.
 #
 # This format is line-based, so end-of-line is important.
@@ -33,11 +33,13 @@
 #
 # Method definition:
 #
-# method <name> [returns <type> <occurrence>]
+# method <name> [returns <type> <occurrence>] [apiVersion <version>]
 #     <type> <name> <occurrence>
 #     ...
 # end
 #
+# If apiVersion is not specified, it defaults to 2.5
+#
 # The _this parameter can have a type attached to it:
 #
 # _this:<member>
@@ -1317,6 +1319,11 @@ method CreateFilter                  returns ManagedObjectReference         r
 end
 
 
+method CreateScreenshot_Task         returns ManagedObjectReference         r       apiVersion      4.0
+    ManagedObjectReference                  _this                           r
+end
+
+
 method CreateSnapshot_Task           returns ManagedObjectReference         r
     ManagedObjectReference                   _this                          r
     String                                   name                           r
@@ -1376,6 +1383,14 @@ method Logout
 end
 
 
+method DeleteDatastoreFile_Task     returns ManagedObjectReference          r
+    ManagedObjectReference                  _this:fileManager               r
+    String                                  name                            r
+    ManagedObjectReference                  datacenter                      o
+end
+
+
+
 method MakeDirectory
     ManagedObjectReference                   _this:fileManager              r
     String                                   name                           r
-- 
1.9.0




More information about the libvir-list mailing list