0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-08-22 19:38:35 +00:00

Changed file upload code to use storage devices instead of memory

This commit is contained in:
Dan Petersen 2019-12-12 23:15:13 +01:00
parent ecf05f1cfb
commit d981cc7f3e
2 changed files with 48 additions and 7 deletions

View File

@ -43,6 +43,7 @@ type VirtualEnvironmentClient struct {
type VirtualEnvironmentMultiPartData struct { type VirtualEnvironmentMultiPartData struct {
Boundary string Boundary string
Reader io.Reader Reader io.Reader
Size *int64
} }
// NewVirtualEnvironmentClient creates and initializes a VirtualEnvironmentClient instance. // NewVirtualEnvironmentClient creates and initializes a VirtualEnvironmentClient instance.
@ -85,6 +86,7 @@ func NewVirtualEnvironmentClient(endpoint, username, password string, insecure b
// DoRequest performs a HTTP request against a JSON API endpoint. // DoRequest performs a HTTP request against a JSON API endpoint.
func (c *VirtualEnvironmentClient) DoRequest(method, path string, requestBody interface{}, responseBody interface{}) error { func (c *VirtualEnvironmentClient) DoRequest(method, path string, requestBody interface{}, responseBody interface{}) error {
var reqBodyReader io.Reader var reqBodyReader io.Reader
var reqContentLength *int64
log.Printf("[DEBUG] Performing HTTP %s request (path: %s)", method, path) log.Printf("[DEBUG] Performing HTTP %s request (path: %s)", method, path)
@ -98,6 +100,7 @@ func (c *VirtualEnvironmentClient) DoRequest(method, path string, requestBody in
if multipart { if multipart {
reqBodyReader = multipartData.Reader reqBodyReader = multipartData.Reader
reqBodyType = fmt.Sprintf("multipart/form-data; boundary=%s", multipartData.Boundary) reqBodyType = fmt.Sprintf("multipart/form-data; boundary=%s", multipartData.Boundary)
reqContentLength = multipartData.Size
log.Printf("[DEBUG] Added multipart request body to HTTP %s request (path: %s)", method, modifiedPath) log.Printf("[DEBUG] Added multipart request body to HTTP %s request (path: %s)", method, modifiedPath)
} else if pipedBody { } else if pipedBody {
@ -140,6 +143,10 @@ func (c *VirtualEnvironmentClient) DoRequest(method, path string, requestBody in
req.Header.Add("Accept", "application/json") req.Header.Add("Accept", "application/json")
if reqContentLength != nil {
req.ContentLength = *reqContentLength
}
if reqBodyType != "" { if reqBodyType != "" {
req.Header.Add("Content-Type", reqBodyType) req.Header.Add("Content-Type", reqBodyType)
} }

View File

@ -5,11 +5,12 @@
package proxmox package proxmox
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"mime/multipart" "mime/multipart"
"os"
"sort" "sort"
) )
@ -99,18 +100,51 @@ func (c *VirtualEnvironmentClient) UploadFileToDatastore(d *VirtualEnvironmentDa
} }
}() }()
// Due to Proxmox VE not supporting chunked transfers, we sadly need to load the file into memory. // We need to store the multipart content in a temporary file to avoid using high amounts of memory.
// This is not optimal for large files but there's no alternative right now. // This is necessary due to Proxmox VE not supporting chunked transfers in v6.1 and earlier versions.
workaroundReader := new(bytes.Buffer) tempMultipartFile, err := ioutil.TempFile("", "multipart")
workaroundReader.ReadFrom(r)
if err != nil {
return nil, err
}
tempMultipartFileName := tempMultipartFile.Name()
io.Copy(tempMultipartFile, r)
err = tempMultipartFile.Close()
if err != nil {
return nil, err
}
defer os.Remove(tempMultipartFileName)
// Now that the multipart data is stored in a file, we can go ahead and do a HTTP POST request.
fileReader, err := os.Open(tempMultipartFileName)
if err != nil {
return nil, err
}
defer fileReader.Close()
fileInfo, err := fileReader.Stat()
if err != nil {
return nil, err
}
fileSize := fileInfo.Size()
reqBody := &VirtualEnvironmentMultiPartData{ reqBody := &VirtualEnvironmentMultiPartData{
Boundary: m.Boundary(), Boundary: m.Boundary(),
Reader: workaroundReader, Reader: fileReader,
Size: &fileSize,
} }
resBody := &VirtualEnvironmentDatastoreUploadResponseBody{} resBody := &VirtualEnvironmentDatastoreUploadResponseBody{}
err := c.DoRequest(hmPOST, fmt.Sprintf("nodes/%s/storage/%s/upload", d.NodeName, d.DatastoreID), reqBody, resBody) err = c.DoRequest(hmPOST, fmt.Sprintf("nodes/%s/storage/%s/upload", d.NodeName, d.DatastoreID), reqBody, resBody)
if err != nil { if err != nil {
return nil, err return nil, err