diff --git a/docs/guides/setup-proxmox-for-tests.md b/docs/guides/setup-proxmox-for-tests.md
index 2d2f9f72..71ea146f 100644
--- a/docs/guides/setup-proxmox-for-tests.md
+++ b/docs/guides/setup-proxmox-for-tests.md
@@ -92,4 +92,4 @@ Goal is to have a proxmox node in VM using for a job
10. Now you can run `make example`.
-11. If you see error with proxmox_virtual_environment_file: the datastore "local" does not support content type "snippets"; supported content types are: `[backup, iso, vztmpl]`, you need to enable them, see .
+11. If you see error with proxmox_virtual_environment_file: the datastore "local" does not support content type "snippets"; supported content types are: `[backup, iso, vztmpl, import]`, you need to enable them, see .
diff --git a/docs/resources/virtual_environment_file.md b/docs/resources/virtual_environment_file.md
index 90c36275..6fcd3fba 100644
--- a/docs/resources/virtual_environment_file.md
+++ b/docs/resources/virtual_environment_file.md
@@ -126,6 +126,7 @@ resource "proxmox_virtual_environment_file" "ubuntu_container_template" {
- `backup` (allowed extensions: `.vzdump`, `.tar.gz`, `.tar.xz`, `tar.zst`)
- `iso` (allowed extensions: `.iso`, `.img`)
- `snippets` (allowed extensions: any)
+ - `import` (allowed extensions: `.raw`, `.qcow2`, `.vmdk`)
- `vztmpl` (allowed extensions: `.tar.gz`, `.tar.xz`, `tar.zst`)
- `datastore_id` - (Required) The datastore id.
- `file_mode` - The file mode in octal format, e.g. `0700` or `600`. Note that the prefixes `0o` and `0x` is not supported! Setting this attribute is also only allowed for `root@pam` authenticated user.
diff --git a/fwprovider/nodes/resource_download_file.go b/fwprovider/nodes/resource_download_file.go
index e0421efe..b433fda9 100644
--- a/fwprovider/nodes/resource_download_file.go
+++ b/fwprovider/nodes/resource_download_file.go
@@ -205,23 +205,22 @@ func (r *downloadFileResource) Schema(
Attributes: map[string]schema.Attribute{
"id": attribute.ResourceID(),
"content_type": schema.StringAttribute{
- Description: "The file content type. Must be `iso` for VM images or `vztmpl` for LXC images.",
+ Description: "The file content type. Must be `iso` or `import` for VM images or `vztmpl` for LXC images.",
Required: true,
Validators: []validator.String{stringvalidator.OneOf([]string{
"iso",
"vztmpl",
+ "import",
}...)},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"file_name": schema.StringAttribute{
- Description: "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.",
- Computed: true,
- Required: false,
- Optional: true,
+ Description: "The file name. If not provided, it is calculated using `url`.",
+ Computed: true,
+ Required: false,
+ Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.UseStateForUnknown(),
diff --git a/proxmoxtf/resource/file.go b/proxmoxtf/resource/file.go
index 3e62558b..01ed9a2b 100644
--- a/proxmoxtf/resource/file.go
+++ b/proxmoxtf/resource/file.go
@@ -20,6 +20,7 @@ import (
"path/filepath"
"slices"
"sort"
+ "strconv"
"strings"
"time"
@@ -325,9 +326,6 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
var diags diag.Diagnostics
- contentType, dg := fileGetContentType(d)
- diags = append(diags, dg...)
-
fileName, err := fileGetSourceFileName(d)
diags = append(diags, diag.FromErr(err)...)
@@ -345,6 +343,9 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
return diag.FromErr(err)
}
+ contentType, dg := fileGetContentType(ctx, d, capi)
+ diags = append(diags, dg...)
+
list, err := capi.Node(nodeName).Storage(datastoreID).ListDatastoreFiles(ctx)
if err != nil {
return diag.FromErr(err)
@@ -553,7 +554,7 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
}
switch *contentType {
- case "iso", "vztmpl":
+ case "iso", "vztmpl", "import":
_, err = capi.Node(nodeName).Storage(datastoreID).APIUpload(
ctx, request, config.TempDir(),
)
@@ -600,7 +601,7 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
}
- volID, di := fileGetVolumeID(d)
+ volID, di := fileGetVolumeID(ctx, d, capi)
diags = append(diags, di...)
if diags.HasError() {
return diags
@@ -617,11 +618,33 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
return diags
}
-func fileGetContentType(d *schema.ResourceData) (*string, diag.Diagnostics) {
+func fileGetContentType(ctx context.Context, d *schema.ResourceData, c proxmoxtf.ProviderConfiguration) (*string, diag.Diagnostics) {
contentType := d.Get(mkResourceVirtualEnvironmentFileContentType).(string)
sourceFile := d.Get(mkResourceVirtualEnvironmentFileSourceFile).([]interface{})
sourceRaw := d.Get(mkResourceVirtualEnvironmentFileSourceRaw).([]interface{})
+ release := 0.0
+ pc, err := c.GetClient()
+ if err != nil {
+ tflog.Warn(ctx, "failed to determine Proxmox Client API version", map[string]interface{}{
+ "error": err,
+ })
+ } else {
+ version, err := pc.Version().Version(context.Background())
+ if err != nil {
+ tflog.Warn(ctx, "failed to determine Proxmox VE version", map[string]interface{}{
+ "error": err,
+ })
+ } else {
+ release, err = strconv.ParseFloat(version.Release, 32)
+ if err != nil {
+ tflog.Warn(ctx, "failed to parse Proxmox VE version", map[string]interface{}{
+ "error": err,
+ })
+ }
+ }
+ }
+
sourceFilePath := ""
if len(sourceFile) > 0 {
@@ -638,22 +661,26 @@ func fileGetContentType(d *schema.ResourceData) (*string, diag.Diagnostics) {
mkResourceVirtualEnvironmentFileSourceRaw,
)
}
-
if contentType == "" {
if strings.HasSuffix(sourceFilePath, ".tar.gz") ||
strings.HasSuffix(sourceFilePath, ".tar.xz") {
contentType = "vztmpl"
+ } else if release > 8.4 && (strings.HasSuffix(sourceFilePath, ".qcow2") ||
+ strings.HasSuffix(sourceFilePath, ".raw") ||
+ strings.HasSuffix(sourceFilePath, ".vmdk")) {
+ contentType = "import"
} else {
ext := strings.TrimLeft(strings.ToLower(filepath.Ext(sourceFilePath)), ".")
switch ext {
- case "img", "iso":
+ case "iso":
contentType = "iso"
case "yaml", "yml":
contentType = "snippets"
}
}
+ // We cannot determine, for example, the content type of an .img file, so we require the user to specify it.
if contentType == "" {
return nil, diag.Errorf(
"cannot determine the content type of source \"%s\" - Please manually define the \"%s\" argument",
@@ -715,14 +742,14 @@ func fileGetSourceFileName(d *schema.ResourceData) (*string, error) {
return &sourceFileFileName, nil
}
-func fileGetVolumeID(d *schema.ResourceData) (fileVolumeID, diag.Diagnostics) {
+func fileGetVolumeID(ctx context.Context, d *schema.ResourceData, c proxmoxtf.ProviderConfiguration) (fileVolumeID, diag.Diagnostics) {
fileName, err := fileGetSourceFileName(d)
if err != nil {
return fileVolumeID{}, diag.FromErr(err)
}
datastoreID := d.Get(mkResourceVirtualEnvironmentFileDatastoreID).(string)
- contentType, diags := fileGetContentType(d)
+ contentType, diags := fileGetContentType(ctx, d, c)
return fileVolumeID{
datastoreID: datastoreID,
diff --git a/proxmoxtf/resource/validators/file.go b/proxmoxtf/resource/validators/file.go
index 8cd2e57e..0c8e5908 100644
--- a/proxmoxtf/resource/validators/file.go
+++ b/proxmoxtf/resource/validators/file.go
@@ -24,6 +24,7 @@ func ContentType() schema.SchemaValidateDiagFunc {
"iso",
"snippets",
"vztmpl",
+ "import",
}, false))
}