[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] esx_storage_driver: Add API to upload volumes (virStorageVolUpload for ESX storage driver)



Patch to add API to upload Volume contents using ESX driver. As stream driver is not supported for ESX, I have used libcurl to transfer the volume, second, using flags here to pass
file descriptor of the source file.
 
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 9b64891..0519efc 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -1643,6 +1643,94 @@ esxStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
     return 1;
 }
 
+/**
+ * esxStorageVolumeUpload
+ *
+ * Upload file contents to a given volume.
+ * Method uses libcurl to POST the contents to ESX server.
+ * flags is used to pass file descriptor of the
+ * source file to be read.
+ */
+static int
+esxStorageVolumeUpload(virStorageVolPtr volume,
+                       virStreamPtr stream,
+                       unsigned long long offset,
+                       unsigned long long length,
+                       unsigned int flags)
+{
+    esxPrivate *priv = volume->conn->privateData;
+    int err = -1;
+    char *escapedDatastoreName = NULL;
+    char *url = "">+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    int fd = (int)flags;
+
+    /**
+     * Use CURL module to transfer the file to ESX.
+     * Use flags to pass the file handle.
+     */
+    const char *unescapedDatastoreName = virStorageVolGetPoolName(volume);
+    const char *volumeName = virStorageVolGetName(volume);
+
+    if (!unescapedDatastoreName) {
+        goto cleanup;
+    }
+
+    if (volume->conn != stream->conn) {
+        virReportInvalidArg(conn,
+                _("conn in %s must match stream connection."),
+                __FUNCTION__);
+        goto cleanup;
+    }
+  
+    virBufferAsprintf(&buffer, "%s://%s:%d/folder/",
+            priv->parsedUri->transport,
+            volume->conn->uri->server, volume->conn->uri->port);
+
+    escapedDatastoreName = esxUtil_EscapeDatastoreItem(unescapedDatastoreName);
+
+    if (escapedDatastoreName == NULL) {
+        goto cleanup;
+    }
+
+    /* Prepare URL to upload file */
+    virBufferAdd(&buffer, volumeName, strlen(volumeName));
+    virBufferAddLit(&buffer, "?dcPath=");
+    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
+    virBufferAddLit(&buffer, "&dsName=");
+    virBufferURIEncodeString(&buffer, escapedDatastoreName);
+
+    if (virBufferError(&buffer)) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    url = "">+
+    if (esxVI_EnsureSession(priv->primary) < 0) {
+        return -1;
+    }  
+
+    /* Upload file */
+    if (esxVI_CURL_UploadFile(priv->primary->curl, url,
+                              fd, offset, length) < 0) {
+        goto cleanup;
+    }
+
+    err = 0;
+
+  cleanup:
+
+    if (url == NULL) {
+        virBufferFreeAndReset(&buffer);
+    }
+
+    VIR_FREE(escapedDatastoreName);
+    VIR_FREE(url);
+
+    return err;
+
+}
 
 
 static virStorageDriver esxStorageDriver = {
@@ -1673,6 +1761,7 @@ static virStorageDriver esxStorageDriver = {
     .volGetInfo = esxStorageVolumeGetInfo, /* 0.8.4 */
     .volGetXMLDesc = esxStorageVolumeGetXMLDesc, /* 0.8.4 */
     .volGetPath = esxStorageVolumeGetPath, /* 0.8.4 */
+    .volUpload = esxStorageVolumeUpload, /* 0.9.x */
     .poolIsActive = esxStoragePoolIsActive, /* 0.8.2 */
     .poolIsPersistent = esxStoragePoolIsPersistent, /* 0.8.2 */
 };
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 5b5ab69..831ae36 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -425,7 +425,67 @@ esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content)
     return 0;
 }
 
+static size_t
+esxVI_CURL_read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+    size_t retcode = read((int) stream, ptr, size*nmemb);
+
+    VIR_DEBUG("Read bytes: %d", retcode);
+
+    return retcode;
+}
+
+int
+esxVI_CURL_UploadFile(esxVI_CURL *curl,
+                      const char *url,
+                      int fd,
+                      unsigned long long offset,
+                      unsigned long long length)
+{                     
+    int error = -1;
+    int responseCode = 0;
+
+    if (fd < 0) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "Invalid file descriptor: %d",
+                     fd);
+        goto cleanup;
+    }
+   
+    if (lseek(fd, (off_t) offset, SEEK_SET) < 0) {
+        virReportSystemError(errno, "%s",
+                _("Cannot seek file descriptor "));
+        goto cleanup;
+    }
+
+    virMutexLock(&curl->lock);
+
+    /* set CURL headers */
+    curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L);
+    curl_easy_setopt(curl->handle, CURLOPT_URL, url);
+    curl_easy_setopt(curl->handle, CURLOPT_READDATA, fd);
+    curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE_LARGE,
+                     (curl_off_t) length);
+    curl_easy_setopt(curl->handle, CURLOPT_READFUNCTION,
+                     esxVI_CURL_read_callback);
 
