From d1e755cd28ac68574dcfa98e61e1bcb7e269d1ef Mon Sep 17 00:00:00 2001 From: Pavel Boldyrev <627562+bpg@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:01:30 -0400 Subject: [PATCH 1/2] fix(file): SSH file upload on Windows --- proxmox/datastores.go | 36 ++++++++++++++++++++++++---- proxmox/datastores_types.go | 12 +++++----- proxmox/virtual_environment_nodes.go | 20 +++++++++++++++- proxmoxtf/resource/file.go | 2 +- 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/proxmox/datastores.go b/proxmox/datastores.go index 5eb66b126..9f46457cf 100644 --- a/proxmox/datastores.go +++ b/proxmox/datastores.go @@ -17,6 +17,7 @@ import ( "os" "path/filepath" "sort" + "strings" "github.com/hashicorp/terraform-plugin-log/tflog" "golang.org/x/crypto/ssh" @@ -183,6 +184,13 @@ func (c *VirtualEnvironmentClient) UploadFileToDatastore( ) (*DatastoreUploadResponseBody, error) { switch d.ContentType { case "iso", "vztmpl": + tflog.Debug(ctx, "uploading file to datastore using PVE API", map[string]interface{}{ + "node_name": d.NodeName, + "datastore_id": d.DatastoreID, + "file_name": d.FileName, + "content_type": d.ContentType, + }) + r, w := io.Pipe() defer func(r *io.PipeReader) { @@ -227,7 +235,7 @@ func (c *VirtualEnvironmentClient) UploadFileToDatastore( return } - _, err = io.Copy(part, d.FileReader) + _, err = io.Copy(part, d.File) if err != nil { return @@ -311,6 +319,19 @@ func (c *VirtualEnvironmentClient) UploadFileToDatastore( default: // We need to upload all other files using SFTP due to API limitations. // Hopefully, this will not be required in future releases of Proxmox VE. + tflog.Debug(ctx, "uploading file to datastore using SFTP", map[string]interface{}{ + "node_name": d.NodeName, + "datastore_id": d.DatastoreID, + "file_name": d.FileName, + "content_type": d.ContentType, + }) + + fileInfo, err := d.File.Stat() + if err != nil { + return nil, fmt.Errorf("failed to get file info: %w", err) + } + fileSize := fileInfo.Size() + sshClient, err := c.OpenNodeShell(ctx, d.NodeName) if err != nil { return nil, err @@ -337,8 +358,8 @@ func (c *VirtualEnvironmentClient) UploadFileToDatastore( if d.ContentType != "" { remoteFileDir = filepath.Join(remoteFileDir, d.ContentType) } + remoteFilePath := strings.ReplaceAll(filepath.Join(remoteFileDir, d.FileName), `\`, `/`) - remoteFilePath := filepath.Join(remoteFileDir, d.FileName) sftpClient, err := sftp.NewClient(sshClient) if err != nil { return nil, fmt.Errorf("failed to create SFTP client: %w", err) @@ -372,11 +393,18 @@ func (c *VirtualEnvironmentClient) UploadFileToDatastore( } }(remoteFile) - _, err = remoteFile.ReadFrom(d.FileReader) + bytesUploaded, err := remoteFile.ReadFrom(d.File) if err != nil { return nil, fmt.Errorf("failed to upload file %s: %w", remoteFilePath, err) } - + if bytesUploaded != fileSize { + return nil, fmt.Errorf("failed to upload file %s: uploaded %d bytes, expected %d bytes", + remoteFilePath, bytesUploaded, fileSize) + } + tflog.Debug(ctx, "uploaded file to datastore", map[string]interface{}{ + "remote_file_path": remoteFilePath, + "size": bytesUploaded, + }) return &DatastoreUploadResponseBody{}, nil } } diff --git a/proxmox/datastores_types.go b/proxmox/datastores_types.go index ed47af543..1084bc385 100644 --- a/proxmox/datastores_types.go +++ b/proxmox/datastores_types.go @@ -5,7 +5,7 @@ package proxmox import ( - "io" + "os" "github.com/bpg/terraform-provider-proxmox/proxmox/types" ) @@ -88,11 +88,11 @@ type DatastoreListResponseData struct { // DatastoreUploadRequestBody contains the body for a datastore upload request. type DatastoreUploadRequestBody struct { - ContentType string `json:"content,omitempty"` - DatastoreID string `json:"storage,omitempty"` - FileName string `json:"filename,omitempty"` - FileReader io.Reader `json:"-"` - NodeName string `json:"node,omitempty"` + ContentType string `json:"content,omitempty"` + DatastoreID string `json:"storage,omitempty"` + FileName string `json:"filename,omitempty"` + NodeName string `json:"node,omitempty"` + File *os.File `json:"-"` } // DatastoreUploadResponseBody contains the body from a datastore upload response. diff --git a/proxmox/virtual_environment_nodes.go b/proxmox/virtual_environment_nodes.go index 0494b8f0f..3487a444e 100644 --- a/proxmox/virtual_environment_nodes.go +++ b/proxmox/virtual_environment_nodes.go @@ -12,6 +12,7 @@ import ( "net/http" "net/url" "os" + "path" "sort" "strings" "time" @@ -199,7 +200,20 @@ func (c *VirtualEnvironmentClient) OpenNodeShell( return nil, fmt.Errorf("failed to determine the home directory: %w", err) } sshHost := fmt.Sprintf("%s:22", *nodeAddress) - khPath := fmt.Sprintf("%s/.ssh/known_hosts", homeDir) + sshPath := path.Join(homeDir, ".ssh") + if _, err = os.Stat(sshPath); os.IsNotExist(err) { + e := os.Mkdir(sshPath, 0o700) + if e != nil { + return nil, fmt.Errorf("failed to create %s: %w", sshPath, e) + } + } + khPath := path.Join(sshPath, "known_hosts") + if _, err = os.Stat(khPath); os.IsNotExist(err) { + e := os.WriteFile(khPath, []byte{}, 0o600) + if e != nil { + return nil, fmt.Errorf("failed to create %s: %w", khPath, e) + } + } kh, err := knownhosts.New(khPath) if err != nil { return nil, fmt.Errorf("failed to read %s: %w", khPath, err) @@ -243,6 +257,10 @@ func (c *VirtualEnvironmentClient) OpenNodeShell( return nil, fmt.Errorf("failed to dial %s: %w", sshHost, err) } + tflog.Debug(ctx, "SSH connection established", map[string]interface{}{ + "host": sshHost, + "user": ur[0], + }) return sshClient, nil } diff --git a/proxmoxtf/resource/file.go b/proxmoxtf/resource/file.go index 1ec1eb733..90ef3478e 100644 --- a/proxmoxtf/resource/file.go +++ b/proxmoxtf/resource/file.go @@ -382,7 +382,7 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag ContentType: *contentType, DatastoreID: datastoreID, FileName: *fileName, - FileReader: file, + File: file, NodeName: nodeName, } From ed6e28d7c8bbece951d9fb4748fd8cb211ee43a9 Mon Sep 17 00:00:00 2001 From: Pavel Boldyrev <627562+bpg@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:11:18 -0400 Subject: [PATCH 2/2] update bug report template --- .github/ISSUE_TEMPLATE/bug_report.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 4d327a9ed..c555ab6a5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,10 +12,14 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +1. Create a resource '....' +2. Run '....' +3. See error +4. Modify the resource '....' +5. Run '....' +6. See error + +Please also provide a minimal Terraform configuration that reproduces the issue. **Expected behavior** A clear and concise description of what you expected to happen. @@ -25,3 +29,7 @@ If applicable, add screenshots to help explain your problem. **Additional context** Add any other context about the problem here. +- Provider version (ideally it should be the latest version): +- Terraform version: +- OS (where you run Terraform from)): +- Debug logs (`TF_LOG=DEBUG terraform apply`):