mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-07-06 14:03:58 +00:00
Continue work on container resource
This commit is contained in:
parent
6dac302a01
commit
f6c4ad2af7
40
example/resource_virtual_environment_container.tf
Normal file
40
example/resource_virtual_environment_container.tf
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
resource "proxmox_virtual_environment_container" "example" {
|
||||||
|
description = "Managed by Terraform"
|
||||||
|
|
||||||
|
initialization {
|
||||||
|
dns {
|
||||||
|
server = "1.1.1.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname = "terraform-provider-proxmox-example-lxc"
|
||||||
|
|
||||||
|
ip_config {
|
||||||
|
ipv4 {
|
||||||
|
address = "dhcp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user_account {
|
||||||
|
keys = ["${trimspace(tls_private_key.example.public_key_openssh)}"]
|
||||||
|
password = "example"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network_interface {
|
||||||
|
name = "veth0"
|
||||||
|
}
|
||||||
|
|
||||||
|
node_name = "${data.proxmox_virtual_environment_nodes.example.names[0]}"
|
||||||
|
|
||||||
|
operating_system {
|
||||||
|
template_file_id = "${proxmox_virtual_environment_file.ubuntu_container_template.id}"
|
||||||
|
type = "ubuntu"
|
||||||
|
}
|
||||||
|
|
||||||
|
pool_id = "${proxmox_virtual_environment_pool.example.id}"
|
||||||
|
vm_id = 2039
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_container_example_id" {
|
||||||
|
value = "${proxmox_virtual_environment_container.example.id}"
|
||||||
|
}
|
@ -1,12 +1,6 @@
|
|||||||
resource "proxmox_virtual_environment_file" "ubuntu_cloud_image" {
|
#===============================================================================
|
||||||
content_type = "iso"
|
# Cloud Config (cloud-init)
|
||||||
datastore_id = "${element(data.proxmox_virtual_environment_datastores.example.datastore_ids, index(data.proxmox_virtual_environment_datastores.example.datastore_ids, "local"))}"
|
#===============================================================================
|
||||||
node_name = "${data.proxmox_virtual_environment_datastores.example.node_name}"
|
|
||||||
|
|
||||||
source_file {
|
|
||||||
path = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "proxmox_virtual_environment_file" "cloud_config" {
|
resource "proxmox_virtual_environment_file" "cloud_config" {
|
||||||
content_type = "snippets"
|
content_type = "snippets"
|
||||||
@ -37,6 +31,20 @@ users:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Ubuntu Cloud Image
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
resource "proxmox_virtual_environment_file" "ubuntu_cloud_image" {
|
||||||
|
content_type = "iso"
|
||||||
|
datastore_id = "${element(data.proxmox_virtual_environment_datastores.example.datastore_ids, index(data.proxmox_virtual_environment_datastores.example.datastore_ids, "local"))}"
|
||||||
|
node_name = "${data.proxmox_virtual_environment_datastores.example.node_name}"
|
||||||
|
|
||||||
|
source_file {
|
||||||
|
path = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
output "resource_proxmox_virtual_environment_file_ubuntu_cloud_image_content_type" {
|
output "resource_proxmox_virtual_environment_file_ubuntu_cloud_image_content_type" {
|
||||||
value = "${proxmox_virtual_environment_file.ubuntu_cloud_image.content_type}"
|
value = "${proxmox_virtual_environment_file.ubuntu_cloud_image.content_type}"
|
||||||
}
|
}
|
||||||
@ -72,3 +80,53 @@ output "resource_proxmox_virtual_environment_file_ubuntu_cloud_image_node_name"
|
|||||||
output "resource_proxmox_virtual_environment_file_ubuntu_cloud_image_source_file" {
|
output "resource_proxmox_virtual_environment_file_ubuntu_cloud_image_source_file" {
|
||||||
value = "${proxmox_virtual_environment_file.ubuntu_cloud_image.source_file}"
|
value = "${proxmox_virtual_environment_file.ubuntu_cloud_image.source_file}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Ubuntu Container Template
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
resource "proxmox_virtual_environment_file" "ubuntu_container_template" {
|
||||||
|
content_type = "vztmpl"
|
||||||
|
datastore_id = "${element(data.proxmox_virtual_environment_datastores.example.datastore_ids, index(data.proxmox_virtual_environment_datastores.example.datastore_ids, "local"))}"
|
||||||
|
node_name = "${data.proxmox_virtual_environment_datastores.example.node_name}"
|
||||||
|
|
||||||
|
source_file {
|
||||||
|
path = "http://download.proxmox.com/images/system/ubuntu-18.04-standard_18.04.1-1_amd64.tar.gz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_content_type" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.content_type}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_datastore_id" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.datastore_id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_file_modification_date" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.file_modification_date}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_file_name" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.file_name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_file_size" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.file_size}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_file_tag" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.file_tag}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_id" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_node_name" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.node_name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "resource_proxmox_virtual_environment_file_ubuntu_container_template_source_file" {
|
||||||
|
value = "${proxmox_virtual_environment_file.ubuntu_container_template.source_file}"
|
||||||
|
}
|
||||||
|
@ -58,21 +58,6 @@ resource "proxmox_virtual_environment_vm" "example" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "local_file" "example_ssh_private_key" {
|
|
||||||
filename = "${path.module}/autogenerated/id_rsa"
|
|
||||||
sensitive_content = "${tls_private_key.example.private_key_pem}"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "local_file" "example_ssh_public_key" {
|
|
||||||
filename = "${path.module}/autogenerated/id_rsa.pub"
|
|
||||||
sensitive_content = "${tls_private_key.example.public_key_openssh}"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "tls_private_key" "example" {
|
|
||||||
algorithm = "RSA"
|
|
||||||
rsa_bits = 2048
|
|
||||||
}
|
|
||||||
|
|
||||||
output "resource_proxmox_virtual_environment_vm_example_id" {
|
output "resource_proxmox_virtual_environment_vm_example_id" {
|
||||||
value = "${proxmox_virtual_environment_vm.example.id}"
|
value = "${proxmox_virtual_environment_vm.example.id}"
|
||||||
}
|
}
|
||||||
|
14
example/ssh.tf
Normal file
14
example/ssh.tf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
resource "local_file" "example_ssh_private_key" {
|
||||||
|
filename = "${path.module}/autogenerated/id_rsa"
|
||||||
|
sensitive_content = "${tls_private_key.example.private_key_pem}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "local_file" "example_ssh_public_key" {
|
||||||
|
filename = "${path.module}/autogenerated/id_rsa.pub"
|
||||||
|
sensitive_content = "${tls_private_key.example.public_key_openssh}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "tls_private_key" "example" {
|
||||||
|
algorithm = "RSA"
|
||||||
|
rsa_bits = 2048
|
||||||
|
}
|
1
go.mod
1
go.mod
@ -8,4 +8,5 @@ require (
|
|||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/pkg/sftp v1.10.1
|
github.com/pkg/sftp v1.10.1
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55
|
||||||
)
|
)
|
||||||
|
@ -110,3 +110,33 @@ func (c *VirtualEnvironmentClient) WaitForContainerState(nodeName string, vmID i
|
|||||||
|
|
||||||
return fmt.Errorf("Timeout while waiting for container \"%d\" to enter the state \"%s\"", vmID, state)
|
return fmt.Errorf("Timeout while waiting for container \"%d\" to enter the state \"%s\"", vmID, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WaitForContainerLock waits for a container lock to be released.
|
||||||
|
func (c *VirtualEnvironmentClient) WaitForContainerLock(nodeName string, vmID int, timeout int, delay int) error {
|
||||||
|
timeDelay := int64(delay)
|
||||||
|
timeMax := float64(timeout)
|
||||||
|
timeStart := time.Now()
|
||||||
|
timeElapsed := timeStart.Sub(timeStart)
|
||||||
|
|
||||||
|
for timeElapsed.Seconds() < timeMax {
|
||||||
|
if int64(timeElapsed.Seconds())%timeDelay == 0 {
|
||||||
|
data, err := c.GetContainerStatus(nodeName, vmID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Lock == nil || *data.Lock == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
|
||||||
|
timeElapsed = time.Now().Sub(timeStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Timeout while waiting for container \"%d\" to become unlocked", vmID)
|
||||||
|
}
|
||||||
|
@ -34,7 +34,7 @@ type VirtualEnvironmentContainerCreateRequestBody struct {
|
|||||||
Lock *string `json:"lock,omitempty" url:"lock,omitempty,int"`
|
Lock *string `json:"lock,omitempty" url:"lock,omitempty,int"`
|
||||||
MountPoints VirtualEnvironmentContainerCustomMountPointArray `json:"mp,omitempty" url:"mp,omitempty,numbered"`
|
MountPoints VirtualEnvironmentContainerCustomMountPointArray `json:"mp,omitempty" url:"mp,omitempty,numbered"`
|
||||||
NetworkInterfaces VirtualEnvironmentContainerCustomNetworkInterfaceArray `json:"net,omitempty" url:"net,omitempty,numbered"`
|
NetworkInterfaces VirtualEnvironmentContainerCustomNetworkInterfaceArray `json:"net,omitempty" url:"net,omitempty,numbered"`
|
||||||
OSTemplateFileVolume string `json:"ostemplate" url:"ostemplate"`
|
OSTemplateFileVolume *string `json:"ostemplate,omitempty" url:"ostemplate,omitempty"`
|
||||||
OSType *string `json:"ostype,omitempty" url:"ostype,omitempty"`
|
OSType *string `json:"ostype,omitempty" url:"ostype,omitempty"`
|
||||||
Password *string `json:"password,omitempty" url:"password,omitempty"`
|
Password *string `json:"password,omitempty" url:"password,omitempty"`
|
||||||
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
|
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
|
||||||
@ -51,7 +51,7 @@ type VirtualEnvironmentContainerCreateRequestBody struct {
|
|||||||
TTY *int `json:"tty,omitempty" url:"tty,omitempty"`
|
TTY *int `json:"tty,omitempty" url:"tty,omitempty"`
|
||||||
Unique *CustomBool `json:"unique,omitempty" url:"unique,omitempty,int"`
|
Unique *CustomBool `json:"unique,omitempty" url:"unique,omitempty,int"`
|
||||||
Unprivileged *CustomBool `json:"unprivileged,omitempty" url:"unprivileged,omitempty,int"`
|
Unprivileged *CustomBool `json:"unprivileged,omitempty" url:"unprivileged,omitempty,int"`
|
||||||
VMID int `json:"vmid" url:"vmid"`
|
VMID *int `json:"vmid,omitempty" url:"vmid,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VirtualEnvironmentContainerCustomFeatures contains the values for the "features" property.
|
// VirtualEnvironmentContainerCustomFeatures contains the values for the "features" property.
|
||||||
@ -66,7 +66,7 @@ type VirtualEnvironmentContainerCustomFeatures struct {
|
|||||||
type VirtualEnvironmentContainerCustomMountPoint struct {
|
type VirtualEnvironmentContainerCustomMountPoint struct {
|
||||||
ACL *CustomBool `json:"acl,omitempty" url:"acl,omitempty,int"`
|
ACL *CustomBool `json:"acl,omitempty" url:"acl,omitempty,int"`
|
||||||
Backup *CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
|
Backup *CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
|
||||||
DiskSize *int `json:"size,omitempty" url:"size,omitempty"`
|
DiskSize *string `json:"size,omitempty" url:"size,omitempty"`
|
||||||
Enabled bool `json:"-" url:"-"`
|
Enabled bool `json:"-" url:"-"`
|
||||||
MountOptions *[]string `json:"mountoptions,omitempty" url:"mountoptions,omitempty"`
|
MountOptions *[]string `json:"mountoptions,omitempty" url:"mountoptions,omitempty"`
|
||||||
MountPoint string `json:"mp" url:"mp"`
|
MountPoint string `json:"mp" url:"mp"`
|
||||||
@ -92,7 +92,7 @@ type VirtualEnvironmentContainerCustomNetworkInterface struct {
|
|||||||
MACAddress *string `json:"hwaddr,omitempty" url:"hwaddr,omitempty"`
|
MACAddress *string `json:"hwaddr,omitempty" url:"hwaddr,omitempty"`
|
||||||
MTU *int `json:"mtu,omitempty" url:"mtu,omitempty"`
|
MTU *int `json:"mtu,omitempty" url:"mtu,omitempty"`
|
||||||
Name string `json:"name" url:"name"`
|
Name string `json:"name" url:"name"`
|
||||||
RateLimit *int `json:"rate,omitempty" url:"rate,omitempty"`
|
RateLimit *float64 `json:"rate,omitempty" url:"rate,omitempty"`
|
||||||
Tag *int `json:"tag,omitempty" url:"tag,omitempty"`
|
Tag *int `json:"tag,omitempty" url:"tag,omitempty"`
|
||||||
Trunks *[]int `json:"trunks,omitempty" url:"trunks,omitempty"`
|
Trunks *[]int `json:"trunks,omitempty" url:"trunks,omitempty"`
|
||||||
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
||||||
@ -104,7 +104,7 @@ type VirtualEnvironmentContainerCustomNetworkInterfaceArray []VirtualEnvironment
|
|||||||
// VirtualEnvironmentContainerCustomRootFS contains the values for the "rootfs" property.
|
// VirtualEnvironmentContainerCustomRootFS contains the values for the "rootfs" property.
|
||||||
type VirtualEnvironmentContainerCustomRootFS struct {
|
type VirtualEnvironmentContainerCustomRootFS struct {
|
||||||
ACL *CustomBool `json:"acl,omitempty" url:"acl,omitempty,int"`
|
ACL *CustomBool `json:"acl,omitempty" url:"acl,omitempty,int"`
|
||||||
DiskSize *int `json:"size,omitempty" url:"size,omitempty"`
|
DiskSize *string `json:"size,omitempty" url:"size,omitempty"`
|
||||||
MountOptions *[]string `json:"mountoptions,omitempty" url:"mountoptions,omitempty"`
|
MountOptions *[]string `json:"mountoptions,omitempty" url:"mountoptions,omitempty"`
|
||||||
Quota *CustomBool `json:"quota,omitempty" url:"quota,omitempty,int"`
|
Quota *CustomBool `json:"quota,omitempty" url:"quota,omitempty,int"`
|
||||||
ReadOnly *CustomBool `json:"ro,omitempty" url:"ro,omitempty,int"`
|
ReadOnly *CustomBool `json:"ro,omitempty" url:"ro,omitempty,int"`
|
||||||
@ -181,7 +181,7 @@ type VirtualEnvironmentContainerGetStatusResponseData struct {
|
|||||||
Lock *string `json:"lock,omitempty"`
|
Lock *string `json:"lock,omitempty"`
|
||||||
MemoryAllocation *int `json:"maxmem,omitempty"`
|
MemoryAllocation *int `json:"maxmem,omitempty"`
|
||||||
Name *string `json:"name,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
RootDiskSize *int `json:"maxdisk,omitempty"`
|
RootDiskSize *interface{} `json:"maxdisk,omitempty"`
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
SwapAllocation *int `json:"maxswap,omitempty"`
|
SwapAllocation *int `json:"maxswap,omitempty"`
|
||||||
Tags *string `json:"tags,omitempty"`
|
Tags *string `json:"tags,omitempty"`
|
||||||
@ -265,7 +265,7 @@ func (r VirtualEnvironmentContainerCustomMountPoint) EncodeValues(key string, v
|
|||||||
}
|
}
|
||||||
|
|
||||||
if r.DiskSize != nil {
|
if r.DiskSize != nil {
|
||||||
values = append(values, fmt.Sprintf("size=%d", *r.DiskSize))
|
values = append(values, fmt.Sprintf("size=%s", *r.DiskSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.MountOptions != nil {
|
if r.MountOptions != nil {
|
||||||
@ -317,6 +317,15 @@ func (r VirtualEnvironmentContainerCustomMountPoint) EncodeValues(key string, v
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeValues converts a VirtualEnvironmentContainerCustomMountPointArray array to multiple URL values.
|
||||||
|
func (r VirtualEnvironmentContainerCustomMountPointArray) EncodeValues(key string, v *url.Values) error {
|
||||||
|
for i, d := range r {
|
||||||
|
d.EncodeValues(fmt.Sprintf("%s%d", key, i), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// EncodeValues converts a VirtualEnvironmentContainerCustomNetworkInterface struct to a URL vlaue.
|
// EncodeValues converts a VirtualEnvironmentContainerCustomNetworkInterface struct to a URL vlaue.
|
||||||
func (r VirtualEnvironmentContainerCustomNetworkInterface) EncodeValues(key string, v *url.Values) error {
|
func (r VirtualEnvironmentContainerCustomNetworkInterface) EncodeValues(key string, v *url.Values) error {
|
||||||
values := []string{}
|
values := []string{}
|
||||||
@ -360,7 +369,7 @@ func (r VirtualEnvironmentContainerCustomNetworkInterface) EncodeValues(key stri
|
|||||||
values = append(values, fmt.Sprintf("name=%s", r.Name))
|
values = append(values, fmt.Sprintf("name=%s", r.Name))
|
||||||
|
|
||||||
if r.RateLimit != nil {
|
if r.RateLimit != nil {
|
||||||
values = append(values, fmt.Sprintf("rate=%d", *r.RateLimit))
|
values = append(values, fmt.Sprintf("rate=%.2f", *r.RateLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Tag != nil {
|
if r.Tag != nil {
|
||||||
@ -388,6 +397,15 @@ func (r VirtualEnvironmentContainerCustomNetworkInterface) EncodeValues(key stri
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeValues converts a VirtualEnvironmentContainerCustomNetworkInterfaceArray array to multiple URL values.
|
||||||
|
func (r VirtualEnvironmentContainerCustomNetworkInterfaceArray) EncodeValues(key string, v *url.Values) error {
|
||||||
|
for i, d := range r {
|
||||||
|
d.EncodeValues(fmt.Sprintf("%s%d", key, i), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// EncodeValues converts a VirtualEnvironmentContainerCustomRootFS struct to a URL vlaue.
|
// EncodeValues converts a VirtualEnvironmentContainerCustomRootFS struct to a URL vlaue.
|
||||||
func (r VirtualEnvironmentContainerCustomRootFS) EncodeValues(key string, v *url.Values) error {
|
func (r VirtualEnvironmentContainerCustomRootFS) EncodeValues(key string, v *url.Values) error {
|
||||||
values := []string{}
|
values := []string{}
|
||||||
@ -401,7 +419,7 @@ func (r VirtualEnvironmentContainerCustomRootFS) EncodeValues(key string, v *url
|
|||||||
}
|
}
|
||||||
|
|
||||||
if r.DiskSize != nil {
|
if r.DiskSize != nil {
|
||||||
values = append(values, fmt.Sprintf("size=%d", *r.DiskSize))
|
values = append(values, fmt.Sprintf("size=%s", *r.DiskSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.MountOptions != nil {
|
if r.MountOptions != nil {
|
||||||
@ -453,7 +471,7 @@ func (r VirtualEnvironmentContainerCustomRootFS) EncodeValues(key string, v *url
|
|||||||
|
|
||||||
// EncodeValues converts a VirtualEnvironmentContainerCustomSSHKeys array to a URL vlaue.
|
// EncodeValues converts a VirtualEnvironmentContainerCustomSSHKeys array to a URL vlaue.
|
||||||
func (r VirtualEnvironmentContainerCustomSSHKeys) EncodeValues(key string, v *url.Values) error {
|
func (r VirtualEnvironmentContainerCustomSSHKeys) EncodeValues(key string, v *url.Values) error {
|
||||||
v.Add(key, strings.ReplaceAll(url.QueryEscape(strings.Join(r, "\n")), "+", "%20"))
|
v.Add(key, strings.Join(r, "\n"))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -538,7 +556,7 @@ func (r *VirtualEnvironmentContainerCustomMountPoint) UnmarshalJSON(b []byte) er
|
|||||||
v := strings.Split(strings.TrimSpace(p), "=")
|
v := strings.Split(strings.TrimSpace(p), "=")
|
||||||
|
|
||||||
if len(v) == 1 {
|
if len(v) == 1 {
|
||||||
r.Volume = v[1]
|
r.Volume = v[0]
|
||||||
} else if len(v) == 2 {
|
} else if len(v) == 2 {
|
||||||
switch v[0] {
|
switch v[0] {
|
||||||
case "acl":
|
case "acl":
|
||||||
@ -570,13 +588,7 @@ func (r *VirtualEnvironmentContainerCustomMountPoint) UnmarshalJSON(b []byte) er
|
|||||||
bv := CustomBool(v[1] == "1")
|
bv := CustomBool(v[1] == "1")
|
||||||
r.Shared = &bv
|
r.Shared = &bv
|
||||||
case "size":
|
case "size":
|
||||||
iv, err := strconv.Atoi(v[1])
|
r.DiskSize = &v[1]
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
r.DiskSize = &iv
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -600,7 +612,7 @@ func (r *VirtualEnvironmentContainerCustomNetworkInterface) UnmarshalJSON(b []by
|
|||||||
v := strings.Split(strings.TrimSpace(p), "=")
|
v := strings.Split(strings.TrimSpace(p), "=")
|
||||||
|
|
||||||
if len(v) == 1 {
|
if len(v) == 1 {
|
||||||
r.Name = v[1]
|
r.Name = v[0]
|
||||||
} else if len(v) == 2 {
|
} else if len(v) == 2 {
|
||||||
switch v[0] {
|
switch v[0] {
|
||||||
case "bridge":
|
case "bridge":
|
||||||
@ -629,13 +641,13 @@ func (r *VirtualEnvironmentContainerCustomNetworkInterface) UnmarshalJSON(b []by
|
|||||||
case "name":
|
case "name":
|
||||||
r.Name = v[1]
|
r.Name = v[1]
|
||||||
case "rate":
|
case "rate":
|
||||||
iv, err := strconv.Atoi(v[1])
|
fv, err := strconv.ParseFloat(v[1], 64)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.RateLimit = &iv
|
r.RateLimit = &fv
|
||||||
case "tag":
|
case "tag":
|
||||||
iv, err := strconv.Atoi(v[1])
|
iv, err := strconv.Atoi(v[1])
|
||||||
|
|
||||||
@ -687,7 +699,7 @@ func (r *VirtualEnvironmentContainerCustomRootFS) UnmarshalJSON(b []byte) error
|
|||||||
v := strings.Split(strings.TrimSpace(p), "=")
|
v := strings.Split(strings.TrimSpace(p), "=")
|
||||||
|
|
||||||
if len(v) == 1 {
|
if len(v) == 1 {
|
||||||
r.Volume = v[1]
|
r.Volume = v[0]
|
||||||
} else if len(v) == 2 {
|
} else if len(v) == 2 {
|
||||||
switch v[0] {
|
switch v[0] {
|
||||||
case "acl":
|
case "acl":
|
||||||
@ -714,13 +726,7 @@ func (r *VirtualEnvironmentContainerCustomRootFS) UnmarshalJSON(b []byte) error
|
|||||||
bv := CustomBool(v[1] == "1")
|
bv := CustomBool(v[1] == "1")
|
||||||
r.Shared = &bv
|
r.Shared = &bv
|
||||||
case "size":
|
case "size":
|
||||||
iv, err := strconv.Atoi(v[1])
|
r.DiskSize = &v[1]
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
r.DiskSize = &iv
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ func Provider() *schema.Provider {
|
|||||||
},
|
},
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"proxmox_virtual_environment_certificate": resourceVirtualEnvironmentCertificate(),
|
"proxmox_virtual_environment_certificate": resourceVirtualEnvironmentCertificate(),
|
||||||
|
"proxmox_virtual_environment_container": resourceVirtualEnvironmentContainer(),
|
||||||
"proxmox_virtual_environment_dns": resourceVirtualEnvironmentDNS(),
|
"proxmox_virtual_environment_dns": resourceVirtualEnvironmentDNS(),
|
||||||
"proxmox_virtual_environment_file": resourceVirtualEnvironmentFile(),
|
"proxmox_virtual_environment_file": resourceVirtualEnvironmentFile(),
|
||||||
"proxmox_virtual_environment_group": resourceVirtualEnvironmentGroup(),
|
"proxmox_virtual_environment_group": resourceVirtualEnvironmentGroup(),
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package proxmoxtf
|
package proxmoxtf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ const (
|
|||||||
mkResourceVirtualEnvironmentContainerMemory = "memory"
|
mkResourceVirtualEnvironmentContainerMemory = "memory"
|
||||||
mkResourceVirtualEnvironmentContainerMemoryDedicated = "dedicated"
|
mkResourceVirtualEnvironmentContainerMemoryDedicated = "dedicated"
|
||||||
mkResourceVirtualEnvironmentContainerMemorySwap = "swap"
|
mkResourceVirtualEnvironmentContainerMemorySwap = "swap"
|
||||||
mkResourceVirtualEnvironmentContainerNetworkInterface = "network_device"
|
mkResourceVirtualEnvironmentContainerNetworkInterface = "network_interface"
|
||||||
mkResourceVirtualEnvironmentContainerNetworkInterfaceBridge = "bridge"
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceBridge = "bridge"
|
||||||
mkResourceVirtualEnvironmentContainerNetworkInterfaceEnabled = "enabled"
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceEnabled = "enabled"
|
||||||
mkResourceVirtualEnvironmentContainerNetworkInterfaceMACAddress = "mac_address"
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceMACAddress = "mac_address"
|
||||||
@ -324,7 +325,7 @@ func resourceVirtualEnvironmentContainer() *schema.Resource {
|
|||||||
Sensitive: true,
|
Sensitive: true,
|
||||||
Default: dvResourceVirtualEnvironmentContainerInitializationUserAccountPassword,
|
Default: dvResourceVirtualEnvironmentContainerInitializationUserAccountPassword,
|
||||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||||
return strings.ReplaceAll(old, "*", "") == ""
|
return len(old) > 0 && strings.ReplaceAll(old, "*", "") == ""
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -459,7 +460,7 @@ func resourceVirtualEnvironmentContainer() *schema.Resource {
|
|||||||
},
|
},
|
||||||
mkResourceVirtualEnvironmentContainerPoolID: {
|
mkResourceVirtualEnvironmentContainerPoolID: {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Description: "The ID of the pool to assign the virtual machine to",
|
Description: "The ID of the pool to assign the container to",
|
||||||
Optional: true,
|
Optional: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
Default: dvResourceVirtualEnvironmentContainerPoolID,
|
Default: dvResourceVirtualEnvironmentContainerPoolID,
|
||||||
@ -576,7 +577,7 @@ func resourceVirtualEnvironmentContainerCreate(d *schema.ResourceData, m interfa
|
|||||||
initializationUserAccountBlock := initializationUserAccount[0].(map[string]interface{})
|
initializationUserAccountBlock := initializationUserAccount[0].(map[string]interface{})
|
||||||
|
|
||||||
keys := initializationUserAccountBlock[mkResourceVirtualEnvironmentContainerInitializationUserAccountKeys].([]interface{})
|
keys := initializationUserAccountBlock[mkResourceVirtualEnvironmentContainerInitializationUserAccountKeys].([]interface{})
|
||||||
initializationUserAccountKeys := make(proxmox.VirtualEnvironmentContainerCustomSSHKeys, len(keys))
|
initializationUserAccountKeys = make(proxmox.VirtualEnvironmentContainerCustomSSHKeys, len(keys))
|
||||||
|
|
||||||
for ki, kv := range keys {
|
for ki, kv := range keys {
|
||||||
initializationUserAccountKeys[ki] = kv.(string)
|
initializationUserAccountKeys[ki] = kv.(string)
|
||||||
@ -606,7 +607,7 @@ func resourceVirtualEnvironmentContainerCreate(d *schema.ResourceData, m interfa
|
|||||||
enabled := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceEnabled].(bool)
|
enabled := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceEnabled].(bool)
|
||||||
macAddress := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceMACAddress].(string)
|
macAddress := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceMACAddress].(string)
|
||||||
name := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceName].(string)
|
name := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceName].(string)
|
||||||
rateLimit := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceRateLimit].(int)
|
rateLimit := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceRateLimit].(float64)
|
||||||
vlanID := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceVLANID].(int)
|
vlanID := networkInterfaceMap[mkResourceVirtualEnvironmentContainerNetworkInterfaceVLANID].(int)
|
||||||
|
|
||||||
if bridge != "" {
|
if bridge != "" {
|
||||||
@ -637,9 +638,7 @@ func resourceVirtualEnvironmentContainerCreate(d *schema.ResourceData, m interfa
|
|||||||
networkInterfaceObject.MACAddress = &macAddress
|
networkInterfaceObject.MACAddress = &macAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
if name != "" {
|
|
||||||
networkInterfaceObject.Name = name
|
networkInterfaceObject.Name = name
|
||||||
}
|
|
||||||
|
|
||||||
if rateLimit != 0 {
|
if rateLimit != 0 {
|
||||||
networkInterfaceObject.RateLimit = &rateLimit
|
networkInterfaceObject.RateLimit = &rateLimit
|
||||||
@ -676,20 +675,23 @@ func resourceVirtualEnvironmentContainerCreate(d *schema.ResourceData, m interfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to create the resource using the retrieved values.
|
// Attempt to create the resource using the retrieved values.
|
||||||
|
datastoreID := "local-lvm"
|
||||||
|
|
||||||
body := proxmox.VirtualEnvironmentContainerCreateRequestBody{
|
body := proxmox.VirtualEnvironmentContainerCreateRequestBody{
|
||||||
ConsoleEnabled: &consoleEnabled,
|
ConsoleEnabled: &consoleEnabled,
|
||||||
ConsoleMode: &consoleMode,
|
ConsoleMode: &consoleMode,
|
||||||
CPUArchitecture: &cpuArchitecture,
|
CPUArchitecture: &cpuArchitecture,
|
||||||
CPUCores: &cpuCores,
|
CPUCores: &cpuCores,
|
||||||
CPUUnits: &cpuUnits,
|
CPUUnits: &cpuUnits,
|
||||||
|
DatastoreID: &datastoreID,
|
||||||
DedicatedMemory: &memoryDedicated,
|
DedicatedMemory: &memoryDedicated,
|
||||||
NetworkInterfaces: networkInterfaceArray,
|
NetworkInterfaces: networkInterfaceArray,
|
||||||
OSTemplateFileVolume: operatingSystemTemplateFileID,
|
OSTemplateFileVolume: &operatingSystemTemplateFileID,
|
||||||
OSType: &operatingSystemType,
|
OSType: &operatingSystemType,
|
||||||
StartOnBoot: &started,
|
StartOnBoot: &started,
|
||||||
Swap: &memorySwap,
|
Swap: &memorySwap,
|
||||||
TTY: &consoleTTYCount,
|
TTY: &consoleTTYCount,
|
||||||
VMID: vmID,
|
VMID: &vmID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if description != "" {
|
if description != "" {
|
||||||
@ -728,6 +730,13 @@ func resourceVirtualEnvironmentContainerCreate(d *schema.ResourceData, m interfa
|
|||||||
|
|
||||||
d.SetId(strconv.Itoa(vmID))
|
d.SetId(strconv.Itoa(vmID))
|
||||||
|
|
||||||
|
// Wait for the container's lock to be released.
|
||||||
|
err = veClient.WaitForContainerLock(nodeName, vmID, 300, 5)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return resourceVirtualEnvironmentContainerCreateStart(d, m)
|
return resourceVirtualEnvironmentContainerCreateStart(d, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,10 +824,11 @@ func resourceVirtualEnvironmentContainerRead(d *schema.ResourceData, m interface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the entire configuration in order to compare it to the state.
|
// Retrieve the entire configuration in order to compare it to the state.
|
||||||
_, err = veClient.GetContainer(nodeName, vmID)
|
containerConfig, err := veClient.GetContainer(nodeName, vmID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "HTTP 404") {
|
if strings.Contains(err.Error(), "HTTP 404") ||
|
||||||
|
(strings.Contains(err.Error(), "HTTP 500") && strings.Contains(err.Error(), "does not exist")) {
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -827,6 +837,276 @@ func resourceVirtualEnvironmentContainerRead(d *schema.ResourceData, m interface
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare the primitive values to those stored in the state.
|
||||||
|
if containerConfig.Description != nil {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerDescription, strings.TrimSpace(*containerConfig.Description))
|
||||||
|
} else {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerDescription, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the console configuration to the one stored in the state.
|
||||||
|
console := map[string]interface{}{}
|
||||||
|
|
||||||
|
if containerConfig.ConsoleEnabled != nil {
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleEnabled] = *containerConfig.ConsoleEnabled
|
||||||
|
} else {
|
||||||
|
// Default value of "console" is "1" according to the API documentation.
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleEnabled] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if containerConfig.ConsoleMode != nil {
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleMode] = *containerConfig.ConsoleMode
|
||||||
|
} else {
|
||||||
|
// Default value of "cmode" is "tty" according to the API documentation.
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleMode] = "tty"
|
||||||
|
}
|
||||||
|
|
||||||
|
if containerConfig.TTY != nil {
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleTTYCount] = *containerConfig.TTY
|
||||||
|
} else {
|
||||||
|
// Default value of "tty" is "2" according to the API documentation.
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleTTYCount] = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
currentConsole := d.Get(mkResourceVirtualEnvironmentContainerConsole).([]interface{})
|
||||||
|
|
||||||
|
if len(currentConsole) > 0 ||
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleEnabled] != proxmox.CustomBool(dvResourceVirtualEnvironmentContainerConsoleEnabled) ||
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleMode] != dvResourceVirtualEnvironmentContainerConsoleMode ||
|
||||||
|
console[mkResourceVirtualEnvironmentContainerConsoleTTYCount] != dvResourceVirtualEnvironmentContainerConsoleTTYCount {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerConsole, []interface{}{console})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the CPU configuration to the one stored in the state.
|
||||||
|
cpu := map[string]interface{}{}
|
||||||
|
|
||||||
|
if containerConfig.CPUArchitecture != nil {
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUArchitecture] = *containerConfig.CPUArchitecture
|
||||||
|
} else {
|
||||||
|
// Default value of "arch" is "amd64" according to the API documentation.
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUArchitecture] = "amd64"
|
||||||
|
}
|
||||||
|
|
||||||
|
if containerConfig.CPUCores != nil {
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUCores] = *containerConfig.CPUCores
|
||||||
|
} else {
|
||||||
|
// Default value of "cores" is "1" according to the API documentation.
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUCores] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if containerConfig.CPUUnits != nil {
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUUnits] = *containerConfig.CPUUnits
|
||||||
|
} else {
|
||||||
|
// Default value of "cpuunits" is "1024" according to the API documentation.
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUUnits] = 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCPU := d.Get(mkResourceVirtualEnvironmentContainerCPU).([]interface{})
|
||||||
|
|
||||||
|
if len(currentCPU) > 0 ||
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUArchitecture] != dvResourceVirtualEnvironmentContainerCPUArchitecture ||
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUCores] != dvResourceVirtualEnvironmentContainerCPUCores ||
|
||||||
|
cpu[mkResourceVirtualEnvironmentContainerCPUUnits] != dvResourceVirtualEnvironmentContainerCPUUnits {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerCPU, []interface{}{cpu})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the memory configuration to the one stored in the state.
|
||||||
|
memory := map[string]interface{}{}
|
||||||
|
|
||||||
|
if containerConfig.DedicatedMemory != nil {
|
||||||
|
memory[mkResourceVirtualEnvironmentContainerMemoryDedicated] = *containerConfig.DedicatedMemory
|
||||||
|
} else {
|
||||||
|
memory[mkResourceVirtualEnvironmentContainerMemoryDedicated] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if containerConfig.Swap != nil {
|
||||||
|
memory[mkResourceVirtualEnvironmentContainerMemorySwap] = *containerConfig.Swap
|
||||||
|
} else {
|
||||||
|
memory[mkResourceVirtualEnvironmentContainerMemorySwap] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
currentMemory := d.Get(mkResourceVirtualEnvironmentContainerMemory).([]interface{})
|
||||||
|
|
||||||
|
if len(currentMemory) > 0 ||
|
||||||
|
memory[mkResourceVirtualEnvironmentContainerMemoryDedicated] != dvResourceVirtualEnvironmentContainerMemoryDedicated ||
|
||||||
|
memory[mkResourceVirtualEnvironmentContainerMemorySwap] != dvResourceVirtualEnvironmentContainerMemorySwap {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerMemory, []interface{}{memory})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the initialization and network interface configuration to the one stored in the state.
|
||||||
|
initialization := map[string]interface{}{}
|
||||||
|
|
||||||
|
if containerConfig.DNSDomain != nil || containerConfig.DNSServer != nil {
|
||||||
|
initializationDNS := map[string]interface{}{}
|
||||||
|
|
||||||
|
if containerConfig.DNSDomain != nil {
|
||||||
|
initializationDNS[mkResourceVirtualEnvironmentContainerInitializationDNSDomain] = *containerConfig.DNSDomain
|
||||||
|
} else {
|
||||||
|
initializationDNS[mkResourceVirtualEnvironmentContainerInitializationDNSDomain] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if containerConfig.DNSServer != nil {
|
||||||
|
initializationDNS[mkResourceVirtualEnvironmentContainerInitializationDNSServer] = *containerConfig.DNSServer
|
||||||
|
} else {
|
||||||
|
initializationDNS[mkResourceVirtualEnvironmentContainerInitializationDNSServer] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
initialization[mkResourceVirtualEnvironmentContainerInitializationDNS] = []interface{}{initializationDNS}
|
||||||
|
}
|
||||||
|
|
||||||
|
if containerConfig.Hostname != nil {
|
||||||
|
initialization[mkResourceVirtualEnvironmentContainerInitializationHostname] = *containerConfig.Hostname
|
||||||
|
} else {
|
||||||
|
initialization[mkResourceVirtualEnvironmentContainerInitializationHostname] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ipConfigList := []interface{}{}
|
||||||
|
networkInterfaceArray := []*proxmox.VirtualEnvironmentContainerCustomNetworkInterface{
|
||||||
|
containerConfig.NetworkInterface0,
|
||||||
|
containerConfig.NetworkInterface1,
|
||||||
|
containerConfig.NetworkInterface2,
|
||||||
|
containerConfig.NetworkInterface3,
|
||||||
|
containerConfig.NetworkInterface4,
|
||||||
|
containerConfig.NetworkInterface5,
|
||||||
|
containerConfig.NetworkInterface6,
|
||||||
|
containerConfig.NetworkInterface7,
|
||||||
|
}
|
||||||
|
networkInterfaceList := []interface{}{}
|
||||||
|
|
||||||
|
for _, nv := range networkInterfaceArray {
|
||||||
|
if nv == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if nv.IPv4Address != nil || nv.IPv4Gateway != nil || nv.IPv6Address != nil || nv.IPv6Gateway != nil {
|
||||||
|
ipConfig := map[string]interface{}{}
|
||||||
|
|
||||||
|
if nv.IPv4Address != nil || nv.IPv4Gateway != nil {
|
||||||
|
ip := map[string]interface{}{}
|
||||||
|
|
||||||
|
if nv.IPv4Address != nil {
|
||||||
|
ip[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4Address] = *nv.IPv4Address
|
||||||
|
} else {
|
||||||
|
ip[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4Address] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if nv.IPv4Gateway != nil {
|
||||||
|
ip[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4Gateway] = *nv.IPv4Gateway
|
||||||
|
} else {
|
||||||
|
ip[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4Gateway] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ipConfig[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4] = []interface{}{ip}
|
||||||
|
} else {
|
||||||
|
ipConfig[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4] = []interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nv.IPv6Address != nil || nv.IPv6Gateway != nil {
|
||||||
|
ip := map[string]interface{}{}
|
||||||
|
|
||||||
|
if nv.IPv6Address != nil {
|
||||||
|
ip[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6Address] = *nv.IPv6Address
|
||||||
|
} else {
|
||||||
|
ip[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6Address] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if nv.IPv6Gateway != nil {
|
||||||
|
ip[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6Gateway] = *nv.IPv6Gateway
|
||||||
|
} else {
|
||||||
|
ip[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6Gateway] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ipConfig[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6] = []interface{}{ip}
|
||||||
|
} else {
|
||||||
|
ipConfig[mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6] = []interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
ipConfigList = append(ipConfigList, ipConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
networkInterface := map[string]interface{}{}
|
||||||
|
|
||||||
|
if nv.Bridge != nil {
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceBridge] = *nv.Bridge
|
||||||
|
} else {
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceBridge] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceEnabled] = true
|
||||||
|
|
||||||
|
if nv.MACAddress != nil {
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceMACAddress] = *nv.MACAddress
|
||||||
|
} else {
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceMACAddress] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceName] = nv.Name
|
||||||
|
|
||||||
|
if nv.RateLimit != nil {
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceRateLimit] = *nv.RateLimit
|
||||||
|
} else {
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceRateLimit] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if nv.Tag != nil {
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceVLANID] = *nv.Tag
|
||||||
|
} else {
|
||||||
|
networkInterface[mkResourceVirtualEnvironmentContainerNetworkInterfaceVLANID] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
networkInterfaceList = append(networkInterfaceList, networkInterface)
|
||||||
|
}
|
||||||
|
|
||||||
|
initialization[mkResourceVirtualEnvironmentContainerInitializationIPConfig] = ipConfigList
|
||||||
|
|
||||||
|
currentInitialization := d.Get(mkResourceVirtualEnvironmentContainerInitialization).([]interface{})
|
||||||
|
|
||||||
|
if len(currentInitialization) > 0 {
|
||||||
|
currentInitializationMap := currentInitialization[0].(map[string]interface{})
|
||||||
|
|
||||||
|
initialization[mkResourceVirtualEnvironmentContainerInitializationUserAccount] = currentInitializationMap[mkResourceVirtualEnvironmentContainerInitializationUserAccount].([]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(initialization) > 0 {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerInitialization, []interface{}{initialization})
|
||||||
|
} else {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerInitialization, []interface{}{})
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerNetworkInterface, networkInterfaceList)
|
||||||
|
|
||||||
|
// Compare the operating system configuration to the one stored in the state.
|
||||||
|
operatingSystem := map[string]interface{}{}
|
||||||
|
|
||||||
|
if containerConfig.OSType != nil {
|
||||||
|
operatingSystem[mkResourceVirtualEnvironmentContainerOperatingSystemType] = *containerConfig.OSType
|
||||||
|
} else {
|
||||||
|
// Default value of "ostype" is "" according to the API documentation.
|
||||||
|
operatingSystem[mkResourceVirtualEnvironmentContainerOperatingSystemType] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
currentOperatingSystem := d.Get(mkResourceVirtualEnvironmentContainerOperatingSystem).([]interface{})
|
||||||
|
|
||||||
|
if len(currentOperatingSystem) > 0 {
|
||||||
|
currentOperatingSystemMap := currentOperatingSystem[0].(map[string]interface{})
|
||||||
|
|
||||||
|
operatingSystem[mkResourceVirtualEnvironmentContainerOperatingSystemTemplateFileID] = currentOperatingSystemMap[mkResourceVirtualEnvironmentContainerOperatingSystemTemplateFileID]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(currentOperatingSystem) > 0 ||
|
||||||
|
operatingSystem[mkResourceVirtualEnvironmentContainerOperatingSystemType] != dvResourceVirtualEnvironmentContainerOperatingSystemType {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerOperatingSystem, []interface{}{operatingSystem})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the state of the container in order to update the "started" argument.
|
||||||
|
status, err := veClient.GetContainerStatus(nodeName, vmID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set(mkResourceVirtualEnvironmentContainerStarted, status.Status == "running")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,13 +1125,132 @@ func resourceVirtualEnvironmentContainerUpdate(d *schema.ResourceData, m interfa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the entire configuration as we need to process certain values.
|
// Prepare the new request object.
|
||||||
_, err = veClient.GetContainer(nodeName, vmID)
|
body := proxmox.VirtualEnvironmentContainerUpdateRequestBody{}
|
||||||
|
rebootRequired := false
|
||||||
|
resource := resourceVirtualEnvironmentContainer()
|
||||||
|
|
||||||
|
// Prepare the new primitive values.
|
||||||
|
if d.HasChange(mkResourceVirtualEnvironmentContainerDescription) {
|
||||||
|
description := d.Get(mkResourceVirtualEnvironmentContainerDescription).(string)
|
||||||
|
|
||||||
|
body.Description = &description
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the new console configuration.
|
||||||
|
if d.HasChange(mkResourceVirtualEnvironmentContainerConsole) {
|
||||||
|
consoleBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentContainerConsole}, 0, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
consoleEnabled := proxmox.CustomBool(consoleBlock[mkResourceVirtualEnvironmentContainerConsoleEnabled].(bool))
|
||||||
|
consoleMode := consoleBlock[mkResourceVirtualEnvironmentContainerConsoleMode].(string)
|
||||||
|
consoleTTYCount := consoleBlock[mkResourceVirtualEnvironmentContainerConsoleTTYCount].(int)
|
||||||
|
|
||||||
|
body.ConsoleEnabled = &consoleEnabled
|
||||||
|
body.ConsoleMode = &consoleMode
|
||||||
|
body.TTY = &consoleTTYCount
|
||||||
|
|
||||||
|
rebootRequired = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the new CPU configuration.
|
||||||
|
if d.HasChange(mkResourceVirtualEnvironmentContainerCPU) {
|
||||||
|
cpuBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentContainerCPU}, 0, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cpuArchitecture := cpuBlock[mkResourceVirtualEnvironmentContainerCPUArchitecture].(string)
|
||||||
|
cpuCores := cpuBlock[mkResourceVirtualEnvironmentContainerCPUCores].(int)
|
||||||
|
cpuUnits := cpuBlock[mkResourceVirtualEnvironmentContainerCPUUnits].(int)
|
||||||
|
|
||||||
|
body.CPUArchitecture = &cpuArchitecture
|
||||||
|
body.CPUCores = &cpuCores
|
||||||
|
body.CPUUnits = &cpuUnits
|
||||||
|
|
||||||
|
rebootRequired = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the new memory configuration.
|
||||||
|
if d.HasChange(mkResourceVirtualEnvironmentContainerMemory) {
|
||||||
|
memoryBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentContainerMemory}, 0, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
memoryDedicated := memoryBlock[mkResourceVirtualEnvironmentContainerMemoryDedicated].(int)
|
||||||
|
memorySwap := memoryBlock[mkResourceVirtualEnvironmentContainerMemorySwap].(int)
|
||||||
|
|
||||||
|
body.DedicatedMemory = &memoryDedicated
|
||||||
|
body.Swap = &memorySwap
|
||||||
|
|
||||||
|
rebootRequired = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the configuration now that everything has been prepared.
|
||||||
|
err = veClient.UpdateContainer(nodeName, vmID, &body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if the state of the container needs to be changed.
|
||||||
|
if d.HasChange(mkResourceVirtualEnvironmentContainerStarted) {
|
||||||
|
started := d.Get(mkResourceVirtualEnvironmentContainerStarted).(bool)
|
||||||
|
|
||||||
|
if started {
|
||||||
|
err = veClient.StartContainer(nodeName, vmID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = veClient.WaitForContainerState(nodeName, vmID, "running", 120, 5)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forceStop := proxmox.CustomBool(true)
|
||||||
|
shutdownTimeout := 300
|
||||||
|
|
||||||
|
err = veClient.ShutdownContainer(nodeName, vmID, &proxmox.VirtualEnvironmentContainerShutdownRequestBody{
|
||||||
|
ForceStop: &forceStop,
|
||||||
|
Timeout: &shutdownTimeout,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = veClient.WaitForContainerState(nodeName, vmID, "stopped", 30, 5)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rebootRequired = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// As a final step in the update procedure, we might need to reboot the virtual machine.
|
||||||
|
if rebootRequired {
|
||||||
|
rebootTimeout := 300
|
||||||
|
|
||||||
|
err = veClient.RebootContainer(nodeName, vmID, &proxmox.VirtualEnvironmentContainerRebootRequestBody{
|
||||||
|
Timeout: &rebootTimeout,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return resourceVirtualEnvironmentContainerRead(d, m)
|
return resourceVirtualEnvironmentContainerRead(d, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -870,6 +1269,33 @@ func resourceVirtualEnvironmentContainerDelete(d *schema.ResourceData, m interfa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shut down the container before deleting it.
|
||||||
|
status, err := veClient.GetContainerStatus(nodeName, vmID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Status != "stopped" {
|
||||||
|
forceStop := proxmox.CustomBool(true)
|
||||||
|
shutdownTimeout := 300
|
||||||
|
|
||||||
|
err = veClient.ShutdownContainer(nodeName, vmID, &proxmox.VirtualEnvironmentContainerShutdownRequestBody{
|
||||||
|
ForceStop: &forceStop,
|
||||||
|
Timeout: &shutdownTimeout,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = veClient.WaitForContainerState(nodeName, vmID, "stopped", 30, 5)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = veClient.DeleteContainer(nodeName, vmID)
|
err = veClient.DeleteContainer(nodeName, vmID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -882,6 +1308,13 @@ func resourceVirtualEnvironmentContainerDelete(d *schema.ResourceData, m interfa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the state to become unavailable as that clearly indicates the destruction of the container.
|
||||||
|
err = veClient.WaitForContainerState(nodeName, vmID, "", 60, 2)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Failed to delete container \"%d\"", vmID)
|
||||||
|
}
|
||||||
|
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
237
proxmoxtf/resource_virtual_environment_container_test.go
Normal file
237
proxmoxtf/resource_virtual_environment_container_test.go
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
/* 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 proxmoxtf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestResourceVirtualEnvironmentContainerInstantiation tests whether the ResourceVirtualEnvironmentContainer instance can be instantiated.
|
||||||
|
func TestResourceVirtualEnvironmentContainerInstantiation(t *testing.T) {
|
||||||
|
s := resourceVirtualEnvironmentContainer()
|
||||||
|
|
||||||
|
if s == nil {
|
||||||
|
t.Fatalf("Cannot instantiate resourceVirtualEnvironmentContainer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestResourceVirtualEnvironmentContainerSchema tests the resourceVirtualEnvironmentContainer schema.
|
||||||
|
func TestResourceVirtualEnvironmentContainerSchema(t *testing.T) {
|
||||||
|
s := resourceVirtualEnvironmentContainer()
|
||||||
|
|
||||||
|
testRequiredArguments(t, s, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerNodeName,
|
||||||
|
mkResourceVirtualEnvironmentContainerOperatingSystem,
|
||||||
|
})
|
||||||
|
|
||||||
|
testOptionalArguments(t, s, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerCPU,
|
||||||
|
mkResourceVirtualEnvironmentContainerDescription,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitialization,
|
||||||
|
mkResourceVirtualEnvironmentContainerMemory,
|
||||||
|
mkResourceVirtualEnvironmentContainerPoolID,
|
||||||
|
mkResourceVirtualEnvironmentContainerStarted,
|
||||||
|
mkResourceVirtualEnvironmentContainerVMID,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, s, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerCPU,
|
||||||
|
mkResourceVirtualEnvironmentContainerDescription,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitialization,
|
||||||
|
mkResourceVirtualEnvironmentContainerMemory,
|
||||||
|
mkResourceVirtualEnvironmentContainerOperatingSystem,
|
||||||
|
mkResourceVirtualEnvironmentContainerPoolID,
|
||||||
|
mkResourceVirtualEnvironmentContainerStarted,
|
||||||
|
mkResourceVirtualEnvironmentContainerVMID,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeList,
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeList,
|
||||||
|
schema.TypeList,
|
||||||
|
schema.TypeList,
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeBool,
|
||||||
|
schema.TypeInt,
|
||||||
|
})
|
||||||
|
|
||||||
|
cpuSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentContainerCPU)
|
||||||
|
|
||||||
|
testOptionalArguments(t, cpuSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerCPUArchitecture,
|
||||||
|
mkResourceVirtualEnvironmentContainerCPUCores,
|
||||||
|
mkResourceVirtualEnvironmentContainerCPUUnits,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, cpuSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerCPUArchitecture,
|
||||||
|
mkResourceVirtualEnvironmentContainerCPUCores,
|
||||||
|
mkResourceVirtualEnvironmentContainerCPUUnits,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeInt,
|
||||||
|
schema.TypeInt,
|
||||||
|
})
|
||||||
|
|
||||||
|
initializationSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentContainerInitialization)
|
||||||
|
|
||||||
|
testOptionalArguments(t, initializationSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationDNS,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationHostname,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfig,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationUserAccount,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, initializationSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationDNS,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationHostname,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfig,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationUserAccount,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeList,
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeList,
|
||||||
|
schema.TypeList,
|
||||||
|
})
|
||||||
|
|
||||||
|
initializationDNSSchema := testNestedSchemaExistence(t, initializationSchema, mkResourceVirtualEnvironmentContainerInitializationDNS)
|
||||||
|
|
||||||
|
testOptionalArguments(t, initializationDNSSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationDNSDomain,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationDNSServer,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, initializationDNSSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationDNSDomain,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationDNSServer,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeString,
|
||||||
|
})
|
||||||
|
|
||||||
|
initializationIPConfigSchema := testNestedSchemaExistence(t, initializationSchema, mkResourceVirtualEnvironmentContainerInitializationIPConfig)
|
||||||
|
|
||||||
|
testOptionalArguments(t, initializationIPConfigSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, initializationIPConfigSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeList,
|
||||||
|
schema.TypeList,
|
||||||
|
})
|
||||||
|
|
||||||
|
initializationIPConfigIPv4Schema := testNestedSchemaExistence(t, initializationIPConfigSchema, mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4)
|
||||||
|
|
||||||
|
testOptionalArguments(t, initializationIPConfigIPv4Schema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4Address,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4Gateway,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, initializationIPConfigIPv4Schema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4Address,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv4Gateway,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeString,
|
||||||
|
})
|
||||||
|
|
||||||
|
initializationIPConfigIPv6Schema := testNestedSchemaExistence(t, initializationIPConfigSchema, mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6)
|
||||||
|
|
||||||
|
testOptionalArguments(t, initializationIPConfigIPv6Schema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6Address,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6Gateway,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, initializationIPConfigIPv6Schema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6Address,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationIPConfigIPv6Gateway,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeString,
|
||||||
|
})
|
||||||
|
|
||||||
|
initializationUserAccountSchema := testNestedSchemaExistence(t, initializationSchema, mkResourceVirtualEnvironmentContainerInitializationUserAccount)
|
||||||
|
|
||||||
|
testOptionalArguments(t, initializationUserAccountSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationUserAccountKeys,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationUserAccountPassword,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, initializationUserAccountSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationUserAccountKeys,
|
||||||
|
mkResourceVirtualEnvironmentContainerInitializationUserAccountPassword,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeList,
|
||||||
|
schema.TypeString,
|
||||||
|
})
|
||||||
|
|
||||||
|
memorySchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentContainerMemory)
|
||||||
|
|
||||||
|
testOptionalArguments(t, memorySchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerMemoryDedicated,
|
||||||
|
mkResourceVirtualEnvironmentContainerMemorySwap,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, memorySchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerMemoryDedicated,
|
||||||
|
mkResourceVirtualEnvironmentContainerMemorySwap,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeInt,
|
||||||
|
schema.TypeInt,
|
||||||
|
})
|
||||||
|
|
||||||
|
networkInterfaceSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentContainerNetworkInterface)
|
||||||
|
|
||||||
|
testRequiredArguments(t, networkInterfaceSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceName,
|
||||||
|
})
|
||||||
|
|
||||||
|
testOptionalArguments(t, networkInterfaceSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceBridge,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceEnabled,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceMACAddress,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceRateLimit,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceVLANID,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, networkInterfaceSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceBridge,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceEnabled,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceMACAddress,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceName,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceRateLimit,
|
||||||
|
mkResourceVirtualEnvironmentContainerNetworkInterfaceVLANID,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeBool,
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeFloat,
|
||||||
|
schema.TypeInt,
|
||||||
|
})
|
||||||
|
|
||||||
|
operatingSystemSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentContainerOperatingSystem)
|
||||||
|
|
||||||
|
testRequiredArguments(t, operatingSystemSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerOperatingSystemTemplateFileID,
|
||||||
|
})
|
||||||
|
|
||||||
|
testOptionalArguments(t, operatingSystemSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerOperatingSystemType,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, operatingSystemSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentContainerOperatingSystemTemplateFileID,
|
||||||
|
mkResourceVirtualEnvironmentContainerOperatingSystemType,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeString,
|
||||||
|
schema.TypeString,
|
||||||
|
})
|
||||||
|
}
|
@ -402,7 +402,8 @@ func resourceVirtualEnvironmentFileGetContentType(d *schema.ResourceData, m inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if contentType == "" {
|
if contentType == "" {
|
||||||
if strings.HasSuffix(sourceFilePath, ".tar.xz") {
|
if strings.HasSuffix(sourceFilePath, ".tar.gz") ||
|
||||||
|
strings.HasSuffix(sourceFilePath, ".tar.xz") {
|
||||||
contentType = "vztmpl"
|
contentType = "vztmpl"
|
||||||
} else {
|
} else {
|
||||||
ext := strings.TrimLeft(strings.ToLower(filepath.Ext(sourceFilePath)), ".")
|
ext := strings.TrimLeft(strings.ToLower(filepath.Ext(sourceFilePath)), ".")
|
||||||
|
@ -547,7 +547,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
|||||||
Sensitive: true,
|
Sensitive: true,
|
||||||
Default: dvResourceVirtualEnvironmentVMInitializationUserAccountPassword,
|
Default: dvResourceVirtualEnvironmentVMInitializationUserAccountPassword,
|
||||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||||
return strings.ReplaceAll(old, "*", "") == ""
|
return len(old) > 0 && strings.ReplaceAll(old, "*", "") == ""
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mkResourceVirtualEnvironmentVMInitializationUserAccountUsername: {
|
mkResourceVirtualEnvironmentVMInitializationUserAccountUsername: {
|
||||||
@ -1484,7 +1484,8 @@ func resourceVirtualEnvironmentVMRead(d *schema.ResourceData, m interface{}) err
|
|||||||
vmConfig, err := veClient.GetVM(nodeName, vmID)
|
vmConfig, err := veClient.GetVM(nodeName, vmID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "HTTP 404") {
|
if strings.Contains(err.Error(), "HTTP 404") ||
|
||||||
|
(strings.Contains(err.Error(), "HTTP 500") && strings.Contains(err.Error(), "does not exist")) {
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -2502,6 +2503,13 @@ func resourceVirtualEnvironmentVMDelete(d *schema.ResourceData, m interface{}) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Shut down the virtual machine before deleting it.
|
// Shut down the virtual machine before deleting it.
|
||||||
|
status, err := veClient.GetVMStatus(nodeName, vmID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Status != "stopped" {
|
||||||
forceStop := proxmox.CustomBool(true)
|
forceStop := proxmox.CustomBool(true)
|
||||||
shutdownTimeout := 300
|
shutdownTimeout := 300
|
||||||
|
|
||||||
@ -2519,11 +2527,13 @@ func resourceVirtualEnvironmentVMDelete(d *schema.ResourceData, m interface{}) e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = veClient.DeleteVM(nodeName, vmID)
|
err = veClient.DeleteVM(nodeName, vmID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "HTTP 404") {
|
if strings.Contains(err.Error(), "HTTP 404") ||
|
||||||
|
(strings.Contains(err.Error(), "HTTP 500") && strings.Contains(err.Error(), "does not exist")) {
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -2533,7 +2543,7 @@ func resourceVirtualEnvironmentVMDelete(d *schema.ResourceData, m interface{}) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the state to become unavailable as that clearly indicates the destruction of the VM.
|
// Wait for the state to become unavailable as that clearly indicates the destruction of the VM.
|
||||||
err = veClient.WaitForVMState(nodeName, vmID, "", 30, 2)
|
err = veClient.WaitForVMState(nodeName, vmID, "", 60, 2)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return fmt.Errorf("Failed to delete VM \"%d\"", vmID)
|
return fmt.Errorf("Failed to delete VM \"%d\"", vmID)
|
||||||
|
Loading…
Reference in New Issue
Block a user