mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-30 18:42:58 +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:
parent
b6bcfe75aa
commit
d88f0efd75
@ -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`.
|
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>.
|
||||||
|
@ -126,6 +126,7 @@ resource "proxmox_virtual_environment_file" "ubuntu_container_template" {
|
|||||||
- `backup` (allowed extensions: `.vzdump`, `.tar.gz`, `.tar.xz`, `tar.zst`)
|
- `backup` (allowed extensions: `.vzdump`, `.tar.gz`, `.tar.xz`, `tar.zst`)
|
||||||
- `iso` (allowed extensions: `.iso`, `.img`)
|
- `iso` (allowed extensions: `.iso`, `.img`)
|
||||||
- `snippets` (allowed extensions: any)
|
- `snippets` (allowed extensions: any)
|
||||||
|
- `import` (allowed extensions: `.raw`, `.qcow2`, `.vmdk`)
|
||||||
- `vztmpl` (allowed extensions: `.tar.gz`, `.tar.xz`, `tar.zst`)
|
- `vztmpl` (allowed extensions: `.tar.gz`, `.tar.xz`, `tar.zst`)
|
||||||
- `datastore_id` - (Required) The datastore id.
|
- `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.
|
- `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.
|
||||||
|
@ -205,23 +205,22 @@ func (r *downloadFileResource) Schema(
|
|||||||
Attributes: map[string]schema.Attribute{
|
Attributes: map[string]schema.Attribute{
|
||||||
"id": attribute.ResourceID(),
|
"id": attribute.ResourceID(),
|
||||||
"content_type": schema.StringAttribute{
|
"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,
|
Required: true,
|
||||||
Validators: []validator.String{stringvalidator.OneOf([]string{
|
Validators: []validator.String{stringvalidator.OneOf([]string{
|
||||||
"iso",
|
"iso",
|
||||||
"vztmpl",
|
"vztmpl",
|
||||||
|
"import",
|
||||||
}...)},
|
}...)},
|
||||||
PlanModifiers: []planmodifier.String{
|
PlanModifiers: []planmodifier.String{
|
||||||
stringplanmodifier.RequiresReplace(),
|
stringplanmodifier.RequiresReplace(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"file_name": schema.StringAttribute{
|
"file_name": schema.StringAttribute{
|
||||||
Description: "The file name. If not provided, it is calculated " +
|
Description: "The file name. If not provided, it is calculated using `url`.",
|
||||||
"using `url`. PVE will raise 'wrong file extension' error for some popular " +
|
Computed: true,
|
||||||
"extensions file `.raw` or `.qcow2`. Workaround is to use e.g. `.img` instead.",
|
Required: false,
|
||||||
Computed: true,
|
Optional: true,
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
PlanModifiers: []planmodifier.String{
|
PlanModifiers: []planmodifier.String{
|
||||||
stringplanmodifier.RequiresReplace(),
|
stringplanmodifier.RequiresReplace(),
|
||||||
stringplanmodifier.UseStateForUnknown(),
|
stringplanmodifier.UseStateForUnknown(),
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -325,9 +326,6 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
|
|||||||
|
|
||||||
var diags diag.Diagnostics
|
var diags diag.Diagnostics
|
||||||
|
|
||||||
contentType, dg := fileGetContentType(d)
|
|
||||||
diags = append(diags, dg...)
|
|
||||||
|
|
||||||
fileName, err := fileGetSourceFileName(d)
|
fileName, err := fileGetSourceFileName(d)
|
||||||
diags = append(diags, diag.FromErr(err)...)
|
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)
|
return diag.FromErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contentType, dg := fileGetContentType(ctx, d, capi)
|
||||||
|
diags = append(diags, dg...)
|
||||||
|
|
||||||
list, err := capi.Node(nodeName).Storage(datastoreID).ListDatastoreFiles(ctx)
|
list, err := capi.Node(nodeName).Storage(datastoreID).ListDatastoreFiles(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return diag.FromErr(err)
|
return diag.FromErr(err)
|
||||||
@ -553,7 +554,7 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch *contentType {
|
switch *contentType {
|
||||||
case "iso", "vztmpl":
|
case "iso", "vztmpl", "import":
|
||||||
_, err = capi.Node(nodeName).Storage(datastoreID).APIUpload(
|
_, err = capi.Node(nodeName).Storage(datastoreID).APIUpload(
|
||||||
ctx, request, config.TempDir(),
|
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...)
|
diags = append(diags, di...)
|
||||||
if diags.HasError() {
|
if diags.HasError() {
|
||||||
return diags
|
return diags
|
||||||
@ -617,11 +618,33 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
|
|||||||
return diags
|
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)
|
contentType := d.Get(mkResourceVirtualEnvironmentFileContentType).(string)
|
||||||
sourceFile := d.Get(mkResourceVirtualEnvironmentFileSourceFile).([]interface{})
|
sourceFile := d.Get(mkResourceVirtualEnvironmentFileSourceFile).([]interface{})
|
||||||
sourceRaw := d.Get(mkResourceVirtualEnvironmentFileSourceRaw).([]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 := ""
|
sourceFilePath := ""
|
||||||
|
|
||||||
if len(sourceFile) > 0 {
|
if len(sourceFile) > 0 {
|
||||||
@ -638,22 +661,26 @@ func fileGetContentType(d *schema.ResourceData) (*string, diag.Diagnostics) {
|
|||||||
mkResourceVirtualEnvironmentFileSourceRaw,
|
mkResourceVirtualEnvironmentFileSourceRaw,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if contentType == "" {
|
if contentType == "" {
|
||||||
if strings.HasSuffix(sourceFilePath, ".tar.gz") ||
|
if strings.HasSuffix(sourceFilePath, ".tar.gz") ||
|
||||||
strings.HasSuffix(sourceFilePath, ".tar.xz") {
|
strings.HasSuffix(sourceFilePath, ".tar.xz") {
|
||||||
contentType = "vztmpl"
|
contentType = "vztmpl"
|
||||||
|
} else if release > 8.4 && (strings.HasSuffix(sourceFilePath, ".qcow2") ||
|
||||||
|
strings.HasSuffix(sourceFilePath, ".raw") ||
|
||||||
|
strings.HasSuffix(sourceFilePath, ".vmdk")) {
|
||||||
|
contentType = "import"
|
||||||
} else {
|
} else {
|
||||||
ext := strings.TrimLeft(strings.ToLower(filepath.Ext(sourceFilePath)), ".")
|
ext := strings.TrimLeft(strings.ToLower(filepath.Ext(sourceFilePath)), ".")
|
||||||
|
|
||||||
switch ext {
|
switch ext {
|
||||||
case "img", "iso":
|
case "iso":
|
||||||
contentType = "iso"
|
contentType = "iso"
|
||||||
case "yaml", "yml":
|
case "yaml", "yml":
|
||||||
contentType = "snippets"
|
contentType = "snippets"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We cannot determine, for example, the content type of an .img file, so we require the user to specify it.
|
||||||
if contentType == "" {
|
if contentType == "" {
|
||||||
return nil, diag.Errorf(
|
return nil, diag.Errorf(
|
||||||
"cannot determine the content type of source \"%s\" - Please manually define the \"%s\" argument",
|
"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
|
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)
|
fileName, err := fileGetSourceFileName(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fileVolumeID{}, diag.FromErr(err)
|
return fileVolumeID{}, diag.FromErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
datastoreID := d.Get(mkResourceVirtualEnvironmentFileDatastoreID).(string)
|
datastoreID := d.Get(mkResourceVirtualEnvironmentFileDatastoreID).(string)
|
||||||
contentType, diags := fileGetContentType(d)
|
contentType, diags := fileGetContentType(ctx, d, c)
|
||||||
|
|
||||||
return fileVolumeID{
|
return fileVolumeID{
|
||||||
datastoreID: datastoreID,
|
datastoreID: datastoreID,
|
||||||
|
@ -24,6 +24,7 @@ func ContentType() schema.SchemaValidateDiagFunc {
|
|||||||
"iso",
|
"iso",
|
||||||
"snippets",
|
"snippets",
|
||||||
"vztmpl",
|
"vztmpl",
|
||||||
|
"import",
|
||||||
}, false))
|
}, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user