Skip to content

Commit

Permalink
compute: Add user_data to VM & VMSS resources (#13888)
Browse files Browse the repository at this point in the history
Co-authored-by: tombuildsstuff <[email protected]>
Co-authored-by: Matthew Frahry <[email protected]>

Fix for #11846
  • Loading branch information
mouellet authored Dec 18, 2021
1 parent ddb2fd4 commit adb4525
Show file tree
Hide file tree
Showing 15 changed files with 349 additions and 16 deletions.
21 changes: 19 additions & 2 deletions internal/services/compute/linux_virtual_machine_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,12 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource {

"tags": tags.Schema(),

"user_data": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsBase64,
},

"zone": {
Type: pluginsdk.TypeString,
Optional: true,
Expand Down Expand Up @@ -533,6 +539,10 @@ func resourceLinuxVirtualMachineCreate(d *pluginsdk.ResourceData, meta interface
params.PlatformFaultDomain = utils.Int32(int32(platformFaultDomain))
}

if v, ok := d.GetOk("user_data"); ok {
params.UserData = utils.String(v.(string))
}

if v, ok := d.GetOk("zone"); ok {
params.Zones = &[]string{
v.(string),
Expand Down Expand Up @@ -586,7 +596,7 @@ func resourceLinuxVirtualMachineRead(d *pluginsdk.ResourceData, meta interface{}
return err
}

resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "")
resp, err := client.Get(ctx, id.ResourceGroup, id.Name, compute.InstanceViewTypesUserData)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[DEBUG] Linux Virtual Machine %q was not found in Resource Group %q - removing from state!", id.Name, id.ResourceGroup)
Expand Down Expand Up @@ -766,6 +776,8 @@ func resourceLinuxVirtualMachineRead(d *pluginsdk.ResourceData, meta interface{}

d.Set("virtual_machine_id", props.VMID)

d.Set("user_data", props.UserData)

zone := ""
if resp.Zones != nil {
if zones := *resp.Zones; len(zones) > 0 {
Expand Down Expand Up @@ -799,7 +811,7 @@ func resourceLinuxVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interface
defer locks.UnlockByName(id.Name, virtualMachineResourceName)

log.Printf("[DEBUG] Retrieving Linux Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup)
existing, err := client.Get(ctx, id.ResourceGroup, id.Name, "")
existing, err := client.Get(ctx, id.ResourceGroup, id.Name, compute.InstanceViewTypesUserData)
if err != nil {
if utils.ResponseWasNotFound(existing.Response) {
return nil
Expand Down Expand Up @@ -1062,6 +1074,11 @@ func resourceLinuxVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interface
}
}

if d.HasChange("user_data") {
shouldUpdate = true
update.UserData = utils.String(d.Get("user_data").(string))
}

if instanceView.Statuses != nil {
for _, status := range *instanceView.Statuses {
if status.Code == nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,28 @@ func TestAccLinuxVirtualMachine_otherCustomData(t *testing.T) {
})
}

func TestAccLinuxVirtualMachine_otherUserData(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test")
r := LinuxVirtualMachineResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.otherUserData(data, "Hello World"),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.otherUserData(data, "Goodbye World"),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccLinuxVirtualMachine_otherSkipShutdownAndForceDelete(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test")
r := LinuxVirtualMachineResource{}
Expand Down Expand Up @@ -1039,6 +1061,41 @@ resource "azurerm_linux_virtual_machine" "test" {
`, r.template(data), data.RandomInteger)
}

func (r LinuxVirtualMachineResource) otherUserData(data acceptance.TestData, userData string) string {
return fmt.Sprintf(`
%s
resource "azurerm_linux_virtual_machine" "test" {
name = "acctestVM-%d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
size = "Standard_F2"
admin_username = "adminuser"
user_data = base64encode(%q)
network_interface_ids = [
azurerm_network_interface.test.id,
]
admin_ssh_key {
username = "adminuser"
public_key = local.first_public_key
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
}
`, r.template(data), data.RandomInteger, userData)
}

func (r LinuxVirtualMachineResource) otherSkipShutdownAndForceDelete(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ func TestAccLinuxVirtualMachineScaleSet_otherCustomData(t *testing.T) {
},
data.ImportStep(
"admin_password",
"custom_data",
),
{
Config: r.otherCustomData(data, "/bin/zsh"),
Expand All @@ -123,7 +122,6 @@ func TestAccLinuxVirtualMachineScaleSet_otherCustomData(t *testing.T) {
},
data.ImportStep(
"admin_password",
"custom_data",
),
{
// removed
Expand All @@ -134,7 +132,45 @@ func TestAccLinuxVirtualMachineScaleSet_otherCustomData(t *testing.T) {
},
data.ImportStep(
"admin_password",
"custom_data",
),
})
}

func TestAccLinuxVirtualMachineScaleSet_otherUserData(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine_scale_set", "test")
r := LinuxVirtualMachineScaleSetResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.otherUserData(data, "Hello World"),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(
"admin_password",
"user_data",
),
{
Config: r.otherUserData(data, "Goodbye Wolrd"),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(
"admin_password",
"user_data",
),
{
// removed
Config: r.authPassword(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(
"admin_password",
"user_data",
),
})
}
Expand Down Expand Up @@ -880,6 +916,48 @@ resource "azurerm_linux_virtual_machine_scale_set" "test" {
`, r.template(data), data.RandomInteger, customData)
}

func (r LinuxVirtualMachineScaleSetResource) otherUserData(data acceptance.TestData, userData string) string {
return fmt.Sprintf(`
%s
resource "azurerm_linux_virtual_machine_scale_set" "test" {
name = "acctestvmss-%d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
sku = "Standard_F2"
instances = 1
admin_username = "adminuser"
admin_password = "P@ssword1234!"
user_data = base64encode(%q)
disable_password_authentication = false
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
os_disk {
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
network_interface {
name = "example"
primary = true
ip_configuration {
name = "internal"
primary = true
subnet_id = azurerm_subnet.test.id
}
}
}
`, r.template(data), data.RandomInteger, userData)
}

func (r LinuxVirtualMachineScaleSetResource) otherForceDelete(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,12 @@ func resourceLinuxVirtualMachineScaleSet() *pluginsdk.Resource {
}, false),
},

"user_data": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsBase64,
},

"vtpm_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Expand Down Expand Up @@ -494,6 +500,10 @@ func resourceLinuxVirtualMachineScaleSetCreate(d *pluginsdk.ResourceData, meta i
virtualMachineProfile.SecurityProfile.UefiSettings.VTpmEnabled = utils.Bool(vtpmEnabled.(bool))
}

if v, ok := d.GetOk("user_data"); ok {
virtualMachineProfile.UserData = utils.String(v.(string))
}

// Azure API: "Authentication using either SSH or by user name and password must be enabled in Linux profile."
if disablePasswordAuthentication && virtualMachineProfile.OsProfile.AdminPassword == nil && len(sshKeys) == 0 {
return fmt.Errorf("at least one SSH key must be specified if `disable_password_authentication` is enabled")
Expand Down Expand Up @@ -879,6 +889,11 @@ func resourceLinuxVirtualMachineScaleSetUpdate(d *pluginsdk.ResourceData, meta i
update.Tags = tags.Expand(d.Get("tags").(map[string]interface{}))
}

if d.HasChange("user_data") {
updateInstances = true
updateProps.VirtualMachineProfile.UserData = utils.String(d.Get("user_data").(string))
}

update.VirtualMachineScaleSetUpdateProperties = &updateProps

metaData := virtualMachineScaleSetUpdateMetaData{
Expand Down Expand Up @@ -1099,6 +1114,7 @@ func resourceLinuxVirtualMachineScaleSetRead(d *pluginsdk.ResourceData, meta int
d.Set("encryption_at_host_enabled", encryptionAtHostEnabled)
d.Set("vtpm_enabled", vtpmEnabled)
d.Set("secure_boot_enabled", secureBootEnabled)
d.Set("user_data", profile.UserData)
}

if policy := props.UpgradePolicy; policy != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ func (r LinuxVirtualMachineScaleSetResource) Exists(ctx context.Context, clients
return nil, err
}

// Upgrading to the 2021-07-01 exposed a new expand parameter in the GET method
resp, err := clients.Compute.VMScaleSetClient.Get(ctx, id.ResourceGroup, id.Name, "")
if err != nil {
return nil, fmt.Errorf("retrieving Compute Linux Virtual Machine Scale Set %q: %+v", id, err)
Expand Down
2 changes: 1 addition & 1 deletion internal/services/compute/virtual_machine_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func importVirtualMachine(osType compute.OperatingSystemTypes, resourceType stri
}

client := meta.(*clients.Client).Compute.VMClient
vm, err := client.Get(ctx, id.ResourceGroup, id.Name, "")
vm, err := client.Get(ctx, id.ResourceGroup, id.Name, compute.InstanceViewTypesUserData)
if err != nil {
return []*pluginsdk.ResourceData{}, fmt.Errorf("retrieving Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}
Expand Down
23 changes: 20 additions & 3 deletions internal/services/compute/windows_virtual_machine_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,12 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource {
ValidateFunc: validation.IntAtLeast(-1),
},

"user_data": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsBase64,
},

"vtpm_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Expand Down Expand Up @@ -351,7 +357,7 @@ func resourceWindowsVirtualMachineCreate(d *pluginsdk.ResourceData, meta interfa
locks.ByName(name, virtualMachineResourceName)
defer locks.UnlockByName(name, virtualMachineResourceName)

resp, err := client.Get(ctx, resourceGroup, name, "")
resp, err := client.Get(ctx, resourceGroup, name, compute.InstanceViewTypesUserData)
if err != nil {
if !utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("checking for existing Windows Virtual Machine %q (Resource Group %q): %+v", name, resourceGroup, err)
Expand Down Expand Up @@ -576,6 +582,10 @@ func resourceWindowsVirtualMachineCreate(d *pluginsdk.ResourceData, meta interfa
params.VirtualMachineProperties.OsProfile.WindowsConfiguration.TimeZone = utils.String(v.(string))
}

if v, ok := d.GetOk("user_data"); ok {
params.UserData = utils.String(v.(string))
}

if v, ok := d.GetOk("zone"); ok {
params.Zones = &[]string{
v.(string),
Expand Down Expand Up @@ -617,7 +627,7 @@ func resourceWindowsVirtualMachineRead(d *pluginsdk.ResourceData, meta interface
return err
}

resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "")
resp, err := client.Get(ctx, id.ResourceGroup, id.Name, compute.InstanceViewTypesUserData)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[DEBUG] Windows Virtual Machine %q was not found in Resource Group %q - removing from state!", id.Name, id.ResourceGroup)
Expand Down Expand Up @@ -794,6 +804,8 @@ func resourceWindowsVirtualMachineRead(d *pluginsdk.ResourceData, meta interface

d.Set("virtual_machine_id", props.VMID)

d.Set("user_data", props.UserData)

zone := ""
if resp.Zones != nil {
if zones := *resp.Zones; len(zones) > 0 {
Expand Down Expand Up @@ -827,7 +839,7 @@ func resourceWindowsVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interfa
defer locks.UnlockByName(id.Name, virtualMachineResourceName)

log.Printf("[DEBUG] Retrieving Windows Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup)
existing, err := client.Get(ctx, id.ResourceGroup, id.Name, "")
existing, err := client.Get(ctx, id.ResourceGroup, id.Name, compute.InstanceViewTypesUserData)
if err != nil {
if utils.ResponseWasNotFound(existing.Response) {
return nil
Expand Down Expand Up @@ -1091,6 +1103,11 @@ func resourceWindowsVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interfa
update.VirtualMachineProperties.LicenseType = &license
}

if d.HasChange("user_data") {
shouldUpdate = true
update.UserData = utils.String(d.Get("user_data").(string))
}

if instanceView.Statuses != nil {
for _, status := range *instanceView.Statuses {
if status.Code == nil {
Expand Down
Loading

0 comments on commit adb4525

Please sign in to comment.