diff --git a/azurerm/resource_arm_virtual_machine_scale_set_test.go b/azurerm/resource_arm_virtual_machine_scale_set_test.go index 3406a3406e0a..b631f3947d9f 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set_test.go +++ b/azurerm/resource_arm_virtual_machine_scale_set_test.go @@ -662,6 +662,25 @@ func TestAccAzureRMVirtualMachineScaleSet_multipleNetworkProfiles(t *testing.T) }) } +func TestAccAzureRMVirtualMachineScaleSet_AutoUpdates(t *testing.T) { + resourceName := "azurerm_virtual_machine_scale_set.test" + ri := acctest.RandInt() + config := testAccAzureRMVirtualMachineScaleSet_RollingAutoUpdates(ri, testLocation()) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineScaleSetExists(resourceName), + ), + }, + }, + }) +} + func testGetAzureRMVirtualMachineScaleSet(s *terraform.State, resourceName string) (result *compute.VirtualMachineScaleSet, err error) { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[resourceName] @@ -3873,3 +3892,136 @@ resource "azurerm_virtual_machine_scale_set" "test" { } `, rInt, location) } + +func testAccAzureRMVirtualMachineScaleSet_RollingAutoUpdates(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%[1]d" + address_space = ["10.0.0.0/8"] + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_subnet" "test" { + name = "acctsub-%[1]d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.0.0.0/16" +} + +resource "azurerm_public_ip" "test" { + name = "PublicIPForLB" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + public_ip_address_allocation = "Dynamic" + idle_timeout_in_minutes = 4 +} + +resource "azurerm_lb" "test" { + name = "acctestlb-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + frontend_ip_configuration { + name = "PublicIPAddress" + public_ip_address_id = "${azurerm_public_ip.test.id}" + } +} + +resource "azurerm_lb_rule" "test" { + resource_group_name = "${azurerm_resource_group.test.name}" + loadbalancer_id = "${azurerm_lb.test.id}" + name = "LBRule" + protocol = "Tcp" + frontend_port = 22 + backend_port = 22 + frontend_ip_configuration_name = "PublicIPAddress" + probe_id = "${azurerm_lb_probe.test.id}" + backend_address_pool_id = "${azurerm_lb_backend_address_pool.test.id}" +} + +resource "azurerm_lb_probe" "test" { + resource_group_name = "${azurerm_resource_group.test.name}" + loadbalancer_id = "${azurerm_lb.test.id}" + name = "ssh-running-probe" + port = 22 + protocol = "Tcp" +} + +resource "azurerm_lb_backend_address_pool" "test" { + name = "test" + resource_group_name = "${azurerm_resource_group.test.name}" + loadbalancer_id = "${azurerm_lb.test.id}" +} + +resource "azurerm_virtual_machine_scale_set" "test" { + name = "acctvmss-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + upgrade_policy_mode = "Rolling" + + automatic_os_upgrade = true + + rolling_upgrade_policy { + max_batch_instance_percent = 20 + max_unhealthy_instance_percent = 20 + max_unhealthy_upgraded_instance_percent = 20 + pause_time_between_batches = "PT0S" + } + + health_probe_id = "${azurerm_lb_probe.test.id}" + + sku { + name = "Standard_A0" + tier = "Standard" + capacity = 1 + } + + os_profile { + computer_name_prefix = "testvm-%[1]d" + admin_username = "myadmin" + admin_password = "Passwword1234" + } + + 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}"] + primary = true + } + } + + storage_profile_os_disk { + name = "" + caching = "ReadWrite" + create_option = "FromImage" + managed_disk_type = "Standard_LRS" + } + + storage_profile_data_disk { + lun = 0 + caching = "ReadWrite" + create_option = "Empty" + disk_size_gb = 10 + managed_disk_type = "Standard_LRS" + } + + storage_profile_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } +} +`, rInt, location) +} diff --git a/examples/vmss-automatic-rolling-updates/README.md b/examples/vmss-automatic-rolling-updates/README.md new file mode 100644 index 000000000000..84d335bc5de3 --- /dev/null +++ b/examples/vmss-automatic-rolling-updates/README.md @@ -0,0 +1,22 @@ +# Linux VM Scale Set with Automatic OS upgrades and Rolling Upgrade Policy + +This template deploys a Linux (Ubuntu) VM Scale Set. Once the VMSS is deployed, the user can deploy an application inside each of the VMs (either by directly logging into the VMs or via a [`remote-exec` provisioner](https://www.terraform.io/docs/provisioners/remote-exec.html)). + +Please review the official documentation first : [Azure virtual machine scale set automatic OS upgrades](https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-automatic-upgrade) + +## main.tf +The `main.tf` file contains the actual resources that will be deployed. It also contains the Azure Resource Group definition and any defined variables. + +## outputs.tf +This data is outputted when `terraform apply` is called, and can be queried using the `terraform output` command. + +You may leave the provider block in the `main.tf`, as it is in this template, or you can create a file called `provider.tf` and add it to your `.gitignore` file. + +Azure requires that an application is added to Azure Active Directory to generate the `client_id`, `client_secret`, and `tenant_id` needed by Terraform (`subscription_id` can be recovered from your Azure account details). Please go [here](https://www.terraform.io/docs/providers/azurerm/) for full instructions on how to create this to populate your `provider.tf` file. + +## terraform.tfvars +If a `terraform.tfvars` or any `.auto.tfvars` files are present in the current directory, Terraform automatically loads them to populate variables. We don't recommend saving usernames and password to version control, but you can create a local secret variables file and use the `-var-file` flag or the `.auto.tfvars` extension to load it. + +## variables.tf +The `variables.tf` file contains all of the input parameters that the user can specify when deploying this Terraform template. + diff --git a/examples/vmss-automatic-rolling-updates/main.tf b/examples/vmss-automatic-rolling-updates/main.tf new file mode 100644 index 000000000000..ed6b18fe56e6 --- /dev/null +++ b/examples/vmss-automatic-rolling-updates/main.tf @@ -0,0 +1,143 @@ +resource "azurerm_resource_group" "rg" { + name = "${var.resource_group_name}" + location = "${var.location}" +} + +resource "azurerm_virtual_network" "vnet" { + name = "${var.resource_group_name}vnet" + location = "${azurerm_resource_group.rg.location}" + address_space = ["10.0.0.0/16"] + resource_group_name = "${azurerm_resource_group.rg.name}" +} + +resource "azurerm_subnet" "subnet" { + name = "subnet" + address_prefix = "10.0.0.0/24" + resource_group_name = "${azurerm_resource_group.rg.name}" + virtual_network_name = "${azurerm_virtual_network.vnet.name}" +} + +resource "azurerm_public_ip" "pip" { + name = "${var.hostname}-pip" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" + public_ip_address_allocation = "Dynamic" + domain_name_label = "${var.hostname}" +} + +resource "azurerm_lb" "lb" { + name = "LoadBalancer" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" + depends_on = ["azurerm_public_ip.pip"] + + frontend_ip_configuration { + name = "LBFrontEnd" + public_ip_address_id = "${azurerm_public_ip.pip.id}" + } +} + +resource "azurerm_lb_backend_address_pool" "backlb" { + name = "BackEndAddressPool" + resource_group_name = "${azurerm_resource_group.rg.name}" + loadbalancer_id = "${azurerm_lb.lb.id}" +} + +resource "azurerm_lb_probe" "prob" { + resource_group_name = "${azurerm_resource_group.test.name}" + loadbalancer_id = "${azurerm_lb.lb.id}" + name = "ssh-running-probe" + port = 22 + protocol = "Tcp" +} + +resource "azurerm_lb_rule" "lbr" { + resource_group_name = "${azurerm_resource_group.rg.name}" + loadbalancer_id = "${azurerm_lb.lb.id}" + name = "LBRule" + protocol = "Tcp" + frontend_port = 22 + backend_port = 22 + frontend_ip_configuration_name = "LBFrontEnd" + probe_id = "${azurerm_lb_probe.prob.id}" + backend_address_pool_id = "${azurerm_lb_backend_address_pool.backlb.id}" +} + +resource "azurerm_storage_account" "stor" { + name = "${var.resource_group_name}stor" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" + account_tier = "${var.storage_account_tier}" + account_replication_type = "${var.storage_replication_type}" +} + +resource "azurerm_storage_container" "vhds" { + name = "vhds" + resource_group_name = "${azurerm_resource_group.rg.name}" + storage_account_name = "${azurerm_storage_account.stor.name}" + container_access_type = "blob" +} + +resource "azurerm_virtual_machine_scale_set" "scaleset" { + name = "autoscalewad" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" + upgrade_policy_mode = "Manual" + overprovision = true + depends_on = ["azurerm_lb.lb", "azurerm_virtual_network.vnet"] + + upgrade_policy_mode = "Rolling" + + automatic_os_upgrade = true + + rolling_upgrade_policy { + max_batch_instance_percent = 20 + max_unhealthy_instance_percent = 20 + max_unhealthy_upgraded_instance_percent = 20 + pause_time_between_batches = "PT0S" + } + + health_probe_id = "${azurerm_lb_probe.prob.id}" + + sku { + name = "${var.vm_sku}" + tier = "Standard" + capacity = "${var.instance_count}" + } + + os_profile { + computer_name_prefix = "${var.vmss_name_prefix}" + admin_username = "${var.admin_username}" + admin_password = "${var.admin_password}" + } + + os_profile_linux_config { + disable_password_authentication = false + } + + network_profile { + name = "${var.hostname}-nic" + primary = true + + ip_configuration { + primary = true + name = "${var.hostname}ipconfig" + subnet_id = "${azurerm_subnet.subnet.id}" + load_balancer_backend_address_pool_ids = ["${azurerm_lb_backend_address_pool.backlb.id}"] + } + } + + storage_profile_os_disk { + name = "${var.hostname}" + caching = "ReadWrite" + create_option = "FromImage" + vhd_containers = ["${azurerm_storage_account.stor.primary_blob_endpoint}${azurerm_storage_container.vhds.name}"] + } + + storage_profile_image_reference { + publisher = "${var.image_publisher}" + offer = "${var.image_offer}" + sku = "${var.ubuntu_os_version}" + version = "latest" + } +} diff --git a/examples/vmss-automatic-rolling-updates/outputs.tf b/examples/vmss-automatic-rolling-updates/outputs.tf new file mode 100644 index 000000000000..668e48e29c18 --- /dev/null +++ b/examples/vmss-automatic-rolling-updates/outputs.tf @@ -0,0 +1,3 @@ +output "hostname" { + value = "${var.vmss_name_prefix}" +} diff --git a/examples/vmss-automatic-rolling-updates/variables.tf b/examples/vmss-automatic-rolling-updates/variables.tf new file mode 100644 index 000000000000..c8fbdc9e6684 --- /dev/null +++ b/examples/vmss-automatic-rolling-updates/variables.tf @@ -0,0 +1,66 @@ +# variable "subscription_id" {} +# variable "client_id" {} +# variable "client_secret" {} +# variable "tenant_id" {} + +variable "resource_group_name" { + description = "The name of the resource group in which to create the virtual network." + default = "tfex-vmss-ubuntu" +} + +variable "location" { + description = "The location/region where the virtual network is created. Changing this forces a new resource to be created." + default = "southcentralus" +} + +variable "storage_account_tier" { + description = "Defines the Tier of storage account to be created. Valid options are Standard and Premium." + default = "Standard" +} + +variable "storage_replication_type" { + description = "Defines the Replication Type to use for this storage account. Valid options include LRS, GRS etc." + default = "LRS" +} + +variable "hostname" { + description = "A string that determines the hostname/IP address of the origin server. This string could be a domain name, IPv4 address or IPv6 address." + default = "tfex-vmss-ubuntu" +} + +variable "vm_sku" { + description = "Size of VMs in the VM Scale Set." + default = "Standard_A1" +} + +variable "ubuntu_os_version" { + description = "The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version. Allowed values are: 15.10, 14.04.4-LTS." + default = "16.04.0-LTS" +} + +variable "image_publisher" { + description = "The name of the publisher of the image (az vm image list)" + default = "Canonical" +} + +variable "image_offer" { + description = "The name of the offer (az vm image list)" + default = "UbuntuServer" +} + +variable "vmss_name_prefix" { + description = "String used as a base for naming resources. Must be 1-9 characters in length for windows and 1-58 for linux images and globally unique across Azure. A hash is prepended to this string for some resources, and resource-specific information is appended." +} + +variable "instance_count" { + description = "Number of VM instances (100 or less)." + default = "5" +} + +variable "admin_username" { + description = "Admin username on all VMs." +} + +variable "admin_password" { + description = "Admin password on all VMs." +}