mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-29 18:21:10 +00:00
feat(hardwaremapping): Introduce support for directory mappings (#1902)
Signed-off-by: Fina Wilke <code@felinira.net> Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com> Co-authored-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
parent
6c447acb2e
commit
6dbff43bd1
@ -0,0 +1,45 @@
|
||||
---
|
||||
layout: page
|
||||
title: proxmox_virtual_environment_hardware_mapping_dir
|
||||
parent: Data Sources
|
||||
subcategory: Virtual Environment
|
||||
description: |-
|
||||
Retrieves a directory mapping from a Proxmox VE cluster.
|
||||
---
|
||||
|
||||
# Data Source: proxmox_virtual_environment_hardware_mapping_dir
|
||||
|
||||
Retrieves a directory mapping from a Proxmox VE cluster.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "proxmox_virtual_environment_hardware_mapping_dir" "example" {
|
||||
name = "example"
|
||||
}
|
||||
|
||||
output "data_proxmox_virtual_environment_hardware_mapping_dir" {
|
||||
value = data.proxmox_virtual_environment_hardware_mapping_dir.example
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- `name` (String) The name of this directory mapping.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `comment` (String) The comment of this directory mapping.
|
||||
- `id` (String) The unique identifier of this directory mapping data source.
|
||||
- `map` (Attributes Set) The actual map of devices for the directory mapping. (see [below for nested schema](#nestedatt--map))
|
||||
|
||||
<a id="nestedatt--map"></a>
|
||||
### Nested Schema for `map`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `node` (String) The node name attribute of the map.
|
||||
- `path` (String) The path attribute of the map.
|
@ -14,6 +14,11 @@ Retrieves a list of hardware mapping resources.
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "proxmox_virtual_environment_hardware_mappings" "example-dir" {
|
||||
check_node = "pve"
|
||||
type = "dir"
|
||||
}
|
||||
|
||||
data "proxmox_virtual_environment_hardware_mappings" "example-pci" {
|
||||
check_node = "pve"
|
||||
type = "pci"
|
||||
|
62
docs/resources/virtual_environment_hardware_mapping_dir.md
Normal file
62
docs/resources/virtual_environment_hardware_mapping_dir.md
Normal file
@ -0,0 +1,62 @@
|
||||
---
|
||||
layout: page
|
||||
title: proxmox_virtual_environment_hardware_mapping_dir
|
||||
parent: Resources
|
||||
subcategory: Virtual Environment
|
||||
description: |-
|
||||
Manages a directory mapping in a Proxmox VE cluster.
|
||||
---
|
||||
|
||||
# Resource: proxmox_virtual_environment_hardware_mapping_dir
|
||||
|
||||
Manages a directory mapping in a Proxmox VE cluster.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "proxmox_virtual_environment_hardware_mapping_dir" "example" {
|
||||
comment = "This is a comment"
|
||||
name = "example"
|
||||
# The actual map of devices.
|
||||
map = [
|
||||
{
|
||||
node = "pve"
|
||||
path = "/mnt/data"
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- `map` (Attributes Set) The actual map of devices for the hardware mapping. (see [below for nested schema](#nestedatt--map))
|
||||
- `name` (String) The name of this directory mapping.
|
||||
|
||||
### Optional
|
||||
|
||||
- `comment` (String) The comment of this directory mapping.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `id` (String) The unique identifier of this directory mapping resource.
|
||||
|
||||
<a id="nestedatt--map"></a>
|
||||
### Nested Schema for `map`
|
||||
|
||||
Required:
|
||||
|
||||
- `node` (String) The node this mapping applies to.
|
||||
- `path` (String) The path of the map. For directory mappings the path is required and refers to the POSIX path of the directory as visible from the node.
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env sh
|
||||
# A directory mapping can be imported using their name, e.g.:
|
||||
terraform import proxmox_virtual_environment_hardware_mapping_dir.example example
|
||||
```
|
@ -240,6 +240,15 @@ resource "proxmox_virtual_environment_vm" "data_vm" {
|
||||
}
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_hardware_mapping_dir" "dir_mapping" {
|
||||
name = "terraform-provider-proxmox-dir-mapping"
|
||||
|
||||
map = [{
|
||||
node = data.proxmox_virtual_environment_nodes.example.names[0]
|
||||
path = "/mnt"
|
||||
}]
|
||||
}
|
||||
|
||||
output "resource_proxmox_virtual_environment_vm_example_id" {
|
||||
value = proxmox_virtual_environment_vm.example.id
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
data "proxmox_virtual_environment_hardware_mapping_dir" "example" {
|
||||
name = "example"
|
||||
}
|
||||
|
||||
output "data_proxmox_virtual_environment_hardware_mapping_dir" {
|
||||
value = data.proxmox_virtual_environment_hardware_mapping_dir.example
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
data "proxmox_virtual_environment_hardware_mappings" "example-dir" {
|
||||
check_node = "pve"
|
||||
type = "dir"
|
||||
}
|
||||
|
||||
data "proxmox_virtual_environment_hardware_mappings" "example-pci" {
|
||||
check_node = "pve"
|
||||
type = "pci"
|
||||
|
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env sh
|
||||
# A directory mapping can be imported using their name, e.g.:
|
||||
terraform import proxmox_virtual_environment_hardware_mapping_dir.example example
|
@ -0,0 +1,11 @@
|
||||
resource "proxmox_virtual_environment_hardware_mapping_dir" "example" {
|
||||
comment = "This is a comment"
|
||||
name = "example"
|
||||
# The actual map of devices.
|
||||
map = [
|
||||
{
|
||||
node = "pve"
|
||||
path = "/mnt/data"
|
||||
},
|
||||
]
|
||||
}
|
@ -111,10 +111,12 @@ func (d *dataSource) Read(ctx context.Context, req datasource.ReadRequest, resp
|
||||
// name.
|
||||
// Note that the Proxmox VE API, for whatever reason, only returns one error at a time, even though the field is an
|
||||
// array.
|
||||
if (len(data.ChecksPCI) > 0) || len(data.ChecksUSB) > 0 {
|
||||
if (len(data.Checks) > 0) || len(data.ChecksUSB) > 0 {
|
||||
switch data.Type {
|
||||
case proxmoxtypes.TypeDir:
|
||||
hm.Checks = append(hm.Checks, createCheckDiagnostics(data.ID, data.Checks)...)
|
||||
case proxmoxtypes.TypePCI:
|
||||
hm.Checks = append(hm.Checks, createCheckDiagnostics(data.ID, data.ChecksPCI)...)
|
||||
hm.Checks = append(hm.Checks, createCheckDiagnostics(data.ID, data.Checks)...)
|
||||
case proxmoxtypes.TypeUSB:
|
||||
hm.Checks = append(hm.Checks, createCheckDiagnostics(data.ID, data.ChecksUSB)...)
|
||||
}
|
||||
@ -188,6 +190,7 @@ func (d *dataSource) Schema(
|
||||
Validators: []validator.String{
|
||||
stringvalidator.OneOf(
|
||||
[]string{
|
||||
proxmoxtypes.TypeDir.String(),
|
||||
proxmoxtypes.TypePCI.String(),
|
||||
proxmoxtypes.TypeUSB.String(),
|
||||
}...,
|
||||
|
140
fwprovider/nodes/hardwaremapping/datasource_dir.go
Normal file
140
fwprovider/nodes/hardwaremapping/datasource_dir.go
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package hardwaremapping
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
|
||||
mappings "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types/hardwaremapping"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the required interfaces.
|
||||
var (
|
||||
_ datasource.DataSource = &dirDataSource{}
|
||||
_ datasource.DataSourceWithConfigure = &dirDataSource{}
|
||||
)
|
||||
|
||||
// dirDataSource is the data source implementation for a directory mapping.
|
||||
type dirDataSource struct {
|
||||
client *mappings.Client
|
||||
}
|
||||
|
||||
// Configure adds the provider-configured client to the data source.
|
||||
func (d *dirDataSource) Configure(
|
||||
_ context.Context,
|
||||
req datasource.ConfigureRequest,
|
||||
resp *datasource.ConfigureResponse,
|
||||
) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = cfg.Client.Cluster().HardwareMapping()
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
func (d *dirDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_hardware_mapping_dir"
|
||||
}
|
||||
|
||||
// Read fetches the specified directory mapping from the Proxmox VE API.
|
||||
func (d *dirDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var hm modelDir
|
||||
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &hm)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
hmID := hm.Name.ValueString()
|
||||
// Ensure to keep both in sync since the name represents the ID.
|
||||
hm.ID = hm.Name
|
||||
|
||||
data, err := d.client.Get(ctx, proxmoxtypes.TypeDir, hmID)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Unable to read directory mapping %q", hmID),
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
hm.importFromAPI(ctx, data)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &hm)...)
|
||||
}
|
||||
|
||||
// Schema defines the schema for the directory mapping.
|
||||
func (d *dirDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
comment := dataSourceSchemaBaseAttrComment
|
||||
comment.Optional = false
|
||||
comment.Computed = true
|
||||
comment.Description = "The comment of this directory mapping."
|
||||
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Retrieves a directory mapping from a Proxmox VE cluster.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
schemaAttrNameComment: comment,
|
||||
schemaAttrNameMap: schema.SetNestedAttribute{
|
||||
Computed: true,
|
||||
Description: "The actual map of devices for the directory mapping.",
|
||||
NestedObject: schema.NestedAttributeObject{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
schemaAttrNameMapNode: schema.StringAttribute{
|
||||
Computed: true,
|
||||
Description: "The node name attribute of the map.",
|
||||
},
|
||||
schemaAttrNameMapPath: schema.StringAttribute{
|
||||
// For directory mappings the path is required and refers
|
||||
// to the POSIX path of the directory as visible from the node.
|
||||
Computed: true,
|
||||
CustomType: customtypes.PathType{},
|
||||
Description: "The path attribute of the map.",
|
||||
},
|
||||
},
|
||||
},
|
||||
Validators: []validator.Set{
|
||||
setvalidator.SizeAtLeast(1),
|
||||
},
|
||||
},
|
||||
schemaAttrNameName: schema.StringAttribute{
|
||||
Description: "The name of this directory mapping.",
|
||||
Required: true,
|
||||
},
|
||||
schemaAttrNameTerraformID: attribute.ResourceID(
|
||||
"The unique identifier of this directory mapping data source.",
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDirDataSource returns a new data source for a directory mapping.
|
||||
// This is a helper function to simplify the provider implementation.
|
||||
func NewDirDataSource() datasource.DataSource {
|
||||
return &dirDataSource{}
|
||||
}
|
@ -89,6 +89,15 @@ const (
|
||||
schemaAttrNameHWMIDs = "ids"
|
||||
)
|
||||
|
||||
// modelDirMap maps the schema data for the map of a directory mapping.
|
||||
type modelDirMap struct {
|
||||
// Node is the "node name" for the map.
|
||||
Node types.String `tfsdk:"node"`
|
||||
|
||||
// Path is the "path" for the map.
|
||||
Path customtypes.PathValue `tfsdk:"path"`
|
||||
}
|
||||
|
||||
// modelPCIMap maps the schema data for the map of a PCI hardware mapping.
|
||||
type modelPCIMap struct {
|
||||
// Comment is the "comment" for the map.
|
||||
@ -140,6 +149,26 @@ type modelUSBMap struct {
|
||||
Path customtypes.PathValue `tfsdk:"path"`
|
||||
}
|
||||
|
||||
// modelDir maps the schema data for a directory mapping.
|
||||
type modelDir struct {
|
||||
// Comment is the comment of the directory mapping.
|
||||
// Note that the Proxmox VE API attribute is named "description", but we map it as a comment since this naming is
|
||||
// generally across the Proxmox VE web UI and API documentations. This still follows the [Terraform "best practices"]
|
||||
// as it improves the user experience by matching the field name to the naming used in the human-facing interfaces.
|
||||
//
|
||||
// [Terraform "best practices"]: https://developer.hashicorp.com/terraform/plugin/best-practices/hashicorp-provider-design-principles#resource-and-attribute-schema-should-closely-match-the-underlying-api
|
||||
Comment types.String `tfsdk:"comment"`
|
||||
|
||||
// ID is the Terraform identifier.
|
||||
ID types.String `tfsdk:"id"`
|
||||
|
||||
// Name is the name of the directory mapping.
|
||||
Name types.String `tfsdk:"name"`
|
||||
|
||||
// Map is the map of the directory mapping.
|
||||
Map []modelDirMap `tfsdk:"map"`
|
||||
}
|
||||
|
||||
// modelPCI maps the schema data for a PCI hardware mapping.
|
||||
type modelPCI struct {
|
||||
// Comment is the comment of the PCI hardware mapping.
|
||||
@ -223,6 +252,78 @@ type modelNodeCheckDiag struct {
|
||||
Severity types.String `tfsdk:"severity"`
|
||||
}
|
||||
|
||||
// importFromAPI imports the contents of a directory mapping model from the Proxmox VE API's response data.
|
||||
func (hm *modelDir) importFromAPI(_ context.Context, data *apitypes.GetResponseData) {
|
||||
// Ensure that both the ID and name are in sync.
|
||||
hm.Name = hm.ID
|
||||
// The attribute is named "description" by the Proxmox VE API, but we map it as a comment since this naming is
|
||||
// generally across the Proxmox VE web UI and API documentations.
|
||||
hm.Comment = types.StringPointerValue(data.Description)
|
||||
maps := make([]modelDirMap, len(data.Map))
|
||||
|
||||
for idx, pveMap := range data.Map {
|
||||
tfMap := modelDirMap{
|
||||
Node: types.StringValue(pveMap.Node),
|
||||
Path: customtypes.NewPathPointerValue(pveMap.Path),
|
||||
}
|
||||
|
||||
maps[idx] = tfMap
|
||||
}
|
||||
|
||||
hm.Map = maps
|
||||
}
|
||||
|
||||
// toCreateRequest builds the request data structure for creating a new directory mapping.
|
||||
func (hm *modelDir) toCreateRequest() *apitypes.CreateRequestBody {
|
||||
return &apitypes.CreateRequestBody{
|
||||
DataBase: hm.toRequestBase(),
|
||||
ID: hm.ID.ValueString(),
|
||||
}
|
||||
}
|
||||
|
||||
// toRequestBase builds the common request data structure for the directory mapping creation or update API calls.
|
||||
func (hm *modelDir) toRequestBase() apitypes.DataBase {
|
||||
dataBase := apitypes.DataBase{
|
||||
// The attribute is named "description" by the Proxmox VE API, but we map it as a comment since this naming is
|
||||
// generally across the Proxmox VE web UI and API documentations.
|
||||
Description: hm.Comment.ValueStringPointer(),
|
||||
}
|
||||
maps := make([]proxmoxtypes.Map, len(hm.Map))
|
||||
|
||||
for idx, tfMap := range hm.Map {
|
||||
pveMap := proxmoxtypes.Map{
|
||||
Node: tfMap.Node.ValueString(),
|
||||
Path: tfMap.Path.ValueStringPointer(),
|
||||
}
|
||||
|
||||
maps[idx] = pveMap
|
||||
}
|
||||
|
||||
dataBase.Map = maps
|
||||
|
||||
return dataBase
|
||||
}
|
||||
|
||||
// toUpdateRequest builds the request data structure for updating an existing USB hardware mapping.
|
||||
func (hm *modelDir) toUpdateRequest(currentState *modelDir) *apitypes.UpdateRequestBody {
|
||||
var del []string
|
||||
|
||||
if hm.Comment.IsNull() && !currentState.Comment.IsNull() {
|
||||
// The Proxmox VE API attribute is named "description" while we name it "comment" internally since this naming is
|
||||
// generally used across the Proxmox VE web UI and API documentations.
|
||||
// This still follows the Terraform "best practices" [1] as it improves the user experience by matching the field
|
||||
// name to the naming used in the human-facing interfaces.
|
||||
// References:
|
||||
// 1. https://developer.hashicorp.com/terraform/plugin/best-practices/hashicorp-provider-design-principles#resource-and-attribute-schema-should-closely-match-the-underlying-api
|
||||
del = append(del, proxmoxtypes.AttrNameDescription)
|
||||
}
|
||||
|
||||
return &apitypes.UpdateRequestBody{
|
||||
DataBase: hm.toRequestBase(),
|
||||
Delete: del,
|
||||
}
|
||||
}
|
||||
|
||||
// importFromAPI imports the contents of a PCI hardware mapping model from the Proxmox VE API's response data.
|
||||
func (hm *modelPCI) importFromAPI(_ context.Context, data *apitypes.GetResponseData) {
|
||||
// Ensure that both the ID and name are in sync.
|
||||
|
280
fwprovider/nodes/hardwaremapping/resource_dir.go
Normal file
280
fwprovider/nodes/hardwaremapping/resource_dir.go
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package hardwaremapping
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
|
||||
mappings "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types/hardwaremapping"
|
||||
)
|
||||
|
||||
// Ensure the resource implements the required interfaces.
|
||||
var (
|
||||
_ resource.Resource = &dirResource{}
|
||||
_ resource.ResourceWithConfigure = &dirResource{}
|
||||
_ resource.ResourceWithImportState = &dirResource{}
|
||||
)
|
||||
|
||||
// dirResource contains the directory mapping resource's internal data.
|
||||
type dirResource struct {
|
||||
// client is the hardware mapping API client.
|
||||
client *mappings.Client
|
||||
}
|
||||
|
||||
// read reads information about a directory mapping from the Proxmox VE API.
|
||||
func (r *dirResource) read(ctx context.Context, hm *modelDir) (bool, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
hmName := hm.Name.ValueString()
|
||||
|
||||
data, err := r.client.Get(ctx, proxmoxtypes.TypeDir, hmName)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no such resource") {
|
||||
diags.AddError("Could not read directory mapping", err.Error())
|
||||
}
|
||||
|
||||
return false, diags
|
||||
}
|
||||
|
||||
hm.importFromAPI(ctx, data)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// readBack reads information about a created or modified directory mapping from the Proxmox VE API then updates the
|
||||
// response state accordingly.
|
||||
// The Terraform resource identifier must have been set in the state before this method is called!
|
||||
func (r *dirResource) readBack(ctx context.Context, hm *modelDir, respDiags *diag.Diagnostics, respState *tfsdk.State) {
|
||||
found, diags := r.read(ctx, hm)
|
||||
|
||||
respDiags.Append(diags...)
|
||||
|
||||
if !found {
|
||||
respDiags.AddError(
|
||||
"directory mapping resource not found after update",
|
||||
"Failed to find the resource when trying to read back the updated directory mapping's data.",
|
||||
)
|
||||
}
|
||||
|
||||
if !respDiags.HasError() {
|
||||
respDiags.Append(respState.Set(ctx, *hm)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Configure adds the provider-configured client to the resource.
|
||||
func (r *dirResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = cfg.Client.Cluster().HardwareMapping()
|
||||
}
|
||||
|
||||
// Create creates a new directory mapping.
|
||||
func (r *dirResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
||||
var hm modelDir
|
||||
|
||||
resp.Diagnostics.Append(req.Plan.Get(ctx, &hm)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
hmName := hm.Name.ValueString()
|
||||
// Ensure to keep both in sync since the name represents the ID.
|
||||
hm.ID = hm.Name
|
||||
|
||||
apiReq := hm.toCreateRequest()
|
||||
|
||||
if err := r.client.Create(ctx, proxmoxtypes.TypeDir, apiReq); err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Could not create directory mapping %q.", hmName),
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.readBack(ctx, &hm, &resp.Diagnostics, &resp.State)
|
||||
}
|
||||
|
||||
// Delete deletes an existing directory mapping.
|
||||
func (r *dirResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
|
||||
var hm modelDir
|
||||
|
||||
resp.Diagnostics.Append(req.State.Get(ctx, &hm)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
hmID := hm.Name.ValueString()
|
||||
|
||||
if err := r.client.Delete(ctx, proxmoxtypes.TypeDir, hmID); err != nil {
|
||||
if strings.Contains(err.Error(), "no such resource") {
|
||||
resp.Diagnostics.AddWarning(
|
||||
"directory mapping does not exist",
|
||||
fmt.Sprintf(
|
||||
"Could not delete directory mapping %q, it does not exist or has been deleted outside of Terraform.",
|
||||
hmID,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
resp.Diagnostics.AddError(fmt.Sprintf("Could not delete directory mapping %q.", hmID), err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ImportState imports a directory mapping from the Proxmox VE API.
|
||||
func (r *dirResource) ImportState(
|
||||
ctx context.Context,
|
||||
req resource.ImportStateRequest,
|
||||
resp *resource.ImportStateResponse,
|
||||
) {
|
||||
data := modelDir{
|
||||
ID: types.StringValue(req.ID),
|
||||
Name: types.StringValue(req.ID),
|
||||
}
|
||||
|
||||
resource.ImportStatePassthroughID(ctx, path.Root(schemaAttrNameTerraformID), req, resp)
|
||||
r.readBack(ctx, &data, &resp.Diagnostics, &resp.State)
|
||||
}
|
||||
|
||||
// Metadata defines the name of the directory mapping.
|
||||
func (r *dirResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_hardware_mapping_dir"
|
||||
}
|
||||
|
||||
// Read reads the directory mapping.
|
||||
//
|
||||
|
||||
func (r *dirResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
|
||||
var data modelDir
|
||||
|
||||
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
found, diags := r.read(ctx, &data)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
if !resp.Diagnostics.HasError() {
|
||||
if found {
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
|
||||
} else {
|
||||
resp.State.RemoveResource(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Schema defines the schema for the directory mapping.
|
||||
func (r *dirResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
comment := resourceSchemaBaseAttrComment
|
||||
comment.Description = "The comment of this directory mapping."
|
||||
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Manages a directory mapping in a Proxmox VE cluster.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
schemaAttrNameComment: comment,
|
||||
schemaAttrNameMap: schema.SetNestedAttribute{
|
||||
Description: "The actual map of devices for the hardware mapping.",
|
||||
NestedObject: schema.NestedAttributeObject{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
schemaAttrNameMapNode: schema.StringAttribute{
|
||||
Description: "The node this mapping applies to.",
|
||||
Required: true,
|
||||
},
|
||||
schemaAttrNameMapPath: schema.StringAttribute{
|
||||
CustomType: customtypes.PathType{},
|
||||
Description: "The path of the map. For directory mappings the path is required and refers" +
|
||||
" to the POSIX path of the directory as visible from the node.",
|
||||
Required: true,
|
||||
Validators: []validator.String{
|
||||
stringvalidator.RegexMatches(
|
||||
customtypes.PathDirValueRegEx,
|
||||
ErrResourceMessageInvalidPath(proxmoxtypes.TypeDir),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: true,
|
||||
Validators: []validator.Set{
|
||||
setvalidator.SizeAtLeast(1),
|
||||
},
|
||||
},
|
||||
schemaAttrNameName: schema.StringAttribute{
|
||||
Description: "The name of this directory mapping.",
|
||||
Required: true,
|
||||
},
|
||||
schemaAttrNameTerraformID: attribute.ResourceID(
|
||||
"The unique identifier of this directory mapping resource.",
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates an existing directory mapping.
|
||||
func (r *dirResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
|
||||
var hmCurrent, hmPlan modelDir
|
||||
|
||||
resp.Diagnostics.Append(req.Plan.Get(ctx, &hmPlan)...)
|
||||
resp.Diagnostics.Append(req.State.Get(ctx, &hmCurrent)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
hmName := hmPlan.Name.ValueString()
|
||||
|
||||
apiReq := hmPlan.toUpdateRequest(&hmCurrent)
|
||||
|
||||
if err := r.client.Update(ctx, proxmoxtypes.TypeDir, hmName, apiReq); err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Could not update directory mapping %q.", hmName),
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.readBack(ctx, &hmPlan, &resp.Diagnostics, &resp.State)
|
||||
}
|
||||
|
||||
// NewDirResource returns a new resource for managing a directory mapping.
|
||||
// This is a helper function to simplify the provider implementation.
|
||||
func NewDirResource() resource.Resource {
|
||||
return &dirResource{}
|
||||
}
|
@ -27,15 +27,18 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
accTestHardwareMappingNameDir = "proxmox_virtual_environment_hardware_mapping_dir.test"
|
||||
accTestHardwareMappingNamePCI = "proxmox_virtual_environment_hardware_mapping_pci.test"
|
||||
accTestHardwareMappingNameUSB = "proxmox_virtual_environment_hardware_mapping_usb.test"
|
||||
)
|
||||
|
||||
type accTestHardwareMappingFakeData struct {
|
||||
Comments []string `fake:"{sentence:3}" fakesize:"2"`
|
||||
MapComments []string `fake:"{sentence:3}" fakesize:"2"`
|
||||
MapDeviceIDs []string `fake:"{linuxdeviceid}" fakesize:"2"`
|
||||
MapIOMMUGroups []uint `fake:"{number:1,20}" fakesize:"2"`
|
||||
Comments []string `fake:"{sentence:3}" fakesize:"2"`
|
||||
MapComments []string `fake:"{sentence:3}" fakesize:"2"`
|
||||
MapDeviceIDs []string `fake:"{linuxdeviceid}" fakesize:"2"`
|
||||
MapIOMMUGroups []uint `fake:"{number:1,20}" fakesize:"2"`
|
||||
// These paths must exist on the host system, use a hardcoded list
|
||||
MapPathsDir []string `fake:"{randomstring:[/home,/root,/mnt,/tmp]}" fakesize:"2"`
|
||||
MapPathsPCI []string `fake:"{linuxdevicepathpci}" fakesize:"2"`
|
||||
MapPathsUSB []string `fake:"{linuxdevicepathusb}" fakesize:"2"`
|
||||
MapSubsystemIDs []string `fake:"{linuxdeviceid}" fakesize:"2"`
|
||||
@ -94,6 +97,226 @@ func testAccResourceHardwareMappingInit(t *testing.T) (*accTestHardwareMappingFa
|
||||
return &data, te
|
||||
}
|
||||
|
||||
// TestAccResourceHardwareMappingDirValidInput runs tests for directory mapping resource definitions with valid input
|
||||
// where all possible attributes are
|
||||
// specified.
|
||||
// All implementations of the [github.com/hashicorp/terraform-plugin-framework/resource.Resource] interface are tested
|
||||
// in sequential steps.
|
||||
func TestAccResourceHardwareMappingDirValidInput(t *testing.T) {
|
||||
data, te := testAccResourceHardwareMappingInit(t)
|
||||
|
||||
resource.Test(
|
||||
t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: te.AccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
// Test the "Create" and "Read" implementations where all possible attributes are specified.
|
||||
{
|
||||
Config: fmt.Sprintf(
|
||||
`
|
||||
resource "proxmox_virtual_environment_hardware_mapping_dir" "test" {
|
||||
comment = "%s"
|
||||
name = "%s"
|
||||
map = [
|
||||
{
|
||||
node = "%s"
|
||||
path = "%s"
|
||||
},
|
||||
]
|
||||
}
|
||||
`,
|
||||
data.Comments[0],
|
||||
data.Names[0],
|
||||
te.NodeName,
|
||||
data.MapPathsDir[0],
|
||||
),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(accTestHardwareMappingNameDir, "comment", data.Comments[0]),
|
||||
resource.TestCheckResourceAttrSet(accTestHardwareMappingNameDir, "id"),
|
||||
resource.TestCheckTypeSetElemNestedAttrs(
|
||||
accTestHardwareMappingNameDir, "map.*", map[string]string{
|
||||
"node": te.NodeName,
|
||||
"path": data.MapPathsDir[0],
|
||||
},
|
||||
),
|
||||
resource.TestCheckResourceAttr(accTestHardwareMappingNameDir, "name", data.Names[0]),
|
||||
),
|
||||
},
|
||||
|
||||
// Test the "ImportState" implementation and ensure that PCI-only attributes are not set.
|
||||
{
|
||||
ImportState: true,
|
||||
ImportStateId: data.Names[0],
|
||||
ImportStateVerify: true,
|
||||
ResourceName: accTestHardwareMappingNameDir,
|
||||
},
|
||||
|
||||
// Test the "Update" implementation where all possible attributes are specified.
|
||||
{
|
||||
Config: fmt.Sprintf(
|
||||
`
|
||||
resource "proxmox_virtual_environment_hardware_mapping_dir" "test" {
|
||||
comment = "%s"
|
||||
name = "%s"
|
||||
map = [
|
||||
{
|
||||
node = "%s"
|
||||
path = "%s"
|
||||
},
|
||||
]
|
||||
}
|
||||
`,
|
||||
data.Comments[1],
|
||||
data.Names[0],
|
||||
te.NodeName,
|
||||
data.MapPathsDir[1],
|
||||
),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(accTestHardwareMappingNameDir, "comment", data.Comments[1]),
|
||||
resource.TestCheckResourceAttrSet(accTestHardwareMappingNameDir, "id"),
|
||||
resource.TestCheckTypeSetElemNestedAttrs(
|
||||
accTestHardwareMappingNameDir, "map.*", map[string]string{
|
||||
"node": te.NodeName,
|
||||
"path": data.MapPathsDir[1],
|
||||
},
|
||||
),
|
||||
resource.TestCheckResourceAttr(accTestHardwareMappingNameDir, "name", data.Names[0]),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TestAccResourceHardwareMappingDirValidInputMinimal runs tests for directory mapping resource definitions with
|
||||
// valid input that only have the minimum
|
||||
// amount of attributes set to test computed and default values within the resulting plan and state. The last step sets
|
||||
// the undefined values to test the update
|
||||
// logic.
|
||||
// All implementations of the [github.com/hashicorp/terraform-plugin-framework/resource.Resource] interface are tested
|
||||
// in sequential steps.
|
||||
func TestAccResourceHardwareMappingDirValidInputMinimal(t *testing.T) {
|
||||
data, te := testAccResourceHardwareMappingInit(t)
|
||||
|
||||
resource.Test(
|
||||
t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: te.AccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
// Test the "Create" and "Read" implementations with only the minimum amount of attributes being set.
|
||||
{
|
||||
Config: fmt.Sprintf(
|
||||
`
|
||||
resource "proxmox_virtual_environment_hardware_mapping_dir" "test" {
|
||||
name = "%s"
|
||||
map = [
|
||||
{
|
||||
node = "%s"
|
||||
path = "%s"
|
||||
},
|
||||
]
|
||||
}
|
||||
`,
|
||||
data.Names[0],
|
||||
te.NodeName,
|
||||
data.MapPathsDir[0],
|
||||
),
|
||||
ConfigStateChecks: []statecheck.StateCheck{
|
||||
// Optional attributes should all be unset.
|
||||
statecheck.ExpectKnownValue(accTestHardwareMappingNameDir,
|
||||
tfjsonpath.New("comment"),
|
||||
knownvalue.Null()),
|
||||
},
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttrSet(accTestHardwareMappingNameDir, "id"),
|
||||
resource.TestCheckTypeSetElemNestedAttrs(
|
||||
accTestHardwareMappingNameDir, "map.*", map[string]string{
|
||||
"node": te.NodeName,
|
||||
"path": data.MapPathsDir[0],
|
||||
},
|
||||
),
|
||||
resource.TestCheckResourceAttr(accTestHardwareMappingNameDir, "name", data.Names[0]),
|
||||
),
|
||||
},
|
||||
|
||||
// Test the "Update" implementation by setting all previously undefined attributes.
|
||||
{
|
||||
Config: fmt.Sprintf(
|
||||
`
|
||||
resource "proxmox_virtual_environment_hardware_mapping_dir" "test" {
|
||||
comment = "%s"
|
||||
name = "%s"
|
||||
map = [
|
||||
{
|
||||
node = "%s"
|
||||
path = "%s"
|
||||
},
|
||||
]
|
||||
}
|
||||
`,
|
||||
data.Comments[0],
|
||||
data.Names[0],
|
||||
te.NodeName,
|
||||
data.MapPathsDir[0],
|
||||
),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(accTestHardwareMappingNameDir, "comment", data.Comments[0]),
|
||||
resource.TestCheckResourceAttrSet(accTestHardwareMappingNameDir, "id"),
|
||||
resource.TestCheckTypeSetElemNestedAttrs(
|
||||
accTestHardwareMappingNameDir, "map.*", map[string]string{
|
||||
"node": te.NodeName,
|
||||
"path": data.MapPathsDir[0],
|
||||
},
|
||||
),
|
||||
resource.TestCheckResourceAttr(accTestHardwareMappingNameDir, "name", data.Names[0]),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TestAccResourceHardwareMappingDirInvalidInput runs tests for directory mapping resource definitions where all
|
||||
// possible attributes are specified.
|
||||
// Only the "Create" method implementation of the [github.com/hashicorp/terraform-plugin-framework/resource.Resource]
|
||||
// interface is tested in sequential steps.
|
||||
func TestAccResourceHardwareMappingDirInvalidInput(t *testing.T) {
|
||||
data, te := testAccResourceHardwareMappingInit(t)
|
||||
|
||||
resource.Test(
|
||||
t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: te.AccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
// Test the "Create" method implementation where all possible attributes are specified, but an error is expected
|
||||
// when using an invalid device path.
|
||||
{
|
||||
Config: fmt.Sprintf(
|
||||
`
|
||||
resource "proxmox_virtual_environment_hardware_mapping_usb" "test" {
|
||||
comment = "%s"
|
||||
name = "%s"
|
||||
map = [
|
||||
{
|
||||
comment = "%s"
|
||||
id = "%s"
|
||||
node = "%s"
|
||||
# Only valid Linux USB device paths should pass the verification.
|
||||
path = "xyz3:1337foobar"
|
||||
},
|
||||
]
|
||||
}
|
||||
`,
|
||||
data.Comments[0],
|
||||
data.Names[0],
|
||||
data.Comments[1],
|
||||
data.MapDeviceIDs[0],
|
||||
te.NodeName,
|
||||
),
|
||||
ExpectError: regexp.MustCompile(`valid Linux device path for hardware mapping of type "usb"`),
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TestAccResourceHardwareMappingPCIValidInput runs tests for PCI hardware mapping resource definitions with valid input
|
||||
// where all possible attributes are
|
||||
// specified.
|
||||
|
@ -506,6 +506,7 @@ func (p *proxmoxProvider) Resources(_ context.Context) []func() resource.Resourc
|
||||
apt.NewStandardRepositoryResource,
|
||||
ha.NewHAGroupResource,
|
||||
ha.NewHAResourceResource,
|
||||
hardwaremapping.NewDirResource,
|
||||
hardwaremapping.NewPCIResource,
|
||||
hardwaremapping.NewUSBResource,
|
||||
metrics.NewMetricsServerResource,
|
||||
@ -532,6 +533,7 @@ func (p *proxmoxProvider) DataSources(_ context.Context) []func() datasource.Dat
|
||||
ha.NewHAResourceDataSource,
|
||||
ha.NewHAResourcesDataSource,
|
||||
hardwaremapping.NewDataSource,
|
||||
hardwaremapping.NewDirDataSource,
|
||||
hardwaremapping.NewPCIDataSource,
|
||||
hardwaremapping.NewUSBDataSource,
|
||||
metrics.NewMetricsServerDatasource,
|
||||
|
@ -9,9 +9,11 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v7"
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-testing/plancheck"
|
||||
|
||||
@ -22,6 +24,10 @@ func TestAccResourceVM(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
te := InitEnvironment(t)
|
||||
dirName := fmt.Sprintf("dir_%s", gofakeit.Word())
|
||||
te.AddTemplateVars(map[string]interface{}{
|
||||
"DirName": dirName,
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -396,51 +402,50 @@ func TestAccResourceVM(t *testing.T) {
|
||||
),
|
||||
},
|
||||
}},
|
||||
// Depends on #1902
|
||||
// {"create virtiofs block", []resource.TestStep{
|
||||
// {
|
||||
// Config: te.RenderConfig(`
|
||||
// resource "proxmox_virtual_environment_hardware_mapping_dir" "test" {
|
||||
// name = "test"
|
||||
{"create virtiofs block", []resource.TestStep{
|
||||
{
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_hardware_mapping_dir" "test" {
|
||||
name = "{{.DirName}}"
|
||||
|
||||
// map {
|
||||
// node = "{{.NodeName}}"
|
||||
// path = "/mnt"
|
||||
// }
|
||||
// }`, WithRootUser()),
|
||||
// Check: resource.ComposeTestCheckFunc(
|
||||
// ResourceAttributes("proxmox_virtual_environment_hardware_mapping_dir.test", map[string]string{
|
||||
// "name": "test",
|
||||
// "map.0.node": "{{.NodeName}}",
|
||||
// "map.0.path": "/mnt",
|
||||
// }),
|
||||
// ),
|
||||
// },
|
||||
// {
|
||||
// Config: te.RenderConfig(`
|
||||
// resource "proxmox_virtual_environment_vm" "test_vm" {
|
||||
// node_name = "{{.NodeName}}"
|
||||
// started = false
|
||||
map = [{
|
||||
node = "{{.NodeName}}"
|
||||
path = "/mnt"
|
||||
}]
|
||||
}`, WithRootUser()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
ResourceAttributes("proxmox_virtual_environment_hardware_mapping_dir.test", map[string]string{
|
||||
"name": dirName,
|
||||
"map.0.node": te.NodeName,
|
||||
"map.0.path": "/mnt",
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
started = false
|
||||
|
||||
// virtiofs {
|
||||
// mapping = "test"
|
||||
// cache = "always"
|
||||
// direct_io = true
|
||||
// expose_acl = false
|
||||
// expose_xattr = false
|
||||
// }
|
||||
// }`, WithRootUser()),
|
||||
// Check: resource.ComposeTestCheckFunc(
|
||||
// ResourceAttributes("proxmox_virtual_environment_vm.test_vm", map[string]string{
|
||||
// "virtiofs.0.mapping": "test",
|
||||
// "virtiofs.0.cache": "always",
|
||||
// "virtiofs.0.direct_io": "true",
|
||||
// "virtiofs.0.expose_acl": "false",
|
||||
// "virtiofs.0.expose_xattr": "false",
|
||||
// }),
|
||||
// ),
|
||||
// },
|
||||
// }},
|
||||
virtiofs {
|
||||
mapping = "{{.DirName}}"
|
||||
cache = "always"
|
||||
direct_io = true
|
||||
expose_acl = false
|
||||
expose_xattr = false
|
||||
}
|
||||
}`, WithRootUser()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
ResourceAttributes("proxmox_virtual_environment_vm.test_vm", map[string]string{
|
||||
"virtiofs.0.mapping": dirName,
|
||||
"virtiofs.0.cache": "always",
|
||||
"virtiofs.0.direct_io": "true",
|
||||
"virtiofs.0.expose_acl": "false",
|
||||
"virtiofs.0.expose_xattr": "false",
|
||||
}),
|
||||
),
|
||||
},
|
||||
}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
@ -37,6 +37,9 @@ var ErrValueConversion = func(format string, attrs ...any) error {
|
||||
}
|
||||
|
||||
var (
|
||||
// PathDirValueRegEx is the regular expression for a POSIX path.
|
||||
PathDirValueRegEx = regexp.MustCompile(`^/.+$`)
|
||||
|
||||
// PathPCIValueRegEx is the regular expression for a PCI hardware mapping path.
|
||||
PathPCIValueRegEx = regexp.MustCompile(`^[a-f0-9]{4,}:[a-f0-9]{2}:[a-f0-9]{2}(\.[a-f0-9])?$`)
|
||||
|
||||
@ -128,6 +131,8 @@ func (v PathValue) Equal(o attr.Value) bool {
|
||||
// IsProxmoxType checks whether the value match the given hardware mapping type.
|
||||
func (v PathValue) IsProxmoxType(hmType proxmoxtypes.Type) bool {
|
||||
switch hmType {
|
||||
case proxmoxtypes.TypeDir:
|
||||
return PathDirValueRegEx.MatchString(v.ValueString())
|
||||
case proxmoxtypes.TypePCI:
|
||||
return PathPCIValueRegEx.MatchString(v.ValueString())
|
||||
case proxmoxtypes.TypeUSB:
|
||||
|
2
main.go
2
main.go
@ -42,6 +42,7 @@ import (
|
||||
//go:generate cp ./build/docs-gen/data-sources/virtual_environment_datastores.md ./docs/data-sources/
|
||||
//go:generate cp ./build/docs-gen/data-sources/virtual_environment_hagroup.md ./docs/data-sources/
|
||||
//go:generate cp ./build/docs-gen/data-sources/virtual_environment_hagroups.md ./docs/data-sources/
|
||||
//go:generate cp ./build/docs-gen/data-sources/virtual_environment_hardware_mapping_dir.md ./docs/data-sources/
|
||||
//go:generate cp ./build/docs-gen/data-sources/virtual_environment_hardware_mapping_pci.md ./docs/data-sources/
|
||||
//go:generate cp ./build/docs-gen/data-sources/virtual_environment_hardware_mapping_usb.md ./docs/data-sources/
|
||||
//go:generate cp ./build/docs-gen/data-sources/virtual_environment_hardware_mappings.md ./docs/data-sources/
|
||||
@ -58,6 +59,7 @@ import (
|
||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_cluster_options.md ./docs/resources/
|
||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_download_file.md ./docs/resources/
|
||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_hagroup.md ./docs/resources/
|
||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_hardware_mapping_dir.md ./docs/resources/
|
||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_hardware_mapping_pci.md ./docs/resources/
|
||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_hardware_mapping_usb.md ./docs/resources/
|
||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_haresource.md ./docs/resources/
|
||||
|
@ -70,11 +70,11 @@ type GetResponseData struct {
|
||||
type ListResponseData struct {
|
||||
DataBase
|
||||
|
||||
// ChecksPCI might contain relevant diagnostics about incorrect [typesHWM.TypePCI] configurations.
|
||||
// Checks might contain relevant diagnostics about incorrect [typesHWM.TypePCI] configurations.
|
||||
// The name of the node must be passed to the Proxmox VE API call which maps to the "check-node" URL parameter.
|
||||
// Note that the Proxmox VE API, for whatever reason, only returns one error at a time, even though the field is an
|
||||
// array.
|
||||
ChecksPCI []NodeCheckDiag `json:"checks,omitempty"`
|
||||
Checks []NodeCheckDiag `json:"checks,omitempty"`
|
||||
|
||||
// ChecksUSB might contain relevant diagnostics about incorrect [typesHWM.TypeUSB] configurations.
|
||||
// The name of the node must be passed to the Proxmox VE API call which maps to the "check-node" URL parameter.
|
||||
|
@ -116,11 +116,14 @@ func (hm Map) String() string {
|
||||
return fmt.Sprintf("%s%s%s", k, string(attrValueSeparator), v)
|
||||
}
|
||||
attrs := make([]string, 0, attrCountMax)
|
||||
attrs = append(
|
||||
attrs,
|
||||
joinKV(attrNameDeviceID, hm.ID.String()),
|
||||
joinKV(attrNameNode, hm.Node),
|
||||
)
|
||||
|
||||
// ID is optional for directory mappings
|
||||
if hm.ID != "" {
|
||||
attrs = append(attrs, joinKV(attrNameDeviceID, hm.ID.String()))
|
||||
}
|
||||
|
||||
// Node is common among all mappings
|
||||
attrs = append(attrs, joinKV(attrNameNode, hm.Node))
|
||||
|
||||
if hm.Path != nil {
|
||||
attrs = append(attrs, joinKV(attrNamePath, *hm.Path))
|
||||
|
@ -12,11 +12,15 @@ import (
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
// TypeDir is an identifier for a directory mapping type.
|
||||
// Do not modify this package-global variable as it acts as a safer variant compared to "iota" based constants!
|
||||
TypeDir = Type{"dir"}
|
||||
|
||||
// TypePCI is an identifier for a PCI hardware mapping type.
|
||||
// Do not modify this package-global variable as it acts as a safer variant compared to "iota" based constants!
|
||||
TypePCI = Type{"pci"}
|
||||
|
||||
// TypeUSB is an identifier for a PCI hardware mapping type.
|
||||
// TypeUSB is an identifier for a USB hardware mapping type.
|
||||
// Do not modify this package-global variable as it acts as a safer variant compared to "iota" based constants!
|
||||
TypeUSB = Type{"usb"}
|
||||
)
|
||||
@ -81,6 +85,8 @@ func (t *Type) UnmarshalJSON(b []byte) error {
|
||||
// An error is returned if the input string does not match any known type.
|
||||
func ParseType(input string) (Type, error) {
|
||||
switch input {
|
||||
case TypeDir.String():
|
||||
return TypeDir, nil
|
||||
case TypePCI.String():
|
||||
return TypePCI, nil
|
||||
case TypeUSB.String():
|
||||
|
Loading…
Reference in New Issue
Block a user