diff --git a/fwprovider/test/resource_vm_test.go b/fwprovider/test/resource_vm_test.go index a2e94225..27baa2cd 100644 --- a/fwprovider/test/resource_vm_test.go +++ b/fwprovider/test/resource_vm_test.go @@ -488,11 +488,9 @@ func TestAccResourceVMInitialization(t *testing.T) { upgrade = false } }`), - Check: resource.ComposeTestCheckFunc( - ResourceAttributes("proxmox_virtual_environment_vm.test_vm_cloudinit3", map[string]string{ - "initialization.0.upgrade": "false", - }), - ), + Check: ResourceAttributes("proxmox_virtual_environment_vm.test_vm_cloudinit3", map[string]string{ + "initialization.0.upgrade": "false", + }), }}}, {"native cloud-init: username should not change", []resource.TestStep{{ Config: te.RenderConfig(` @@ -505,12 +503,49 @@ func TestAccResourceVMInitialization(t *testing.T) { } } }`), - Check: resource.ComposeTestCheckFunc( - NoResourceAttributesSet("proxmox_virtual_environment_vm.test_vm_cloudinit4", []string{ - "initialization.0.username", - "initialization.0.password", - }), - ), + Check: NoResourceAttributesSet("proxmox_virtual_environment_vm.test_vm_cloudinit4", []string{ + "initialization.0.username", + "initialization.0.password", + }), + }}}, + {"native cloud-init: username should not change after update", []resource.TestStep{{ + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_vm" "test_vm_cloudinit4" { + node_name = "{{.NodeName}}" + started = false + initialization { + user_account { + username = "ubuntu" + password = "password" + } + } + }`), + Check: ResourceAttributes("proxmox_virtual_environment_vm.test_vm_cloudinit4", map[string]string{ + "initialization.0.user_account.0.username": "ubuntu", + // override by PVE, set when reading back from the API + // have to escape the asterisks because of regex match + "initialization.0.user_account.0.password": `\*\*\*\*\*\*\*\*\*\*`, + }), + }, { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_vm" "test_vm_cloudinit4" { + node_name = "{{.NodeName}}" + started = false + initialization { + user_account { + username = "ubuntu" + password = "password" + } + dns { + servers = ["172.16.0.15", "172.16.0.16"] + domain = "example.com" + } + } + }`), + Check: ResourceAttributes("proxmox_virtual_environment_vm.test_vm_cloudinit4", map[string]string{ + "initialization.0.user_account.0.username": "ubuntu", + "initialization.0.user_account.0.password": `\*\*\*\*\*\*\*\*\*\*`, + }), }}}, } diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go index 70da07e3..d538917b 100644 --- a/proxmoxtf/resource/vm/vm.go +++ b/proxmoxtf/resource/vm/vm.go @@ -296,6 +296,13 @@ const ( mkWatchdogAction = "action" ) +// MaskedPassword represents a value that PVE returns instead of the configured ciuser password when we read the +// VM config back, and we store this value in the state. +// I don't want to change this "security feature" at the moment to avoid breaking change, but +// the provider should avoid overriding config / state in general. Instead, the state encryption feature should +// be used for data protection. +const MaskedPassword = "**********" + // VM returns a resource that manages VMs. func VM() *schema.Resource { s := map[string]*schema.Schema{ @@ -2932,7 +2939,7 @@ func vmGetCloudInitConfig(d *schema.ResourceData) *vms.CustomCloudInitConfig { } password := initializationUserAccountBlock[mkInitializationUserAccountPassword].(string) - if password != "" { + if password != "" && password != MaskedPassword { initializationConfig.Password = &password }