From f5f28d82942ce47325848e4e43268e8d551e2e0b Mon Sep 17 00:00:00 2001 From: michalbil <92343355+michalbil@users.noreply.github.com> Date: Tue, 1 Mar 2022 11:34:32 +0100 Subject: [PATCH] feat(vmseries)!: Basic config bootstrap support (#142) * feat(vmseries)!: Add support for simple bootstrap * feat(vmss)!: Add support for simple bootstrap in vmseries scaleset --- examples/transit_vnet_common/README.md | 8 +-- examples/transit_vnet_common/example.tfvars | 2 +- examples/transit_vnet_common/main.tf | 35 ++++++----- examples/transit_vnet_common/versions.tf | 2 +- examples/transit_vnet_dedicated/main.tf | 68 +++++++++++++-------- examples/vmseries_scaleset/main.tf | 34 ++++++++--- modules/vmseries/README.md | 4 +- modules/vmseries/main.tf | 14 +---- modules/vmseries/variables.tf | 24 ++++---- modules/vmss/README.md | 5 +- modules/vmss/main.tf | 12 +--- modules/vmss/variables.tf | 30 ++++----- 12 files changed, 125 insertions(+), 113 deletions(-) diff --git a/examples/transit_vnet_common/README.md b/examples/transit_vnet_common/README.md index 4213b574..00208a3a 100644 --- a/examples/transit_vnet_common/README.md +++ b/examples/transit_vnet_common/README.md @@ -17,7 +17,7 @@ $ terraform apply | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 0.13, < 2.0 | -| [azurerm](#requirement\_azurerm) | = 2.64 | +| [azurerm](#requirement\_azurerm) | = 2.97 | | [random](#requirement\_random) | ~> 3.0 | ## Modules @@ -34,9 +34,9 @@ $ terraform apply | Name | Type | |------|------| -| [azurerm_network_security_rule.mgmt](https://registry.terraform.io/providers/hashicorp/azurerm/2.64/docs/resources/network_security_rule) | resource | -| [azurerm_public_ip.public](https://registry.terraform.io/providers/hashicorp/azurerm/2.64/docs/resources/public_ip) | resource | -| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/2.64/docs/resources/resource_group) | resource | +| [azurerm_network_security_rule.mgmt](https://registry.terraform.io/providers/hashicorp/azurerm/2.97/docs/resources/network_security_rule) | resource | +| [azurerm_public_ip.public](https://registry.terraform.io/providers/hashicorp/azurerm/2.97/docs/resources/public_ip) | resource | +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/2.97/docs/resources/resource_group) | resource | | [random_password.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | ## Inputs diff --git a/examples/transit_vnet_common/example.tfvars b/examples/transit_vnet_common/example.tfvars index 7772cdc4..8166b38c 100644 --- a/examples/transit_vnet_common/example.tfvars +++ b/examples/transit_vnet_common/example.tfvars @@ -65,7 +65,7 @@ vmseries = { common_vmseries_version = "9.1.3" common_vmseries_sku = "bundle1" storage_account_name = "pantfstorage" -storage_share_name = "ibbootstrapshare" +storage_share_name = "bootstrapshare" files = { "files/authcodes" = "license/authcodes" # authcode is required only with common_vmseries_sku = "byol" diff --git a/examples/transit_vnet_common/main.tf b/examples/transit_vnet_common/main.tf index 0f39421c..e2f0230c 100644 --- a/examples/transit_vnet_common/main.tf +++ b/examples/transit_vnet_common/main.tf @@ -1,6 +1,6 @@ # Create the Resource Group. resource "azurerm_resource_group" "this" { - name = coalesce(var.resource_group_name, "${var.name_prefix}vmseries") + name = coalesce(var.resource_group_name, "${var.name_prefix}vmseries-transit-vnet-common") location = var.location } @@ -115,19 +115,24 @@ module "common_vmseries" { for_each = var.vmseries - location = var.location - resource_group_name = azurerm_resource_group.this.name - name = "${var.name_prefix}${each.key}" - avzone = try(each.value.avzone, 1) - username = var.username - password = coalesce(var.password, random_password.this.result) - img_version = var.common_vmseries_version - img_sku = var.common_vmseries_sku - vm_size = var.common_vmseries_vm_size - tags = var.common_vmseries_tags - enable_zones = var.enable_zones - bootstrap_storage_account = module.bootstrap.storage_account - bootstrap_share_name = module.bootstrap.storage_share.name + location = var.location + resource_group_name = azurerm_resource_group.this.name + name = "${var.name_prefix}${each.key}" + avzone = try(each.value.avzone, 1) + username = var.username + password = coalesce(var.password, random_password.this.result) + img_version = var.common_vmseries_version + img_sku = var.common_vmseries_sku + vm_size = var.common_vmseries_vm_size + tags = var.common_vmseries_tags + enable_zones = var.enable_zones + bootstrap_options = join(",", + [ + "storage-account=${module.bootstrap.storage_account.name}", + "access-key=${module.bootstrap.storage_account.primary_access_key}", + "file-share=${module.bootstrap.storage_share.name}", + "share-directory=None" + ]) interfaces = [ { name = "${each.key}-mgmt" @@ -153,5 +158,7 @@ module "common_vmseries" { }, ] + diagnostics_storage_uri = module.bootstrap.storage_account.primary_blob_endpoint + depends_on = [module.bootstrap] } diff --git a/examples/transit_vnet_common/versions.tf b/examples/transit_vnet_common/versions.tf index 1c5f42c0..13881f48 100644 --- a/examples/transit_vnet_common/versions.tf +++ b/examples/transit_vnet_common/versions.tf @@ -3,7 +3,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "= 2.64" + version = "= 2.97" } random = { source = "hashicorp/random" diff --git a/examples/transit_vnet_dedicated/main.tf b/examples/transit_vnet_dedicated/main.tf index 69574e0f..bac80016 100644 --- a/examples/transit_vnet_dedicated/main.tf +++ b/examples/transit_vnet_dedicated/main.tf @@ -1,6 +1,6 @@ # Create the Resource Group. resource "azurerm_resource_group" "this" { - name = coalesce(var.resource_group_name, "${var.name_prefix}vmseries") + name = coalesce(var.resource_group_name, "${var.name_prefix}vmseries-transit-vnet-dedicated") location = var.location } @@ -124,19 +124,24 @@ module "inbound_vmseries" { for_each = var.inbound_vmseries - location = var.location - resource_group_name = azurerm_resource_group.this.name - name = "${var.name_prefix}${each.key}" - avzone = try(each.value.avzone, 1) - username = var.username - password = coalesce(var.password, random_password.this.result) - img_sku = var.common_vmseries_sku - img_version = var.inbound_vmseries_version - vm_size = var.inbound_vmseries_vm_size - tags = var.inbound_vmseries_tags - enable_zones = var.enable_zones - bootstrap_storage_account = module.bootstrap.storage_account - bootstrap_share_name = module.bootstrap.storage_share.name + location = var.location + resource_group_name = azurerm_resource_group.this.name + name = "${var.name_prefix}${each.key}" + avzone = try(each.value.avzone, 1) + username = var.username + password = coalesce(var.password, random_password.this.result) + img_sku = var.common_vmseries_sku + img_version = var.inbound_vmseries_version + vm_size = var.inbound_vmseries_vm_size + tags = var.inbound_vmseries_tags + enable_zones = var.enable_zones + bootstrap_options = join(",", + [ + "storage-account=${module.bootstrap.storage_account.name}", + "access-key=${module.bootstrap.storage_account.primary_access_key}", + "file-share=${module.bootstrap.storage_share.name}", + "share-directory=None" + ]) interfaces = [ { name = "${each.key}-mgmt" @@ -160,6 +165,8 @@ module "inbound_vmseries" { }, ] + diagnostics_storage_uri = module.bootstrap.storage_account.primary_blob_endpoint + depends_on = [module.bootstrap] } @@ -171,19 +178,24 @@ module "outbound_vmseries" { for_each = var.outbound_vmseries - location = var.location - resource_group_name = azurerm_resource_group.this.name - name = "${var.name_prefix}${each.key}" - avzone = try(each.value.avzone, 1) - username = var.username - password = coalesce(var.password, random_password.this.result) - img_sku = var.common_vmseries_sku - img_version = var.outbound_vmseries_version - vm_size = var.outbound_vmseries_vm_size - tags = var.outbound_vmseries_tags - enable_zones = var.enable_zones - bootstrap_storage_account = module.outbound_bootstrap.storage_account - bootstrap_share_name = module.outbound_bootstrap.storage_share.name + location = var.location + resource_group_name = azurerm_resource_group.this.name + name = "${var.name_prefix}${each.key}" + avzone = try(each.value.avzone, 1) + username = var.username + password = coalesce(var.password, random_password.this.result) + img_sku = var.common_vmseries_sku + img_version = var.outbound_vmseries_version + vm_size = var.outbound_vmseries_vm_size + tags = var.outbound_vmseries_tags + enable_zones = var.enable_zones + bootstrap_options = join(",", + [ + "storage-account=${module.outbound_bootstrap.storage_account.name}", + "access-key=${module.outbound_bootstrap.storage_account.primary_access_key}", + "file-share=${module.outbound_bootstrap.storage_share.name}", + "share-directory=None" + ]) interfaces = [ { name = "${each.key}-mgmt" @@ -208,5 +220,7 @@ module "outbound_vmseries" { }, ] + diagnostics_storage_uri = module.bootstrap.storage_account.primary_blob_endpoint + depends_on = [module.outbound_bootstrap] } diff --git a/examples/vmseries_scaleset/main.tf b/examples/vmseries_scaleset/main.tf index af456ba7..479f1cac 100644 --- a/examples/vmseries_scaleset/main.tf +++ b/examples/vmseries_scaleset/main.tf @@ -240,11 +240,18 @@ module "inbound_scale_set" { subnet_mgmt = { id = module.vnet.subnet_ids["management"] } subnet_private = { id = module.vnet.subnet_ids["inbound_private"] } subnet_public = { id = module.vnet.subnet_ids["inbound_public"] } - bootstrap_storage_account = module.inbound_bootstrap.storage_account - bootstrap_share_name = module.inbound_bootstrap.storage_share.name - public_backend_pool_id = module.inbound_lb.backend_pool_id - create_mgmt_pip = false - create_public_pip = false + bootstrap_options = (join(",", + [ + "storage-account=${module.inbound_bootstrap.storage_account.name}", + "access-key=${module.inbound_bootstrap.storage_account.primary_access_key}", + "file-share=${module.inbound_bootstrap.storage_share.name}", + "share-directory=None" + ] + )) + public_backend_pool_id = module.inbound_lb.backend_pool_id + create_mgmt_pip = false + create_public_pip = false + diagnostics_storage_uri = module.inbound_bootstrap.storage_account.primary_blob_endpoint } # Create the outbound scale set. @@ -277,9 +284,16 @@ module "outbound_scale_set" { subnet_mgmt = { id = module.vnet.subnet_ids["management"] } subnet_private = { id = module.vnet.subnet_ids["outbound_private"] } subnet_public = { id = module.vnet.subnet_ids["outbound_public"] } - bootstrap_storage_account = module.outbound_bootstrap.storage_account - bootstrap_share_name = module.outbound_bootstrap.storage_share.name - private_backend_pool_id = module.outbound_lb.backend_pool_id - create_mgmt_pip = false - create_public_pip = false + bootstrap_options = (join(",", + [ + "storage-account=${module.outbound_bootstrap.storage_account.name}", + "access-key=${module.outbound_bootstrap.storage_account.primary_access_key}", + "file-share=${module.outbound_bootstrap.storage_share.name}", + "share-directory=None" + ] + )) + private_backend_pool_id = module.outbound_lb.backend_pool_id + create_mgmt_pip = false + create_public_pip = false + diagnostics_storage_uri = module.outbound_bootstrap.storage_account.primary_blob_endpoint } diff --git a/modules/vmseries/README.md b/modules/vmseries/README.md index 1cdd88dd..3a161b1e 100644 --- a/modules/vmseries/README.md +++ b/modules/vmseries/README.md @@ -76,9 +76,9 @@ No modules. | [accelerated\_networking](#input\_accelerated\_networking) | Enable Azure accelerated networking (SR-IOV) for all network interfaces except the primary one (it is the PAN-OS management interface, which [does not support](https://docs.paloaltonetworks.com/pan-os/9-0/pan-os-new-features/virtualization-features/support-for-azure-accelerated-networking-sriov) acceleration). | `bool` | `true` | no | | [avset\_id](#input\_avset\_id) | The identifier of the Availability Set to use. When using this variable, set `avzone = null`. | `string` | `null` | no | | [avzone](#input\_avzone) | The availability zone to use, for example "1", "2", "3". Ignored if `enable_zones` is false. Conflicts with `avset_id`, in which case use `avzone = null`. | `string` | `"1"` | no | -| [bootstrap\_share\_name](#input\_bootstrap\_share\_name) | Azure File Share holding the bootstrap data. Should reside on `bootstrap_storage_account`. Bootstrapping is omitted if `bootstrap_share_name` is left at null. | `string` | `null` | no | -| [bootstrap\_storage\_account](#input\_bootstrap\_storage\_account) | Existing storage account object for bootstrapping and for holding small-sized boot diagnostics. Usually the object is passed from a bootstrap module's output. | `any` | `null` | no | +| [bootstrap\_options](#input\_bootstrap\_options) | Bootstrap options to pass to VM-Series instance. | `string` | `""` | no | | [custom\_image\_id](#input\_custom\_image\_id) | Absolute ID of your own Custom Image to be used for creating new VM-Series. If set, the `username`, `password`, `img_version`, `img_publisher`, `img_offer`, `img_sku` inputs are all ignored (these are used only for published images, not custom ones). The Custom Image is expected to contain PAN-OS software. | `string` | `null` | no | +| [diagnostics\_storage\_uri](#input\_diagnostics\_storage\_uri) | The storage account's blob endpoint to hold diagnostic files. | `string` | `null` | no | | [enable\_plan](#input\_enable\_plan) | Enable usage of the Offer/Plan on Azure Marketplace. Even plan sku "byol", which means "bring your own license", still requires accepting on the Marketplace (as of 2021). Can be set to `false` when using a custom image. | `bool` | `true` | no | | [enable\_zones](#input\_enable\_zones) | If false, the input `avzone` is ignored and also all created Public IP addresses default to not to use Availability Zones (the `No-Zone` setting). It is intended for the regions that do not yet support Availability Zones. | `bool` | `true` | no | | [identity\_ids](#input\_identity\_ids) | See the [provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine#identity_ids). | `list(string)` | `null` | no | diff --git a/modules/vmseries/main.tf b/modules/vmseries/main.tf index 7eee9acc..3deb2e3d 100644 --- a/modules/vmseries/main.tf +++ b/modules/vmseries/main.tf @@ -90,15 +90,7 @@ resource "azurerm_virtual_machine" "this" { computer_name = var.name admin_username = var.username admin_password = var.password - custom_data = var.bootstrap_share_name == null ? null : join( - ",", - [ - "storage-account=${var.bootstrap_storage_account.name}", - "access-key=${var.bootstrap_storage_account.primary_access_key}", - "file-share=${var.bootstrap_share_name}", - "share-directory=None" - ] - ) + custom_data = var.bootstrap_options } os_profile_linux_config { @@ -108,11 +100,11 @@ resource "azurerm_virtual_machine" "this" { # After converting to azurerm_linux_virtual_machine, an empty block boot_diagnostics {} will use managed storage. Want. # 2.36 in required_providers per https://github.com/terraform-providers/terraform-provider-azurerm/pull/8917 dynamic "boot_diagnostics" { - for_each = var.bootstrap_storage_account != null ? ["one"] : [] + for_each = var.diagnostics_storage_uri != null ? ["one"] : [] content { enabled = true - storage_uri = var.bootstrap_storage_account.primary_blob_endpoint + storage_uri = var.diagnostics_storage_uri } } diff --git a/modules/vmseries/variables.tf b/modules/vmseries/variables.tf index 6e673e65..2f550219 100644 --- a/modules/vmseries/variables.tf +++ b/modules/vmseries/variables.tf @@ -58,18 +58,6 @@ variable "interfaces" { EOF } -variable "bootstrap_storage_account" { - description = "Existing storage account object for bootstrapping and for holding small-sized boot diagnostics. Usually the object is passed from a bootstrap module's output." - default = null - type = any -} - -variable "bootstrap_share_name" { - description = "Azure File Share holding the bootstrap data. Should reside on `bootstrap_storage_account`. Bootstrapping is omitted if `bootstrap_share_name` is left at null." - default = null - type = string -} - variable "username" { description = "Initial administrative username to use for VM-Series. Mind the [Azure-imposed restrictions](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/faq#what-are-the-username-requirements-when-creating-a-vm)." type = string @@ -173,3 +161,15 @@ variable "enable_zones" { default = true type = bool } + +variable "bootstrap_options" { + description = "Bootstrap options to pass to VM-Series instance." + default = "" + type = string +} + +variable "diagnostics_storage_uri" { + description = "The storage account's blob endpoint to hold diagnostic files." + default = null + type = string +} \ No newline at end of file diff --git a/modules/vmss/README.md b/modules/vmss/README.md index 3319800d..6f241e15 100644 --- a/modules/vmss/README.md +++ b/modules/vmss/README.md @@ -52,13 +52,12 @@ No modules. | [autoscale\_metrics](#input\_autoscale\_metrics) | Map of objects, where each key is the metric name to be used for autoscaling.
Each value of the map has the attributes `scaleout_threshold` and `scalein_threshold`, which cause the instance count to grow by 1 when metrics are greater or equal, or decrease by 1 when lower or equal, respectively.
The thresholds are applied to results of metrics' aggregation over a time window.
Example:
{
"DataPlaneCPUUtilizationPct" = {
scaleout_threshold = 80
scalein_threshold = 20
}
"panSessionUtilization" = {
scaleout_threshold = 80
scalein_threshold = 20
}
}
Other possible metrics include panSessionActive, panSessionThroughputKbps, panSessionThroughputPps, DataPlanePacketBufferUtilization. | `map` |
{
"DataPlaneCPUUtilizationPct": {
"scalein_threshold": 20,
"scaleout_threshold": 80
},
"panSessionUtilization": {
"scalein_threshold": 20,
"scaleout_threshold": 80
}
}
| no | | [autoscale\_notification\_emails](#input\_autoscale\_notification\_emails) | List of email addresses to notify about autoscaling events. | `list(string)` | `[]` | no | | [autoscale\_webhooks\_uris](#input\_autoscale\_webhooks\_uris) | Map where each key is an arbitrary identifier and each value is a webhook URI. The URIs receive autoscaling events. | `map(string)` | `{}` | no | -| [boot\_diagnostics\_storage\_account\_uri](#input\_boot\_diagnostics\_storage\_account\_uri) | n/a | `string` | `null` | no | -| [bootstrap\_share\_name](#input\_bootstrap\_share\_name) | File share for bootstrap config | `string` | n/a | yes | -| [bootstrap\_storage\_account](#input\_bootstrap\_storage\_account) | Storage account setup for bootstrapping |
object({
name = string
primary_access_key = string
})
| n/a | yes | +| [bootstrap\_options](#input\_bootstrap\_options) | Bootstrap options to pass to VM-Series instance. | `string` | `""` | no | | [create\_mgmt\_pip](#input\_create\_mgmt\_pip) | n/a | `bool` | `true` | no | | [create\_public\_interface](#input\_create\_public\_interface) | If true, create the third network interface for virtual machines. | `bool` | `true` | no | | [create\_public\_pip](#input\_create\_public\_pip) | n/a | `bool` | `true` | no | | [custom\_image\_id](#input\_custom\_image\_id) | Absolute ID of your own Custom Image to be used for creating new VM-Series. The Custom Image is expected to contain PAN-OS software. | `string` | `null` | no | +| [diagnostics\_storage\_uri](#input\_diagnostics\_storage\_uri) | The storage account's blob endpoint to hold diagnostic files. | `any` | `null` | no | | [disable\_password\_authentication](#input\_disable\_password\_authentication) | If true, disables password-based authentication on VM-Series instances. | `bool` | `false` | no | | [disk\_encryption\_set\_id](#input\_disk\_encryption\_set\_id) | n/a | `string` | `null` | no | | [enable\_plan](#input\_enable\_plan) | Enable usage of the Offer/Plan on Azure Marketplace. Even plan sku "byol", which means "bring your own license", still requires accepting on the Marketplace (as of 2021). Can be set to `false` when using a custom image. | `bool` | `true` | no | diff --git a/modules/vmss/main.tf b/modules/vmss/main.tf index 5800c067..2614d2b2 100644 --- a/modules/vmss/main.tf +++ b/modules/vmss/main.tf @@ -55,15 +55,7 @@ resource "azurerm_linux_virtual_machine_scale_set" "this" { # "Automatic repairs not supported for this Virtual Machine Scale Set because a health probe or health extension was not provided." upgrade_mode = "Manual" - custom_data = base64encode(join( - ",", - [ - "storage-account=${var.bootstrap_storage_account.name}", - "access-key=${var.bootstrap_storage_account.primary_access_key}", - "file-share=${var.bootstrap_share_name}", - "share-directory=None" - ] - )) + custom_data = base64encode(var.bootstrap_options) network_interface { name = "${var.name_prefix}${var.name_mgmt_nic_profile}" @@ -132,7 +124,7 @@ resource "azurerm_linux_virtual_machine_scale_set" "this" { } boot_diagnostics { - storage_account_uri = var.boot_diagnostics_storage_account_uri + storage_account_uri = var.diagnostics_storage_uri } identity { diff --git a/modules/vmss/variables.tf b/modules/vmss/variables.tf index d869681d..ec4e2caf 100644 --- a/modules/vmss/variables.tf +++ b/modules/vmss/variables.tf @@ -54,19 +54,6 @@ variable "public_pip_domain_name_label" { type = string } -variable "bootstrap_storage_account" { - description = "Storage account setup for bootstrapping" - type = object({ - name = string - primary_access_key = string - }) -} - -variable "bootstrap_share_name" { - description = "File share for bootstrap config" - type = string -} - variable "username" { description = "Initial administrative username to use for VM-Series." default = "panadmin" @@ -144,11 +131,6 @@ variable "storage_account_type" { type = string } -variable "boot_diagnostics_storage_account_uri" { - default = null - type = string -} - variable "disk_encryption_set_id" { default = null type = string @@ -400,3 +382,15 @@ variable "name_private_nic_profile" { variable "name_private_nic_ip" { default = "nic-fw-private" } + +variable "bootstrap_options" { + description = "Bootstrap options to pass to VM-Series instance." + default = "" + type = string +} + +variable "diagnostics_storage_uri" { + description = "The storage account's blob endpoint to hold diagnostic files." + default = null + type = any +} \ No newline at end of file