mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-30 02:31:10 +00:00
feat(lxc): add support for device_passthrough
config option (#1706)
Signed-off-by: Tarasa24 <tarasa24@tarasa24.dev>
This commit is contained in:
parent
c57dc78119
commit
7cbd1b46fa
@ -170,6 +170,13 @@ output "ubuntu_container_public_key" {
|
||||
Can be specified with a unit suffix (e.g. `10G`).
|
||||
- `volume` (Required) Volume, device or directory to mount into the
|
||||
container.
|
||||
- `device_passthrough` - (Optional) Device to pass through to the container (multiple blocks supported).
|
||||
- `deny_write` - (Optional) Deny the container to write to the device (defaults to `false`).
|
||||
- `gid` - (Optional) Group ID to be assigned to the device node.
|
||||
- `mode` - (Optional) Access mode to be set on the device node. Must be a
|
||||
4-digit octal number.
|
||||
- `path` - (Required) Device to pass through to the container (e.g. `/dev/sda`).
|
||||
- `uid` - (Optional) User ID to be assigned to the device node.
|
||||
- `network_interface` - (Optional) A network interface (multiple blocks
|
||||
supported).
|
||||
- `bridge` - (Optional) The name of the network bridge (defaults
|
||||
|
@ -75,6 +75,9 @@ func TestAccResourceContainer(t *testing.T) {
|
||||
size = "4G"
|
||||
path = "mnt/local"
|
||||
}
|
||||
device_passthrough {
|
||||
path = "/dev/zero"
|
||||
}
|
||||
description = <<-EOT
|
||||
my
|
||||
description
|
||||
@ -199,6 +202,9 @@ func TestAccResourceContainer(t *testing.T) {
|
||||
size = "4G"
|
||||
path = "mnt/local"
|
||||
}
|
||||
device_passthrough {
|
||||
path = "/dev/zero"
|
||||
}
|
||||
initialization {
|
||||
hostname = "test"
|
||||
ip_config {
|
||||
|
@ -31,45 +31,46 @@ type CloneRequestBody struct {
|
||||
|
||||
// CreateRequestBody contains the data for a user create request.
|
||||
type CreateRequestBody struct {
|
||||
BandwidthLimit *float64 `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
|
||||
ConsoleEnabled *types.CustomBool `json:"console,omitempty" url:"console,omitempty,int"`
|
||||
ConsoleMode *string `json:"cmode,omitempty" url:"cmode,omitempty"`
|
||||
CPUArchitecture *string `json:"arch,omitempty" url:"arch,omitempty"`
|
||||
CPUCores *int `json:"cores,omitempty" url:"cores,omitempty"`
|
||||
CPULimit *int `json:"cpulimit,omitempty" url:"cpulimit,omitempty"`
|
||||
CPUUnits *int `json:"cpuunits,omitempty" url:"cpuunits,omitempty"`
|
||||
DatastoreID *string `json:"storage,omitempty" url:"storage,omitempty"`
|
||||
DedicatedMemory *int `json:"memory,omitempty" url:"memory,omitempty"`
|
||||
Delete []string `json:"delete,omitempty" url:"delete,omitempty"`
|
||||
Description *string `json:"description,omitempty" url:"description,omitempty"`
|
||||
DNSDomain *string `json:"searchdomain,omitempty" url:"searchdomain,omitempty"`
|
||||
DNSServer *string `json:"nameserver,omitempty" url:"nameserver,omitempty"`
|
||||
Features *CustomFeatures `json:"features,omitempty" url:"features,omitempty"`
|
||||
Force *types.CustomBool `json:"force,omitempty" url:"force,omitempty,int"`
|
||||
HookScript *string `json:"hookscript,omitempty" url:"hookscript,omitempty"`
|
||||
Hostname *string `json:"hostname,omitempty" url:"hostname,omitempty"`
|
||||
IgnoreUnpackErrors *types.CustomBool `json:"ignore-unpack-errors,omitempty" url:"force,omitempty,int"`
|
||||
Lock *string `json:"lock,omitempty" url:"lock,omitempty,int"`
|
||||
MountPoints CustomMountPointArray `json:"mp,omitempty" url:"mp,omitempty,numbered"`
|
||||
NetworkInterfaces CustomNetworkInterfaceArray `json:"net,omitempty" url:"net,omitempty,numbered"`
|
||||
OSTemplateFileVolume *string `json:"ostemplate,omitempty" url:"ostemplate,omitempty"`
|
||||
OSType *string `json:"ostype,omitempty" url:"ostype,omitempty"`
|
||||
Password *string `json:"password,omitempty" url:"password,omitempty"`
|
||||
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
|
||||
Protection *types.CustomBool `json:"protection,omitempty" url:"protection,omitempty,int"`
|
||||
Restore *types.CustomBool `json:"restore,omitempty" url:"restore,omitempty,int"`
|
||||
RootFS *CustomRootFS `json:"rootfs,omitempty" url:"rootfs,omitempty"`
|
||||
SSHKeys *CustomSSHKeys `json:"ssh-public-keys,omitempty" url:"ssh-public-keys,omitempty"`
|
||||
Start *types.CustomBool `json:"start,omitempty" url:"start,omitempty,int"`
|
||||
StartOnBoot *types.CustomBool `json:"onboot,omitempty" url:"onboot,omitempty,int"`
|
||||
StartupBehavior *CustomStartupBehavior `json:"startup,omitempty" url:"startup,omitempty"`
|
||||
Swap *int `json:"swap,omitempty" url:"swap,omitempty"`
|
||||
Tags *string `json:"tags,omitempty" url:"tags,omitempty"`
|
||||
Template *types.CustomBool `json:"template,omitempty" url:"template,omitempty,int"`
|
||||
TTY *int `json:"tty,omitempty" url:"tty,omitempty"`
|
||||
Unique *types.CustomBool `json:"unique,omitempty" url:"unique,omitempty,int"`
|
||||
Unprivileged *types.CustomBool `json:"unprivileged,omitempty" url:"unprivileged,omitempty,int"`
|
||||
VMID *int `json:"vmid,omitempty" url:"vmid,omitempty"`
|
||||
BandwidthLimit *float64 `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
|
||||
ConsoleEnabled *types.CustomBool `json:"console,omitempty" url:"console,omitempty,int"`
|
||||
ConsoleMode *string `json:"cmode,omitempty" url:"cmode,omitempty"`
|
||||
CPUArchitecture *string `json:"arch,omitempty" url:"arch,omitempty"`
|
||||
CPUCores *int `json:"cores,omitempty" url:"cores,omitempty"`
|
||||
CPULimit *int `json:"cpulimit,omitempty" url:"cpulimit,omitempty"`
|
||||
CPUUnits *int `json:"cpuunits,omitempty" url:"cpuunits,omitempty"`
|
||||
DatastoreID *string `json:"storage,omitempty" url:"storage,omitempty"`
|
||||
DedicatedMemory *int `json:"memory,omitempty" url:"memory,omitempty"`
|
||||
Delete []string `json:"delete,omitempty" url:"delete,omitempty"`
|
||||
Description *string `json:"description,omitempty" url:"description,omitempty"`
|
||||
DNSDomain *string `json:"searchdomain,omitempty" url:"searchdomain,omitempty"`
|
||||
DNSServer *string `json:"nameserver,omitempty" url:"nameserver,omitempty"`
|
||||
Features *CustomFeatures `json:"features,omitempty" url:"features,omitempty"`
|
||||
Force *types.CustomBool `json:"force,omitempty" url:"force,omitempty,int"`
|
||||
HookScript *string `json:"hookscript,omitempty" url:"hookscript,omitempty"`
|
||||
Hostname *string `json:"hostname,omitempty" url:"hostname,omitempty"`
|
||||
IgnoreUnpackErrors *types.CustomBool `json:"ignore-unpack-errors,omitempty" url:"force,omitempty,int"`
|
||||
Lock *string `json:"lock,omitempty" url:"lock,omitempty,int"`
|
||||
MountPoints CustomMountPointArray `json:"mp,omitempty" url:"mp,omitempty,numbered"`
|
||||
DevicePassthrough CustomDevicePassthroughArray `json:"dev,omitempty" url:"dev,omitempty,numbered"`
|
||||
NetworkInterfaces CustomNetworkInterfaceArray `json:"net,omitempty" url:"net,omitempty,numbered"`
|
||||
OSTemplateFileVolume *string `json:"ostemplate,omitempty" url:"ostemplate,omitempty"`
|
||||
OSType *string `json:"ostype,omitempty" url:"ostype,omitempty"`
|
||||
Password *string `json:"password,omitempty" url:"password,omitempty"`
|
||||
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
|
||||
Protection *types.CustomBool `json:"protection,omitempty" url:"protection,omitempty,int"`
|
||||
Restore *types.CustomBool `json:"restore,omitempty" url:"restore,omitempty,int"`
|
||||
RootFS *CustomRootFS `json:"rootfs,omitempty" url:"rootfs,omitempty"`
|
||||
SSHKeys *CustomSSHKeys `json:"ssh-public-keys,omitempty" url:"ssh-public-keys,omitempty"`
|
||||
Start *types.CustomBool `json:"start,omitempty" url:"start,omitempty,int"`
|
||||
StartOnBoot *types.CustomBool `json:"onboot,omitempty" url:"onboot,omitempty,int"`
|
||||
StartupBehavior *CustomStartupBehavior `json:"startup,omitempty" url:"startup,omitempty"`
|
||||
Swap *int `json:"swap,omitempty" url:"swap,omitempty"`
|
||||
Tags *string `json:"tags,omitempty" url:"tags,omitempty"`
|
||||
Template *types.CustomBool `json:"template,omitempty" url:"template,omitempty,int"`
|
||||
TTY *int `json:"tty,omitempty" url:"tty,omitempty"`
|
||||
Unique *types.CustomBool `json:"unique,omitempty" url:"unique,omitempty,int"`
|
||||
Unprivileged *types.CustomBool `json:"unprivileged,omitempty" url:"unprivileged,omitempty,int"`
|
||||
VMID *int `json:"vmid,omitempty" url:"vmid,omitempty"`
|
||||
}
|
||||
|
||||
// CustomFeatures contains the values for the "features" property.
|
||||
@ -116,6 +117,18 @@ type CustomNetworkInterface struct {
|
||||
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
||||
}
|
||||
|
||||
// CustomDevicePassthroughArray is an array of CustomDevicePassthrough.
|
||||
type CustomDevicePassthroughArray []CustomDevicePassthrough
|
||||
|
||||
// CustomDevicePassthrough contains the values for the "dev[n]" properties.
|
||||
type CustomDevicePassthrough struct {
|
||||
DenyWrite *types.CustomBool `json:"deny-write,omitempty" url:"deny-write,omitempty,int"`
|
||||
Path string `json:"path" url:"path"`
|
||||
UID *int `json:"uid,omitempty" url:"uid,omitempty"`
|
||||
GID *int `json:"gid,omitempty" url:"gid,omitempty"`
|
||||
Mode *string `json:"mode,omitempty" url:"mode,omitempty"`
|
||||
}
|
||||
|
||||
// CustomNetworkInterfaceArray is an array of CustomNetworkInterface.
|
||||
type CustomNetworkInterfaceArray []CustomNetworkInterface
|
||||
|
||||
@ -153,48 +166,56 @@ type GetResponseBody struct {
|
||||
|
||||
// GetResponseData contains the data from a user get response.
|
||||
type GetResponseData struct {
|
||||
ConsoleEnabled *types.CustomBool `json:"console,omitempty"`
|
||||
ConsoleMode *string `json:"cmode,omitempty"`
|
||||
CPUArchitecture *string `json:"arch,omitempty"`
|
||||
CPUCores *int `json:"cores,omitempty"`
|
||||
CPULimit *types.CustomInt `json:"cpulimit,omitempty"`
|
||||
CPUUnits *int `json:"cpuunits,omitempty"`
|
||||
DedicatedMemory *int `json:"memory,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Digest string `json:"digest"`
|
||||
DNSDomain *string `json:"searchdomain,omitempty"`
|
||||
DNSServer *string `json:"nameserver,omitempty"`
|
||||
Features *CustomFeatures `json:"features,omitempty"`
|
||||
HookScript *string `json:"hookscript,omitempty"`
|
||||
Hostname *string `json:"hostname,omitempty"`
|
||||
Lock *types.CustomBool `json:"lock,omitempty"`
|
||||
LXCConfiguration *[][2]string `json:"lxc,omitempty"`
|
||||
MountPoint0 *CustomMountPoint `json:"mp0,omitempty"`
|
||||
MountPoint1 *CustomMountPoint `json:"mp1,omitempty"`
|
||||
MountPoint2 *CustomMountPoint `json:"mp2,omitempty"`
|
||||
MountPoint3 *CustomMountPoint `json:"mp3,omitempty"`
|
||||
MountPoint4 *CustomMountPoint `json:"mp4,omitempty"`
|
||||
MountPoint5 *CustomMountPoint `json:"mp5,omitempty"`
|
||||
MountPoint6 *CustomMountPoint `json:"mp6,omitempty"`
|
||||
MountPoint7 *CustomMountPoint `json:"mp7,omitempty"`
|
||||
NetworkInterface0 *CustomNetworkInterface `json:"net0,omitempty"`
|
||||
NetworkInterface1 *CustomNetworkInterface `json:"net1,omitempty"`
|
||||
NetworkInterface2 *CustomNetworkInterface `json:"net2,omitempty"`
|
||||
NetworkInterface3 *CustomNetworkInterface `json:"net3,omitempty"`
|
||||
NetworkInterface4 *CustomNetworkInterface `json:"net4,omitempty"`
|
||||
NetworkInterface5 *CustomNetworkInterface `json:"net5,omitempty"`
|
||||
NetworkInterface6 *CustomNetworkInterface `json:"net6,omitempty"`
|
||||
NetworkInterface7 *CustomNetworkInterface `json:"net7,omitempty"`
|
||||
OSType *string `json:"ostype,omitempty"`
|
||||
Protection *types.CustomBool `json:"protection,omitempty"`
|
||||
RootFS *CustomRootFS `json:"rootfs,omitempty"`
|
||||
StartOnBoot *types.CustomBool `json:"onboot,omitempty"`
|
||||
StartupBehavior *CustomStartupBehavior `json:"startup,omitempty"`
|
||||
Swap *int `json:"swap,omitempty"`
|
||||
Tags *string `json:"tags,omitempty"`
|
||||
Template *types.CustomBool `json:"template,omitempty"`
|
||||
TTY *int `json:"tty,omitempty"`
|
||||
Unprivileged *types.CustomBool `json:"unprivileged,omitempty"`
|
||||
ConsoleEnabled *types.CustomBool `json:"console,omitempty"`
|
||||
ConsoleMode *string `json:"cmode,omitempty"`
|
||||
CPUArchitecture *string `json:"arch,omitempty"`
|
||||
CPUCores *int `json:"cores,omitempty"`
|
||||
CPULimit *types.CustomInt `json:"cpulimit,omitempty"`
|
||||
CPUUnits *int `json:"cpuunits,omitempty"`
|
||||
DedicatedMemory *int `json:"memory,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Digest string `json:"digest"`
|
||||
DNSDomain *string `json:"searchdomain,omitempty"`
|
||||
DNSServer *string `json:"nameserver,omitempty"`
|
||||
Features *CustomFeatures `json:"features,omitempty"`
|
||||
HookScript *string `json:"hookscript,omitempty"`
|
||||
Hostname *string `json:"hostname,omitempty"`
|
||||
Lock *types.CustomBool `json:"lock,omitempty"`
|
||||
LXCConfiguration *[][2]string `json:"lxc,omitempty"`
|
||||
DevicePassthrough0 *CustomDevicePassthrough `json:"dev0,omitempty"`
|
||||
DevicePassthrough1 *CustomDevicePassthrough `json:"dev1,omitempty"`
|
||||
DevicePassthrough2 *CustomDevicePassthrough `json:"dev2,omitempty"`
|
||||
DevicePassthrough3 *CustomDevicePassthrough `json:"dev3,omitempty"`
|
||||
DevicePassthrough4 *CustomDevicePassthrough `json:"dev4,omitempty"`
|
||||
DevicePassthrough5 *CustomDevicePassthrough `json:"dev5,omitempty"`
|
||||
DevicePassthrough6 *CustomDevicePassthrough `json:"dev6,omitempty"`
|
||||
DevicePassthrough7 *CustomDevicePassthrough `json:"dev7,omitempty"`
|
||||
MountPoint0 *CustomMountPoint `json:"mp0,omitempty"`
|
||||
MountPoint1 *CustomMountPoint `json:"mp1,omitempty"`
|
||||
MountPoint2 *CustomMountPoint `json:"mp2,omitempty"`
|
||||
MountPoint3 *CustomMountPoint `json:"mp3,omitempty"`
|
||||
MountPoint4 *CustomMountPoint `json:"mp4,omitempty"`
|
||||
MountPoint5 *CustomMountPoint `json:"mp5,omitempty"`
|
||||
MountPoint6 *CustomMountPoint `json:"mp6,omitempty"`
|
||||
MountPoint7 *CustomMountPoint `json:"mp7,omitempty"`
|
||||
NetworkInterface0 *CustomNetworkInterface `json:"net0,omitempty"`
|
||||
NetworkInterface1 *CustomNetworkInterface `json:"net1,omitempty"`
|
||||
NetworkInterface2 *CustomNetworkInterface `json:"net2,omitempty"`
|
||||
NetworkInterface3 *CustomNetworkInterface `json:"net3,omitempty"`
|
||||
NetworkInterface4 *CustomNetworkInterface `json:"net4,omitempty"`
|
||||
NetworkInterface5 *CustomNetworkInterface `json:"net5,omitempty"`
|
||||
NetworkInterface6 *CustomNetworkInterface `json:"net6,omitempty"`
|
||||
NetworkInterface7 *CustomNetworkInterface `json:"net7,omitempty"`
|
||||
OSType *string `json:"ostype,omitempty"`
|
||||
Protection *types.CustomBool `json:"protection,omitempty"`
|
||||
RootFS *CustomRootFS `json:"rootfs,omitempty"`
|
||||
StartOnBoot *types.CustomBool `json:"onboot,omitempty"`
|
||||
StartupBehavior *CustomStartupBehavior `json:"startup,omitempty"`
|
||||
Swap *int `json:"swap,omitempty"`
|
||||
Tags *string `json:"tags,omitempty"`
|
||||
Template *types.CustomBool `json:"template,omitempty"`
|
||||
TTY *int `json:"tty,omitempty"`
|
||||
Unprivileged *types.CustomBool `json:"unprivileged,omitempty"`
|
||||
}
|
||||
|
||||
// GetStatusResponseBody contains the body from a container get status response.
|
||||
@ -276,6 +297,55 @@ func (r *CustomFeatures) EncodeValues(key string, v *url.Values) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomDevicePassthrough struct to a URL value.
|
||||
func (r *CustomDevicePassthrough) EncodeValues(key string, v *url.Values) error {
|
||||
var values []string
|
||||
|
||||
if r.DenyWrite != nil {
|
||||
if *r.DenyWrite {
|
||||
values = append(values, "deny-write=1")
|
||||
} else {
|
||||
values = append(values, "deny-write=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.Path != "" {
|
||||
values = append(values, fmt.Sprintf("path=%s", r.Path))
|
||||
}
|
||||
|
||||
if r.UID != nil {
|
||||
values = append(values, fmt.Sprintf("uid=%d", *r.UID))
|
||||
}
|
||||
|
||||
if r.GID != nil {
|
||||
values = append(values, fmt.Sprintf("gid=%d", *r.GID))
|
||||
}
|
||||
|
||||
if r.Mode != nil && *r.Mode != "" {
|
||||
values = append(values, fmt.Sprintf("mode=%s", *r.Mode))
|
||||
}
|
||||
|
||||
if len(values) > 0 {
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomDevicePassthroughArray array to multiple URL values.
|
||||
func (r CustomDevicePassthroughArray) EncodeValues(
|
||||
key string,
|
||||
v *url.Values,
|
||||
) error {
|
||||
for i, d := range r {
|
||||
if err := d.EncodeValues(fmt.Sprintf("%s%d", key, i), v); err != nil {
|
||||
return fmt.Errorf("failed to encode CustomDevicePassthroughArray: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomMountPoint struct to a URL value.
|
||||
func (r *CustomMountPoint) EncodeValues(key string, v *url.Values) error {
|
||||
var values []string
|
||||
@ -587,6 +657,56 @@ func (r *CustomFeatures) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomDevicePassthrough string to an object.
|
||||
func (r *CustomDevicePassthrough) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
err := json.Unmarshal(b, &s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to unmarshal CustomDevicePassthrough: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
var path string
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 1 {
|
||||
path = v[0]
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "deny-write":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.DenyWrite = &bv
|
||||
case "path":
|
||||
path = v[1]
|
||||
case "uid":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to unmarshal 'uid': %w", err)
|
||||
}
|
||||
|
||||
r.UID = &iv
|
||||
case "gid":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to unmarshal 'gid': %w", err)
|
||||
}
|
||||
|
||||
r.GID = &iv
|
||||
case "mode":
|
||||
r.Mode = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.Path = path
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomMountPoint string to an object.
|
||||
func (r *CustomMountPoint) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -140,6 +141,12 @@ const (
|
||||
mkMountPointShared = "shared"
|
||||
mkMountPointSize = "size"
|
||||
mkMountPointVolume = "volume"
|
||||
mkDevicePassthroughDenyWrite = "deny_write"
|
||||
mkDevicePassthrough = "device_passthrough" // #nosec G101
|
||||
mkDevicePassthroughPath = "path"
|
||||
mkDevicePassthroughUID = "uid"
|
||||
mkDevicePassthroughGID = "gid"
|
||||
mkDevicePassthroughMode = "mode"
|
||||
mkNetworkInterface = "network_interface"
|
||||
mkNetworkInterfaceBridge = "bridge"
|
||||
mkNetworkInterfaceEnabled = "enabled"
|
||||
@ -680,6 +687,49 @@ func Container() *schema.Resource {
|
||||
MaxItems: 8,
|
||||
MinItems: 0,
|
||||
},
|
||||
mkDevicePassthrough: {
|
||||
Type: schema.TypeList,
|
||||
Description: "Device to pass through to the container",
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
mkDevicePassthroughDenyWrite: {
|
||||
Type: schema.TypeBool,
|
||||
Description: "Deny the container to write to the device",
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
mkDevicePassthroughGID: {
|
||||
Type: schema.TypeInt,
|
||||
Description: "Group ID to be assigned to the device node",
|
||||
Optional: true,
|
||||
ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(0)),
|
||||
},
|
||||
mkDevicePassthroughMode: {
|
||||
Type: schema.TypeString,
|
||||
Description: "Access mode to be set on the device node (e.g. 0666)",
|
||||
Optional: true,
|
||||
ValidateDiagFunc: validation.ToDiagFunc(validation.StringMatch(
|
||||
regexp.MustCompile(`0[0-7]{3}`), "Octal access mode",
|
||||
)),
|
||||
},
|
||||
mkDevicePassthroughPath: {
|
||||
Type: schema.TypeString,
|
||||
Description: "Device to pass through to the container",
|
||||
Required: true,
|
||||
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotEmpty),
|
||||
},
|
||||
mkDevicePassthroughUID: {
|
||||
Type: schema.TypeInt,
|
||||
Description: "Device UID in the container",
|
||||
Optional: true,
|
||||
ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(0)),
|
||||
},
|
||||
},
|
||||
},
|
||||
MaxItems: 8,
|
||||
MinItems: 0,
|
||||
},
|
||||
mkNetworkInterface: {
|
||||
Type: schema.TypeList,
|
||||
Description: "The network interfaces",
|
||||
@ -1209,6 +1259,36 @@ func containerCreateClone(ctx context.Context, d *schema.ResourceData, m interfa
|
||||
updateBody.Swap = &memorySwap
|
||||
}
|
||||
|
||||
devicePassthrough := d.Get(mkDevicePassthrough).([]interface{})
|
||||
|
||||
devicePassthroughArray := make(
|
||||
containers.CustomDevicePassthroughArray,
|
||||
len(devicePassthrough),
|
||||
)
|
||||
|
||||
for di, dv := range devicePassthrough {
|
||||
devicePassthroughMap := dv.(map[string]interface{})
|
||||
devicePassthroughObject := containers.CustomDevicePassthrough{}
|
||||
|
||||
denyWrite := types.CustomBool(
|
||||
devicePassthroughMap[mkDevicePassthroughDenyWrite].(bool),
|
||||
)
|
||||
gid := devicePassthroughMap[mkDevicePassthroughGID].(int)
|
||||
mode := devicePassthroughMap[mkDevicePassthroughMode].(string)
|
||||
path := devicePassthroughMap[mkDevicePassthroughPath].(string)
|
||||
uid := devicePassthroughMap[mkDevicePassthroughUID].(int)
|
||||
|
||||
devicePassthroughObject.DenyWrite = &denyWrite
|
||||
devicePassthroughObject.GID = &gid
|
||||
devicePassthroughObject.Mode = &mode
|
||||
devicePassthroughObject.Path = path
|
||||
devicePassthroughObject.UID = &uid
|
||||
|
||||
devicePassthroughArray[di] = devicePassthroughObject
|
||||
}
|
||||
|
||||
updateBody.DevicePassthrough = devicePassthroughArray
|
||||
|
||||
networkInterface := d.Get(mkNetworkInterface).([]interface{})
|
||||
|
||||
if len(networkInterface) == 0 {
|
||||
@ -2232,6 +2312,65 @@ func containerRead(ctx context.Context, d *schema.ResourceData, m interface{}) d
|
||||
initialization[mkInitializationHostname] = ""
|
||||
}
|
||||
|
||||
devicePassthroughArray := []*containers.CustomDevicePassthrough{
|
||||
containerConfig.DevicePassthrough0,
|
||||
containerConfig.DevicePassthrough1,
|
||||
containerConfig.DevicePassthrough2,
|
||||
containerConfig.DevicePassthrough3,
|
||||
containerConfig.DevicePassthrough4,
|
||||
containerConfig.DevicePassthrough5,
|
||||
containerConfig.DevicePassthrough6,
|
||||
containerConfig.DevicePassthrough7,
|
||||
}
|
||||
|
||||
devicePassthroughList := make([]interface{}, 0, len(devicePassthroughArray))
|
||||
|
||||
for _, dp := range devicePassthroughArray {
|
||||
if dp == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
devicePassthrough := map[string]interface{}{}
|
||||
|
||||
if dp.DenyWrite != nil {
|
||||
devicePassthrough[mkDevicePassthroughDenyWrite] = *dp.DenyWrite
|
||||
} else {
|
||||
devicePassthrough[mkDevicePassthroughDenyWrite] = false
|
||||
}
|
||||
|
||||
if dp.GID != nil {
|
||||
devicePassthrough[mkDevicePassthroughGID] = *dp.GID
|
||||
} else {
|
||||
devicePassthrough[mkDevicePassthroughGID] = 0
|
||||
}
|
||||
|
||||
if dp.Mode != nil {
|
||||
devicePassthrough[mkDevicePassthroughMode] = *dp.Mode
|
||||
} else {
|
||||
devicePassthrough[mkDevicePassthroughMode] = ""
|
||||
}
|
||||
|
||||
devicePassthrough[mkDevicePassthroughPath] = dp.Path
|
||||
|
||||
if dp.UID != nil {
|
||||
devicePassthrough[mkDevicePassthroughUID] = *dp.UID
|
||||
} else {
|
||||
devicePassthrough[mkDevicePassthroughUID] = 0
|
||||
}
|
||||
|
||||
devicePassthroughList = append(devicePassthroughList, devicePassthrough)
|
||||
}
|
||||
|
||||
if len(clone) > 0 {
|
||||
if len(devicePassthroughList) > 0 {
|
||||
err := d.Set(mkDevicePassthrough, devicePassthroughList)
|
||||
diags = append(diags, diag.FromErr(err)...)
|
||||
}
|
||||
} else if len(devicePassthroughList) > 0 {
|
||||
err := d.Set(mkDevicePassthrough, devicePassthroughList)
|
||||
diags = append(diags, diag.FromErr(err)...)
|
||||
}
|
||||
|
||||
mountPointArray := []*containers.CustomMountPoint{
|
||||
containerConfig.MountPoint0,
|
||||
containerConfig.MountPoint1,
|
||||
@ -2860,6 +2999,40 @@ func containerUpdate(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
rebootRequired = true
|
||||
}
|
||||
|
||||
// Prepare the new device passthrough configuration.
|
||||
if d.HasChange(mkDevicePassthrough) {
|
||||
_, newDevicePassthrough := d.GetChange(mkDevicePassthrough)
|
||||
|
||||
devicePassthrough := newDevicePassthrough.([]interface{})
|
||||
devicePassthroughArray := make(
|
||||
containers.CustomDevicePassthroughArray,
|
||||
len(devicePassthrough),
|
||||
)
|
||||
|
||||
for i, dp := range devicePassthrough {
|
||||
devicePassthroughMap := dp.(map[string]interface{})
|
||||
devicePassthroughObject := containers.CustomDevicePassthrough{}
|
||||
|
||||
denyWrite := types.CustomBool(devicePassthroughMap[mkDevicePassthroughDenyWrite].(bool))
|
||||
gid := devicePassthroughMap[mkDevicePassthroughGID].(int)
|
||||
mode := devicePassthroughMap[mkDevicePassthroughMode].(string)
|
||||
path := devicePassthroughMap[mkDevicePassthroughPath].(string)
|
||||
uid := devicePassthroughMap[mkDevicePassthroughUID].(int)
|
||||
|
||||
devicePassthroughObject.DenyWrite = &denyWrite
|
||||
devicePassthroughObject.GID = &gid
|
||||
devicePassthroughObject.Mode = &mode
|
||||
devicePassthroughObject.Path = path
|
||||
devicePassthroughObject.UID = &uid
|
||||
|
||||
devicePassthroughArray[i] = devicePassthroughObject
|
||||
}
|
||||
|
||||
updateBody.DevicePassthrough = devicePassthroughArray
|
||||
|
||||
rebootRequired = true
|
||||
}
|
||||
|
||||
// Prepare the new mount point configuration.
|
||||
if d.HasChange(mkMountPoint) {
|
||||
_, newMountPoints := d.GetChange(mkMountPoint)
|
||||
|
@ -41,6 +41,7 @@ func TestContainerSchema(t *testing.T) {
|
||||
mkInitialization,
|
||||
mkHookScriptFileID,
|
||||
mkMemory,
|
||||
mkDevicePassthrough,
|
||||
mkMountPoint,
|
||||
mkOperatingSystem,
|
||||
mkPoolID,
|
||||
@ -55,23 +56,24 @@ func TestContainerSchema(t *testing.T) {
|
||||
})
|
||||
|
||||
test.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
mkCPU: schema.TypeList,
|
||||
mkDescription: schema.TypeString,
|
||||
mkDisk: schema.TypeList,
|
||||
mkInitialization: schema.TypeList,
|
||||
mkHookScriptFileID: schema.TypeString,
|
||||
mkMemory: schema.TypeList,
|
||||
mkMountPoint: schema.TypeList,
|
||||
mkOperatingSystem: schema.TypeList,
|
||||
mkPoolID: schema.TypeString,
|
||||
mkProtection: schema.TypeBool,
|
||||
mkStarted: schema.TypeBool,
|
||||
mkTags: schema.TypeList,
|
||||
mkTemplate: schema.TypeBool,
|
||||
mkUnprivileged: schema.TypeBool,
|
||||
mkStartOnBoot: schema.TypeBool,
|
||||
mkFeatures: schema.TypeList,
|
||||
mkVMID: schema.TypeInt,
|
||||
mkCPU: schema.TypeList,
|
||||
mkDescription: schema.TypeString,
|
||||
mkDisk: schema.TypeList,
|
||||
mkInitialization: schema.TypeList,
|
||||
mkHookScriptFileID: schema.TypeString,
|
||||
mkMemory: schema.TypeList,
|
||||
mkDevicePassthrough: schema.TypeList,
|
||||
mkMountPoint: schema.TypeList,
|
||||
mkOperatingSystem: schema.TypeList,
|
||||
mkPoolID: schema.TypeString,
|
||||
mkProtection: schema.TypeBool,
|
||||
mkStarted: schema.TypeBool,
|
||||
mkTags: schema.TypeList,
|
||||
mkTemplate: schema.TypeBool,
|
||||
mkUnprivileged: schema.TypeBool,
|
||||
mkStartOnBoot: schema.TypeBool,
|
||||
mkFeatures: schema.TypeList,
|
||||
mkVMID: schema.TypeInt,
|
||||
})
|
||||
|
||||
cloneSchema := test.AssertNestedSchemaExistence(t, s, mkClone)
|
||||
@ -243,6 +245,27 @@ func TestContainerSchema(t *testing.T) {
|
||||
mkMemorySwap: schema.TypeInt,
|
||||
})
|
||||
|
||||
devicePassthroughSchema := test.AssertNestedSchemaExistence(t, s, mkDevicePassthrough)
|
||||
|
||||
test.AssertRequiredArguments(t, devicePassthroughSchema, []string{
|
||||
mkDevicePassthroughPath,
|
||||
})
|
||||
|
||||
test.AssertOptionalArguments(t, devicePassthroughSchema, []string{
|
||||
mkDevicePassthroughDenyWrite,
|
||||
mkDevicePassthroughGID,
|
||||
mkDevicePassthroughMode,
|
||||
mkDevicePassthroughUID,
|
||||
})
|
||||
|
||||
test.AssertValueTypes(t, devicePassthroughSchema, map[string]schema.ValueType{
|
||||
mkDevicePassthroughDenyWrite: schema.TypeBool,
|
||||
mkDevicePassthroughGID: schema.TypeInt,
|
||||
mkDevicePassthroughMode: schema.TypeString,
|
||||
mkDevicePassthroughPath: schema.TypeString,
|
||||
mkDevicePassthroughUID: schema.TypeInt,
|
||||
})
|
||||
|
||||
mountPointSchema := test.AssertNestedSchemaExistence(t, s, mkMountPoint)
|
||||
|
||||
test.AssertOptionalArguments(t, mountPointSchema, []string{
|
||||
|
Loading…
Reference in New Issue
Block a user