Skip to content

Commit

Permalink
Merge pull request #559 from terraform-providers/vmss-custom-data
Browse files Browse the repository at this point in the history
`azurerm_virtual_machine_scale_set`: Support for updating the customData field
  • Loading branch information
tombuildsstuff authored Nov 16, 2017
2 parents fde0b34 + 8a6346c commit a00bce9
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 34 deletions.
43 changes: 34 additions & 9 deletions azurerm/import_arm_virtual_machine_scale_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ func TestAccAzureRMVirtualMachineScaleSet_importBasic(t *testing.T) {
Config: config,
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"os_profile.0.admin_password"},
},
},
})
Expand All @@ -45,9 +46,10 @@ func TestAccAzureRMVirtualMachineScaleSet_importBasic_managedDisk(t *testing.T)
Config: config,
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"os_profile.0.admin_password"},
},
},
})
Expand All @@ -71,6 +73,10 @@ func TestAccAzureRMVirtualMachineScaleSet_importLinux(t *testing.T) {
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"os_profile.0.admin_password",
"os_profile.0.custom_data",
},
},
},
})
Expand All @@ -91,9 +97,10 @@ func TestAccAzureRMVirtualMachineScaleSet_importLoadBalancer(t *testing.T) {
Config: config,
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"os_profile.0.admin_password"},
},
},
})
Expand All @@ -116,6 +123,12 @@ func TestAccAzureRMVirtualMachineScaleSet_importOverProvision(t *testing.T) {
testCheckAzureRMVirtualMachineScaleSetOverprovision(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"os_profile.0.admin_password"},
},
},
})
}
Expand All @@ -137,6 +150,12 @@ func TestAccAzureRMVirtualMachineScaleSet_importExtension(t *testing.T) {
testCheckAzureRMVirtualMachineScaleSetExtension(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"os_profile.0.admin_password"},
},
},
})
}
Expand All @@ -158,6 +177,12 @@ func TestAccAzureRMVirtualMachineScaleSet_importMultipleExtensions(t *testing.T)
testCheckAzureRMVirtualMachineScaleSetExtension(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"os_profile.0.admin_password"},
},
},
})
}
5 changes: 5 additions & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,11 @@ func ignoreCaseStateFunc(val interface{}) string {
return strings.ToLower(val.(string))
}

func userDataDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool {
oldValue := userDataStateFunc(old)
return oldValue == new
}

func userDataStateFunc(v interface{}) string {
switch s := v.(type) {
case string:
Expand Down
45 changes: 21 additions & 24 deletions azurerm/resource_arm_virtual_machine_scale_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func resourceArmVirtualMachineScaleSet() *schema.Resource {
},

"os_profile": {
Type: schema.TypeSet,
Type: schema.TypeList,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Expand All @@ -102,14 +102,13 @@ func resourceArmVirtualMachineScaleSet() *schema.Resource {
},

"custom_data": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
StateFunc: userDataStateFunc,
Type: schema.TypeString,
Optional: true,
StateFunc: userDataStateFunc,
DiffSuppressFunc: userDataDiffSuppressFunc,
},
},
},
Set: resourceArmVirtualMachineScaleSetsOsProfileHash,
},