+    responseCode = esxVI_CURL_Perform(curl, url);
+
+    virMutexUnlock(&curl->lock);
+
+    if (responseCode < 0) {
+        goto cleanup;
+    } else if (responseCode != 200) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("HTTP response code %d for upload to '%s'"),
+                     responseCode, url);
+        goto cleanup;
+    }
+    error = 0;
+
+ cleanup:
+
+    return error;
+}
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * SharedCURL
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 78d3986..f95ad1d 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -92,7 +92,6 @@ typedef struct _esxVI_EnumerationValue esxVI_EnumerationValue;
 typedef struct _esxVI_List esxVI_List;
 
 
-
 enum _esxVI_APIVersion {
     esxVI_APIVersion_Undefined = 0,
     esxVI_APIVersion_Unknown,
@@ -167,6 +166,9 @@ void esxVI_CURL_Free(esxVI_CURL **curl);
 int esxVI_CURL_Connect(esxVI_CURL *curl, esxUtil_ParsedUri *parsedUri);
 int esxVI_CURL_Download(esxVI_CURL *curl, const char *url, char **content);
 int esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content);
+int esxVI_CURL_UploadFile(esxVI_CURL *curl, const char *url, int fd,
+                          unsigned long long offset,
+                          unsigned long long length);
 
 
 
diff --git a/src/libvirt.c b/src/libvirt.c
index 0aa50cb..508593b 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -12537,6 +12537,28 @@ error:
     return NULL;
 }
 
+/**
+ * virStorageVolGetPoolName:
+ * @vol: pointer to storage volume
+ *
+ * Fetch the storage volume pool name.
+ *
+ * Returns the pool name, or NULL on error
+ */
+const char*
+virStorageVolGetPoolName(virStorageVolPtr vol)
+{
+    VIR_DEBUG("vol=%p", vol);
+
+    virResetLastError();
+
+    if (!VIR_IS_STORAGE_VOL(vol)) {
+        virLibStorageVolError(VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        virDispatchError(NULL);
+        return NULL;
+    }
+    return vol->pool;
+}
 
 /**
  * virStorageVolGetName:
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 2913a81..cdfbf15 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -542,6 +542,7 @@ LIBVIRT_0.9.13 {
         virDomainSnapshotIsCurrent;
         virDomainSnapshotListAllChildren;
         virDomainSnapshotRef;
+        virStorageVolGetPoolName;
 } LIBVIRT_0.9.11;
 
 # .... define new API here using predicted next version number ....
 
Thanks!
Ata
 
Attachment:
1. StorageVolUpload.diff

diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 9b64891..0519efc 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -1643,6 +1643,94 @@ esxStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
     return 1;
 }
 
+/**
+ * esxStorageVolumeUpload
+ *
+ * Upload file contents to a given volume. 
+ * Method uses libcurl to POST the contents to ESX server.
+ * flags is used to pass file descriptor of the 
+ * source file to be read.
+ */
+static int
+esxStorageVolumeUpload(virStorageVolPtr volume,
+                       virStreamPtr stream,
+                       unsigned long long offset,
+                       unsigned long long length,
+                       unsigned int flags)
+{
+    esxPrivate *priv = volume->conn->privateData;
+    int err = -1;
+    char *escapedDatastoreName = NULL;
+    char *url = NULL;
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    int fd = (int)flags;
+
+    /**
+     * Use CURL module to transfer the file to ESX. 
+     * Use flags to pass the file handle.
+     */
+    const char *unescapedDatastoreName = virStorageVolGetPoolName(volume);
+    const char *volumeName = virStorageVolGetName(volume);
+
+    if (!unescapedDatastoreName) {
+        goto cleanup;
+    }
+
+    if (volume->conn != stream->conn) {
+        virReportInvalidArg(conn,
+                _("conn in %s must match stream connection."),
+                __FUNCTION__);
+        goto cleanup;
+    }
+   
+    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", 
+            priv->parsedUri->transport,
+            volume->conn->uri->server, volume->conn->uri->port);
+
+    escapedDatastoreName = esxUtil_EscapeDatastoreItem(unescapedDatastoreName);
+
+    if (escapedDatastoreName == NULL) {
+        goto cleanup;
+    }
+
+    /* Prepare URL to upload file */
+    virBufferAdd(&buffer, volumeName, strlen(volumeName));
+    virBufferAddLit(&buffer, "?dcPath=");
+    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
+    virBufferAddLit(&buffer, "&dsName=");
+    virBufferURIEncodeString(&buffer, escapedDatastoreName);
+
+    if (virBufferError(&buffer)) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    url = virBufferContentAndReset(&buffer);
+
+    if (esxVI_EnsureSession(priv->primary) < 0) {
+        return -1;
+    }   
+
+    /* Upload file */
+    if (esxVI_CURL_UploadFile(priv->primary->curl, url, 
+                              fd, offset, length) < 0) {
+        goto cleanup;
+    }
+
+    err = 0;
+
+  cleanup:
+
+    if (url == NULL) {
+        virBufferFreeAndReset(&buffer);
+    }
+
+    VIR_FREE(escapedDatastoreName);
+    VIR_FREE(url);
+
+    return err;
+
+}
 
 
 static virStorageDriver esxStorageDriver = {
@@ -1673,6 +1761,7 @@ static virStorageDriver esxStorageDriver = {
     .volGetInfo = esxStorageVolumeGetInfo, /* 0.8.4 */
     .volGetXMLDesc = esxStorageVolumeGetXMLDesc, /* 0.8.4 */
     .volGetPath = esxStorageVolumeGetPath, /* 0.8.4 */
+    .volUpload = esxStorageVolumeUpload, /* 0.9.x */
     .poolIsActive = esxStoragePoolIsActive, /* 0.8.2 */
     .poolIsPersistent = esxStoragePoolIsPersistent, /* 0.8.2 */
 };
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 5b5ab69..831ae36 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -425,7 +425,67 @@ esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content)
     return 0;
 }
 
