Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_virtual_machine_scale_set: Support for updating the customData field #559

Merged
merged 1 commit into from
Nov 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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