0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-30 02:31:10 +00:00

feat: add support for 'import' content type in Proxmox file resources

Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com>
This commit is contained in:
Marco Attia 2025-06-06 15:51:17 +00:00
parent b6bcfe75aa
commit d88f0efd75
No known key found for this signature in database
5 changed files with 46 additions and 18 deletions

View File

@ -92,4 +92,4 @@ Goal is to have a proxmox node in VM using <https://virt-manager.org/> 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 <https://registry.terraform.io/providers/bpg/proxmox/latest/docs/resources/virtual_environment_file#snippets>.
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 <https://registry.terraform.io/providers/bpg/proxmox/latest/docs/resources/virtual_environment_file#snippets>.

View File

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

View File

@ -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(),

View File

@ -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,

View File

@ -24,6 +24,7 @@ func ContentType() schema.SchemaValidateDiagFunc {
"iso",
"snippets",
"vztmpl",
"import",
}, false))
}