+static size_t
+esxVI_CURL_read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+    size_t retcode = read((int) stream, ptr, size*nmemb);
+
+    VIR_DEBUG("Read bytes: %d", retcode);
+
+    return retcode;
+}
+
+int 
+esxVI_CURL_UploadFile(esxVI_CURL *curl, 
+                      const char *url, 
+                      int fd, 
+                      unsigned long long offset,
+                      unsigned long long length)
+{                      
+    int error = -1;
+    int responseCode = 0;
+
+    if (fd < 0) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "Invalid file descriptor: %d",
+                     fd);
+        goto cleanup;
+    }
+    
+    if (lseek(fd, (off_t) offset, SEEK_SET) < 0) {
+        virReportSystemError(errno, "%s",
+                _("Cannot seek file descriptor "));
+        goto cleanup;
+    }
+
+    virMutexLock(&curl->lock);
+
+    /* set CURL headers */
+    curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L);
+    curl_easy_setopt(curl->handle, CURLOPT_URL, url);
+    curl_easy_setopt(curl->handle, CURLOPT_READDATA, fd);
+    curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE_LARGE, 
+                     (curl_off_t) length);
+    curl_easy_setopt(curl->handle, CURLOPT_READFUNCTION, 
+                     esxVI_CURL_read_callback);
 
+    responseCode = esxVI_CURL_Perform(curl, url);
+
+    virMutexUnlock(&curl->lock);
+
+    if (responseCode < 0) {
+        goto cleanup;
+    } else if (responseCode != 200) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("HTTP response code %d for upload to '%s'"),
+                     responseCode, url);
+        goto cleanup;
+    }
+    error = 0;
+
+ cleanup:
+
+    return error;
+}
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * SharedCURL
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 78d3986..f95ad1d 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -92,7 +92,6 @@ typedef struct _esxVI_EnumerationValue esxVI_EnumerationValue;
 typedef struct _esxVI_List esxVI_List;
 
 
-
 enum _esxVI_APIVersion {
     esxVI_APIVersion_Undefined = 0,
     esxVI_APIVersion_Unknown,
@@ -167,6 +166,9 @@ void esxVI_CURL_Free(esxVI_CURL **curl);
 int esxVI_CURL_Connect(esxVI_CURL *curl, esxUtil_ParsedUri *parsedUri);
 int esxVI_CURL_Download(esxVI_CURL *curl, const char *url, char **content);
 int esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content);
+int esxVI_CURL_UploadFile(esxVI_CURL *curl, const char *url, int fd, 
+                          unsigned long long offset,
+                          unsigned long long length);
 
 
 
diff --git a/src/libvirt.c b/src/libvirt.c
index 0aa50cb..508593b 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -12537,6 +12537,28 @@ error:
     return NULL;
 }
 
+/**
+ * virStorageVolGetPoolName:
+ * @vol: pointer to storage volume
+ *
+ * Fetch the storage volume pool name.
+ *
+ * Returns the pool name, or NULL on error
+ */
+const char*
+virStorageVolGetPoolName(virStorageVolPtr vol)
+{
+    VIR_DEBUG("vol=%p", vol);
+
+    virResetLastError();
+
+    if (!VIR_IS_STORAGE_VOL(vol)) {
+        virLibStorageVolError(VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        virDispatchError(NULL);
+        return NULL;
+    }
+    return vol->pool;
+}
 
 /**
  * virStorageVolGetName:
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 2913a81..cdfbf15 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -542,6 +542,7 @@ LIBVIRT_0.9.13 {
         virDomainSnapshotIsCurrent;
         virDomainSnapshotListAllChildren;
         virDomainSnapshotRef;
+        virStorageVolGetPoolName;
 } LIBVIRT_0.9.11;
 
 # .... define new API here using predicted next version number ....

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]