diff --git a/docs/resources/virtual_environment_container.md b/docs/resources/virtual_environment_container.md index 5e0d578d..bbd5f5cc 100644 --- a/docs/resources/virtual_environment_container.md +++ b/docs/resources/virtual_environment_container.md @@ -47,8 +47,16 @@ resource "proxmox_virtual_environment_container" "ubuntu_container" { } mount_point { + # bind mount, *requires* root@pam authentication volume = "/mnt/bindmounts/shared" - path = "/shared" + path = "/mnt/shared" + } + + mount_point { + # volume mount, a new volume will be created by PVE + volume = "local-lvm" + size = "10G" + path = "/mnt/volume" } } @@ -155,7 +163,7 @@ output "ubuntu_container_public_key" { - `replicate` (Optional) Will include this volume to a storage replica job. - `shared` (Optional) Mark this non-volume mount point as available on all nodes. - - `size` (Optional) Volume size (only for ZFS storage backed mount points). + - `size` (Optional) Volume size (only for volume mount points). Can be specified with a unit suffix (e.g. `10G`). - `volume` (Required) Volume, device or directory to mount into the container. diff --git a/example/resource_virtual_environment_container.tf b/example/resource_virtual_environment_container.tf index 68b41d88..bc4dd9ba 100644 --- a/example/resource_virtual_environment_container.tf +++ b/example/resource_virtual_environment_container.tf @@ -6,6 +6,13 @@ resource "proxmox_virtual_environment_container" "example_template" { size = 10 } + mount_point { + // volume mount + volume = element(data.proxmox_virtual_environment_datastores.example.datastore_ids, index(data.proxmox_virtual_environment_datastores.example.datastore_ids, "local-lvm")) + size = "4G" + path = "mnt/local" + } + initialization { dns { server = "1.1.1.1" @@ -63,6 +70,7 @@ resource "proxmox_virtual_environment_container" "example" { } mount_point { + // bind mount, requires root@pam volume = "/mnt/bindmounts/shared" path = "/shared" } diff --git a/proxmoxtf/resource/container.go b/proxmoxtf/resource/container.go index f93e0c54..af41d25c 100644 --- a/proxmoxtf/resource/container.go +++ b/proxmoxtf/resource/container.go @@ -51,6 +51,7 @@ const ( dvResourceVirtualEnvironmentContainerMemorySwap = 0 dvResourceVirtualEnvironmentContainerMountPointACL = false dvResourceVirtualEnvironmentContainerMountPointBackup = true + dvResourceVirtualEnvironmentContainerMountPointPath = "" dvResourceVirtualEnvironmentContainerMountPointQuota = false dvResourceVirtualEnvironmentContainerMountPointReadOnly = false dvResourceVirtualEnvironmentContainerMountPointReplicate = true @@ -576,10 +577,17 @@ func Container() *schema.Resource { Type: schema.TypeString, Description: "Path to the mount point as seen from inside the container", Required: true, + // StateFunc: func(i interface{}) string { + // // PVE strips leading slashes from the path, so we have to do the same + // return strings.TrimPrefix(i.(string), "/") + // }, + DiffSuppressFunc: func(k, oldVal, newVal string, d *schema.ResourceData) bool { + return "/"+oldVal == newVal + }, }, mkResourceVirtualEnvironmentContainerMountPointQuota: { Type: schema.TypeBool, - Description: "Enable user quotas inside the container (not supported with zfs subvolumes)", + Description: "Enable user quotas inside the container (not supported with volume mounts)", Optional: true, Default: dvResourceVirtualEnvironmentContainerMountPointQuota, }, @@ -612,6 +620,16 @@ func Container() *schema.Resource { Type: schema.TypeString, Description: "Volume, device or directory to mount into the container", Required: true, + DiffSuppressFunc: func(k, oldVal, newVal string, d *schema.ResourceData) bool { + // For *new* volume mounts PVE returns an actual volume ID which is saved in the stare, + // so on reapply the provider will try override it:" + // "local-lvm" -> "local-lvm:vm-101-disk-1" + // "local-lvm:8" -> "local-lvm:vm-101-disk-1" + // There is also an option to mount an existing volume, so + // "local-lvm:vm-101-disk-1" -> "local-lvm:vm-101-disk-1" + // which is a valid case. + return oldVal == newVal || strings.HasPrefix(oldVal, strings.Split(newVal, ":")[0]+":") + }, }, }, }, @@ -1330,6 +1348,8 @@ func containerCreateCustom(ctx context.Context, d *schema.ResourceData, m interf mountPoint := d.Get(mkResourceVirtualEnvironmentContainerMountPoint).([]interface{}) mountPointArray := make(containers.CustomMountPointArray, 0, len(mountPoint)) + // because of default bool values: + //nolint:gosimple for _, mp := range mountPoint { mountPointMap := mp.(map[string]interface{}) mountPointObject := containers.CustomMountPoint{} @@ -1345,13 +1365,34 @@ func containerCreateCustom(ctx context.Context, d *schema.ResourceData, m interf size := mountPointMap[mkResourceVirtualEnvironmentContainerMountPointSize].(string) volume := mountPointMap[mkResourceVirtualEnvironmentContainerMountPointVolume].(string) - mountPointObject.ACL = &acl - mountPointObject.Backup = &backup - mountPointObject.MountPoint = path - mountPointObject.Quota = "a - mountPointObject.ReadOnly = &readOnly - mountPointObject.Replicate = &replicate - mountPointObject.Shared = &shared + // we have to set only the values that are different from the provider's defaults, + if acl != dvResourceVirtualEnvironmentContainerMountPointACL { + mountPointObject.ACL = &acl + } + + if backup != dvResourceVirtualEnvironmentContainerMountPointBackup { + mountPointObject.Backup = &backup + } + + if path != dvResourceVirtualEnvironmentContainerMountPointPath { + mountPointObject.MountPoint = path + } + + if quota != dvResourceVirtualEnvironmentContainerMountPointQuota { + mountPointObject.Quota = "a + } + + if readOnly != dvResourceVirtualEnvironmentContainerMountPointReadOnly { + mountPointObject.ReadOnly = &readOnly + } + + if replicate != dvResourceVirtualEnvironmentContainerMountPointReplicate { + mountPointObject.Replicate = &replicate + } + + if shared != dvResourceVirtualEnvironmentContainerMountPointShared { + mountPointObject.Shared = &shared + } if len(size) > 0 { var ds types.DiskSize