diff --git a/docs/resources/virtual_environment_download_file.md b/docs/resources/virtual_environment_download_file.md index 733cbe72..74609db3 100644 --- a/docs/resources/virtual_environment_download_file.md +++ b/docs/resources/virtual_environment_download_file.md @@ -84,7 +84,7 @@ resource "proxmox_virtual_environment_download_file" "latest_ubuntu_22_jammy_lxc - `checksum_algorithm` (String) The algorithm to calculate the checksum of the file. Must be `md5` | `sha1` | `sha224` | `sha256` | `sha384` | `sha512`. - `decompression_algorithm` (String) Decompress the downloaded file using the specified compression algorithm. Must be one of `gz` | `lzo` | `zst` | `bz2`. - `file_name` (String) The file name. If not provided, it is calculated using `url`. PVE will raise 'wrong file extension' error for some popular extensions file `.raw` or `.qcow2`. Workaround is to use e.g. `.img` instead. -- `overwrite` (Boolean) If `true` and size of uploaded file is different, than size from `url` Content-Length header, file will be downloaded again. If `false`, there will be no checks. +- `overwrite` (Boolean) By default `true`. If `true` and file size has changed in the datastore, it will be replaced. If `false`, there will be no check. - `overwrite_unmanaged` (Boolean) If `true` and a file with the same name already exists in the datastore, it will be deleted and the new file will be downloaded. If `false` and the file already exists, an error will be returned. - `upload_timeout` (Number) The file download timeout seconds. Default is 600 (10min). - `verify` (Boolean) By default `true`. If `false`, no SSL/TLS certificates will be verified. @@ -92,4 +92,4 @@ resource "proxmox_virtual_environment_download_file" "latest_ubuntu_22_jammy_lxc ### Read-Only - `id` (String) The unique identifier of this resource. -- `size` (Number) The file size. +- `size` (Number) The file size in PVE. diff --git a/fwprovider/nodes/resource_download_file.go b/fwprovider/nodes/resource_download_file.go index e0421efe..abee921d 100644 --- a/fwprovider/nodes/resource_download_file.go +++ b/fwprovider/nodes/resource_download_file.go @@ -26,7 +26,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute" "github.com/bpg/terraform-provider-proxmox/fwprovider/config" @@ -74,11 +73,10 @@ func (r sizeRequiresReplaceModifier) PlanModifyInt64( originalStateSize, err := strconv.ParseInt(string(originalStateSizeBytes), 10, 64) if err != nil { resp.Diagnostics.AddError( - "Unexpected error when reading originalStateSize from Private", - fmt.Sprintf( - "Unexpected error in ParseInt: %s", - err.Error(), - ), + "Unable to convert original state file size to int64", + "Unexpected error in parsing string to int64, key original_state_size. "+ + "Please retry the operation or report this issue to the provider developers.\n\n"+ + "Error: "+err.Error(), ) return @@ -89,9 +87,10 @@ func (r sizeRequiresReplaceModifier) PlanModifyInt64( resp.PlanValue = types.Int64Value(originalStateSize) resp.Diagnostics.AddWarning( - "The file size in datastore has changed.", + "The file size in datastore has changed outside of terraform.", fmt.Sprintf( - "Previous size %d does not match size from datastore: %d", + "Previous size: %d saved in state does not match current size from datastore: %d. "+ + "You can disable this behaviour by using overwrite=false", originalStateSize, state.Size.ValueInt64(), ), @@ -100,53 +99,6 @@ func (r sizeRequiresReplaceModifier) PlanModifyInt64( return } } - - urlSizeBytes, diags := req.Private.GetKey(ctx, "url_size") - - resp.Diagnostics.Append(diags...) - - if (urlSizeBytes != nil) && (plan.URL.ValueString() == state.URL.ValueString()) { - urlSize, err := strconv.ParseInt(string(urlSizeBytes), 10, 64) - if err != nil { - resp.Diagnostics.AddError( - "Unexpected error when reading urlSize from Private", - fmt.Sprintf( - "Unexpected error in ParseInt: %s", - err.Error(), - ), - ) - - return - } - - if state.Size.ValueInt64() != urlSize { - if urlSize < 0 { - resp.Diagnostics.AddWarning( - "Could not read the file metadata from URL.", - fmt.Sprintf( - "The remote file at URL %q most likely doesn’t exist or can’t be accessed.\n"+ - "To skip the remote file check, set `overwrite` to `false`.", - plan.URL.ValueString(), - ), - ) - } else { - resp.RequiresReplace = true - resp.PlanValue = types.Int64Value(urlSize) - - resp.Diagnostics.AddWarning( - "The file size from url has changed.", - fmt.Sprintf( - "Size %d from url %q does not match size from datastore: %d", - urlSize, - plan.URL.ValueString(), - state.Size.ValueInt64(), - ), - ) - } - - return - } - } } func (r sizeRequiresReplaceModifier) Description(_ context.Context) string { @@ -242,13 +194,12 @@ func (r *downloadFileResource) Schema( }, }, "size": schema.Int64Attribute{ - Description: "The file size.", + Description: "The file size in PVE.", Optional: false, Required: false, Computed: true, PlanModifiers: []planmodifier.Int64{ int64planmodifier.UseStateForUnknown(), - int64planmodifier.RequiresReplace(), sizeRequiresReplaceModifier{}, }, }, @@ -284,6 +235,9 @@ func (r *downloadFileResource) Schema( "specified compression algorithm. Must be one of `gz` | `lzo` | `zst` | `bz2`.", Optional: true, Default: nil, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, Validators: []validator.String{ stringvalidator.OneOf([]string{ "gz", @@ -320,9 +274,8 @@ func (r *downloadFileResource) Schema( Default: booldefault.StaticBool(true), }, "overwrite": schema.BoolAttribute{ - Description: "If `true` and size of uploaded file is different, " + - "than size from `url` Content-Length header, file will be downloaded again. " + - "If `false`, there will be no checks.", + Description: "By default `true`. If `true` and file size has changed in the datastore, " + + "it will be replaced. If `false`, there will be no check.", Optional: true, Computed: true, Default: booldefault.StaticBool(true), @@ -554,25 +507,6 @@ func (r *downloadFileResource) Read( return } - if state.Overwrite.ValueBool() { - // with overwrite, use url to get proper target size - urlMetadata, err := r.getURLMetadata( - ctx, - &state, - ) - if err != nil { - tflog.Error(ctx, "Could not get file metadata from url", map[string]interface{}{ - "error": err, - "url": state.URL.ValueString(), - }) - // force size to -1, which is a special value used in sizeRequiresReplaceModifier - resp.Private.SetKey(ctx, "url_size", []byte("-1")) - } else if urlMetadata.Size != nil { - setValue := []byte(strconv.FormatInt(*urlMetadata.Size, 10)) - resp.Private.SetKey(ctx, "url_size", setValue) - } - } - resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } diff --git a/fwprovider/nodes/resource_download_file_test.go b/fwprovider/nodes/resource_download_file_test.go index 953de97e..aad1a6c6 100644 --- a/fwprovider/nodes/resource_download_file_test.go +++ b/fwprovider/nodes/resource_download_file_test.go @@ -263,11 +263,12 @@ func uploadIsoFile(t *testing.T, fileName string) { sshAgent := utils.GetAnyBoolEnv("PROXMOX_VE_SSH_AGENT") sshUsername := utils.GetAnyStringEnv("PROXMOX_VE_SSH_USERNAME") + sshPassword := utils.GetAnyStringEnv("PROXMOX_VE_SSH_PASSWORD") sshAgentSocket := utils.GetAnyStringEnv("SSH_AUTH_SOCK", "PROXMOX_VE_SSH_AUTH_SOCK") sshPrivateKey := utils.GetAnyStringEnv("PROXMOX_VE_SSH_PRIVATE_KEY") sshPort := utils.GetAnyIntEnv("PROXMOX_VE_ACC_NODE_SSH_PORT") sshClient, err := ssh.NewClient( - sshUsername, "", sshAgent, sshAgentSocket, sshPrivateKey, + sshUsername, sshPassword, sshAgent, sshAgentSocket, sshPrivateKey, "", "", "", &nodeResolver{ node: ssh.ProxmoxNode{ diff --git a/fwprovider/test/resource_file_test.go b/fwprovider/test/resource_file_test.go index 6ab688c5..8ba91737 100644 --- a/fwprovider/test/resource_file_test.go +++ b/fwprovider/test/resource_file_test.go @@ -252,11 +252,12 @@ func uploadSnippetFile(t *testing.T, fileName string) { sshAgent := utils.GetAnyBoolEnv("PROXMOX_VE_SSH_AGENT") sshUsername := utils.GetAnyStringEnv("PROXMOX_VE_SSH_USERNAME") + sshPassword := utils.GetAnyStringEnv("PROXMOX_VE_SSH_PASSWORD") sshAgentSocket := utils.GetAnyStringEnv("SSH_AUTH_SOCK", "PROXMOX_VE_SSH_AUTH_SOCK") sshPrivateKey := utils.GetAnyStringEnv("PROXMOX_VE_SSH_PRIVATE_KEY") sshPort := utils.GetAnyIntEnv("PROXMOX_VE_ACC_NODE_SSH_PORT") sshClient, err := ssh.NewClient( - sshUsername, "", sshAgent, sshAgentSocket, sshPrivateKey, + sshUsername, sshPassword, sshAgent, sshAgentSocket, sshPrivateKey, "", "", "", &nodeResolver{ node: ssh.ProxmoxNode{