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 ....