"os_profile_secrets": {
Expand Down Expand Up @@ -697,7 +696,7 @@ func resourceArmVirtualMachineScaleSetRead(d *schema.ResourceData, meta interfac
d.Set("overprovision", properties.Overprovision)
d.Set("single_placement_group", properties.SinglePlacementGroup)

osProfile, err := flattenAzureRMVirtualMachineScaleSetOsProfile(properties.VirtualMachineProfile.OsProfile)
osProfile, err := flattenAzureRMVirtualMachineScaleSetOsProfile(d, properties.VirtualMachineProfile.OsProfile)
if err != nil {
return fmt.Errorf("[DEBUG] Error flattening Virtual Machine Scale Set OS Profile. Error: %#v", err)
}
Expand Down Expand Up @@ -964,14 +963,27 @@ func flattenAzureRmVirtualMachineScaleSetNetworkProfile(profile *compute.Virtual
return result
}

func flattenAzureRMVirtualMachineScaleSetOsProfile(profile *compute.VirtualMachineScaleSetOSProfile) ([]interface{}, error) {
func flattenAzureRMVirtualMachineScaleSetOsProfile(d *schema.ResourceData, profile *compute.VirtualMachineScaleSetOSProfile) ([]interface{}, error) {
result := make(map[string]interface{})

result["computer_name_prefix"] = *profile.ComputerNamePrefix
result["admin_username"] = *profile.AdminUsername

// admin password isn't returned, so let's look it up
if v, ok := d.GetOk("os_profile.0.admin_password"); ok {
password := v.(string)
result["admin_password"] = password
}

if profile.CustomData != nil {
result["custom_data"] = *profile.CustomData
} else {
// look up the current custom data
value := d.Get("os_profile.0.custom_data").(string)
if !isBase64Encoded(value) {
value = base64Encode(value)
}
result["custom_data"] = value
}

return []interface{}{result}, nil
Expand Down Expand Up @@ -1146,21 +1158,6 @@ func resourceArmVirtualMachineScaleSetNetworkConfigurationHash(v interface{}) in
return hashcode.String(buf.String())
}

func resourceArmVirtualMachineScaleSetsOsProfileHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["computer_name_prefix"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["admin_username"].(string)))
if m["custom_data"] != nil {
customData := m["custom_data"].(string)
if !isBase64Encoded(customData) {
customData = base64Encode(customData)
}
buf.WriteString(fmt.Sprintf("%s-", customData))
}
return hashcode.String(buf.String())
}

func resourceArmVirtualMachineScaleSetOsProfileLinuxConfigHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
Expand Down Expand Up @@ -1325,7 +1322,7 @@ func expandAzureRmVirtualMachineScaleSetNetworkProfile(d *schema.ResourceData) *
}

func expandAzureRMVirtualMachineScaleSetsOsProfile(d *schema.ResourceData) (*compute.VirtualMachineScaleSetOSProfile, error) {
osProfileConfigs := d.Get("os_profile").(*schema.Set).List()
osProfileConfigs := d.Get("os_profile").([]interface{})

osProfileConfig := osProfileConfigs[0].(map[string]interface{})
namePrefix := osProfileConfig["computer_name_prefix"].(string)
Expand Down
128 changes: 128 additions & 0 deletions azurerm/resource_arm_virtual_machine_scale_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,34 @@ func TestAccAzureRMVirtualMachineScaleSet_linuxUpdated(t *testing.T) {
})
}

func TestAccAzureRMVirtualMachineScaleSet_customDataUpdated(t *testing.T) {
resourceName := "azurerm_virtual_machine_scale_set.test"
ri := acctest.RandInt()
location := testLocation()
config := testAccAzureRMVirtualMachineScaleSet_linux(ri, location)
updatedConfig := testAccAzureRMVirtualMachineScaleSet_linuxCustomDataUpdated(ri, location)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMVirtualMachineScaleSetExists(resourceName),
),
},
{
Config: updatedConfig,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMVirtualMachineScaleSetExists(resourceName),
),
},
},
})
}

func TestAccAzureRMVirtualMachineScaleSet_basicLinux_managedDisk(t *testing.T) {
ri := acctest.RandInt()
config := testAccAzureRMVirtualMachineScaleSet_basicLinux_managedDisk(ri, testLocation())
Expand Down Expand Up @@ -1659,6 +1687,106 @@ resource "azurerm_virtual_machine_scale_set" "test" {
`, rInt, location, rInt, rInt, rInt, rInt, rInt, rInt, rInt, rInt)
}

func testAccAzureRMVirtualMachineScaleSet_linuxCustomDataUpdated(rInt int, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
name = "acctestrg-%d"
location = "%s"
}
resource "azurerm_virtual_network" "test" {
name = "acctestvn-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
address_space = ["10.0.0.0/8"]
}
resource "azurerm_subnet" "test" {
name = "acctestsn-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
virtual_network_name = "${azurerm_virtual_network.test.name}"
address_prefix = "10.0.1.0/24"
}
resource "azurerm_storage_account" "test" {
name = "accsa%d"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_storage_container" "test" {
name = "acctestsc-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
storage_account_name = "${azurerm_storage_account.test.name}"
container_access_type = "private"
}
resource "azurerm_public_ip" "test" {
name = "acctestpip-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
public_ip_address_allocation = "static"
}
resource "azurerm_lb" "test" {
name = "acctestlb-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
frontend_ip_configuration {
name = "ip-address"
public_ip_address_id = "${azurerm_public_ip.test.id}"
}
}
resource "azurerm_lb_backend_address_pool" "test" {
name = "acctestbap-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
loadbalancer_id = "${azurerm_lb.test.id}"
}
resource "azurerm_virtual_machine_scale_set" "test" {
name = "acctestvmss-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
upgrade_policy_mode = "Automatic"
sku {
name = "Standard_A0"
tier = "Standard"
capacity = "1"
}
os_profile {
computer_name_prefix = "prefix"
admin_username = "ubuntu"
admin_password = "password"
custom_data = "updated custom data!"
}
os_profile_linux_config {
disable_password_authentication = true
ssh_keys {
path = "/home/ubuntu/.ssh/authorized_keys"
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDCsTcryUl51Q2VSEHqDRNmceUFo55ZtcIwxl2QITbN1RREti5ml/VTytC0yeBOvnZA4x4CFpdw/lCDPk0yrH9Ei5vVkXmOrExdTlT3qI7YaAzj1tUVlBd4S6LX1F7y6VLActvdHuDDuXZXzCDd/97420jrDfWZqJMlUK/EmCE5ParCeHIRIvmBxcEnGfFIsw8xQZl0HphxWOtJil8qsUWSdMyCiJYYQpMoMliO99X40AUc4/AlsyPyT5ddbKk08YrZ+rKDVHF7o29rh4vi5MmHkVgVQHKiKybWlHq+b71gIAUQk9wrJxD+dqt4igrmDSpIjfjwnd+l5UIn5fJSO5DYV4YT/4hwK7OKmuo7OFHD0WyY5YnkYEMtFgzemnRBdE8ulcT60DQpVgRMXFWHvhyCWy0L6sgj1QWDZlLpvsIvNfHsyhKFMG1frLnMt/nP0+YCcfg+v1JYeCKjeoJxB8DWcRBsjzItY0CGmzP8UYZiYKl/2u+2TgFS5r7NWH11bxoUzjKdaa1NLw+ieA8GlBFfCbfWe6YVB9ggUte4VtYFMZGxOjS2bAiYtfgTKFJv+XqORAwExG6+G2eDxIDyo80/OA9IG7Xv/jwQr7D6KDjDuULFcN/iTxuttoKrHeYz1hf5ZQlBdllwJHYx6fK2g8kha6r2JIQKocvsAXiiONqSfw== hello@world.com"
}
}
network_profile {
name = "TestNetworkProfile"
primary = true
ip_configuration {
name = "TestIPConfiguration"
subnet_id = "${azurerm_subnet.test.id}"
load_balancer_backend_address_pool_ids = ["${azurerm_lb_backend_address_pool.test.id}"]
}
}
storage_profile_os_disk {
name = "osDiskProfile"
caching = "ReadWrite"
create_option = "FromImage"
os_type = "linux"
vhd_containers = ["${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}"]
}
storage_profile_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
}
`, rInt, location, rInt, rInt, rInt, rInt, rInt, rInt, rInt, rInt)
}

func testAccAzureRMVirtualMachineScaleSet_basicLinux_managedDisk(rInt int, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
Expand Down
2 changes: 1 addition & 1 deletion website/docs/r/virtual_machine_scale_set.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ The following arguments are supported:
* `computer_name_prefix` - (Required) Specifies the computer name prefix for all of the virtual machines in the scale set. Computer name prefixes must be 1 to 15 characters long.
* `admin_username` - (Required) Specifies the administrator account name to use for all the instances of virtual machines in the scale set.
* `admin_password` - (Required) Specifies the administrator password to use for all the instances of virtual machines in a scale set..
* `custom_data` - (Optional) Specifies custom data to supply to the machine. On linux-based systems, this can be used as a cloud-init script. On other systems, this will be copied as a file on disk. Internally, Terraform will base64 encode this value before sending it to the API. The maximum length of the binary array is 65535 bytes. Changing this forces a new resource to be created.
* `custom_data` - (Optional) Specifies custom data to supply to the machine. On linux-based systems, this can be used as a cloud-init script. On other systems, this will be copied as a file on disk. Internally, Terraform will base64 encode this value before sending it to the API. The maximum length of the binary array is 65535 bytes.

`os_profile_secrets` supports the following:

Expand Down

0 comments on commit a00bce9

Please sign in to comment.