diff --git a/README.md b/README.md
index 5d7e8f51..2afb9647 100644
--- a/README.md
+++ b/README.md
@@ -65,6 +65,40 @@ private_dns_rg_name = "myResourceGroup"
```
**If you don't pass these params, we will automatically create the network resources for you.**
+## Storage account
+### We create/use the following storage accounts
+- Logic app storage account - Stores the logic app configuration. Created by our module.
+- Deployment storage account - Stores the deployment states (cluster and also NFS if configured). Created by our module if not provided.
+- Weka OBS storage account - Created by our function app if OBS is configured and OBS storage account is not provided.
+
+### Storage account networking options
+```hcl
+variable "storage_account_public_network_access" {
+ type = string
+ description = "Public network access to the storage accounts."
+ default = "Enabled"
+
+ validation {
+ condition = contains(["Enabled", "Disabled", "EnabledForVnet"], var.storage_account_public_network_access)
+ error_message = "Allowed values: [\"Enabled\", \"Disabled\", \"EnabledForVnet\"]."
+ }
+}
+```
+- `Enabled`: By default, the storage account is created with public network access enabled.
+- `EnabledForVnet`: The storage account is created with public network access enabled, but only for the specified virtual network.
+ - Access should be enabled for the vnet, function app subnet delegation.
+ - File share is required (can provide existing via `deployment_file_share_name` or it will be auto-created in case if `storage_account_allowed_ips` are provided).
+ - `storage_account_allowed_ips`: required to allow creating the logic app storage account with the required config and function app file share.
+ - if `storage_account_allowed_ips` if not provided, scale down and autoscaling will not be supported and the file share needs to be created by the user.
+ - OBS storage account: if created by our module only the regular [OBS](#OBS) config is required. If provided by the user needs to have the Vnet enabled.
+- `Disabled`: The storage account is created with public network access disabled.
+ - Scale down and autoscaling is not supported.
+ - Pre created deployment storage account is required.
+ - File share is required (`deployment_file_share_name`).
+ - Blob and file endpoints and private links are required. It can be created by our module if `create_storage_account_private_links` is provided or by the user. In case if there are existing private endpoints and `create_storage_account_private_links` is not set, `storage_blob_private_dns_zone_name` can be also set to specify private DNS zone for blob resource (uses Azure-recommended name as default value).
+ - OBS storage account: if created by our module only the regular [OBS](#OBS) config is required. If provided by the user, blob and file endpoints and private links are required.
+They can be created by our module if `create_storage_account_private_links` is provided.
+
## Usage example
```hcl
provider "azurerm" {
@@ -295,18 +329,16 @@ proxy_url = VALUE
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
| [local](#requirement\_local) | ~>2.4.0 |
-| [random](#requirement\_random) | ~>3.5.1 |
| [tls](#requirement\_tls) | ~>4.0.4 |
## Providers
| Name | Version |
|------|---------|
-| [azurerm](#provider\_azurerm) | ~>3.75.0 |
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
| [local](#provider\_local) | ~>2.4.0 |
-| [random](#provider\_random) | ~>3.5.1 |
| [tls](#provider\_tls) | ~>4.0.4 |
## Modules
@@ -314,7 +346,10 @@ proxy_url = VALUE
| Name | Source | Version |
|------|--------|---------|
| [clients](#module\_clients) | ./modules/clients | n/a |
+| [function\_app\_subnet\_delegation](#module\_function\_app\_subnet\_delegation) | ./modules/subnet_delegation | n/a |
| [iam](#module\_iam) | ./modules/iam | n/a |
+| [logic\_app\_subnet\_delegation](#module\_logic\_app\_subnet\_delegation) | ./modules/subnet_delegation | n/a |
+| [logicapp](#module\_logicapp) | ./modules/logic_app | n/a |
| [network](#module\_network) | ./modules/network | n/a |
| [nfs\_protocol\_gateways](#module\_nfs\_protocol\_gateways) | ./modules/protocol_gateways | n/a |
| [peering](#module\_peering) | ./modules/peering_vnets | n/a |
@@ -327,13 +362,13 @@ proxy_url = VALUE
|------|------|
| [azurerm_application_insights.application_insights](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_insights) | resource |
| [azurerm_key_vault.key_vault](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault) | resource |
-| [azurerm_key_vault_access_policy.function_app_get_secret_permission](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
+| [azurerm_key_vault_access_policy.function_app_secret_permissions](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
| [azurerm_key_vault_access_policy.key_vault_access_policy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
-| [azurerm_key_vault_access_policy.standard_logic_app_get_secret_permission](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
| [azurerm_key_vault_secret.function_app_default_key](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
| [azurerm_key_vault_secret.get_weka_io_token](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
| [azurerm_key_vault_secret.private_ssh_keys](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
| [azurerm_key_vault_secret.public_ssh_keys](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
+| [azurerm_key_vault_secret.weka_deployment_password](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
| [azurerm_key_vault_secret.weka_password_secret](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
| [azurerm_lb.backend_lb](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb) | resource |
| [azurerm_lb.ui_lb](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb) | resource |
@@ -345,7 +380,6 @@ proxy_url = VALUE
| [azurerm_lb_rule.ui_lb_rule](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb_rule) | resource |
| [azurerm_linux_function_app.function_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_function_app) | resource |
| [azurerm_log_analytics_workspace.la_workspace](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_workspace) | resource |
-| [azurerm_logic_app_standard.logic_app_standard](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/logic_app_standard) | resource |
| [azurerm_monitor_diagnostic_setting.function_diagnostic_setting](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_diagnostic_setting) | resource |
| [azurerm_monitor_diagnostic_setting.insights_diagnostic_setting](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_diagnostic_setting) | resource |
| [azurerm_private_dns_a_record.dns_a_record_backend_lb](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_a_record) | resource |
@@ -354,39 +388,36 @@ proxy_url = VALUE
| [azurerm_private_dns_resolver_forwarding_rule.resolver_forwarding_rule](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_resolver_forwarding_rule) | resource |
| [azurerm_private_dns_resolver_outbound_endpoint.outbound_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_resolver_outbound_endpoint) | resource |
| [azurerm_private_dns_resolver_virtual_network_link.dns_forwarding_virtual_network_link](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_resolver_virtual_network_link) | resource |
+| [azurerm_private_dns_zone.blob](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone) | resource |
+| [azurerm_private_dns_zone.file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone) | resource |
+| [azurerm_private_dns_zone_virtual_network_link.blob_privatelink](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone_virtual_network_link) | resource |
+| [azurerm_private_dns_zone_virtual_network_link.file_privatelink](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone_virtual_network_link) | resource |
+| [azurerm_private_endpoint.blob_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.file_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.weka_obs_blob_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
| [azurerm_proximity_placement_group.ppg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/proximity_placement_group) | resource |
| [azurerm_public_ip.backend_ip](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip) | resource |
| [azurerm_public_ip.ui_ip](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip) | resource |
| [azurerm_service_plan.app_service_plan](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/service_plan) | resource |
-| [azurerm_service_plan.logicapp_service_plan](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/service_plan) | resource |
| [azurerm_storage_account.deployment_sa](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) | resource |
| [azurerm_storage_account.logicapp](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) | resource |
| [azurerm_storage_blob.nfs_state](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_blob) | resource |
| [azurerm_storage_blob.state](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_blob) | resource |
-| [azurerm_storage_blob.vmss_config](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_blob) | resource |
| [azurerm_storage_container.deployment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) | resource |
| [azurerm_storage_container.nfs_deployment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) | resource |
-| [azurerm_storage_share_directory.share_directory_scale_down](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_directory) | resource |
-| [azurerm_storage_share_directory.share_directory_scale_up](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_directory) | resource |
-| [azurerm_storage_share_file.connections_share_file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_file) | resource |
-| [azurerm_storage_share_file.scale_down_share_file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_file) | resource |
-| [azurerm_storage_share_file.scale_up_share_file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_file) | resource |
+| [azurerm_storage_share.function_app_share](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share) | resource |
| [azurerm_subnet.dns_resolver_subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource |
-| [azurerm_subnet.logicapp_subnet_delegation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource |
-| [azurerm_subnet.subnet_delegation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource |
-| [local_file.connections_workflow_file](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
| [local_file.private_key](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
| [local_file.public_key](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
-| [local_file.scale_down_workflow_file](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
-| [local_file.scale_up_workflow_file](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
-| [random_password.weka_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |
| [tls_private_key.ssh_key](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource |
| [azurerm_application_insights.application_insights](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/application_insights) | data source |
| [azurerm_client_config.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/client_config) | data source |
| [azurerm_function_app_host_keys.function_keys](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/function_app_host_keys) | data source |
+| [azurerm_private_dns_zone.blob](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
| [azurerm_resource_group.rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source |
| [azurerm_storage_account.deployment_blob](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/storage_account) | data source |
-| [azurerm_storage_share.storage_share](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/storage_share) | data source |
+| [azurerm_storage_account.weka_obs](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/storage_account) | data source |
+| [azurerm_storage_account_blob_container_sas.function_app_code_sas](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/storage_account_blob_container_sas) | data source |
| [azurerm_subnet.subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet) | data source |
| [azurerm_virtual_network.vnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network) | data source |
@@ -409,37 +440,40 @@ proxy_url = VALUE
| [clients\_custom\_data](#input\_clients\_custom\_data) | Custom data to pass to the client instances | `string` | `""` | no |
| [clients\_number](#input\_clients\_number) | The number of client virtual machines to deploy. | `number` | `0` | no |
| [clients\_use\_dpdk](#input\_clients\_use\_dpdk) | Mount weka clients in DPDK mode | `bool` | `true` | no |
+| [clients\_use\_vmss](#input\_clients\_use\_vmss) | Use VMSS for clients | `bool` | `false` | no |
| [cluster\_name](#input\_cluster\_name) | Cluster name | `string` | `"poc"` | no |
| [cluster\_size](#input\_cluster\_size) | The number of virtual machines to deploy. | `number` | `6` | no |
| [clusterization\_target](#input\_clusterization\_target) | The clusterization target | `number` | `null` | no |
| [containers\_config\_map](#input\_containers\_config\_map) | Maps the number of objects and memory size per machine type. |
map(object({
compute = number
drive = number
frontend = number
nvme = number
nics = number
memory = list(string)
}))
| {
"Standard_L16as_v3": {
"compute": 4,
"drive": 2,
"frontend": 1,
"memory": [
"72GB",
"73GB"
],
"nics": 8,
"nvme": 2
},
"Standard_L16s_v3": {
"compute": 4,
"drive": 2,
"frontend": 1,
"memory": [
"79GB",
"72GB"
],
"nics": 8,
"nvme": 2
},
"Standard_L32as_v3": {
"compute": 4,
"drive": 2,
"frontend": 1,
"memory": [
"190GB",
"190GB"
],
"nics": 8,
"nvme": 4
},
"Standard_L32s_v3": {
"compute": 4,
"drive": 2,
"frontend": 1,
"memory": [
"197GB",
"189GB"
],
"nics": 8,
"nvme": 4
},
"Standard_L48as_v3": {
"compute": 3,
"drive": 3,
"frontend": 1,
"memory": [
"308GB",
"308GB"
],
"nics": 8,
"nvme": 6
},
"Standard_L48s_v3": {
"compute": 3,
"drive": 3,
"frontend": 1,
"memory": [
"314GB",
"306GB"
],
"nics": 8,
"nvme": 6
},
"Standard_L64as_v3": {
"compute": 4,
"drive": 2,
"frontend": 1,
"memory": [
"384GB",
"384GB"
],
"nics": 8,
"nvme": 8
},
"Standard_L64s_v3": {
"compute": 4,
"drive": 2,
"frontend": 1,
"memory": [
"357GB",
"384GB"
],
"nics": 8,
"nvme": 8
},
"Standard_L80as_v3": {
"compute": 4,
"drive": 2,
"frontend": 1,
"memory": [
"384GB",
"384GB"
],
"nics": 8,
"nvme": 8
},
"Standard_L80s_v3": {
"compute": 4,
"drive": 2,
"frontend": 1,
"memory": [
"384GB",
"384GB"
],
"nics": 8,
"nvme": 8
},
"Standard_L8as_v3": {
"compute": 1,
"drive": 1,
"frontend": 1,
"memory": [
"29GB",
"29GB"
],
"nics": 4,
"nvme": 1
},
"Standard_L8s_v3": {
"compute": 1,
"drive": 1,
"frontend": 1,
"memory": [
"33GB",
"31GB"
],
"nics": 4,
"nvme": 1
}
}
| no |
| [create\_lb](#input\_create\_lb) | Create backend and UI load balancers for weka cluster. | `bool` | `true` | no |
| [create\_nat\_gateway](#input\_create\_nat\_gateway) | NAT needs to be created when no public ip is assigned to the backend, to allow internet access | `bool` | `false` | no |
+| [create\_storage\_account\_private\_links](#input\_create\_storage\_account\_private\_links) | Create private links for storage accounts (needed in case if public network access for the storage account is disabled). | `bool` | `false` | no |
| [debug\_down\_backends\_removal\_timeout](#input\_debug\_down\_backends\_removal\_timeout) | Don't change this value without consulting weka support team. Timeout for removing down backends. Valid time units are ns, us (or µs), ms, s, m, h. | `string` | `"3h"` | no |
| [default\_disk\_size](#input\_default\_disk\_size) | The default disk size. | `number` | `48` | no |
| [deployment\_container\_name](#input\_deployment\_container\_name) | Name of exising deployment container | `string` | `""` | no |
-| [deployment\_storage\_account\_access\_key](#input\_deployment\_storage\_account\_access\_key) | The access key of the existing Blob object store container. | `string` | `""` | no |
+| [deployment\_file\_share\_name](#input\_deployment\_file\_share\_name) | Name of exising deployment file share. Will use '-share' name if not provided. | `string` | `""` | no |
+| [deployment\_function\_app\_code\_blob](#input\_deployment\_function\_app\_code\_blob) | The path to the function app code blob file. | `string` | `""` | no |
| [deployment\_storage\_account\_name](#input\_deployment\_storage\_account\_name) | Name of exising deployment storage account | `string` | `""` | no |
| [enable\_application\_insights](#input\_enable\_application\_insights) | Enable Application Insights. | `bool` | `true` | no |
| [function\_access\_restriction\_enabled](#input\_function\_access\_restriction\_enabled) | Allow public access, Access restrictions apply to inbound access to internal vent | `bool` | `false` | no |
-| [function\_app\_dist](#input\_function\_app\_dist) | Function app code dist | `string` | `"release"` | no |
+| [function\_app\_dist](#input\_function\_app\_dist) | Function app code dist | `string` | `"dev"` | no |
| [function\_app\_identity\_name](#input\_function\_app\_identity\_name) | The user assigned identity name for the function app (if empty - new one is created). | `string` | `""` | no |
| [function\_app\_log\_level](#input\_function\_app\_log\_level) | Log level for function app (from -1 to 5). See https://github.com/rs/zerolog#leveled-logging | `number` | `1` | no |
| [function\_app\_storage\_account\_container\_prefix](#input\_function\_app\_storage\_account\_container\_prefix) | Weka storage account container name prefix | `string` | `"weka-tf-functions-deployment-"` | no |
| [function\_app\_storage\_account\_prefix](#input\_function\_app\_storage\_account\_prefix) | Weka storage account name prefix | `string` | `"weka"` | no |
| [function\_app\_subnet\_delegation\_cidr](#input\_function\_app\_subnet\_delegation\_cidr) | Subnet delegation enables you to designate a specific subnet for an Azure PaaS service. | `string` | `"10.0.1.0/25"` | no |
| [function\_app\_subnet\_delegation\_id](#input\_function\_app\_subnet\_delegation\_id) | Required to specify if subnet\_name were used to specify pre-defined subnets for weka. Function subnet delegation requires an additional subnet, and in the case of pre-defined networking this one also should be pre-defined | `string` | `""` | no |
-| [function\_app\_version](#input\_function\_app\_version) | Function app code version (hash) | `string` | `"5464597f9be93b3c954324b1811ace7a"` | no |
+| [function\_app\_version](#input\_function\_app\_version) | Function app code version (hash) | `string` | `"70129b9f8d813e6f87aeed9be4764327"` | no |
| [get\_weka\_io\_token](#input\_get\_weka\_io\_token) | The token to download the Weka release from get.weka.io. | `string` | `""` | no |
| [hotspare](#input\_hotspare) | Number of hotspares to set on weka cluster. Refer to https://docs.weka.io/overview/ssd-capacity-management#hot-spare | `number` | `1` | no |
| [install\_cluster\_dpdk](#input\_install\_cluster\_dpdk) | Install weka cluster with DPDK | `bool` | `true` | no |
| [install\_weka\_url](#input\_install\_weka\_url) | The URL of the Weka release download tar file. | `string` | `""` | no |
| [instance\_type](#input\_instance\_type) | The virtual machine type (sku) to deploy. | `string` | `"Standard_L8s_v3"` | no |
+| [key\_vault\_purge\_protection\_enabled](#input\_key\_vault\_purge\_protection\_enabled) | Enable purge protection for the key vault. | `bool` | `false` | no |
| [log\_analytics\_workspace\_id](#input\_log\_analytics\_workspace\_id) | The Log Analytics workspace id. | `string` | `""` | no |
| [logic\_app\_identity\_name](#input\_logic\_app\_identity\_name) | The user assigned identity name for the logic app (if empty - new one is created). | `string` | `""` | no |
| [logic\_app\_subnet\_delegation\_cidr](#input\_logic\_app\_subnet\_delegation\_cidr) | Subnet delegation enables you to designate a specific subnet for an Azure PaaS service. | `string` | `"10.0.3.0/25"` | no |
| [logic\_app\_subnet\_delegation\_id](#input\_logic\_app\_subnet\_delegation\_id) | Required to specify if subnet\_name were used to specify pre-defined subnets for weka. Logicapp subnet delegation requires an additional subnet, and in the case of pre-defined networking this one also should be pre-defined | `string` | `""` | no |
-| [nfs\_client\_group\_name](#input\_nfs\_client\_group\_name) | Client access group name. | `string` | `"weka-cg"` | no |
| [nfs\_deployment\_container\_name](#input\_nfs\_deployment\_container\_name) | Name of exising protocol deployment container | `string` | `""` | no |
| [nfs\_interface\_group\_name](#input\_nfs\_interface\_group\_name) | Interface group name. | `string` | `"weka-ig"` | no |
| [nfs\_protocol\_gateway\_disk\_size](#input\_nfs\_protocol\_gateway\_disk\_size) | The protocol gateways' default disk size. | `number` | `48` | no |
@@ -452,9 +486,11 @@ proxy_url = VALUE
| [prefix](#input\_prefix) | Prefix for all resources | `string` | `"weka"` | no |
| [private\_dns\_rg\_name](#input\_private\_dns\_rg\_name) | The private DNS zone resource group name. Required when private\_dns\_zone\_name is set. | `string` | `""` | no |
| [private\_dns\_zone\_name](#input\_private\_dns\_zone\_name) | The private DNS zone name. | `string` | `""` | no |
+| [private\_dns\_zone\_use](#input\_private\_dns\_zone\_use) | Determines whether to use private DNS zone. Required for LB record creation. | `bool` | `true` | no |
| [protection\_level](#input\_protection\_level) | Cluster data protection level. | `number` | `2` | no |
| [protocol\_gateways\_identity\_name](#input\_protocol\_gateways\_identity\_name) | The user assigned identity name for the protocol gateways instances (if empty - new one is created). | `string` | `""` | no |
| [proxy\_url](#input\_proxy\_url) | Weka home proxy url | `string` | `""` | no |
+| [read\_function\_zip\_from\_storage\_account](#input\_read\_function\_zip\_from\_storage\_account) | Read function app zip from storage account (is read from public distribution storage account by default). | `bool` | `false` | no |
| [rg\_name](#input\_rg\_name) | A predefined resource group in the Azure subscription. | `string` | n/a | yes |
| [s3\_protocol\_gateway\_disk\_size](#input\_s3\_protocol\_gateway\_disk\_size) | The protocol gateways' default disk size. | `number` | `48` | no |
| [s3\_protocol\_gateway\_fe\_cores\_num](#input\_s3\_protocol\_gateway\_fe\_cores\_num) | The number of frontend cores on single protocol gateway machine. | `number` | `1` | no |
@@ -480,6 +516,9 @@ proxy_url = VALUE
| [smbw\_enabled](#input\_smbw\_enabled) | Enable SMBW protocol. This option should be provided before cluster is created to leave extra capacity for SMBW setup. | `bool` | `true` | no |
| [source\_image\_id](#input\_source\_image\_id) | Use weka custom image, ubuntu 20.04 with kernel 5.4 and ofed 5.8-1.1.2.1 | `string` | `"/communityGalleries/WekaIO-d7d3f308-d5a1-4c45-8e8a-818aed57375a/images/ubuntu20.04/versions/latest"` | no |
| [ssh\_public\_key](#input\_ssh\_public\_key) | Ssh public key to pass to vms. | `string` | `null` | no |
+| [storage\_account\_allowed\_ips](#input\_storage\_account\_allowed\_ips) | IP ranges to allow access from the internet or your on-premises networks to storage accounts. | `list(string)` | `[]` | no |
+| [storage\_account\_public\_network\_access](#input\_storage\_account\_public\_network\_access) | Public network access to the storage accounts. | `string` | `"Enabled"` | no |
+| [storage\_blob\_private\_dns\_zone\_name](#input\_storage\_blob\_private\_dns\_zone\_name) | The private DNS zone name for the storage account (blob). | `string` | `"privatelink.blob.core.windows.net"` | no |
| [stripe\_width](#input\_stripe\_width) | Stripe width = cluster\_size - protection\_level - 1 (by default). | `number` | `-1` | no |
| [subnet\_name](#input\_subnet\_name) | The subnet name. | `string` | `""` | no |
| [subnet\_prefix](#input\_subnet\_prefix) | Address prefixes to use for the subnet | `string` | `"10.0.2.0/24"` | no |
@@ -512,6 +551,8 @@ proxy_url = VALUE
| [backend\_ips](#output\_backend\_ips) | If 'assign\_public\_ip' is set to true, it will output the public ips, If no it will output the private ips |
| [backend\_lb\_private\_ip](#output\_backend\_lb\_private\_ip) | Backend load balancer ip address |
| [client\_ips](#output\_client\_ips) | If 'private\_network' is set to false, it will output clients public ips, otherwise private ips. |
+| [client\_vmss\_ips](#output\_client\_vmss\_ips) | If 'private\_network' is set to false, it will output clients public ips, otherwise private ips. |
+| [clients\_vmss\_name](#output\_clients\_vmss\_name) | n/a |
| [cluster\_helper\_commands](#output\_cluster\_helper\_commands) | Useful commands and script to interact with weka cluster |
| [function\_app\_name](#output\_function\_app\_name) | Function app name |
| [function\_key\_name](#output\_function\_key\_name) | Function app key name |
@@ -528,4 +569,5 @@ proxy_url = VALUE
| [vmss\_name](#output\_vmss\_name) | n/a |
| [vnet\_name](#output\_vnet\_name) | Virtual network name |
| [vnet\_rg\_name](#output\_vnet\_rg\_name) | Virtual network resource group name |
+| [weka\_cluster\_admin\_password\_secret\_name](#output\_weka\_cluster\_admin\_password\_secret\_name) | Weka cluster admin password secret name |
diff --git a/blob.tf b/blob.tf
index 65c124f7..abf293ea 100644
--- a/blob.tf
+++ b/blob.tf
@@ -1,15 +1,22 @@
locals {
- clusterization_target = var.clusterization_target != null ? var.clusterization_target : min(var.cluster_size, max(20, ceil(var.cluster_size * 0.8)))
- # fields that depend on LB creation
- vmss_health_probe_id = var.create_lb ? azurerm_lb_probe.backend_lb_probe[0].id : null
- lb_backend_pool_ids = var.create_lb ? [azurerm_lb_backend_address_pool.lb_backend_pool[0].id] : []
+ deployment_storage_account_id = var.deployment_storage_account_name == "" ? azurerm_storage_account.deployment_sa[0].id : data.azurerm_storage_account.deployment_blob[0].id
+ deployment_storage_account_name = var.deployment_storage_account_name == "" ? azurerm_storage_account.deployment_sa[0].name : var.deployment_storage_account_name
+ deployment_sa_connection_string = var.deployment_storage_account_name == "" ? azurerm_storage_account.deployment_sa[0].primary_connection_string : data.azurerm_storage_account.deployment_blob[0].primary_connection_string
+ deployment_container_name = var.deployment_container_name == "" ? "${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}-deployment" : var.deployment_container_name
+ deployment_file_share_name = var.deployment_file_share_name == "" ? "${local.deployment_storage_account_name}-share" : var.deployment_file_share_name
+ deployment_sa_access_key = var.deployment_storage_account_name == "" ? azurerm_storage_account.deployment_sa[0].primary_access_key : data.azurerm_storage_account.deployment_blob[0].primary_access_key
+
+ sa_allowed_ips_provided = length(var.storage_account_allowed_ips) > 0
+ sa_public_access_enabled = var.storage_account_public_network_access == "Enabled"
+ sa_public_access_for_vnet = var.storage_account_public_network_access == "EnabledForVnet"
+ sa_public_access_disabled = var.storage_account_public_network_access == "Disabled"
+ create_sa_resources = local.sa_public_access_enabled || local.sa_public_access_for_vnet && local.sa_allowed_ips_provided
}
-
resource "azurerm_storage_account" "deployment_sa" {
- count = var.deployment_storage_account_name == "" ? 1 : 0
+ count = var.deployment_storage_account_name == "" && local.create_sa_resources ? 1 : 0
name = substr("${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}deployment", 0, 24)
- location = data.azurerm_resource_group.rg.location
+ location = local.location
resource_group_name = var.rg_name
account_kind = "StorageV2"
account_tier = "Standard"
@@ -18,10 +25,20 @@ resource "azurerm_storage_account" "deployment_sa" {
lifecycle {
ignore_changes = [tags]
}
+
+ dynamic "network_rules" {
+ for_each = local.sa_public_access_for_vnet ? [1] : []
+ content {
+ default_action = "Deny"
+ bypass = ["AzureServices"]
+ ip_rules = var.storage_account_allowed_ips
+ virtual_network_subnet_ids = [data.azurerm_subnet.subnet.id, local.function_app_subnet_delegation_id]
+ }
+ }
}
resource "azurerm_storage_container" "deployment" {
- count = var.deployment_container_name == "" ? 1 : 0
+ count = var.deployment_container_name == "" && local.create_sa_resources ? 1 : 0
name = "${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}-deployment"
storage_account_name = local.deployment_storage_account_name
container_access_type = "private"
@@ -29,6 +46,7 @@ resource "azurerm_storage_container" "deployment" {
}
resource "azurerm_storage_blob" "state" {
+ count = local.create_sa_resources ? 1 : 0
name = "state"
storage_account_name = local.deployment_storage_account_name
storage_container_name = local.deployment_container_name
@@ -41,97 +59,18 @@ resource "azurerm_storage_blob" "state" {
}
}
-data "azurerm_storage_account" "deployment_blob" {
- count = var.deployment_storage_account_name != "" ? 1 : 0
- name = var.deployment_storage_account_name
- resource_group_name = var.rg_name
+resource "azurerm_storage_share" "function_app_share" {
+ count = var.deployment_file_share_name == "" && local.sa_public_access_for_vnet && local.sa_allowed_ips_provided ? 1 : 0
+ name = local.deployment_file_share_name
+ storage_account_name = local.deployment_storage_account_name
+ quota = 100
+ depends_on = [azurerm_storage_account.deployment_sa]
}
-resource "azurerm_storage_blob" "vmss_config" {
- name = "vmss-config"
- storage_account_name = local.deployment_storage_account_name
- storage_container_name = local.deployment_container_name
- type = "Block"
-
- source_content = jsonencode({
- name = "${var.prefix}-${var.cluster_name}-vmss"
- location = data.azurerm_resource_group.rg.location
- zones = var.zone != null ? [var.zone] : []
- resource_group_name = var.rg_name
- sku = var.instance_type
- upgrade_mode = "Manual"
- health_probe_id = local.vmss_health_probe_id
- admin_username = var.vm_username
- ssh_public_key = local.public_ssh_key
- computer_name_prefix = "${var.prefix}-${var.cluster_name}-backend"
- custom_data = base64encode(local.custom_data_script)
- disable_password_authentication = true
- proximity_placement_group_id = local.placement_group_id
- single_placement_group = var.vmss_single_placement_group
- source_image_id = var.source_image_id
- overprovision = false
- orchestration_mode = "Uniform"
- tags = merge(var.tags_map, {
- "weka_cluster" : var.cluster_name,
- "user_id" : data.azurerm_client_config.current.object_id,
- })
-
- os_disk = {
- caching = "ReadWrite"
- storage_account_type = "Premium_LRS"
- }
-
- data_disk = {
- lun = 0
- caching = "None"
- create_option = "Empty"
- disk_size_gb = local.disk_size
- storage_account_type = "Premium_LRS"
- }
-
- identity = {
- type = "UserAssigned"
- identity_ids = [local.vmss_identity_id]
- }
-
- primary_nic = {
- name = "${var.prefix}-${var.cluster_name}-backend-nic-0"
- network_security_group_id = local.sg_id
- enable_accelerated_networking = var.install_cluster_dpdk
-
- ip_configurations = [{
- primary = true
- subnet_id = data.azurerm_subnet.subnet.id
- load_balancer_backend_address_pool_ids = local.lb_backend_pool_ids
- public_ip_address = {
- assign = local.assign_public_ip
- name = "${var.prefix}-${var.cluster_name}-public-ip"
- domain_name_label = "${var.prefix}-${var.cluster_name}-backend"
- }
- }]
- }
-
- secondary_nics = {
- number = local.nics_numbers - 1
- name_prefix = "${var.prefix}-${var.cluster_name}-backend-nic"
- network_security_group_id = local.sg_id
- enable_accelerated_networking = var.install_cluster_dpdk
- ip_configurations = [{
- primary = true
- subnet_id = data.azurerm_subnet.subnet.id
- load_balancer_backend_address_pool_ids = local.lb_backend_pool_ids
- }]
- }
- })
- depends_on = [
- azurerm_storage_container.deployment, azurerm_lb_backend_address_pool.lb_backend_pool, azurerm_lb_probe.backend_lb_probe,
- azurerm_proximity_placement_group.ppg, azurerm_lb_rule.backend_lb_rule, azurerm_lb_rule.ui_lb_rule
- ]
-}
# state for protocols
resource "azurerm_storage_container" "nfs_deployment" {
- count = var.nfs_deployment_container_name == "" ? 1 : 0
+ count = var.nfs_deployment_container_name == "" && local.create_sa_resources ? 1 : 0
name = "${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}-protocol-deployment"
storage_account_name = local.deployment_storage_account_name
container_access_type = "private"
@@ -139,7 +78,7 @@ resource "azurerm_storage_container" "nfs_deployment" {
}
resource "azurerm_storage_blob" "nfs_state" {
- count = var.nfs_protocol_gateways_number > 0 ? 1 : 0
+ count = var.nfs_protocol_gateways_number > 0 && local.create_sa_resources ? 1 : 0
name = "nfs_state"
storage_account_name = local.deployment_storage_account_name
storage_container_name = local.nfs_deployment_container_name
@@ -157,3 +96,155 @@ resource "azurerm_storage_blob" "nfs_state" {
ignore_changes = all
}
}
+
+resource "azurerm_storage_account" "logicapp" {
+ count = local.create_sa_resources ? 1 : 0
+ name = substr("${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}logicappsa", 0, 24)
+ resource_group_name = var.rg_name
+ location = local.location
+ account_tier = "Standard"
+ account_replication_type = "LRS"
+
+ dynamic "network_rules" {
+ for_each = local.sa_public_access_for_vnet ? [1] : []
+ content {
+ default_action = "Deny"
+ bypass = ["AzureServices"]
+ ip_rules = var.storage_account_allowed_ips
+ virtual_network_subnet_ids = [data.azurerm_subnet.subnet.id, var.logic_app_subnet_delegation_id == "" ? module.logic_app_subnet_delegation[0].id : var.logic_app_subnet_delegation_id]
+ }
+ }
+}
+
+data "azurerm_storage_account" "deployment_blob" {
+ count = var.deployment_storage_account_name != "" ? 1 : 0
+ name = var.deployment_storage_account_name
+ resource_group_name = local.resource_group_name
+}
+
+resource "azurerm_private_dns_zone" "blob" {
+ count = var.create_storage_account_private_links ? 1 : 0
+ name = "privatelink.blob.core.windows.net"
+ resource_group_name = local.resource_group_name
+}
+
+data "azurerm_private_dns_zone" "blob" {
+ count = !var.create_storage_account_private_links && local.sa_public_access_disabled ? 1 : 0
+ name = var.storage_blob_private_dns_zone_name
+}
+
+resource "azurerm_private_dns_zone" "file" {
+ count = var.create_storage_account_private_links ? 1 : 0
+ name = "privatelink.file.core.windows.net"
+ resource_group_name = local.resource_group_name
+}
+
+resource "azurerm_private_dns_zone_virtual_network_link" "blob_privatelink" {
+ count = var.create_storage_account_private_links ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-blob-privatelink"
+ resource_group_name = local.resource_group_name
+ private_dns_zone_name = azurerm_private_dns_zone.blob[0].name
+ virtual_network_id = data.azurerm_virtual_network.vnet.id
+}
+
+resource "azurerm_private_dns_zone_virtual_network_link" "file_privatelink" {
+ count = var.create_storage_account_private_links ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-file-privatelink"
+ resource_group_name = local.resource_group_name
+ private_dns_zone_name = azurerm_private_dns_zone.file[0].name
+ virtual_network_id = data.azurerm_virtual_network.vnet.id
+}
+
+resource "azurerm_private_endpoint" "file_endpoint" {
+ count = var.create_storage_account_private_links ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-file-endpoint"
+ location = data.azurerm_resource_group.rg.location
+ resource_group_name = data.azurerm_resource_group.rg.name
+ subnet_id = data.azurerm_subnet.subnet.id
+ tags = merge(var.tags_map, { "weka_cluster" : var.cluster_name })
+
+ private_dns_zone_group {
+ name = "${var.prefix}-${var.cluster_name}-dns-zone-group-file"
+ private_dns_zone_ids = [azurerm_private_dns_zone.file[0].id]
+ }
+
+ private_service_connection {
+ name = "${var.prefix}-${var.cluster_name}-privateFileSvcCon"
+ is_manual_connection = false
+ private_connection_resource_id = local.deployment_storage_account_id
+ subresource_names = ["file"]
+ }
+}
+
+resource "azurerm_private_endpoint" "blob_endpoint" {
+ count = var.create_storage_account_private_links ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-blob-endpoint"
+ location = data.azurerm_resource_group.rg.location
+ resource_group_name = data.azurerm_resource_group.rg.name
+ subnet_id = data.azurerm_subnet.subnet.id
+ tags = merge(var.tags_map, { "weka_cluster" : var.cluster_name })
+
+ private_dns_zone_group {
+ name = "${var.prefix}-${var.cluster_name}-dns-zone-group-blob"
+ private_dns_zone_ids = [azurerm_private_dns_zone.blob[0].id]
+ }
+ private_service_connection {
+ name = "${var.prefix}-${var.cluster_name}-privateBlobSvcCon"
+ is_manual_connection = false
+ private_connection_resource_id = local.deployment_storage_account_id
+ subresource_names = ["blob"]
+ }
+}
+
+data "azurerm_storage_account" "weka_obs" {
+ count = var.tiering_obs_name != "" ? 1 : 0
+ name = var.tiering_obs_name
+ resource_group_name = var.rg_name
+}
+
+resource "azurerm_private_endpoint" "weka_obs_blob_endpoint" {
+ count = var.create_storage_account_private_links && var.tiering_blob_obs_access_key != "" ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-obs-blob-endpoint"
+ location = data.azurerm_resource_group.rg.location
+ resource_group_name = data.azurerm_resource_group.rg.name
+ subnet_id = data.azurerm_subnet.subnet.id
+ tags = merge(var.tags_map, { "weka_cluster" : var.cluster_name })
+
+ private_dns_zone_group {
+ name = "${var.prefix}-${var.cluster_name}-dns-zone-group-obs-blob"
+ private_dns_zone_ids = [azurerm_private_dns_zone.blob[0].id]
+ }
+ private_service_connection {
+ name = "${var.prefix}-${var.cluster_name}-private-obs-BlobSvcCon"
+ is_manual_connection = false
+ private_connection_resource_id = data.azurerm_storage_account.weka_obs[0].id
+ subresource_names = ["blob"]
+ }
+
+ lifecycle {
+ precondition {
+ condition = var.tiering_obs_name != ""
+ error_message = "Tiering OBS is not provided"
+ }
+ precondition {
+ condition = var.tiering_obs_container_name != ""
+ error_message = "Tiering OBS container name is not provided"
+ }
+ }
+}
+
+data "azurerm_storage_account_blob_container_sas" "function_app_code_sas" {
+ count = local.sa_public_access_enabled || local.sa_public_access_for_vnet && local.sa_allowed_ips_provided ? 0 : 1
+ connection_string = local.deployment_sa_connection_string
+ container_name = local.deployment_container_name
+ start = timestamp()
+ expiry = formatdate("YYYY-MM-DD'T'hh:mm:ssZ", timeadd(timestamp(), "1h"))
+ permissions {
+ read = true
+ add = false
+ create = false
+ write = false
+ delete = false
+ list = false
+ }
+}
diff --git a/ci/deployment/README.md b/ci/deployment/README.md
index 0b5e9338..0280ca42 100644
--- a/ci/deployment/README.md
+++ b/ci/deployment/README.md
@@ -4,7 +4,7 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
## Providers
diff --git a/ci/deployment/versions.tf b/ci/deployment/versions.tf
index 281dc878..202d92cc 100644
--- a/ci/deployment/versions.tf
+++ b/ci/deployment/versions.tf
@@ -3,7 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
+ version = "~>3.114.0"
}
}
}
diff --git a/ci/service_account/README.md b/ci/service_account/README.md
index 250d4ef7..372f177a 100644
--- a/ci/service_account/README.md
+++ b/ci/service_account/README.md
@@ -5,14 +5,14 @@
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.3.7 |
| [azuread](#requirement\_azuread) | >= 2.33.0 |
-| [azurerm](#requirement\_azurerm) | ~> 3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~> 3.114.0 |
## Providers
| Name | Version |
|------|---------|
| [azuread](#provider\_azuread) | >= 2.33.0 |
-| [azurerm](#provider\_azurerm) | ~> 3.75.0 |
+| [azurerm](#provider\_azurerm) | ~> 3.114.0 |
## Modules
diff --git a/ci/service_account/versions.tf b/ci/service_account/versions.tf
index 1ed01f47..faa76b46 100644
--- a/ci/service_account/versions.tf
+++ b/ci/service_account/versions.tf
@@ -6,7 +6,7 @@ terraform {
}
azurerm = {
source = "hashicorp/azurerm"
- version = "~> 3.75.0"
+ version = "~> 3.114.0"
}
}
required_version = ">= 1.3.7"
diff --git a/clients.tf b/clients.tf
index c493eaf7..189898b6 100644
--- a/clients.tf
+++ b/clients.tf
@@ -20,6 +20,7 @@ module "clients" {
sg_id = local.sg_id
tags_map = var.tags_map
custom_data = var.clients_custom_data
+ use_vmss = var.clients_use_vmss
vmss_name = "${var.prefix}-${var.cluster_name}-vmss"
depends_on = [azurerm_proximity_placement_group.ppg, module.network]
arch = var.client_arch
diff --git a/examples/existing_private_network/README.md b/examples/existing_private_network/README.md
index 74ea14c0..df9cff51 100644
--- a/examples/existing_private_network/README.md
+++ b/examples/existing_private_network/README.md
@@ -4,7 +4,7 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.3.7 |
-| [azurerm](#requirement\_azurerm) | ~> 3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~> 3.114.0 |
## Providers
diff --git a/examples/existing_private_network/versions.tf b/examples/existing_private_network/versions.tf
index 0cf72143..0e54932c 100644
--- a/examples/existing_private_network/versions.tf
+++ b/examples/existing_private_network/versions.tf
@@ -2,7 +2,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~> 3.75.0"
+ version = "~> 3.114.0"
}
}
required_version = ">= 1.3.7"
diff --git a/examples/existing_private_network_with_peering/README.md b/examples/existing_private_network_with_peering/README.md
index 74ea14c0..df9cff51 100644
--- a/examples/existing_private_network_with_peering/README.md
+++ b/examples/existing_private_network_with_peering/README.md
@@ -4,7 +4,7 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.3.7 |
-| [azurerm](#requirement\_azurerm) | ~> 3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~> 3.114.0 |
## Providers
diff --git a/examples/existing_private_network_with_peering/versions.tf b/examples/existing_private_network_with_peering/versions.tf
index 0cf72143..0e54932c 100644
--- a/examples/existing_private_network_with_peering/versions.tf
+++ b/examples/existing_private_network_with_peering/versions.tf
@@ -2,7 +2,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~> 3.75.0"
+ version = "~> 3.114.0"
}
}
required_version = ">= 1.3.7"
diff --git a/examples/public_network/README.md b/examples/public_network/README.md
index 0cac3724..2c904ad2 100644
--- a/examples/public_network/README.md
+++ b/examples/public_network/README.md
@@ -4,7 +4,7 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.3.7 |
-| [azurerm](#requirement\_azurerm) | ~> 3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~> 3.114.0 |
## Providers
diff --git a/examples/public_network/versions.tf b/examples/public_network/versions.tf
index 0cf72143..0e54932c 100644
--- a/examples/public_network/versions.tf
+++ b/examples/public_network/versions.tf
@@ -2,7 +2,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~> 3.75.0"
+ version = "~> 3.114.0"
}
}
required_version = ">= 1.3.7"
diff --git a/examples/public_network_with_existing_obs/README.md b/examples/public_network_with_existing_obs/README.md
index b14f0791..763f3ba3 100644
--- a/examples/public_network_with_existing_obs/README.md
+++ b/examples/public_network_with_existing_obs/README.md
@@ -4,7 +4,7 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.3.7 |
-| [azurerm](#requirement\_azurerm) | ~> 3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~> 3.114.0 |
## Providers
diff --git a/examples/public_network_with_existing_obs/versions.tf b/examples/public_network_with_existing_obs/versions.tf
index 0cf72143..0e54932c 100644
--- a/examples/public_network_with_existing_obs/versions.tf
+++ b/examples/public_network_with_existing_obs/versions.tf
@@ -2,7 +2,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~> 3.75.0"
+ version = "~> 3.114.0"
}
}
required_version = ">= 1.3.7"
diff --git a/function-app/code/common/common.go b/function-app/code/common/common.go
index 091e3d5e..409fc49b 100644
--- a/function-app/code/common/common.go
+++ b/function-app/code/common/common.go
@@ -21,6 +21,7 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
+ "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/lease"
"github.com/google/uuid"
@@ -31,7 +32,10 @@ import (
)
const (
- WekaAdminUsername = "admin"
+ WekaAdminUsername = "admin"
+ WekaAdminPasswordKey = "weka-password"
+ WekaDeploymentUsername = "weka-deployment"
+ WekaDeploymentPasswordKey = "weka-deployment-password"
// NFS VMs tag
NfsInterfaceGroupPortKey = "nfs_interface_group_port"
NfsInterfaceGroupPortValue = "ready"
@@ -58,6 +62,16 @@ type BlobObjParams struct {
BlobName string
}
+type AzureObsParams struct {
+ Name string
+ ContainerName string
+ AccessKey string
+ TieringSsdPercent string
+ NetworkAccess string
+ AllowedSubnets []string
+ AllowedPublicIps []string
+}
+
const FindDrivesScript = `
import json
import sys
@@ -231,6 +245,120 @@ func ReadBlobObject(ctx context.Context, bl BlobObjParams) (state []byte, err er
}
+func containerExists(ctx context.Context, containerClient *container.Client, storageName, containerName string) (bool, error) {
+ _, err := containerClient.GetProperties(ctx, nil)
+ if err != nil {
+ var responseErr *azcore.ResponseError
+ if errors.As(err, &responseErr) && responseErr.ErrorCode == "ContainerNotFound" {
+ return false, nil
+ }
+ err = fmt.Errorf("failed to get container properties: %w", err)
+ return false, err
+ }
+ return true, nil
+}
+
+func ensureStorageContainer(ctx context.Context, storageAccountName, containerName string) (err error) {
+ logger := logging.LoggerFromCtx(ctx)
+
+ credential, err := getCredential(ctx)
+ if err != nil {
+ return
+ }
+
+ containerUrl := getContainerUrl(storageAccountName, containerName)
+ containerClient, err := container.NewClient(containerUrl, credential, nil)
+ if err != nil {
+ err = fmt.Errorf("failed to create container client: %v", err)
+ return err
+ }
+
+ exists, err := containerExists(ctx, containerClient, storageAccountName, containerName)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ if exists {
+ logger.Info().Str("container", containerName).Msg("container already exists")
+ return
+ }
+
+ logger.Info().Str("container", containerName).Msg("container does not exist, creating new container")
+
+ _, err = containerClient.Create(ctx, nil)
+ if err != nil {
+ err = fmt.Errorf("failed to create container: %v", err)
+ logger.Error().Err(err).Send()
+ }
+ return
+}
+
+func blobExists(ctx context.Context, blobClient *blob.Client) (bool, error) {
+ _, err := blobClient.GetProperties(ctx, nil)
+ if err != nil {
+ var responseErr *azcore.ResponseError
+ if errors.As(err, &responseErr) && responseErr.ErrorCode == "BlobNotFound" {
+ return false, nil
+ }
+ err = fmt.Errorf("failed to get blob properties: %w", err)
+ return false, err
+ }
+ return true, nil
+}
+
+func EnsureStateIsCreated(ctx context.Context, p BlobObjParams, initialState protocol.ClusterState) (exists bool, err error) {
+ logger := logging.LoggerFromCtx(ctx)
+
+ err = ensureStorageContainer(ctx, p.StorageName, p.ContainerName)
+ if err != nil {
+ return
+ }
+
+ credential, err := getCredential(ctx)
+ if err != nil {
+ return
+ }
+
+ url := getBlobFileUrl(p.StorageName, p.ContainerName, p.BlobName)
+ blobClient, err := blob.NewClient(url, credential, nil)
+ if err != nil {
+ logger.Error().Err(err).Msg("failed to create blob client")
+ return
+ }
+
+ exists, err = blobExists(ctx, blobClient)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ if exists {
+ logger.Info().Msg("state already exists")
+ return
+ }
+
+ logger.Info().Msg("state does not exist, creating new state")
+
+ err = WriteState(ctx, p, initialState)
+ if err != nil {
+ logger.Error().Err(err).Msg("failed to write initial state")
+ }
+ return
+}
+
+func ReadStateOrCreateNew(ctx context.Context, p BlobObjParams, initialState protocol.ClusterState) (state protocol.ClusterState, err error) {
+ exists, err := EnsureStateIsCreated(ctx, p, initialState)
+ if err != nil {
+ return
+ }
+
+ if exists {
+ return ReadState(ctx, p)
+ }
+ return initialState, nil
+}
+
func ReadState(ctx context.Context, stateParams BlobObjParams) (state protocol.ClusterState, err error) {
logger := logging.LoggerFromCtx(ctx)
@@ -284,6 +412,10 @@ func getBlobUrl(storageName string) string {
return fmt.Sprintf("https://%s.blob.core.windows.net/", storageName)
}
+func getBlobFileUrl(storageName, containerName, blobName string) string {
+ return fmt.Sprintf("https://%s.blob.core.windows.net/%s/%s", storageName, containerName, blobName)
+}
+
func getContainerUrl(storageName, containerName string) string {
return fmt.Sprintf("https://%s.blob.core.windows.net/%s", storageName, containerName)
}
@@ -358,9 +490,118 @@ func UpdateClusterized(ctx context.Context, subscriptionId, resourceGroupName st
return
}
-func CreateStorageAccount(ctx context.Context, subscriptionId, resourceGroupName, obsName, location string) (accessKey string, err error) {
+func CreatePrivateDnsZoneGroup(ctx context.Context, subscriptionId, resourceGroupName, privateEndpointName, privateDNSZoneID string) (privateDNSZoneGroup *armnetwork.PrivateDNSZoneGroup, err error) {
logger := logging.LoggerFromCtx(ctx)
- logger.Info().Msgf("creating storage account: %s", obsName)
+
+ credential, err := getCredential(ctx)
+ if err != nil {
+ return
+ }
+
+ privateDNSZoneGroupName := fmt.Sprintf("%s-dns-group", privateEndpointName)
+
+ parameters := armnetwork.PrivateDNSZoneGroup{
+ Name: &privateDNSZoneGroupName,
+ Properties: &armnetwork.PrivateDNSZoneGroupPropertiesFormat{
+ PrivateDNSZoneConfigs: []*armnetwork.PrivateDNSZoneConfig{
+ {
+ Name: &privateDNSZoneGroupName,
+ Properties: &armnetwork.PrivateDNSZonePropertiesFormat{
+ PrivateDNSZoneID: &privateDNSZoneID,
+ },
+ },
+ },
+ },
+ }
+
+ client, err := armnetwork.NewPrivateDNSZoneGroupsClient(subscriptionId, credential, nil)
+ if err != nil {
+ err = fmt.Errorf("failed to create PrivateDNSZoneGroupsClient: %w", err)
+ return
+ }
+
+ poller, err := client.BeginCreateOrUpdate(ctx, resourceGroupName, privateEndpointName, privateDNSZoneGroupName, parameters, nil)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ res, err := poller.PollUntilDone(ctx, nil)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ privateDNSZoneGroup = &res.PrivateDNSZoneGroup
+ return
+}
+
+func CreateStorageAccountBlobPrivateEndpoint(ctx context.Context, subscriptionId, resourceGroupName, location, storageAccountName, privateEndpointName, subnetId, privateDnsZoneId string) (err error) {
+ logger := logging.LoggerFromCtx(ctx)
+
+ credential, err := getCredential(ctx)
+ if err != nil {
+ return
+ }
+
+ client, err := armnetwork.NewPrivateEndpointsClient(subscriptionId, credential, nil)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ storageAccountId := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s", subscriptionId, resourceGroupName, storageAccountName)
+ connectionName := fmt.Sprintf("%s-conn", privateEndpointName)
+ subresourceName := "blob"
+
+ privateServiceConnection := &armnetwork.PrivateLinkServiceConnection{
+ Name: &connectionName,
+ Properties: &armnetwork.PrivateLinkServiceConnectionProperties{
+ PrivateLinkServiceID: &storageAccountId,
+ GroupIDs: []*string{&subresourceName},
+ },
+ }
+
+ privateEndpoint := armnetwork.PrivateEndpoint{
+ Location: &location,
+ Properties: &armnetwork.PrivateEndpointProperties{
+ Subnet: &armnetwork.Subnet{
+ ID: &subnetId,
+ },
+ PrivateLinkServiceConnections: []*armnetwork.PrivateLinkServiceConnection{
+ privateServiceConnection,
+ },
+ },
+ }
+
+ poller, err := client.BeginCreateOrUpdate(ctx, resourceGroupName, privateEndpointName, privateEndpoint, nil)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ res, err := poller.PollUntilDone(ctx, nil)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ logger.Info().Msgf("private endpoint %s created", *res.PrivateEndpoint.ID)
+
+ dnsZoneGroup, err := CreatePrivateDnsZoneGroup(ctx, subscriptionId, resourceGroupName, privateEndpointName, privateDnsZoneId)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ logger.Info().Msgf("private dns zone group %s created", *dnsZoneGroup.ID)
+
+ return
+}
+
+func CreateStorageAccount(ctx context.Context, subscriptionId, resourceGroupName, location string, obsParams AzureObsParams) (accessKey string, err error) {
+ logger := logging.LoggerFromCtx(ctx)
+ logger.Info().Msgf("creating storage account: %v", obsParams)
credential, err := getCredential(ctx)
if err != nil {
@@ -374,18 +615,45 @@ func CreateStorageAccount(ctx context.Context, subscriptionId, resourceGroupName
}
skuName := armstorage.SKUNameStandardZRS
kind := armstorage.KindStorageV2
- _, err = client.BeginCreate(ctx, resourceGroupName, obsName, armstorage.AccountCreateParameters{
+ publicAccess := armstorage.PublicNetworkAccessEnabled
+ if obsParams.NetworkAccess == "Disabled" {
+ publicAccess = armstorage.PublicNetworkAccessDisabled
+ }
+
+ var networkRuleSet *armstorage.NetworkRuleSet
+ if len(obsParams.AllowedSubnets) > 0 || len(obsParams.AllowedPublicIps) > 0 {
+ action := armstorage.DefaultActionDeny
+ bypass := armstorage.BypassAzureServices
+ networkRuleSet = &armstorage.NetworkRuleSet{
+ DefaultAction: &action,
+ Bypass: &bypass,
+ }
+ for i := 0; i < len(obsParams.AllowedSubnets); i++ {
+ rule := &armstorage.VirtualNetworkRule{VirtualNetworkResourceID: &obsParams.AllowedSubnets[i]}
+ networkRuleSet.VirtualNetworkRules = append(networkRuleSet.VirtualNetworkRules, rule)
+ }
+ for i := 0; i < len(obsParams.AllowedPublicIps); i++ {
+ rule := &armstorage.IPRule{IPAddressOrRange: &obsParams.AllowedPublicIps[i]}
+ networkRuleSet.IPRules = append(networkRuleSet.IPRules, rule)
+ }
+ }
+
+ _, err = client.BeginCreate(ctx, resourceGroupName, obsParams.Name, armstorage.AccountCreateParameters{
Kind: &kind,
Location: &location,
SKU: &armstorage.SKU{
Name: &skuName,
},
+ Properties: &armstorage.AccountPropertiesCreateParameters{
+ PublicNetworkAccess: &publicAccess,
+ NetworkRuleSet: networkRuleSet,
+ },
}, nil)
if err != nil {
if azerr, ok := err.(*azcore.ResponseError); ok {
if azerr.ErrorCode == "StorageAccountAlreadyExists" {
- logger.Debug().Msgf("storage account %s already exists", obsName)
+ logger.Debug().Msgf("storage account %s already exists", obsParams.Name)
err = nil
} else {
logger.Error().Msgf("storage creation failed: %s", err)
@@ -398,7 +666,7 @@ func CreateStorageAccount(ctx context.Context, subscriptionId, resourceGroupName
}
for i := 0; i < 10; i++ {
- accessKey, err = getStorageAccountAccessKey(ctx, subscriptionId, resourceGroupName, obsName)
+ accessKey, err = getStorageAccountAccessKey(ctx, subscriptionId, resourceGroupName, obsParams.Name)
if err != nil {
if azerr, ok := err.(*azcore.ResponseError); ok {
@@ -414,7 +682,7 @@ func CreateStorageAccount(ctx context.Context, subscriptionId, resourceGroupName
return
}
} else {
- logger.Debug().Msgf("storage account '%s' is ready for use", obsName)
+ logger.Debug().Msgf("storage account '%s' is ready for use", obsParams.Name)
break
}
}
@@ -489,7 +757,7 @@ func GetKeyVaultValue(ctx context.Context, keyVaultUri, secretName string) (secr
}
resp, err := client.GetSecret(ctx, secretName, "", nil)
if err != nil {
- logger.Error().Err(err).Send()
+ logger.Info().Err(err).Send()
return
}
@@ -498,6 +766,32 @@ func GetKeyVaultValue(ctx context.Context, keyVaultUri, secretName string) (secr
return
}
+func SetKeyVaultValue(ctx context.Context, keyVaultUri, secretName, secretValue string) (err error) {
+ logger := logging.LoggerFromCtx(ctx)
+ logger.Info().Msgf("setting key vault secret: %s", secretName)
+
+ credential, err := getCredential(ctx)
+ if err != nil {
+ return
+ }
+
+ client, err := azsecrets.NewClient(keyVaultUri, credential, nil)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ params := azsecrets.SetSecretParameters{
+ Value: &secretValue,
+ }
+
+ _, err = client.SetSecret(ctx, secretName, params, nil)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ }
+ return
+}
+
// Gets all network interfaces in a VM scale set (Uniform)
// see https://learn.microsoft.com/en-us/rest/api/virtualnetwork/network-interface-in-vm-ss/list-virtual-machine-scale-set-network-interfaces
func getUniformScaleSetVmsNetworkInterfaces(ctx context.Context, subscriptionId, resourceGroupName, vmScaleSetName string) (networkInterfaces []*armnetwork.Interface, err error) {
@@ -855,15 +1149,6 @@ func AssignStorageBlobDataContributorRoleToScaleSet(
return &res.RoleAssignment, nil
}
-type ScaleSetInfo struct {
- Id string
- Name string
- AdminUsername string
- AdminPassword string
- Capacity int
- VMSize string
-}
-
// Gets scale set
// see https://learn.microsoft.com/en-us/rest/api/compute/virtual-machine-scale-sets/get
func getScaleSet(ctx context.Context, subscriptionId, resourceGroupName, vmScaleSetName string) (*armcompute.VirtualMachineScaleSet, error) {
@@ -904,33 +1189,6 @@ func GetScaleSetOrNil(ctx context.Context, subscriptionId, resourceGroupName, vm
return scaleSet, nil
}
-// Gets single scale set info
-func GetScaleSetInfo(ctx context.Context, subscriptionId, resourceGroupName, vmScaleSetName, keyVaultUri string) (*ScaleSetInfo, error) {
- logger := logging.LoggerFromCtx(ctx)
-
- scaleSet, err := getScaleSet(ctx, subscriptionId, resourceGroupName, vmScaleSetName)
- if err != nil {
- logger.Error().Err(err).Send()
- return nil, err
- }
-
- wekaPassword, err := GetWekaClusterPassword(ctx, keyVaultUri)
- if err != nil {
- logger.Error().Err(err).Send()
- return nil, err
- }
-
- scaleSetInfo := ScaleSetInfo{
- Id: *scaleSet.ID,
- Name: *scaleSet.Name,
- AdminUsername: WekaAdminUsername,
- AdminPassword: wekaPassword,
- Capacity: int(*scaleSet.SKU.Capacity),
- VMSize: *scaleSet.SKU.Name,
- }
- return &scaleSetInfo, err
-}
-
func GetScaleSetInstances(ctx context.Context, vmssParams *ScaleSetParams) (vms []*VMInfoSummary, err error) {
if vmssParams.Flexible {
vms, err = GetFlexibleScaleSetInstances(ctx, vmssParams.SubscriptionId, vmssParams.ResourceGroupName, vmssParams.ScaleSetName, nil)
@@ -1209,8 +1467,38 @@ func ReportMsg(ctx context.Context, hostName string, stateParams BlobObjParams,
_ = UpdateStateReporting(ctx, stateParams, reportObj)
}
-func GetWekaClusterPassword(ctx context.Context, keyVaultUri string) (password string, err error) {
- return GetKeyVaultValue(ctx, keyVaultUri, "weka-password")
+func GetWekaAdminPassword(ctx context.Context, keyVaultUri string) (password string, err error) {
+ return GetKeyVaultValue(ctx, keyVaultUri, WekaAdminPasswordKey)
+}
+
+func GetWekaDeploymentPassword(ctx context.Context, keyVaultUri string) (password string, err error) {
+ return GetKeyVaultValue(ctx, keyVaultUri, WekaDeploymentPasswordKey)
+}
+
+// Get Weka deployment password if exists, otherwise get admin password
+func GetWekaClusterCredentials(ctx context.Context, keyVaultUri string) (protocol.ClusterCreds, error) {
+ usename := WekaDeploymentUsername
+ password, err := GetWekaDeploymentPassword(ctx, keyVaultUri)
+
+ var responseErr *azcore.ResponseError
+ if err != nil && errors.As(err, &responseErr) && responseErr.ErrorCode == "SecretNotFound" || err == nil && password == "" {
+ usename = WekaAdminUsername
+ password, err = GetWekaAdminPassword(ctx, keyVaultUri)
+ }
+
+ credentials := protocol.ClusterCreds{
+ Username: usename,
+ Password: password,
+ }
+ return credentials, err
+}
+
+func SetWekaDeploymentPassword(ctx context.Context, keyVaultUri, password string) (err error) {
+ return SetKeyVaultValue(ctx, keyVaultUri, WekaDeploymentPasswordKey, password)
+}
+
+func SetWekaAdminPassword(ctx context.Context, keyVaultUri, password string) (err error) {
+ return SetKeyVaultValue(ctx, keyVaultUri, WekaAdminPasswordKey, password)
}
func GetVmScaleSetName(prefix, clusterName string) string {
@@ -1432,16 +1720,19 @@ func GetAzureInstanceNameCmd() string {
return "curl -s -H Metadata:true --noproxy * http://169.254.169.254/metadata/instance?api-version=2021-02-01 | jq '.compute.name' | cut -c2- | rev | cut -c2- | rev"
}
-func ReadVmssConfig(ctx context.Context, storageName, containerName string) (vmssConfig VMSSConfig, err error) {
+func ReadVmssConfig(ctx context.Context, vmssConfigStr string) (vmssConfig VMSSConfig, err error) {
logger := logging.LoggerFromCtx(ctx)
- params := BlobObjParams{
- StorageName: storageName,
- ContainerName: containerName,
- BlobName: "vmss-config",
+ if vmssConfigStr == "" {
+ err = fmt.Errorf("vmss config is not set")
+ logger.Error().Err(err).Msg("cannot read vmss config")
+ return
}
- asByteArray, err := ReadBlobObject(ctx, params)
+
+ asByteArray := []byte(vmssConfigStr)
+ err = json.Unmarshal(asByteArray, &vmssConfig)
if err != nil {
+ logger.Error().Err(err).Msg("cannot unmarshal vmss config")
return
}
@@ -1449,12 +1740,6 @@ func ReadVmssConfig(ctx context.Context, storageName, containerName string) (vms
hash := sha256.Sum256(asByteArray)
hashStr := fmt.Sprintf("%x", hash)
- err = json.Unmarshal(asByteArray, &vmssConfig)
- if err != nil {
- logger.Error().Err(err).Send()
- return
- }
-
// take first 16 characters of the hash
vmssConfig.ConfigHash = hashStr[:16]
return
diff --git a/function-app/code/functions/clusterize/clusterize.go b/function-app/code/functions/clusterize/clusterize.go
index e2e21144..7b7fe33d 100644
--- a/function-app/code/functions/clusterize/clusterize.go
+++ b/function-app/code/functions/clusterize/clusterize.go
@@ -11,8 +11,8 @@ import (
"weka-deployment/common"
"weka-deployment/functions/azure_functions_def"
- "github.com/rs/zerolog/log"
"github.com/weka/go-cloud-lib/join"
+ "github.com/weka/go-cloud-lib/utils"
"github.com/lithammer/dedent"
@@ -23,14 +23,7 @@ import (
"github.com/weka/go-cloud-lib/protocol"
)
-type AzureObsParams struct {
- Name string
- ContainerName string
- AccessKey string
- TieringSsdPercent string
-}
-
-func GetObsScript(obsParams AzureObsParams) string {
+func GetObsScript(obsParams common.AzureObsParams) string {
template := `
TIERING_SSD_PERCENT=%s
OBS_NAME=%s
@@ -53,6 +46,10 @@ type ClusterizationParams struct {
Location string
Prefix string
KeyVaultUri string
+ SubnetId string
+ PrivateDNSZoneId string
+ // if network access is disabled and private endpoints do not exist, create them with obs
+ CreateBlobPrivateEndpoint bool
StateParams common.BlobObjParams
InstallDpdk bool
@@ -61,7 +58,7 @@ type ClusterizationParams struct {
Cluster clusterize.ClusterParams
NFSParams protocol.NFSParams
NFSStateParams common.BlobObjParams
- Obs AzureObsParams
+ Obs common.AzureObsParams
FunctionAppName string
}
@@ -84,35 +81,88 @@ func GetShutdownScript() string {
return dedent.Dedent(s)
}
-func HandleLastClusterVm(ctx context.Context, state protocol.ClusterState, p ClusterizationParams, funcDef functions_def.FunctionDef) (clusterizeScript string, err error) {
+func PrepareWekaObs(ctx context.Context, p *ClusterizationParams) (err error) {
logger := logging.LoggerFromCtx(ctx)
- logger.Info().Msg("This is the last instance in the cluster, creating obs and clusterization script")
- vmScaleSetName := common.GetVmScaleSetName(p.Prefix, p.Cluster.ClusterName)
+ noExistingObs := p.Obs.AccessKey == ""
- if p.Cluster.SetObs {
- if p.Obs.AccessKey == "" {
- p.Obs.AccessKey, err = common.CreateStorageAccount(
- ctx, p.SubscriptionId, p.ResourceGroupName, p.Obs.Name, p.Location,
- )
- if err != nil {
- err = fmt.Errorf("failed to create storage account: %w", err)
- logger.Error().Err(err).Send()
- return
- }
+ if p.Obs.NetworkAccess == "Disabled" && noExistingObs && !p.CreateBlobPrivateEndpoint {
+ ignoredErr := fmt.Errorf("private endpoint creation is required for obs when public access is disabled")
+ logger.Error().Err(ignoredErr).Send()
+
+ common.ReportMsg(ctx, p.Vm.Name, p.StateParams, "error", ignoredErr.Error())
+ p.Cluster.SetObs = false
+ return nil
+ }
+
+ if p.Obs.NetworkAccess == "Disabled" && p.CreateBlobPrivateEndpoint && p.PrivateDNSZoneId == "" {
+ ignoredErr := fmt.Errorf("private dns zone id is required for private endpoint creation when public access is disabled")
+ logger.Error().Err(ignoredErr).Send()
+
+ common.ReportMsg(ctx, p.Vm.Name, p.StateParams, "error", ignoredErr.Error())
+ p.Cluster.SetObs = false
+ return nil
+ }
- err = common.CreateContainer(ctx, p.Obs.Name, p.Obs.ContainerName)
+ if noExistingObs {
+ p.Obs.AccessKey, err = common.CreateStorageAccount(
+ ctx, p.SubscriptionId, p.ResourceGroupName, p.Location, p.Obs,
+ )
+ if err != nil {
+ err = fmt.Errorf("failed to create storage account: %w", err)
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ if p.Obs.NetworkAccess == "Disabled" && p.CreateBlobPrivateEndpoint {
+ endpointName := fmt.Sprintf("%s-pe", p.Obs.Name)
+ logger.Info().Msgf("public access is disabled for the storage account, creating private endpoint %s", endpointName)
+
+ err = common.CreateStorageAccountBlobPrivateEndpoint(ctx, p.SubscriptionId, p.ResourceGroupName, p.Location, p.Obs.Name, endpointName, p.SubnetId, p.PrivateDNSZoneId)
if err != nil {
- err = fmt.Errorf("failed to create container: %w", err)
+ err = fmt.Errorf("failed to create private endpoint: %w", err)
logger.Error().Err(err).Send()
return
}
}
}
+ // create container (if it doesn't exist)
+ err = common.CreateContainer(ctx, p.Obs.Name, p.Obs.ContainerName)
+ if err != nil {
+ err = fmt.Errorf("failed to create container: %w", err)
+ logger.Error().Err(err).Send()
+ return
+ }
+ return
+}
- wekaPassword, err := common.GetWekaClusterPassword(ctx, p.KeyVaultUri)
+func HandleLastClusterVm(ctx context.Context, state protocol.ClusterState, p ClusterizationParams, funcDef functions_def.FunctionDef) (clusterizeScript string, err error) {
+ logger := logging.LoggerFromCtx(ctx)
+ logger.Info().Msg("This is the last instance in the cluster, creating obs and clusterization script")
+
+ vmScaleSetName := common.GetVmScaleSetName(p.Prefix, p.Cluster.ClusterName)
+
+ if p.Cluster.SetObs {
+ err = PrepareWekaObs(ctx, &p)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+ }
+
+ logger.Info().Msg("setting weka admin password in secrets manager")
+ adminPassword := utils.GeneratePassword(16, 1, 1, 1)
+ err = common.SetWekaAdminPassword(ctx, p.KeyVaultUri, adminPassword)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ return
+ }
+
+ logger.Info().Msg("setting weka deployment password in key vault")
+ wekaServicePassword := utils.GeneratePassword(16, 1, 1, 1)
+ err = common.SetWekaDeploymentPassword(ctx, p.KeyVaultUri, wekaServicePassword)
if err != nil {
- err = fmt.Errorf("failed to get weka cluster password: %w", err)
+ err = fmt.Errorf("failed to set weka service password: %w", err)
logger.Error().Err(err).Send()
return
}
@@ -145,8 +195,6 @@ func HandleLastClusterVm(ctx context.Context, state protocol.ClusterState, p Clu
clusterParams.VMNames = vmNamesList
clusterParams.IPs = ipsList
clusterParams.ObsScript = GetObsScript(p.Obs)
- clusterParams.WekaPassword = wekaPassword
- clusterParams.WekaUsername = common.WekaAdminUsername
clusterParams.InstallDpdk = p.InstallDpdk
clusterParams.FindDrivesScript = common.FindDrivesScript
clusterParams.ClusterizationTarget = state.ClusterizationTarget
@@ -194,20 +242,21 @@ func Clusterize(ctx context.Context, p ClusterizationParams) (clusterizeScript s
func doNFSClusterize(ctx context.Context, p ClusterizationParams, funcDef functions_def.FunctionDef) (clusterizeScript string, err error) {
nfsInterfaceGroupName := os.Getenv("NFS_INTERFACE_GROUP_NAME")
- nfsClientGroupName := os.Getenv("NFS_CLIENT_GROUP_NAME")
nfsProtocolgwsNum, _ := strconv.Atoi(os.Getenv("NFS_PROTOCOL_GATEWAYS_NUM"))
nfsSecondaryIpsNum, _ := strconv.Atoi(os.Getenv("NFS_SECONDARY_IPS_NUM"))
nfsVmssName := os.Getenv("NFS_VMSS_NAME")
backendLbIp := os.Getenv("BACKEND_LB_IP")
+ logger := logging.LoggerFromCtx(ctx)
+
state, err := common.AddInstanceToState(ctx, p.SubscriptionId, p.ResourceGroupName, p.NFSStateParams, p.Vm)
if err != nil {
- log.Error().Err(err).Send()
+ logger.Error().Err(err).Send()
return
}
msg := fmt.Sprintf("This (%s) is nfs instance %d/%d that is ready for joining the interface group", p.Vm.Name, len(state.Instances), nfsProtocolgwsNum)
- log.Info().Msgf(msg)
+ logger.Info().Msgf(msg)
if len(state.Instances) != nfsProtocolgwsNum {
clusterizeScript = cloudCommon.GetScriptWithReport(msg, funcDef.GetFunctionCmdDefinition(functions_def.Report), p.Vm.Protocol)
return
@@ -229,19 +278,18 @@ func doNFSClusterize(ctx context.Context, p ClusterizationParams, funcDef functi
secondaryIps, err := common.GetScaleSetSecondaryIps(ctx, vmssParams)
if err != nil {
err = fmt.Errorf("failed to get scale set secondary ips: %w", err)
- log.Error().Err(err).Send()
+ logger.Error().Err(err).Send()
return
}
if len(secondaryIps) < nfsSecondaryIpsNum {
err = fmt.Errorf("not enough secondary ips in vmss %s: %d/%d", nfsVmssName, len(secondaryIps), nfsSecondaryIpsNum)
- log.Error().Err(err).Send()
+ logger.Error().Err(err).Send()
return
}
nfsParams := protocol.NFSParams{
InterfaceGroupName: nfsInterfaceGroupName,
- ClientGroupName: nfsClientGroupName,
SecondaryIps: secondaryIps,
ContainersUid: containersUid,
NicNames: nicNames,
@@ -256,7 +304,7 @@ func doNFSClusterize(ctx context.Context, p ClusterizationParams, funcDef functi
}
clusterizeScript = scriptGenerator.GetNFSSetupScript()
- log.Info().Msg("Clusterization script for NFS generated")
+ logger.Info().Msg("Clusterization script for NFS generated")
return
}
@@ -300,12 +348,6 @@ func doClusterize(ctx context.Context, p ClusterizationParams, funcDef functions
clusterizeScript = cloudCommon.GetErrorScript(err, reportFunction, p.Vm.Protocol)
}
} else {
- wekaPassword, err2 := common.GetWekaClusterPassword(ctx, p.KeyVaultUri)
- if err2 != nil {
- logger.Error().Err(err2).Send()
- return
- }
-
vmsPrivateIps, err2 := common.GetVmsPrivateIps(ctx, vmssParams)
if err2 != nil {
err = fmt.Errorf("failed to get vms private ips: %w", err)
@@ -320,9 +362,7 @@ func doClusterize(ctx context.Context, p ClusterizationParams, funcDef functions
}
joinParams := join.JoinParams{
- WekaUsername: common.WekaAdminUsername,
- WekaPassword: wekaPassword,
- IPs: ipsList,
+ IPs: ipsList,
}
joinScriptGenerator := join.JoinScriptGenerator{
@@ -349,12 +389,20 @@ func Handler(w http.ResponseWriter, r *http.Request) {
obsName := os.Getenv("OBS_NAME")
obsContainerName := os.Getenv("OBS_CONTAINER_NAME")
obsAccessKey := os.Getenv("OBS_ACCESS_KEY")
+ obsNetworkAccess := os.Getenv("OBS_NETWORK_ACCESS")
+ obsAllowedSubnetsStr := os.Getenv("OBS_ALLOWED_SUBNETS")
+ obsAllowedSubnets := []string{}
+ obsAllowedPublicIpsStr := os.Getenv("OBS_ALLOWED_PUBLIC_IPS")
+ obsAllowedPublicIps := []string{}
location := os.Getenv("LOCATION")
tieringSsdPercent := os.Getenv("TIERING_SSD_PERCENT")
tieringTargetSsdRetention, _ := strconv.Atoi(os.Getenv("TIERING_TARGET_SSD_RETENTION"))
tieringStartDemote, _ := strconv.Atoi(os.Getenv("TIERING_START_DEMOTE"))
prefix := os.Getenv("PREFIX")
keyVaultUri := os.Getenv("KEY_VAULT_URI")
+ subnetId := os.Getenv("SUBNET_ID")
+ blobPrivateDnsZoneId := os.Getenv("BLOB_PRIVATE_DNS_ZONE_ID")
+ createblobPrivateEndpoint, _ := strconv.ParseBool(os.Getenv("CREATE_BLOB_PRIVATE_ENDPOINT"))
// data protection-related vars
stripeWidth, _ := strconv.Atoi(os.Getenv("STRIPE_WIDTH"))
protectionLevel, _ := strconv.Atoi(os.Getenv("PROTECTION_LEVEL"))
@@ -375,6 +423,13 @@ func Handler(w http.ResponseWriter, r *http.Request) {
addFrontend = true
}
+ if obsAllowedSubnetsStr != "" {
+ obsAllowedSubnets = strings.Split(obsAllowedSubnetsStr, ",")
+ }
+ if obsAllowedPublicIpsStr != "" {
+ obsAllowedPublicIps = strings.Split(obsAllowedPublicIpsStr, ",")
+ }
+
resData := make(map[string]interface{})
var invokeRequest common.InvokeRequest
@@ -403,14 +458,17 @@ func Handler(w http.ResponseWriter, r *http.Request) {
}
params := ClusterizationParams{
- SubscriptionId: subscriptionId,
- ResourceGroupName: resourceGroupName,
- Location: location,
- Prefix: prefix,
- KeyVaultUri: keyVaultUri,
- StateParams: common.BlobObjParams{StorageName: stateStorageName, ContainerName: stateContainerName, BlobName: stateBlobName},
- Vm: vm,
- InstallDpdk: installDpdk,
+ SubscriptionId: subscriptionId,
+ ResourceGroupName: resourceGroupName,
+ Location: location,
+ Prefix: prefix,
+ KeyVaultUri: keyVaultUri,
+ SubnetId: subnetId,
+ PrivateDNSZoneId: blobPrivateDnsZoneId,
+ CreateBlobPrivateEndpoint: createblobPrivateEndpoint,
+ StateParams: common.BlobObjParams{StorageName: stateStorageName, ContainerName: stateContainerName, BlobName: stateBlobName},
+ Vm: vm,
+ InstallDpdk: installDpdk,
Cluster: clusterize.ClusterParams{
ClusterizationTarget: clusterizationTarget,
ClusterName: clusterName,
@@ -429,11 +487,14 @@ func Handler(w http.ResponseWriter, r *http.Request) {
TieringTargetSSDRetention: tieringTargetSsdRetention,
TieringStartDemote: tieringStartDemote,
},
- Obs: AzureObsParams{
+ Obs: common.AzureObsParams{
Name: obsName,
ContainerName: obsContainerName,
AccessKey: obsAccessKey,
TieringSsdPercent: tieringSsdPercent,
+ NetworkAccess: obsNetworkAccess,
+ AllowedSubnets: obsAllowedSubnets,
+ AllowedPublicIps: obsAllowedPublicIps,
},
NFSStateParams: common.BlobObjParams{StorageName: stateStorageName, ContainerName: nfsStateContainerName, BlobName: nfsStateBlobName},
FunctionAppName: functionAppName,
diff --git a/function-app/code/functions/debug/debug.go b/function-app/code/functions/debug/debug.go
index 8b634adf..718eb152 100644
--- a/function-app/code/functions/debug/debug.go
+++ b/function-app/code/functions/debug/debug.go
@@ -116,7 +116,7 @@ func Handler(w http.ResponseWriter, r *http.Request) {
},
SetObs: setObs,
},
- Obs: clusterizeFunc.AzureObsParams{
+ Obs: common.AzureObsParams{
Name: obsName,
ContainerName: obsContainerName,
AccessKey: obsAccessKey,
diff --git a/function-app/code/functions/deploy/deploy.go b/function-app/code/functions/deploy/deploy.go
index 1807fd6f..8a62a4f1 100644
--- a/function-app/code/functions/deploy/deploy.go
+++ b/function-app/code/functions/deploy/deploy.go
@@ -86,12 +86,6 @@ func GetNfsDeployScript(ctx context.Context, funcDef functions_def.FunctionDef,
return
}
- wekaPassword, err := common.GetWekaClusterPassword(ctx, p.KeyVaultUri)
- if err != nil {
- logger.Error().Err(err).Send()
- return
- }
-
var token string
token, err = getWekaIoToken(ctx, p.KeyVaultUri)
if err != nil {
@@ -107,10 +101,7 @@ func GetNfsDeployScript(ctx context.Context, funcDef functions_def.FunctionDef,
ProxyUrl: p.ProxyUrl,
Gateways: p.Gateways,
Protocol: protocol.NFS,
- WekaUsername: common.WekaAdminUsername,
- WekaPassword: wekaPassword,
NFSInterfaceGroupName: p.NFSInterfaceGroupName,
- NFSClientGroupName: p.NFSClientGroupName,
NFSSecondaryIpsNum: p.NFSSecondaryIpsNum,
ProtocolGatewayFeCoresNum: p.NFSGatewayFeCoresNum,
LoadBalancerIP: p.BackendLbIp,
@@ -226,12 +217,6 @@ func GetDeployScript(ctx context.Context, funcDef functions_def.FunctionDef, p A
}
bashScript = deployScriptGenerator.GetDeployScript()
} else {
- wekaPassword, err := common.GetWekaClusterPassword(ctx, p.KeyVaultUri)
- if err != nil {
- logger.Error().Err(err).Send()
- return "", err
- }
-
vmScaleSetName := common.GetVmScaleSetName(p.Prefix, p.ClusterName)
vmssParams := &common.ScaleSetParams{
SubscriptionId: p.SubscriptionId,
@@ -262,8 +247,6 @@ func GetDeployScript(ctx context.Context, funcDef functions_def.FunctionDef, p A
}
joinParams := join.JoinParams{
- WekaUsername: common.WekaAdminUsername,
- WekaPassword: wekaPassword,
IPs: ips,
InstallDpdk: p.InstallDpdk,
InstanceParams: instanceParams,
@@ -331,7 +314,6 @@ func Handler(w http.ResponseWriter, r *http.Request) {
diskSize, _ := strconv.Atoi(os.Getenv("DISK_SIZE"))
// nfs params
nfsInterfaceGroupName := os.Getenv("NFS_INTERFACE_GROUP_NAME")
- nfsClientGroupName := os.Getenv("NFS_CLIENT_GROUP_NAME")
nfsProtocolgwsNum, _ := strconv.Atoi(os.Getenv("NFS_PROTOCOL_GATEWAYS_NUM"))
nfsStateContainerName := os.Getenv("NFS_STATE_CONTAINER_NAME")
nfsStateBlobName := os.Getenv("NFS_STATE_BLOB_NAME")
@@ -401,7 +383,6 @@ func Handler(w http.ResponseWriter, r *http.Request) {
FunctionAppName: functionAppName,
Gateways: getGateways(subnet, nicsNumInt),
NFSInterfaceGroupName: nfsInterfaceGroupName,
- NFSClientGroupName: nfsClientGroupName,
NFSProtocolGWsNum: nfsProtocolgwsNum,
NFSStateParams: common.BlobObjParams{StorageName: stateStorageName, ContainerName: nfsStateContainerName, BlobName: nfsStateBlobName},
NFSSecondaryIpsNum: nfsSecondaryIpsNum,
diff --git a/function-app/code/functions/fetch/fetch.go b/function-app/code/functions/fetch/fetch.go
index 99e48e26..ff1d2247 100644
--- a/function-app/code/functions/fetch/fetch.go
+++ b/function-app/code/functions/fetch/fetch.go
@@ -2,6 +2,7 @@ package fetch
import (
"context"
+ "encoding/json"
"fmt"
"net/http"
"os"
@@ -38,6 +39,13 @@ func Handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := logging.LoggerFromCtx(ctx)
+ fetchRequest, err := parseFetchRequest(r)
+ if err != nil {
+ logger.Error().Err(err).Send()
+ common.WriteErrorResponse(w, err)
+ return
+ }
+
backendsStateParams := common.BlobObjParams{
StorageName: stateStorageName,
ContainerName: stateContainerName,
@@ -58,12 +66,36 @@ func Handler(w http.ResponseWriter, r *http.Request) {
return
}
- wekaAdminPassword, err := common.GetWekaClusterPassword(ctx, keyVaultUri)
- if err != nil {
- err = fmt.Errorf("cannot get weka admin password: %v", err)
- logger.Error().Err(err).Send()
- common.WriteErrorResponse(w, err)
- return
+ var wekaPassword string
+ var adminPassword string
+ username := common.WekaDeploymentUsername
+
+ if fetchRequest.ShowAdminPassword {
+ adminPassword, err = common.GetWekaAdminPassword(ctx, keyVaultUri)
+ if err != nil {
+ err = fmt.Errorf("cannot get weka admin password: %w", err)
+ logger.Error().Err(err).Send()
+ common.WriteErrorResponse(w, err)
+ return
+ }
+
+ wekaPassword, err = common.GetWekaDeploymentPassword(ctx, keyVaultUri)
+ if err != nil {
+ err = fmt.Errorf("cannot get weka deployment password: %w", err)
+ logger.Error().Err(err).Send()
+ common.WriteErrorResponse(w, err)
+ return
+ }
+ } else {
+ credentials, err := common.GetWekaClusterCredentials(ctx, keyVaultUri)
+ if err != nil {
+ err = fmt.Errorf("cannot get weka cluster password: %v", err)
+ logger.Error().Err(err).Send()
+ common.WriteErrorResponse(w, err)
+ return
+ }
+ wekaPassword = credentials.Password
+ username = credentials.Username
}
desiredCapacity, err := getCapacity(ctx, backendsStateParams)
@@ -74,8 +106,9 @@ func Handler(w http.ResponseWriter, r *http.Request) {
}
response := protocol.HostGroupInfoResponse{
- Username: common.WekaAdminUsername,
- Password: wekaAdminPassword,
+ Username: username,
+ Password: wekaPassword,
+ AdminPassword: adminPassword,
WekaBackendsDesiredCapacity: desiredCapacity,
WekaBackendInstances: instances,
DownBackendsRemovalTimeout: downBackendsRemovalTimeout,
@@ -162,3 +195,31 @@ func getCapacity(ctx context.Context, stateParams common.BlobObjParams) (desired
desired = state.DesiredSize
return
}
+
+func parseFetchRequest(r *http.Request) (fetchRequest protocol.FetchRequest, err error) {
+ var invokeRequest common.InvokeRequest
+
+ if err = json.NewDecoder(r.Body).Decode(&invokeRequest); err != nil {
+ err = fmt.Errorf("cannot decode the request: %w", err)
+ return
+ }
+
+ var reqData map[string]interface{}
+ err = json.Unmarshal(invokeRequest.Data["req"], &reqData)
+ if err != nil {
+ err = fmt.Errorf("cannot unmarshal the request data: %w", err)
+ return
+ }
+
+ if reqData["Body"] == nil {
+ return
+ }
+
+ err = json.Unmarshal([]byte(reqData["Body"].(string)), &fetchRequest)
+ if err != nil {
+ err = fmt.Errorf("cannot unmarshal the request body: %w", err)
+ return
+ }
+
+ return
+}
diff --git a/init-script.sh b/function-app/code/functions/scale_up/init_script.go
old mode 100755
new mode 100644
similarity index 67%
rename from init-script.sh
rename to function-app/code/functions/scale_up/init_script.go
index 43b977e6..f02368a5
--- a/init-script.sh
+++ b/function-app/code/functions/scale_up/init_script.go
@@ -1,38 +1,40 @@
-function retry {
- local retry_max=$1
- local retry_sleep=$2
- shift 2
- local count=$retry_max
- while [ $count -gt 0 ]; do
- "$@" && break
- count=$(($count - 1))
- sleep $retry_sleep
- done
- [ $count -eq 0 ] && {
- echo "Retry failed [$retry_max]"
- shutdown -h now
- return 1
- }
- return 0
-}
+package scale_up
+
+import "fmt"
+
+var (
+ initScript = `#!/bin/bash
+set -ex
+
+# user data
+%s
-# retry for 2 minutes
-# NOTE: in some cases it takes time for all access policies to be applied
-retry 12 10 curl --fail ${report_url}?code="${function_app_default_key}" -H "Content-Type:application/json" -d "{\"hostname\": \"$HOSTNAME\", \"type\": \"progress\", \"message\": \"Running init script\"}"
+DISK_SIZE=%d
+NICS_NUM=%d
+SUBNET_RANGE="%s"
+APT_REPO_SERVER="%s"
+
+# report function definition
+%s
+
+# deploy function definition
+%s
+
+report "{\"hostname\": \"$HOSTNAME\", \"type\": \"progress\", \"message\": \"Running init script\"}"
while fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do
sleep 2
done
# set apt private repo
-if [[ "${apt_repo_server}" ]]; then
+if [[ "$APT_REPO_SERVER" ]]; then
mv /etc/apt/sources.list /etc/apt/sources.list.bak
- echo "deb ${apt_repo_server} focal main restricted universe" > /etc/apt/sources.list
- echo "deb ${apt_repo_server} focal-updates main restricted" >> /etc/apt/sources.list
+ echo "deb $APT_REPO_SERVER focal main restricted universe" > /etc/apt/sources.list
+ echo "deb $APT_REPO_SERVER focal-updates main restricted" >> /etc/apt/sources.list
apt update -y
fi
-for(( i=0; i<${nics_num}; i++ )); do
+for(( i=0; i<$NICS_NUM; i++ )); do
cat <<-EOF | sed -i "/ eth$i/r /dev/stdin" /etc/netplan/50-cloud-init.yaml
mtu: 3900
EOF
@@ -47,7 +49,7 @@ gateway=$(ip r | grep default | awk '{print $3}')
eth=$(ifconfig | grep eth0 -C2 | grep 'inet ' | awk '{print $2}')
cat <<-EOF | sed -i "/ set-name: eth0/r /dev/stdin" /etc/netplan/50-cloud-init.yaml
routes:
- - to: ${subnet_range}
+ - to: $SUBNET_RANGE
via: $gateway
metric: 200
table: 200
@@ -63,9 +65,9 @@ EOF
netplan apply
-if [[ ${nics_num} -gt 1 ]]; then
+if [[ $NICS_NUM -gt 1 ]]; then
are_routes_ready='ip route | grep eth1'
- for(( i=2; i<${nics_num}; i++ )); do
+ for(( i=2; i<$NICS_NUM; i++ )); do
are_routes_ready=$are_routes_ready' && ip route | grep eth'"$i"
done
cat >>/usr/sbin/remove-routes.sh < /tmp/deploy.sh 2>/tmp/deploy_err.log || [ ! -s /tmp/deploy.sh ]; do
+while ! deploy "{\"name\": \"$compute_name:$HOSTNAME\"}" > /tmp/deploy.sh 2>/tmp/deploy_err.log || [ ! -s /tmp/deploy.sh ]; do
echo "Retry $retry: waiting for deploy script generation success"
cat /tmp/deploy_err.log
retry=$((retry + 1))
@@ -155,10 +158,16 @@ mv /root/weka-prepackaged $weka_dir
if [ $retry -gt 0 ]; then
msg="Deploy script generation retried $retry times"
echo "$msg"
- curl -i "${report_url}?code=${function_app_default_key}" -H "Content-Type:application/json" -d "{\"hostname\": \"$HOSTNAME\", \"type\": \"debug\", \"message\": \"$msg\"}"
+ report "{\"hostname\": \"$HOSTNAME\", \"type\": \"debug\", \"message\": \"$msg\"}"
fi
echo "$(date -u): running deploy script"
chmod +x /tmp/deploy.sh
/tmp/deploy.sh 2>&1 | tee /tmp/weka_deploy.log
+`
+)
+
+func getInitScript(userData string, diskSize int, nicsNum int, subnetRange string, aptRepoServer string, reportFuncDef string, deployFuncDef string) string {
+ return fmt.Sprintf(initScript, userData, diskSize, nicsNum, subnetRange, aptRepoServer, reportFuncDef, deployFuncDef)
+}
diff --git a/function-app/code/functions/scale_up/scale_up.go b/function-app/code/functions/scale_up/scale_up.go
index 6c597faa..5e21db8e 100644
--- a/function-app/code/functions/scale_up/scale_up.go
+++ b/function-app/code/functions/scale_up/scale_up.go
@@ -2,12 +2,16 @@ package scale_up
import (
"context"
+ "encoding/base64"
"fmt"
"net/http"
"os"
+ "strconv"
"time"
"weka-deployment/common"
+ "weka-deployment/functions/azure_functions_def"
+ "github.com/weka/go-cloud-lib/functions_def"
"github.com/weka/go-cloud-lib/logging"
"github.com/weka/go-cloud-lib/protocol"
)
@@ -23,8 +27,51 @@ var (
nfsContainerName = os.Getenv("NFS_STATE_CONTAINER_NAME")
nfsStateBlobName = os.Getenv("NFS_STATE_BLOB_NAME")
nfsScaleSetName = os.Getenv("NFS_VMSS_NAME")
+ vmssConfigStr = os.Getenv("VMSS_CONFIG")
+ // initial state of the cluster
+ initialClusterSize, _ = strconv.Atoi(os.Getenv("INITIAL_CLUSTER_SIZE"))
+ clusterizeTarget, _ = strconv.Atoi(os.Getenv("CLUSTERIZATION_TARGET"))
+ initialNfsSize, _ = strconv.Atoi(os.Getenv("NFS_PROTOCOL_GATEWAYS_NUM"))
+ clusterInitialState = protocol.ClusterState{
+ InitialSize: initialClusterSize,
+ DesiredSize: initialClusterSize,
+ ClusterizationTarget: clusterizeTarget,
+ }
+ nfsInitialState = protocol.ClusterState{
+ InitialSize: initialNfsSize,
+ DesiredSize: initialNfsSize,
+ ClusterizationTarget: initialNfsSize,
+ }
)
+func getBackendCustomDataScript(ctx context.Context) (customData string, err error) {
+ functionAppName := os.Getenv("FUNCTION_APP_NAME")
+ keyVaultUri := os.Getenv("KEY_VAULT_URI")
+ diskSize, _ := strconv.Atoi(os.Getenv("DISK_SIZE"))
+ nicsNum, _ := strconv.Atoi(os.Getenv("NICS_NUM"))
+ subnet := os.Getenv("SUBNET")
+ aptRepo := os.Getenv("APT_REPO_SERVER")
+ userData := os.Getenv("USER_DATA")
+
+ logger := logging.LoggerFromCtx(ctx)
+
+ functionAppKey, err := common.GetKeyVaultValue(ctx, keyVaultUri, "function-app-default-key")
+ if err != nil {
+ logger.Error().Err(err).Msg("cannot get function app key")
+ return
+ }
+
+ baseFunctionUrl := fmt.Sprintf("https://%s.azurewebsites.net/api/", functionAppName)
+ funcDef := azure_functions_def.NewFuncDef(baseFunctionUrl, functionAppKey)
+ reportFunction := funcDef.GetFunctionCmdDefinition(functions_def.Report)
+ deployFunction := funcDef.GetFunctionCmdDefinition(functions_def.Deploy)
+
+ customDataStr := getInitScript(userData, diskSize, nicsNum, subnet, aptRepo, reportFunction, deployFunction)
+ // base64 encode the custom data
+ customData = base64.StdEncoding.EncodeToString([]byte(customDataStr))
+ return
+}
+
func Handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := logging.LoggerFromCtx(ctx)
@@ -36,7 +83,7 @@ func Handler(w http.ResponseWriter, r *http.Request) {
BlobName: stateBlobName,
}
- state, err := common.ReadState(ctx, stateParams)
+ state, err := common.ReadStateOrCreateNew(ctx, stateParams, clusterInitialState)
if err != nil {
logger.Error().Err(err).Msg("cannot read state")
common.WriteErrorResponse(w, err)
@@ -58,7 +105,7 @@ func Handler(w http.ResponseWriter, r *http.Request) {
}
// get expected vmss config
- vmssConfig, err := common.ReadVmssConfig(ctx, stateStorageName, stateContainerName)
+ vmssConfig, err := common.ReadVmssConfig(ctx, vmssConfigStr)
if err != nil {
logger.Error().Err(err).Msgf("cannot read vmss config")
common.WriteErrorResponse(w, err)
@@ -138,7 +185,7 @@ func handleNFSScaleUp(ctx context.Context) (message string, err error) {
ContainerName: nfsContainerName,
BlobName: nfsStateBlobName,
}
- nfsState, err := common.ReadState(ctx, nfsStateParams)
+ nfsState, err := common.ReadStateOrCreateNew(ctx, nfsStateParams, nfsInitialState)
if err != nil {
logger.Error().Err(err).Msg("cannot read NFS state")
return
@@ -167,12 +214,18 @@ func handleNFSScaleUp(ctx context.Context) (message string, err error) {
return
}
-func createVmss(ctx context.Context, vmssConfig *common.VMSSConfig, vmssName string, vmssSize int) error {
+func createVmss(ctx context.Context, vmssConfig *common.VMSSConfig, vmssName string, vmssSize int) (err error) {
logger := logging.LoggerFromCtx(ctx)
vmssConfigHash := vmssConfig.ConfigHash
+ vmssConfig.CustomData, err = getBackendCustomDataScript(ctx)
+ if err != nil {
+ logger.Error().Err(err).Msg("cannot get custom data script")
+ return err
+ }
+
logger.Info().Msgf("creating new vmss %s of size %d", vmssName, vmssSize)
- _, err := common.CreateOrUpdateVmss(ctx, subscriptionId, resourceGroupName, vmssName, vmssConfigHash, *vmssConfig, vmssSize)
+ _, err = common.CreateOrUpdateVmss(ctx, subscriptionId, resourceGroupName, vmssName, vmssConfigHash, *vmssConfig, vmssSize)
if err != nil {
return err
}
@@ -180,7 +233,7 @@ func createVmss(ctx context.Context, vmssConfig *common.VMSSConfig, vmssName str
return nil
}
-func handleVmssUpdate(ctx context.Context, currentConfig, newConfig *common.VMSSConfig, stateParams common.BlobObjParams, desiredSize int) error {
+func handleVmssUpdate(ctx context.Context, currentConfig, newConfig *common.VMSSConfig, stateParams common.BlobObjParams, desiredSize int) (err error) {
logger := logging.LoggerFromCtx(ctx)
newConfigHash := newConfig.ConfigHash
@@ -200,7 +253,13 @@ func handleVmssUpdate(ctx context.Context, currentConfig, newConfig *common.VMSS
return common.AddClusterUpdate(ctx, stateParams, update)
}
- _, err := common.CreateOrUpdateVmss(ctx, subscriptionId, resourceGroupName, currentConfig.Name, newConfigHash, *newConfig, desiredSize)
+ newConfig.CustomData, err = getBackendCustomDataScript(ctx)
+ if err != nil {
+ logger.Error().Err(err).Msg("cannot get custom data script")
+ return err
+ }
+
+ _, err = common.CreateOrUpdateVmss(ctx, subscriptionId, resourceGroupName, currentConfig.Name, newConfigHash, *newConfig, desiredSize)
if err != nil {
logger.Error().Err(err).Msgf("cannot update vmss %s", currentConfig.Name)
errStr := err.Error()
diff --git a/function-app/code/functions/status/status.go b/function-app/code/functions/status/status.go
index 3d08006c..fc66c053 100644
--- a/function-app/code/functions/status/status.go
+++ b/function-app/code/functions/status/status.go
@@ -136,13 +136,13 @@ func GetClusterStatus(ctx context.Context, vmssParams *common.ScaleSetParams, st
return
}
- wekaPassword, err := common.GetWekaClusterPassword(ctx, keyVaultUri)
+ credentials, err := common.GetWekaClusterCredentials(ctx, keyVaultUri)
if err != nil {
return
}
jrpcBuilder := func(ip string) *jrpc.BaseClient {
- return connectors.NewJrpcClient(ctx, ip, weka.ManagementJrpcPort, common.WekaAdminUsername, wekaPassword)
+ return connectors.NewJrpcClient(ctx, ip, weka.ManagementJrpcPort, credentials.Username, credentials.Password)
}
vmIps, err := common.GetVmsPrivateIps(ctx, vmssParams)
@@ -180,8 +180,8 @@ func GetClusterStatus(ctx context.Context, vmssParams *common.ScaleSetParams, st
return
}
-func GetRefreshStatus(ctx context.Context, vmssParams *common.ScaleSetParams, stateParams common.BlobObjParams, extended bool) (*common.VMSSStateVerbose, error) {
- vmssConfig, err := common.ReadVmssConfig(ctx, stateParams.StorageName, stateParams.ContainerName)
+func GetRefreshStatus(ctx context.Context, vmssParams *common.ScaleSetParams, stateParams common.BlobObjParams, vmssConfigStr string, extended bool) (*common.VMSSStateVerbose, error) {
+ vmssConfig, err := common.ReadVmssConfig(ctx, vmssConfigStr)
if err != nil {
return nil, err
}
@@ -235,6 +235,7 @@ func Handler(w http.ResponseWriter, r *http.Request) {
nfsStateContainerName := os.Getenv("NFS_STATE_CONTAINER_NAME")
nfsStateBlobName := os.Getenv("NFS_STATE_BLOB_NAME")
nfsScaleSetName := os.Getenv("NFS_VMSS_NAME")
+ vmssConfigStr := os.Getenv("VMSS_CONFIG")
ctx := r.Context()
logger := logging.LoggerFromCtx(ctx)
@@ -298,9 +299,9 @@ func Handler(w http.ResponseWriter, r *http.Request) {
} else if requestBody.Type == "progress" {
result, err = GetReports(ctx, stateParams, vmssParams)
} else if requestBody.Type == "vmss" {
- result, err = GetRefreshStatus(ctx, vmssParams, stateParams, false)
+ result, err = GetRefreshStatus(ctx, vmssParams, stateParams, vmssConfigStr, false)
} else if requestBody.Type == "vmss-extended" {
- result, err = GetRefreshStatus(ctx, vmssParams, stateParams, true)
+ result, err = GetRefreshStatus(ctx, vmssParams, stateParams, vmssConfigStr, true)
} else {
result = "Invalid status type"
}
diff --git a/function-app/code/go.mod b/function-app/code/go.mod
index 38a7ba2a..6ab9b82e 100644
--- a/function-app/code/go.mod
+++ b/function-app/code/go.mod
@@ -14,8 +14,7 @@ require (
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
github.com/lithammer/dedent v1.1.0
- github.com/rs/zerolog v1.29.0
- github.com/weka/go-cloud-lib v0.0.0-20240711150309-5e177acf14bf
+ github.com/weka/go-cloud-lib v0.0.0-20240730090621-daac1ef4a039
)
require (
@@ -30,6 +29,7 @@ require (
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/rs/xid v1.4.0 // indirect
+ github.com/rs/zerolog v1.29.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.6.0 // indirect
diff --git a/function-app/code/go.sum b/function-app/code/go.sum
index ea0f30c1..bf02728f 100644
--- a/function-app/code/go.sum
+++ b/function-app/code/go.sum
@@ -55,8 +55,8 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/weka/go-cloud-lib v0.0.0-20240711150309-5e177acf14bf h1:o0s3CopCNc8D97E10n9yU0mHg0Jq+HhMNm7HWqhjUzM=
-github.com/weka/go-cloud-lib v0.0.0-20240711150309-5e177acf14bf/go.mod h1:FCQuk2bLvtDHe2Kjsu0oInJP1VOVsuxqPGHGMmVIPMg=
+github.com/weka/go-cloud-lib v0.0.0-20240730090621-daac1ef4a039 h1:PVACFcS9r4sgtm6Z9UiN7/LMoDySTPP0Ghsxj+MSOtQ=
+github.com/weka/go-cloud-lib v0.0.0-20240730090621-daac1ef4a039/go.mod h1:FCQuk2bLvtDHe2Kjsu0oInJP1VOVsuxqPGHGMmVIPMg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
diff --git a/function-app/distribution/README.md b/function-app/distribution/README.md
index 0ecb8403..d231c971 100644
--- a/function-app/distribution/README.md
+++ b/function-app/distribution/README.md
@@ -4,13 +4,13 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
## Providers
| Name | Version |
|------|---------|
-| [azurerm](#provider\_azurerm) | ~>3.75.0 |
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
## Modules
diff --git a/function-app/distribution/create_sa/README.md b/function-app/distribution/create_sa/README.md
index 450427f1..d597152a 100644
--- a/function-app/distribution/create_sa/README.md
+++ b/function-app/distribution/create_sa/README.md
@@ -4,13 +4,13 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
## Providers
| Name | Version |
|------|---------|
-| [azurerm](#provider\_azurerm) | ~>3.75.0 |
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
## Modules
diff --git a/function-app/distribution/create_sa/versions.tf b/function-app/distribution/create_sa/versions.tf
index 281dc878..202d92cc 100644
--- a/function-app/distribution/create_sa/versions.tf
+++ b/function-app/distribution/create_sa/versions.tf
@@ -3,7 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
+ version = "~>3.114.0"
}
}
}
diff --git a/function-app/distribution/state.tf b/function-app/distribution/state.tf
index 674c0acc..e56ef43b 100644
--- a/function-app/distribution/state.tf
+++ b/function-app/distribution/state.tf
@@ -3,7 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
+ version = "~>3.114.0"
}
}
# https://learn.microsoft.com/en-us/azure/developer/terraform/store-state-in-azure-storage?tabs=azure-cli
diff --git a/functions.tf b/functions.tf
index 2db99ee9..8a89bda7 100644
--- a/functions.tf
+++ b/functions.tf
@@ -1,28 +1,196 @@
locals {
- create_private_function = var.function_access_restriction_enabled ? 1 : 0
- stripe_width_calculated = var.cluster_size - var.protection_level - 1
- stripe_width = local.stripe_width_calculated < 16 ? local.stripe_width_calculated : 16
- location = data.azurerm_resource_group.rg.location
- function_app_zip_name = "${var.function_app_dist}/${var.function_app_version}.zip"
- weka_sa = "${var.function_app_storage_account_prefix}${local.location}"
- weka_sa_container = "${var.function_app_storage_account_container_prefix}${local.location}"
- function_code_path = "${path.module}/function-app/code"
- function_app_code_hash = md5(join("", [for f in fileset(local.function_code_path, "**") : filemd5("${local.function_code_path}/${f}")]))
- get_compute_memory_index = var.set_dedicated_fe_container ? 1 : 0
- deployment_storage_account_id = var.deployment_storage_account_name == "" ? azurerm_storage_account.deployment_sa[0].id : data.azurerm_storage_account.deployment_blob[0].id
- deployment_storage_account_name = var.deployment_storage_account_name == "" ? azurerm_storage_account.deployment_sa[0].name : var.deployment_storage_account_name
- deployment_container_name = var.deployment_container_name == "" ? azurerm_storage_container.deployment[0].name : var.deployment_container_name
- obs_storage_account_name = var.tiering_obs_name == "" ? "${substr("${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}", 0, 21)}obs" : var.tiering_obs_name
- obs_container_name = var.tiering_obs_container_name == "" ? "${var.prefix}-${var.cluster_name}-obs" : var.tiering_obs_container_name
- function_app_name = "${local.alphanumeric_prefix_name}-${local.alphanumeric_cluster_name}-function-app"
- install_weka_url = var.install_weka_url != "" ? var.install_weka_url : "https://$TOKEN@get.weka.io/dist/v1/install/${var.weka_version}/${var.weka_version}"
- supported_regions = split("\n", replace(chomp(file("${path.module}/supported_regions/${var.function_app_dist}.txt")), "\r", ""))
+ create_private_function = var.function_access_restriction_enabled ? 1 : 0
+ stripe_width_calculated = var.cluster_size - var.protection_level - 1
+ stripe_width = local.stripe_width_calculated < 16 ? local.stripe_width_calculated : 16
+ location = data.azurerm_resource_group.rg.location
+ read_remote_function_zip = !var.read_function_zip_from_storage_account
+ function_app_zip_name = local.read_remote_function_zip ? "${var.function_app_dist}/${var.function_app_version}.zip" : var.deployment_function_app_code_blob
+ weka_sa = local.read_remote_function_zip ? "${var.function_app_storage_account_prefix}${local.location}" : var.deployment_storage_account_name
+ weka_sa_container = local.read_remote_function_zip ? "${var.function_app_storage_account_container_prefix}${local.location}" : var.deployment_container_name
+ function_app_blob_sas = local.read_remote_function_zip ? "" : data.azurerm_storage_account_blob_container_sas.function_app_code_sas[0].sas
+ function_code_path = "${path.module}/function-app/code"
+ function_app_code_hash = md5(join("", [for f in fileset(local.function_code_path, "**") : filemd5("${local.function_code_path}/${f}")]))
+ get_compute_memory_index = var.set_dedicated_fe_container ? 1 : 0
+ obs_storage_account_name = var.tiering_obs_name == "" ? "${substr("${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}", 0, 21)}obs" : var.tiering_obs_name
+ obs_container_name = var.tiering_obs_container_name == "" ? "${var.prefix}-${var.cluster_name}-obs" : var.tiering_obs_container_name
+ function_app_name = "${local.alphanumeric_prefix_name}-${local.alphanumeric_cluster_name}-function-app"
+ install_weka_url = var.install_weka_url != "" ? var.install_weka_url : "https://$TOKEN@get.weka.io/dist/v1/install/${var.weka_version}/${var.weka_version}"
+ supported_regions = split("\n", replace(chomp(file("${path.module}/supported_regions/${var.function_app_dist}.txt")), "\r", ""))
# log analytics for function app
log_analytics_workspace_id = var.enable_application_insights ? var.log_analytics_workspace_id == "" ? azurerm_log_analytics_workspace.la_workspace[0].id : var.log_analytics_workspace_id : ""
application_insights_id = var.enable_application_insights ? var.application_insights_name == "" ? azurerm_application_insights.application_insights[0].id : data.azurerm_application_insights.application_insights[0].id : ""
insights_instrumenation_key = var.enable_application_insights ? var.application_insights_name == "" ? azurerm_application_insights.application_insights[0].instrumentation_key : data.azurerm_application_insights.application_insights[0].instrumentation_key : ""
# nfs autoscaling
- nfs_deployment_container_name = var.nfs_deployment_container_name == "" ? azurerm_storage_container.nfs_deployment[0].name : var.nfs_deployment_container_name
+ nfs_deployment_container_name = var.nfs_deployment_container_name == "" ? "${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}-protocol-deployment" : var.nfs_deployment_container_name
+
+ clusterization_target = var.clusterization_target != null ? var.clusterization_target : min(var.cluster_size, max(20, ceil(var.cluster_size * 0.8)))
+ # fields that depend on LB creation
+ vmss_health_probe_id = var.create_lb ? azurerm_lb_probe.backend_lb_probe[0].id : null
+ lb_backend_pool_ids = var.create_lb ? [azurerm_lb_backend_address_pool.lb_backend_pool[0].id] : []
+
+ vmss_config = jsonencode({
+ name = "${var.prefix}-${var.cluster_name}-vmss"
+ location = data.azurerm_resource_group.rg.location
+ zones = var.zone != null ? [var.zone] : []
+ resource_group_name = var.rg_name
+ sku = var.instance_type
+ upgrade_mode = "Manual"
+ health_probe_id = local.vmss_health_probe_id
+ admin_username = var.vm_username
+ ssh_public_key = local.public_ssh_key
+ computer_name_prefix = "${var.prefix}-${var.cluster_name}-backend"
+ custom_data = ""
+ disable_password_authentication = true
+ proximity_placement_group_id = local.placement_group_id
+ single_placement_group = var.vmss_single_placement_group
+ source_image_id = var.source_image_id
+ overprovision = false
+ orchestration_mode = "Uniform"
+ tags = merge(var.tags_map, {
+ "weka_cluster" : var.cluster_name,
+ "user_id" : data.azurerm_client_config.current.object_id,
+ })
+
+ os_disk = {
+ caching = "ReadWrite"
+ storage_account_type = "Premium_LRS"
+ }
+
+ data_disk = {
+ lun = 0
+ caching = "None"
+ create_option = "Empty"
+ disk_size_gb = local.disk_size
+ storage_account_type = "Premium_LRS"
+ }
+
+ identity = {
+ type = "UserAssigned"
+ identity_ids = [local.vmss_identity_id]
+ }
+
+ primary_nic = {
+ name = "${var.prefix}-${var.cluster_name}-backend-nic-0"
+ network_security_group_id = local.sg_id
+ enable_accelerated_networking = var.install_cluster_dpdk
+
+ ip_configurations = [{
+ primary = true
+ subnet_id = data.azurerm_subnet.subnet.id
+ load_balancer_backend_address_pool_ids = local.lb_backend_pool_ids
+ public_ip_address = {
+ assign = local.assign_public_ip
+ name = "${var.prefix}-${var.cluster_name}-public-ip"
+ domain_name_label = "${var.prefix}-${var.cluster_name}-backend"
+ }
+ }]
+ }
+
+ secondary_nics = {
+ number = local.nics_numbers - 1
+ name_prefix = "${var.prefix}-${var.cluster_name}-backend-nic"
+ network_security_group_id = local.sg_id
+ enable_accelerated_networking = var.install_cluster_dpdk
+ ip_configurations = [{
+ primary = true
+ subnet_id = data.azurerm_subnet.subnet.id
+ load_balancer_backend_address_pool_ids = local.lb_backend_pool_ids
+ }]
+ }
+ })
+
+ # function app settings
+ initial_app_settings = {
+ "USER_ASSIGNED_CLIENT_ID" = local.function_app_identity_client_id
+ "STATE_STORAGE_NAME" = local.deployment_storage_account_name
+ "STATE_CONTAINER_NAME" = local.deployment_container_name
+ "STATE_BLOB_NAME" = "state"
+ "HOSTS_NUM" = var.cluster_size
+ "CLUSTER_NAME" = var.cluster_name
+ "PROTECTION_LEVEL" = var.protection_level
+ "STRIPE_WIDTH" = var.stripe_width != -1 ? var.stripe_width : local.stripe_width
+ "HOTSPARE" = var.hotspare
+ "VM_USERNAME" = var.vm_username
+ "SUBSCRIPTION_ID" = var.subscription_id
+ "RESOURCE_GROUP_NAME" = data.azurerm_resource_group.rg.name
+ "LOCATION" = data.azurerm_resource_group.rg.location
+ "SET_OBS" = var.tiering_enable_obs_integration
+ "CREATE_CONFIG_FS" = (var.smbw_enabled && var.smb_setup_protocol) || var.s3_setup_protocol
+ "OBS_NAME" = local.obs_storage_account_name
+ "OBS_CONTAINER_NAME" = local.obs_container_name
+ "OBS_ACCESS_KEY" = var.tiering_blob_obs_access_key
+ "OBS_NETWORK_ACCESS" = var.storage_account_public_network_access
+ "OBS_ALLOWED_SUBNETS" = join(",", local.sa_public_access_for_vnet ? [data.azurerm_subnet.subnet.id, local.function_app_subnet_delegation_id] : [])
+ "OBS_ALLOWED_PUBLIC_IPS" = join(",", var.storage_account_allowed_ips)
+ DRIVE_CONTAINER_CORES_NUM = var.containers_config_map[var.instance_type].drive
+ COMPUTE_CONTAINER_CORES_NUM = var.set_dedicated_fe_container == false ? var.containers_config_map[var.instance_type].compute + 1 : var.containers_config_map[var.instance_type].compute
+ FRONTEND_CONTAINER_CORES_NUM = var.set_dedicated_fe_container == false ? 0 : var.containers_config_map[var.instance_type].frontend
+ COMPUTE_MEMORY = var.containers_config_map[var.instance_type].memory[local.get_compute_memory_index]
+ DISK_SIZE = local.disk_size
+ "NVMES_NUM" = var.containers_config_map[var.instance_type].nvme
+ "TIERING_SSD_PERCENT" = var.tiering_enable_ssd_percent
+ "TIERING_TARGET_SSD_RETENTION" = var.tiering_obs_target_ssd_retention
+ "TIERING_START_DEMOTE" = var.tiering_obs_start_demote
+ "PREFIX" = var.prefix
+ "KEY_VAULT_URI" = azurerm_key_vault.key_vault.vault_uri
+ "INSTALL_DPDK" = var.install_cluster_dpdk
+ "NICS_NUM" = var.containers_config_map[var.instance_type].nics
+ "INSTALL_URL" = local.install_weka_url
+ "LOG_LEVEL" = var.function_app_log_level
+ "SUBNET" = local.subnet_range
+ "SUBNET_ID" = data.azurerm_subnet.subnet.id
+ "BLOB_PRIVATE_DNS_ZONE_ID" = var.create_storage_account_private_links ? azurerm_private_dns_zone.blob[0].id : local.sa_public_access_disabled ? data.azurerm_private_dns_zone.blob[0].id : ""
+ "CREATE_BLOB_PRIVATE_ENDPOINT" = var.create_storage_account_private_links && local.sa_public_access_disabled
+ FUNCTION_APP_NAME = local.function_app_name
+ PROXY_URL = var.proxy_url
+ WEKA_HOME_URL = var.weka_home_url
+ POST_CLUSTER_CREATION_SCRIPT = var.script_post_cluster_creation
+ PRE_START_IO_SCRIPT = var.script_pre_start_io
+ DOWN_BACKENDS_REMOVAL_TIMEOUT = var.debug_down_backends_removal_timeout
+
+ https_only = true
+ FUNCTION_APP_EDIT_MODE = "readonly"
+ HASH = var.function_app_version
+ WEBSITE_RUN_FROM_PACKAGE = "https://${local.weka_sa}.blob.core.windows.net/${local.weka_sa_container}/${local.function_app_zip_name}${local.function_app_blob_sas}"
+
+ NFS_STATE_CONTAINER_NAME = local.nfs_deployment_container_name
+ NFS_STATE_BLOB_NAME = "nfs_state"
+ NFS_INTERFACE_GROUP_NAME = var.nfs_interface_group_name
+ NFS_SECONDARY_IPS_NUM = var.nfs_protocol_gateway_secondary_ips_per_nic
+ NFS_PROTOCOL_GATEWAY_FE_CORES_NUM = var.nfs_protocol_gateway_fe_cores_num
+ NFS_PROTOCOL_GATEWAYS_NUM = var.nfs_protocol_gateways_number
+ NFS_VMSS_NAME = var.nfs_protocol_gateways_number > 0 ? "${var.prefix}-${var.cluster_name}-nfs-protocol-gateway-vmss" : ""
+ NFS_DISK_SIZE = var.nfs_protocol_gateway_disk_size
+ SMB_DISK_SIZE = var.smb_protocol_gateway_disk_size
+ S3_DISK_SIZE = var.s3_protocol_gateway_disk_size
+ SMB_PROTOCOL_GATEWAY_FE_CORES_NUM = var.smb_protocol_gateway_fe_cores_num
+ S3_PROTOCOL_GATEWAY_FE_CORES_NUM = var.s3_protocol_gateway_fe_cores_num
+ TRACES_PER_FRONTEND = var.traces_per_ionode
+
+ BACKEND_LB_IP = var.create_lb ? azurerm_lb.backend_lb[0].private_ip_address : ""
+ # state
+ INITIAL_CLUSTER_SIZE = var.cluster_size
+ CLUSTERIZATION_TARGET = local.clusterization_target
+ VMSS_CONFIG = local.vmss_config
+ # init script inputs
+ APT_REPO_SERVER = var.apt_repo_server
+ USER_DATA = var.user_data
+ }
+
+ secured_storage_account_app_settings = {
+ # "AzureWebJobsStorage" and "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" are not needed as we set storage_account_access_key
+ "WEBSITE_CONTENTSHARE" = local.deployment_file_share_name
+ "WEBSITE_CONTENTOVERVNET" = 1
+ "WEBSITE_VNET_ROUTE_ALL" = 1
+ }
+ dns_storgage_account_app_settings = {
+ "WEBSITE_DNS_SERVER" = "168.63.129.16"
+ }
+ merged_secured_storage_account_app_settings = var.create_storage_account_private_links ? merge(local.secured_storage_account_app_settings, local.dns_storgage_account_app_settings) : local.secured_storage_account_app_settings
+
+ app_settings = local.sa_public_access_enabled ? local.initial_app_settings : merge(local.initial_app_settings, local.merged_secured_storage_account_app_settings)
+
+ function_app_subnet_delegation_id = var.function_app_subnet_delegation_id == "" ? module.function_app_subnet_delegation[0].id : var.function_app_subnet_delegation_id
}
resource "azurerm_log_analytics_workspace" "la_workspace" {
@@ -96,33 +264,22 @@ resource "azurerm_service_plan" "app_service_plan" {
}
}
-resource "azurerm_subnet" "subnet_delegation" {
- count = var.function_app_subnet_delegation_id == "" ? 1 : 0
- name = "${var.prefix}-${var.cluster_name}-subnet-delegation"
- resource_group_name = local.vnet_rg_name
- virtual_network_name = local.vnet_name
- address_prefixes = [var.function_app_subnet_delegation_cidr]
- service_endpoints = ["Microsoft.Storage", "Microsoft.KeyVault", "Microsoft.Web"]
- delegation {
- name = "subnet-delegation"
- service_delegation {
- name = "Microsoft.Web/serverFarms"
- actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
- }
- }
-}
-
resource "azurerm_linux_function_app" "function_app" {
name = local.function_app_name
resource_group_name = data.azurerm_resource_group.rg.name
location = data.azurerm_resource_group.rg.location
service_plan_id = azurerm_service_plan.app_service_plan.id
storage_account_name = local.deployment_storage_account_name
- storage_account_access_key = var.deployment_storage_account_access_key == "" ? azurerm_storage_account.deployment_sa[0].primary_access_key : var.deployment_storage_account_access_key
+ storage_account_access_key = local.deployment_sa_access_key
https_only = true
- virtual_network_subnet_id = var.function_app_subnet_delegation_id == "" ? azurerm_subnet.subnet_delegation[0].id : var.function_app_subnet_delegation_id
+ virtual_network_subnet_id = local.function_app_subnet_delegation_id
+
site_config {
- vnet_route_all_enabled = true
+ vnet_route_all_enabled = true
+ application_insights_key = local.insights_instrumenation_key
+ application_stack {
+ use_custom_runtime = true
+ }
dynamic "ip_restriction" {
for_each = range(local.create_private_function)
content {
@@ -133,9 +290,9 @@ resource "azurerm_linux_function_app" "function_app" {
}
}
dynamic "ip_restriction" {
- for_each = range(local.create_private_function)
+ for_each = range(local.sa_public_access_enabled ? local.create_private_function : 0)
content {
- virtual_network_subnet_id = var.logic_app_subnet_delegation_id == "" ? azurerm_subnet.logicapp_subnet_delegation[0].id : var.logic_app_subnet_delegation_id
+ virtual_network_subnet_id = var.logic_app_subnet_delegation_id == "" ? module.logic_app_subnet_delegation[0].id : var.logic_app_subnet_delegation_id
action = "Allow"
priority = 301
name = "VirtualNetwork"
@@ -143,74 +300,7 @@ resource "azurerm_linux_function_app" "function_app" {
}
}
- app_settings = {
- "USER_ASSIGNED_CLIENT_ID" = local.function_app_identity_client_id
- "APPINSIGHTS_INSTRUMENTATIONKEY" = local.insights_instrumenation_key
- "STATE_STORAGE_NAME" = local.deployment_storage_account_name
- "STATE_CONTAINER_NAME" = local.deployment_container_name
- "STATE_BLOB_NAME" = "state"
- "HOSTS_NUM" = var.cluster_size
- "CLUSTER_NAME" = var.cluster_name
- "PROTECTION_LEVEL" = var.protection_level
- "STRIPE_WIDTH" = var.stripe_width != -1 ? var.stripe_width : local.stripe_width
- "HOTSPARE" = var.hotspare
- "VM_USERNAME" = var.vm_username
- "SUBSCRIPTION_ID" = var.subscription_id
- "RESOURCE_GROUP_NAME" = data.azurerm_resource_group.rg.name
- "LOCATION" = data.azurerm_resource_group.rg.location
- "SET_OBS" = var.tiering_enable_obs_integration
- "CREATE_CONFIG_FS" = (var.smbw_enabled && var.smb_setup_protocol) || var.s3_setup_protocol
- "OBS_NAME" = local.obs_storage_account_name
- "OBS_CONTAINER_NAME" = local.obs_container_name
- "OBS_ACCESS_KEY" = var.tiering_blob_obs_access_key
- DRIVE_CONTAINER_CORES_NUM = var.containers_config_map[var.instance_type].drive
- COMPUTE_CONTAINER_CORES_NUM = var.set_dedicated_fe_container == false ? var.containers_config_map[var.instance_type].compute + 1 : var.containers_config_map[var.instance_type].compute
- FRONTEND_CONTAINER_CORES_NUM = var.set_dedicated_fe_container == false ? 0 : var.containers_config_map[var.instance_type].frontend
- COMPUTE_MEMORY = var.containers_config_map[var.instance_type].memory[local.get_compute_memory_index]
- DISK_SIZE = local.disk_size
- "NVMES_NUM" = var.containers_config_map[var.instance_type].nvme
- "TIERING_SSD_PERCENT" = var.tiering_enable_ssd_percent
- "TIERING_TARGET_SSD_RETENTION" = var.tiering_obs_target_ssd_retention
- "TIERING_START_DEMOTE" = var.tiering_obs_start_demote
- "PREFIX" = var.prefix
- "KEY_VAULT_URI" = azurerm_key_vault.key_vault.vault_uri
- "INSTALL_DPDK" = var.install_cluster_dpdk
- "NICS_NUM" = var.containers_config_map[var.instance_type].nics
- "INSTALL_URL" = local.install_weka_url
- "LOG_LEVEL" = var.function_app_log_level
- "SUBNET" = data.azurerm_subnet.subnet.address_prefix
- FUNCTION_APP_NAME = local.function_app_name
- PROXY_URL = var.proxy_url
- WEKA_HOME_URL = var.weka_home_url
- POST_CLUSTER_CREATION_SCRIPT = var.script_post_cluster_creation
- PRE_START_IO_SCRIPT = var.script_pre_start_io
- DOWN_BACKENDS_REMOVAL_TIMEOUT = var.debug_down_backends_removal_timeout
-
- https_only = true
- FUNCTIONS_EXTENSION_VERSION = "~4"
- FUNCTIONS_WORKER_RUNTIME = "custom"
- FUNCTION_APP_EDIT_MODE = "readonly"
- HASH = var.function_app_version
- WEBSITE_RUN_FROM_PACKAGE = "https://${local.weka_sa}.blob.core.windows.net/${local.weka_sa_container}/${local.function_app_zip_name}"
- WEBSITE_VNET_ROUTE_ALL = true
-
- NFS_STATE_CONTAINER_NAME = local.nfs_deployment_container_name
- NFS_STATE_BLOB_NAME = "nfs_state"
- NFS_INTERFACE_GROUP_NAME = var.nfs_interface_group_name
- NFS_CLIENT_GROUP_NAME = var.nfs_client_group_name
- NFS_SECONDARY_IPS_NUM = var.nfs_protocol_gateway_secondary_ips_per_nic
- NFS_PROTOCOL_GATEWAY_FE_CORES_NUM = var.nfs_protocol_gateway_fe_cores_num
- NFS_PROTOCOL_GATEWAYS_NUM = var.nfs_protocol_gateways_number
- NFS_VMSS_NAME = var.nfs_protocol_gateways_number > 0 ? "${var.prefix}-${var.cluster_name}-nfs-protocol-gateway-vmss" : ""
- NFS_DISK_SIZE = var.nfs_protocol_gateway_disk_size
- SMB_DISK_SIZE = var.smb_protocol_gateway_disk_size
- S3_DISK_SIZE = var.s3_protocol_gateway_disk_size
- SMB_PROTOCOL_GATEWAY_FE_CORES_NUM = var.smb_protocol_gateway_fe_cores_num
- S3_PROTOCOL_GATEWAY_FE_CORES_NUM = var.s3_protocol_gateway_fe_cores_num
- TRACES_PER_FRONTEND = var.traces_per_ionode
-
- BACKEND_LB_IP = var.create_lb ? azurerm_lb.backend_lb[0].private_ip_address : ""
- }
+ app_settings = local.app_settings
identity {
type = "UserAssigned"
@@ -228,7 +318,17 @@ resource "azurerm_linux_function_app" "function_app" {
condition = contains(local.supported_regions, data.azurerm_resource_group.rg.location)
error_message = "The region '${data.azurerm_resource_group.rg.location}' is not supported for the function_app_dist '${var.function_app_dist}'. Supported regions: ${join(", ", local.supported_regions)}"
}
+
+ precondition {
+ condition = local.sa_public_access_enabled || local.sa_public_access_for_vnet && local.sa_allowed_ips_provided || (local.sa_public_access_disabled || local.sa_public_access_for_vnet && !local.sa_allowed_ips_provided) && var.deployment_storage_account_name != ""
+ error_message = "You shoud pick one of 3 options: 1. Public access enabled, 2. Public access enabled for VNET + public IPs whitelisted, 3. Public access disabled (or enabled for VNET without IPs whitelisted) and deployment_storage_account_name provided"
+ }
+
+ precondition {
+ condition = local.read_remote_function_zip || var.deployment_function_app_code_blob != ""
+ error_message = "You should provide value for 'deployment_function_app_code_blob' or 'read_function_zip_from_storage_account' should be false"
+ }
}
- depends_on = [module.network, azurerm_storage_account.deployment_sa, azurerm_subnet.logicapp_subnet_delegation]
+ depends_on = [module.network, module.iam, azurerm_storage_account.deployment_sa, azurerm_private_endpoint.file_endpoint, azurerm_private_endpoint.blob_endpoint]
}
diff --git a/key-vault.tf b/key-vault.tf
index b6840799..79c1f6f3 100644
--- a/key-vault.tf
+++ b/key-vault.tf
@@ -6,7 +6,7 @@ resource "azurerm_key_vault" "key_vault" {
resource_group_name = var.rg_name
enabled_for_deployment = true
tenant_id = data.azurerm_client_config.current.tenant_id
- purge_protection_enabled = false
+ purge_protection_enabled = var.key_vault_purge_protection_enabled
sku_name = "standard"
tags = merge(var.tags_map, { "weka_cluster" : var.cluster_name })
lifecycle {
@@ -14,13 +14,13 @@ resource "azurerm_key_vault" "key_vault" {
}
}
-resource "azurerm_key_vault_access_policy" "function_app_get_secret_permission" {
+resource "azurerm_key_vault_access_policy" "function_app_secret_permissions" {
key_vault_id = azurerm_key_vault.key_vault.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = local.function_app_identity_principal
secret_permissions = [
- "Get",
+ "Get", "Set"
]
depends_on = [azurerm_key_vault.key_vault]
@@ -96,23 +96,25 @@ resource "azurerm_key_vault_secret" "get_weka_io_token" {
}
}
-resource "random_password" "weka_password" {
- length = 16
- lower = true
- min_lower = 1
- upper = true
- min_upper = 1
- numeric = true
- min_numeric = 1
-}
-
resource "azurerm_key_vault_secret" "weka_password_secret" {
name = "weka-password"
- value = random_password.weka_password.result
+ value = ""
+ key_vault_id = azurerm_key_vault.key_vault.id
+ tags = merge(var.tags_map, { "weka_cluster" : var.cluster_name })
+ lifecycle {
+ ignore_changes = [value, tags]
+ }
+ depends_on = [azurerm_key_vault.key_vault, azurerm_key_vault_access_policy.key_vault_access_policy]
+}
+
+
+resource "azurerm_key_vault_secret" "weka_deployment_password" {
+ name = "weka-deployment-password"
+ value = ""
key_vault_id = azurerm_key_vault.key_vault.id
tags = merge(var.tags_map, { "weka_cluster" : var.cluster_name })
lifecycle {
ignore_changes = [value, tags]
}
- depends_on = [azurerm_key_vault.key_vault, random_password.weka_password, azurerm_key_vault_access_policy.key_vault_access_policy]
+ depends_on = [azurerm_key_vault.key_vault, azurerm_key_vault_access_policy.key_vault_access_policy]
}
diff --git a/lb.tf b/lb.tf
index 8209381c..98ecdca9 100644
--- a/lb.tf
+++ b/lb.tf
@@ -150,7 +150,7 @@ resource "azurerm_lb_rule" "backend_lb_rule" {
}
resource "azurerm_private_dns_a_record" "dns_a_record_backend_lb" {
- count = var.create_lb ? 1 : 0
+ count = var.create_lb && var.private_dns_zone_use ? 1 : 0
name = lower("${var.cluster_name}-backend")
zone_name = local.private_dns_zone_name
resource_group_name = local.private_dns_rg_name
diff --git a/main.tf b/main.tf
index 95682ab5..a10507ec 100644
--- a/main.tf
+++ b/main.tf
@@ -7,23 +7,9 @@ locals {
disk_size = var.default_disk_size + var.traces_per_ionode * (var.containers_config_map[var.instance_type].compute + var.containers_config_map[var.instance_type].drive + var.containers_config_map[var.instance_type].frontend)
alphanumeric_cluster_name = lower(replace(var.cluster_name, "/\\W|_|\\s/", ""))
alphanumeric_prefix_name = lower(replace(var.prefix, "/\\W|_|\\s/", ""))
- subnet_range = data.azurerm_subnet.subnet.address_prefix
+ subnet_range = data.azurerm_subnet.subnet.address_prefixes[0]
nics_numbers = var.install_cluster_dpdk ? var.containers_config_map[var.instance_type].nics : 1
- init_script = templatefile("${path.module}/init-script.sh", {
- apt_repo_server = var.apt_repo_server
- user = var.vm_username
- subnet_range = local.subnet_range
- nics_num = local.nics_numbers
- deploy_url = "https://${azurerm_linux_function_app.function_app.name}.azurewebsites.net/api/deploy"
- report_url = "https://${azurerm_linux_function_app.function_app.name}.azurewebsites.net/api/report"
- function_app_default_key = data.azurerm_function_app_host_keys.function_keys.default_function_key
- disk_size = local.disk_size
- })
- custom_data_script = templatefile("${path.module}/user-data.sh", {
- user_data = var.user_data
- init_script = local.init_script
- })
- placement_group_id = var.placement_group_id != "" ? var.placement_group_id : var.vmss_single_placement_group ? azurerm_proximity_placement_group.ppg[0].id : null
+ placement_group_id = var.placement_group_id != "" ? var.placement_group_id : var.vmss_single_placement_group ? azurerm_proximity_placement_group.ppg[0].id : null
}
# ===================== SSH key ++++++++++++++++++++++++= #
diff --git a/modules/clients/README.md b/modules/clients/README.md
index f750557f..90f3defe 100644
--- a/modules/clients/README.md
+++ b/modules/clients/README.md
@@ -4,13 +4,13 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
## Providers
| Name | Version |
|------|---------|
-| [azurerm](#provider\_azurerm) | ~>3.75.0 |
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
## Modules
@@ -21,6 +21,7 @@ No modules.
| Name | Type |
|------|------|
| [azurerm_linux_virtual_machine.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_virtual_machine) | resource |
+| [azurerm_linux_virtual_machine_scale_set.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_virtual_machine_scale_set) | resource |
| [azurerm_network_interface.private_first_nic](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface) | resource |
| [azurerm_network_interface.private_nics](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface) | resource |
| [azurerm_network_interface.public_first_nic](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface) | resource |
@@ -56,6 +57,7 @@ No modules.
| [ssh\_public\_key](#input\_ssh\_public\_key) | Ssh public key to pass to vms. | `string` | n/a | yes |
| [subnet\_name](#input\_subnet\_name) | The subnet names. | `string` | n/a | yes |
| [tags\_map](#input\_tags\_map) | A map of tags to assign the same metadata to all resources in the environment. Format: key:value. | `map(string)` | `{}` | no |
+| [use\_vmss](#input\_use\_vmss) | Use VMSS | `bool` | `false` | no |
| [vm\_identity\_name](#input\_vm\_identity\_name) | The name of the user assigned identity for the client VMs. | `string` | `""` | no |
| [vm\_username](#input\_vm\_username) | The user name for logging in to the virtual machines. | `string` | `"weka"` | no |
| [vmss\_name](#input\_vmss\_name) | The name of the backends virtual machine scale set. | `string` | n/a | yes |
@@ -68,4 +70,5 @@ No modules.
|------|-------------|
| [client\_ips](#output\_client\_ips) | n/a |
| [client\_names](#output\_client\_names) | n/a |
+| [vmss\_name](#output\_vmss\_name) | n/a |
diff --git a/modules/clients/main.tf b/modules/clients/main.tf
index 4d7367b4..01f8cd6d 100644
--- a/modules/clients/main.tf
+++ b/modules/clients/main.tf
@@ -9,16 +9,17 @@ data "azurerm_subnet" "subnet" {
}
locals {
- first_nic_ids = var.assign_public_ip ? azurerm_network_interface.public_first_nic[*].id : azurerm_network_interface.private_first_nic[*].id
- nics_num = var.frontend_container_cores_num + 1
+ first_nic_ids = var.assign_public_ip ? azurerm_network_interface.public_first_nic[*].id : azurerm_network_interface.private_first_nic[*].id
+ private_nic_first_index = var.assign_public_ip ? 1 : 0
+ nics_num = var.frontend_container_cores_num + 1
preparation_script = templatefile("${path.module}/init.sh", {
apt_repo_server = var.apt_repo_server
nics_num = local.nics_num
- subnet_range = data.azurerm_subnet.subnet.address_prefix
+ subnet_range = data.azurerm_subnet.subnet.address_prefixes[0]
})
mount_wekafs_script = templatefile("${path.module}/mount_wekafs.sh", {
- all_gateways = cidrhost(data.azurerm_subnet.subnet.address_prefix, 1)
+ all_gateways = cidrhost(data.azurerm_subnet.subnet.address_prefixes[0], 1)
frontend_container_cores_num = var.frontend_container_cores_num
backend_lb_ip = var.backend_lb_ip
clients_use_dpdk = var.clients_use_dpdk
@@ -47,7 +48,7 @@ locals {
}
resource "azurerm_public_ip" "public_ip" {
- count = var.assign_public_ip ? var.clients_number : 0
+ count = var.use_vmss ? 0 : var.assign_public_ip ? var.clients_number : 0
name = "${var.clients_name}-public-ip-${count.index}"
resource_group_name = var.rg_name
location = data.azurerm_resource_group.rg.location
@@ -57,12 +58,12 @@ resource "azurerm_public_ip" "public_ip" {
}
resource "azurerm_network_interface" "public_first_nic" {
- count = var.assign_public_ip ? var.clients_number : 0
- name = "${var.clients_name}-backend-nic-${count.index}"
- enable_accelerated_networking = var.clients_use_dpdk
- resource_group_name = var.rg_name
- location = data.azurerm_resource_group.rg.location
- tags = var.tags_map
+ count = var.use_vmss ? 0 : var.assign_public_ip ? var.clients_number : 0
+ name = "${var.clients_name}-nic-${count.index}"
+ accelerated_networking_enabled = var.clients_use_dpdk
+ resource_group_name = var.rg_name
+ location = data.azurerm_resource_group.rg.location
+ tags = var.tags_map
ip_configuration {
name = "ipconfig0"
subnet_id = data.azurerm_subnet.subnet.id
@@ -73,18 +74,18 @@ resource "azurerm_network_interface" "public_first_nic" {
}
resource "azurerm_network_interface_security_group_association" "public_first" {
- count = var.assign_public_ip ? var.clients_number : 0
+ count = var.use_vmss ? 0 : var.assign_public_ip ? var.clients_number : 0
network_interface_id = azurerm_network_interface.public_first_nic[count.index].id
network_security_group_id = var.sg_id
}
resource "azurerm_network_interface" "private_first_nic" {
- count = var.assign_public_ip ? 0 : var.clients_number
- name = "${var.clients_name}-backend-nic-${count.index}"
- enable_accelerated_networking = var.clients_use_dpdk
- resource_group_name = var.rg_name
- location = data.azurerm_resource_group.rg.location
- tags = var.tags_map
+ count = var.use_vmss ? 0 : var.assign_public_ip ? 0 : var.clients_number
+ name = "${var.clients_name}-nic-${count.index}"
+ accelerated_networking_enabled = var.clients_use_dpdk
+ resource_group_name = var.rg_name
+ location = data.azurerm_resource_group.rg.location
+ tags = var.tags_map
ip_configuration {
name = "ipconfig0"
subnet_id = data.azurerm_subnet.subnet.id
@@ -94,18 +95,18 @@ resource "azurerm_network_interface" "private_first_nic" {
}
resource "azurerm_network_interface_security_group_association" "private_first" {
- count = var.assign_public_ip ? 0 : var.clients_number
+ count = var.use_vmss ? 0 : var.assign_public_ip ? 0 : var.clients_number
network_interface_id = azurerm_network_interface.private_first_nic[count.index].id
network_security_group_id = var.sg_id
}
resource "azurerm_network_interface" "private_nics" {
- count = (local.nics_num - 1) * var.clients_number
- name = "${var.clients_name}-backend-nic-${count.index + var.clients_number}"
- enable_accelerated_networking = var.clients_use_dpdk
- resource_group_name = var.rg_name
- location = data.azurerm_resource_group.rg.location
- tags = var.tags_map
+ count = var.use_vmss ? 0 : (local.nics_num - 1) * var.clients_number
+ name = "${var.clients_name}-nic-${count.index + var.clients_number}"
+ accelerated_networking_enabled = var.clients_use_dpdk
+ resource_group_name = var.rg_name
+ location = data.azurerm_resource_group.rg.location
+ tags = var.tags_map
ip_configuration {
name = "ipconfig${count.index + var.clients_number}"
subnet_id = data.azurerm_subnet.subnet.id
@@ -114,13 +115,13 @@ resource "azurerm_network_interface" "private_nics" {
}
resource "azurerm_network_interface_security_group_association" "private" {
- count = (local.nics_num - 1) * var.clients_number
+ count = var.use_vmss ? 0 : (local.nics_num - 1) * var.clients_number
network_interface_id = azurerm_network_interface.private_nics[count.index].id
network_security_group_id = var.sg_id
}
resource "azurerm_linux_virtual_machine" "this" {
- count = var.clients_number
+ count = var.use_vmss ? 0 : var.clients_number
name = "${var.clients_name}-vm-${count.index}"
location = data.azurerm_resource_group.rg.location
resource_group_name = var.rg_name
@@ -156,3 +157,85 @@ resource "azurerm_linux_virtual_machine" "this" {
}
depends_on = [azurerm_network_interface.private_first_nic, azurerm_network_interface.private_nics, azurerm_network_interface.public_first_nic]
}
+
+resource "azurerm_linux_virtual_machine_scale_set" "this" {
+ count = var.use_vmss ? 1 : 0
+ instances = var.clients_number
+ name = var.clients_name
+ location = data.azurerm_resource_group.rg.location
+ resource_group_name = var.rg_name
+ admin_username = var.vm_username
+ tags = merge({ "weka_cluster_client" : var.clients_name }, var.tags_map)
+ custom_data = local.vms_custom_data
+ source_image_id = local.source_image_id
+ sku = local.instance_type
+
+ dynamic "network_interface" {
+ for_each = range(local.private_nic_first_index)
+ content {
+ name = "${var.clients_name}-clients-nic-0"
+ network_security_group_id = var.sg_id
+ primary = true
+ enable_accelerated_networking = var.clients_use_dpdk
+ ip_configuration {
+ primary = true
+ name = "ipconfig0"
+ subnet_id = data.azurerm_subnet.subnet.id
+ public_ip_address {
+ name = "${var.clients_name}-public-ip"
+ domain_name_label = var.clients_name
+ }
+ }
+ }
+ }
+ dynamic "network_interface" {
+ for_each = range(local.private_nic_first_index, 1)
+ content {
+ name = "${var.clients_name}-nic-0"
+ network_security_group_id = var.sg_id
+ primary = true
+ enable_accelerated_networking = var.clients_use_dpdk
+ ip_configuration {
+ primary = true
+ name = "ipconfig0"
+ subnet_id = data.azurerm_subnet.subnet.id
+ }
+ }
+ }
+ dynamic "network_interface" {
+ for_each = range(1, local.nics_num)
+ content {
+ name = "${var.clients_name}-nic-${network_interface.value}"
+ network_security_group_id = var.sg_id
+ primary = false
+ enable_accelerated_networking = var.clients_use_dpdk
+ ip_configuration {
+ primary = false
+ name = "ipconfig${network_interface.value}"
+ subnet_id = data.azurerm_subnet.subnet.id
+ }
+ }
+ }
+
+ proximity_placement_group_id = var.ppg_id
+ disable_password_authentication = true
+
+ identity {
+ type = "UserAssigned"
+ identity_ids = [local.client_identity_id]
+ }
+
+ os_disk {
+ caching = "ReadWrite"
+ storage_account_type = "StandardSSD_LRS"
+ }
+
+ admin_ssh_key {
+ public_key = var.ssh_public_key
+ username = var.vm_username
+ }
+ lifecycle {
+ ignore_changes = [tags, custom_data]
+ }
+ depends_on = [azurerm_network_interface.private_first_nic, azurerm_network_interface.private_nics, azurerm_network_interface.public_first_nic]
+}
diff --git a/modules/clients/outputs.tf b/modules/clients/outputs.tf
index d25a94e7..dbbc1c3e 100644
--- a/modules/clients/outputs.tf
+++ b/modules/clients/outputs.tf
@@ -2,6 +2,10 @@ output "client_ips" {
value = var.assign_public_ip ? azurerm_linux_virtual_machine.this[*].public_ip_address : azurerm_linux_virtual_machine.this[*].private_ip_address
}
+output "vmss_name" {
+ value = var.clients_name
+}
+
output "client_names" {
value = azurerm_linux_virtual_machine.this[*].name
}
diff --git a/modules/clients/variables.tf b/modules/clients/variables.tf
index 7b6a0536..cccab788 100644
--- a/modules/clients/variables.tf
+++ b/modules/clients/variables.tf
@@ -119,3 +119,9 @@ variable "source_image_id" {
description = "Use weka custom image, ubuntu 20.04 with kernel 5.4 and ofed 5.8-1.1.2.1"
default = ""
}
+
+variable "use_vmss" {
+ type = bool
+ description = "Use VMSS"
+ default = false
+}
diff --git a/modules/clients/versions.tf b/modules/clients/versions.tf
index 281dc878..202d92cc 100644
--- a/modules/clients/versions.tf
+++ b/modules/clients/versions.tf
@@ -3,7 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
+ version = "~>3.114.0"
}
}
}
diff --git a/modules/iam/README.md b/modules/iam/README.md
index 812bde25..032623c2 100644
--- a/modules/iam/README.md
+++ b/modules/iam/README.md
@@ -4,13 +4,13 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
## Providers
| Name | Version |
|------|---------|
-| [azurerm](#provider\_azurerm) | ~>3.75.0 |
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
## Modules
@@ -23,6 +23,9 @@ No modules.
| [azurerm_role_assignment.function_app_key_vault_secrets_user](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.function_app_reader](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.function_app_scale_set_machine_owner](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
+| [azurerm_role_assignment.join_sg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
+| [azurerm_role_assignment.join_subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
+| [azurerm_role_assignment.key_vault_set_secret](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.logic_app_standard_reader](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.logic_app_standard_reader_secret](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.logic_app_standard_reader_smb_data](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
@@ -31,15 +34,22 @@ No modules.
| [azurerm_role_assignment.nfs_storage_blob_data_contributor](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.obs_data_contributor](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.obs_storage_blob_data_contributor](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
+| [azurerm_role_assignment.private_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.reader](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.storage_account_contributor](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.storage_blob_data_contributor](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_assignment.weka_tar_data_reader](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
+| [azurerm_role_definition.join_sg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
+| [azurerm_role_definition.join_subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
+| [azurerm_role_definition.key_vault_set_secret](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
+| [azurerm_role_definition.private_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
| [azurerm_user_assigned_identity.function_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource |
| [azurerm_user_assigned_identity.logic_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource |
| [azurerm_user_assigned_identity.vmss](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource |
| [azurerm_resource_group.rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source |
+| [azurerm_resource_group.vnet_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source |
| [azurerm_storage_account.obs_sa](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/storage_account) | data source |
+| [azurerm_subnet.subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet) | data source |
| [azurerm_user_assigned_identity.function_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/user_assigned_identity) | data source |
| [azurerm_user_assigned_identity.logic_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/user_assigned_identity) | data source |
| [azurerm_user_assigned_identity.vmss](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/user_assigned_identity) | data source |
@@ -58,11 +68,17 @@ No modules.
| [nfs\_deployment\_container\_name](#input\_nfs\_deployment\_container\_name) | The name of the container for the NFS deployment. | `string` | n/a | yes |
| [nfs\_protocol\_gateways\_number](#input\_nfs\_protocol\_gateways\_number) | The number of NFS protocol gateways. | `number` | n/a | yes |
| [obs\_container\_name](#input\_obs\_container\_name) | The name of the container for the OBS. | `string` | n/a | yes |
+| [obs\_create\_private\_endpoint](#input\_obs\_create\_private\_endpoint) | Create private endpoint for OBS. | `bool` | `false` | no |
| [prefix](#input\_prefix) | Prefix for all resources | `string` | n/a | yes |
| [rg\_name](#input\_rg\_name) | A predefined resource group in the Azure subscription. | `string` | n/a | yes |
+| [sg\_id](#input\_sg\_id) | Security group id | `string` | `""` | no |
+| [subnet\_name](#input\_subnet\_name) | The name of the subnet. | `string` | n/a | yes |
+| [support\_logic\_app](#input\_support\_logic\_app) | Enable support for logic app. | `bool` | `true` | no |
| [tiering\_enable\_obs\_integration](#input\_tiering\_enable\_obs\_integration) | Enable OBS integration for tiering. | `bool` | n/a | yes |
| [tiering\_obs\_name](#input\_tiering\_obs\_name) | Name of existing obs storage account. | `string` | `""` | no |
| [vmss\_identity\_name](#input\_vmss\_identity\_name) | The user assigned identity name for the vmss instances (if empty - new one is created). | `string` | `""` | no |
+| [vnet\_name](#input\_vnet\_name) | The name of the virtual network. | `string` | n/a | yes |
+| [vnet\_rg\_name](#input\_vnet\_rg\_name) | The name of the resource group for the VNet. | `string` | n/a | yes |
| [weka\_tar\_storage\_account\_id](#input\_weka\_tar\_storage\_account\_id) | n/a | `string` | `""` | no |
## Outputs
diff --git a/modules/iam/function_app.tf b/modules/iam/function_app.tf
index 95abacd2..c17de988 100644
--- a/modules/iam/function_app.tf
+++ b/modules/iam/function_app.tf
@@ -42,11 +42,35 @@ resource "azurerm_role_assignment" "obs_storage_blob_data_contributor" {
resource "azurerm_role_assignment" "function_app_key_vault_secrets_user" {
count = var.function_app_identity_name == "" ? 1 : 0
- scope = data.azurerm_resource_group.rg.id
+ scope = var.key_vault_id
role_definition_name = "Key Vault Secrets User"
principal_id = azurerm_user_assigned_identity.function_app[0].principal_id
}
+resource "azurerm_role_definition" "key_vault_set_secret" {
+ count = var.function_app_identity_name == "" ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-key-vault-new-secret-writer"
+ scope = var.key_vault_id
+ description = "Can create new secrets in the key vault"
+
+ permissions {
+ actions = [
+ # See: https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/security#microsoftkeyvault
+ "Microsoft.KeyVault/vaults/secrets/write",
+ ]
+ not_actions = []
+ }
+
+ assignable_scopes = [var.key_vault_id]
+}
+
+resource "azurerm_role_assignment" "key_vault_set_secret" {
+ count = var.function_app_identity_name == "" ? 1 : 0
+ scope = var.key_vault_id
+ role_definition_id = azurerm_role_definition.key_vault_set_secret[0].role_definition_resource_id
+ principal_id = azurerm_user_assigned_identity.function_app[0].principal_id
+}
+
resource "azurerm_role_assignment" "function_app_reader" {
count = var.function_app_identity_name == "" ? 1 : 0
scope = data.azurerm_resource_group.rg.id
@@ -67,3 +91,81 @@ resource "azurerm_role_assignment" "managed_identity_operator" {
role_definition_name = "Managed Identity Operator"
principal_id = azurerm_user_assigned_identity.function_app[0].principal_id
}
+
+data "azurerm_subnet" "subnet" {
+ name = var.subnet_name
+ virtual_network_name = var.vnet_name
+ resource_group_name = var.vnet_rg_name
+}
+
+resource "azurerm_role_definition" "join_subnet" {
+ count = var.function_app_identity_name == "" && var.rg_name != var.vnet_rg_name ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-join-subnet"
+ scope = data.azurerm_subnet.subnet.id
+ description = "Can join subnet"
+
+ permissions {
+ actions = [
+ "Microsoft.Network/virtualNetworks/subnets/join/action", # for VMSS creation from function app
+ "Microsoft.Network/virtualNetworks/subnets/joinViaServiceEndpoint/action", # for using SA service endpoint (when network is in different RG) - for weka obs
+ ]
+ not_actions = []
+ }
+
+ assignable_scopes = [data.azurerm_subnet.subnet.id]
+}
+
+resource "azurerm_role_assignment" "join_subnet" {
+ count = var.function_app_identity_name == "" && var.rg_name != var.vnet_rg_name ? 1 : 0
+ scope = data.azurerm_subnet.subnet.id
+ role_definition_id = azurerm_role_definition.join_subnet[0].role_definition_resource_id
+ principal_id = azurerm_user_assigned_identity.function_app[0].principal_id
+}
+
+resource "azurerm_role_definition" "join_sg" {
+ count = var.function_app_identity_name == "" && var.rg_name != var.vnet_rg_name && var.sg_id != "" ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-join-sg"
+ scope = var.sg_id
+ description = "Can join security group"
+
+ permissions {
+ actions = [
+ "Microsoft.Network/networkSecurityGroups/join/action",
+ ]
+ not_actions = []
+ }
+
+ assignable_scopes = [var.sg_id]
+}
+
+resource "azurerm_role_assignment" "join_sg" {
+ count = var.function_app_identity_name == "" && var.rg_name != var.vnet_rg_name && var.sg_id != "" ? 1 : 0
+ scope = var.sg_id
+ role_definition_id = azurerm_role_definition.join_sg[0].role_definition_resource_id
+ principal_id = azurerm_user_assigned_identity.function_app[0].principal_id
+}
+
+
+resource "azurerm_role_definition" "private_endpoint" {
+ count = var.function_app_identity_name == "" && var.obs_create_private_endpoint ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-private-endpoint"
+ scope = data.azurerm_resource_group.rg.id
+ description = "Can create private endpoint"
+
+ permissions {
+ actions = [
+ "Microsoft.Network/privateEndpoints/write",
+ "Microsoft.Network/privateEndpoints/privateDnsZoneGroups/write",
+ "Microsoft.Network/privateDnsZones/join/action",
+ ]
+ not_actions = []
+ }
+ assignable_scopes = [data.azurerm_resource_group.rg.id]
+}
+
+resource "azurerm_role_assignment" "private_endpoint" {
+ count = var.function_app_identity_name == "" && var.obs_create_private_endpoint ? 1 : 0
+ scope = data.azurerm_resource_group.rg.id
+ role_definition_id = azurerm_role_definition.private_endpoint[0].role_definition_resource_id
+ principal_id = azurerm_user_assigned_identity.function_app[0].principal_id
+}
diff --git a/modules/iam/logic_app.tf b/modules/iam/logic_app.tf
index 46986aa5..226617aa 100644
--- a/modules/iam/logic_app.tf
+++ b/modules/iam/logic_app.tf
@@ -1,32 +1,32 @@
data "azurerm_user_assigned_identity" "logic_app" {
- count = var.logic_app_identity_name != "" ? 1 : 0
+ count = var.logic_app_identity_name != "" && var.support_logic_app ? 1 : 0
name = var.logic_app_identity_name
resource_group_name = data.azurerm_resource_group.rg.name
}
resource "azurerm_user_assigned_identity" "logic_app" {
- count = var.logic_app_identity_name == "" ? 1 : 0
+ count = var.logic_app_identity_name == "" && var.support_logic_app ? 1 : 0
location = data.azurerm_resource_group.rg.location
name = "${var.prefix}-${var.cluster_name}-logic-app-identity"
resource_group_name = data.azurerm_resource_group.rg.name
}
resource "azurerm_role_assignment" "logic_app_standard_reader" {
- count = var.logic_app_identity_name == "" ? 1 : 0
+ count = var.logic_app_identity_name == "" && var.support_logic_app ? 1 : 0
scope = data.azurerm_resource_group.rg.id
role_definition_name = "Reader"
principal_id = azurerm_user_assigned_identity.logic_app[0].principal_id
}
resource "azurerm_role_assignment" "logic_app_standard_reader_secret" {
- count = var.logic_app_identity_name == "" ? 1 : 0
+ count = var.logic_app_identity_name == "" && var.support_logic_app ? 1 : 0
scope = var.key_vault_id
role_definition_name = "Key Vault Secrets User"
principal_id = azurerm_user_assigned_identity.logic_app[0].principal_id
}
resource "azurerm_role_assignment" "logic_app_standard_reader_smb_data" {
- count = var.logic_app_identity_name == "" ? 1 : 0
+ count = var.logic_app_identity_name == "" && var.support_logic_app ? 1 : 0
scope = var.logic_app_storage_account_id
role_definition_name = "Storage File Data SMB Share Contributor"
principal_id = azurerm_user_assigned_identity.logic_app[0].principal_id
diff --git a/modules/iam/main.tf b/modules/iam/main.tf
index 58a4215f..dee59959 100644
--- a/modules/iam/main.tf
+++ b/modules/iam/main.tf
@@ -2,6 +2,10 @@ data "azurerm_resource_group" "rg" {
name = var.rg_name
}
+data "azurerm_resource_group" "vnet_rg" {
+ name = var.vnet_rg_name
+}
+
locals {
obs_scope = var.tiering_obs_name != "" ? "${data.azurerm_storage_account.obs_sa[0].id}/blobServices/default/containers/${var.obs_container_name}" : ""
deployment_storage_account_scope = "${var.deployment_storage_account_id}/blobServices/default/containers/${var.deployment_container_name}"
diff --git a/modules/iam/outputs.tf b/modules/iam/outputs.tf
index a5ea994a..fd3075db 100644
--- a/modules/iam/outputs.tf
+++ b/modules/iam/outputs.tf
@@ -1,10 +1,10 @@
output "logic_app_identity_id" {
- value = var.logic_app_identity_name == "" ? azurerm_user_assigned_identity.logic_app[0].id : data.azurerm_user_assigned_identity.logic_app[0].id
+ value = var.support_logic_app ? var.logic_app_identity_name == "" ? azurerm_user_assigned_identity.logic_app[0].id : data.azurerm_user_assigned_identity.logic_app[0].id : null
description = "The ID of the managed identity for the logic app"
}
output "logic_app_identity_principal_id" {
- value = var.logic_app_identity_name == "" ? azurerm_user_assigned_identity.logic_app[0].principal_id : data.azurerm_user_assigned_identity.logic_app[0].principal_id
+ value = var.support_logic_app ? var.logic_app_identity_name == "" ? azurerm_user_assigned_identity.logic_app[0].principal_id : data.azurerm_user_assigned_identity.logic_app[0].principal_id : null
description = "The principal ID of the managed identity for the logic app"
}
diff --git a/modules/iam/variables.tf b/modules/iam/variables.tf
index 3c750c3d..8fa713a5 100644
--- a/modules/iam/variables.tf
+++ b/modules/iam/variables.tf
@@ -3,6 +3,27 @@ variable "rg_name" {
description = "A predefined resource group in the Azure subscription."
}
+variable "vnet_rg_name" {
+ type = string
+ description = "The name of the resource group for the VNet."
+}
+
+variable "vnet_name" {
+ type = string
+ description = "The name of the virtual network."
+}
+
+variable "subnet_name" {
+ type = string
+ description = "The name of the subnet."
+}
+
+variable "sg_id" {
+ type = string
+ description = "Security group id"
+ default = ""
+}
+
variable "prefix" {
type = string
description = "Prefix for all resources"
@@ -33,6 +54,12 @@ variable "function_app_identity_name" {
default = ""
}
+variable "support_logic_app" {
+ type = bool
+ description = "Enable support for logic app."
+ default = true
+}
+
variable "logic_app_identity_name" {
type = string
description = "The user assigned identity name for the logic app (if empty - new one is created)."
@@ -80,6 +107,12 @@ variable "obs_container_name" {
description = "The name of the container for the OBS."
}
+variable "obs_create_private_endpoint" {
+ type = bool
+ description = "Create private endpoint for OBS."
+ default = false
+}
+
variable "nfs_protocol_gateways_number" {
type = number
description = "The number of NFS protocol gateways."
diff --git a/modules/iam/versions.tf b/modules/iam/versions.tf
index 281dc878..202d92cc 100644
--- a/modules/iam/versions.tf
+++ b/modules/iam/versions.tf
@@ -3,7 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
+ version = "~>3.114.0"
}
}
}
diff --git a/modules/iam/vmss.tf b/modules/iam/vmss.tf
index b8ca29a6..6983fafb 100644
--- a/modules/iam/vmss.tf
+++ b/modules/iam/vmss.tf
@@ -20,7 +20,7 @@ resource "azurerm_role_assignment" "reader" {
resource "azurerm_role_assignment" "network_contributor" {
count = var.vmss_identity_name == "" ? 1 : 0
- scope = data.azurerm_resource_group.rg.id
+ scope = data.azurerm_resource_group.vnet_rg.id
role_definition_name = "Network Contributor"
principal_id = azurerm_user_assigned_identity.vmss[0].principal_id
}
diff --git a/modules/logic_app/README.md b/modules/logic_app/README.md
new file mode 100644
index 00000000..f29acb3b
--- /dev/null
+++ b/modules/logic_app/README.md
@@ -0,0 +1,68 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.4.6 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
+| [local](#requirement\_local) | ~>2.4.0 |
+| [null](#requirement\_null) | ~>3.2.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
+| [local](#provider\_local) | ~>2.4.0 |
+| [null](#provider\_null) | ~>3.2.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_key_vault_access_policy.standard_logic_app_get_secret_permission](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
+| [azurerm_logic_app_standard.logic_app_standard](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/logic_app_standard) | resource |
+| [azurerm_service_plan.logicapp_service_plan](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/service_plan) | resource |
+| [azurerm_storage_share.storage_share](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share) | resource |
+| [azurerm_storage_share_directory.share_directory_scale_down](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_directory) | resource |
+| [azurerm_storage_share_directory.share_directory_scale_up](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_directory) | resource |
+| [azurerm_storage_share_file.connections_share_file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_file) | resource |
+| [azurerm_storage_share_file.scale_down_share_file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_file) | resource |
+| [azurerm_storage_share_file.scale_up_share_file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share_file) | resource |
+| [local_file.connections_workflow_file](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
+| [local_file.scale_down_workflow_file](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
+| [local_file.scale_up_workflow_file](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
+| [null_resource.wait_for_logic_app](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
+| [azurerm_client_config.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/client_config) | data source |
+| [azurerm_storage_account.logicapp](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/storage_account) | data source |
+| [azurerm_storage_share.storage_share](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/storage_share) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [cluster\_name](#input\_cluster\_name) | Cluster name | `string` | n/a | yes |
+| [function\_app\_id](#input\_function\_app\_id) | The ID of the function app. | `string` | n/a | yes |
+| [function\_app\_key](#input\_function\_app\_key) | The key of the function app. | `string` | n/a | yes |
+| [function\_app\_name](#input\_function\_app\_name) | The name of the function app. | `string` | n/a | yes |
+| [key\_vault\_id](#input\_key\_vault\_id) | The id of the Azure Key Vault. | `string` | n/a | yes |
+| [key\_vault\_uri](#input\_key\_vault\_uri) | The URI of the Azure Key Vault. | `string` | n/a | yes |
+| [location](#input\_location) | The Azure region to deploy all resources to. | `string` | n/a | yes |
+| [logic\_app\_identity\_id](#input\_logic\_app\_identity\_id) | The ID of the managed identity for the logic app | `string` | n/a | yes |
+| [logic\_app\_identity\_principal](#input\_logic\_app\_identity\_principal) | The principal ID of the managed identity for the logic app | `string` | n/a | yes |
+| [logic\_app\_subnet\_delegation\_id](#input\_logic\_app\_subnet\_delegation\_id) | Required to specify if subnet\_name were used to specify pre-defined subnets for weka. Logicapp subnet delegation requires an additional subnet, and in the case of pre-defined networking this one also should be pre-defined | `string` | n/a | yes |
+| [prefix](#input\_prefix) | Prefix for all resources | `string` | n/a | yes |
+| [restricted\_inbound\_access](#input\_restricted\_inbound\_access) | Restrict inbound access to internal VNet | `bool` | n/a | yes |
+| [rg\_name](#input\_rg\_name) | A predefined resource group in the Azure subscription. | `string` | n/a | yes |
+| [storage\_account\_name](#input\_storage\_account\_name) | The name of the storage account. | `string` | n/a | yes |
+| [subnet\_id](#input\_subnet\_id) | The ID of the cluster subnet. | `string` | n/a | yes |
+| [use\_secured\_storage\_account](#input\_use\_secured\_storage\_account) | Use secured storage account with logic app. | `bool` | `false` | no |
+
+## Outputs
+
+No outputs.
+
diff --git a/logic_app/connections.json b/modules/logic_app/connections.json
similarity index 100%
rename from logic_app/connections.json
rename to modules/logic_app/connections.json
diff --git a/logic_app.tf b/modules/logic_app/main.tf
similarity index 54%
rename from logic_app.tf
rename to modules/logic_app/main.tf
index 80ab431a..667c47af 100644
--- a/logic_app.tf
+++ b/modules/logic_app/main.tf
@@ -1,30 +1,13 @@
-resource "azurerm_storage_account" "logicapp" {
- name = substr("${local.alphanumeric_prefix_name}${local.alphanumeric_cluster_name}logicappsa", 0, 24)
- resource_group_name = var.rg_name
- location = local.location
- account_tier = "Standard"
- account_replication_type = "LRS"
-}
-
-resource "azurerm_subnet" "logicapp_subnet_delegation" {
- count = var.logic_app_subnet_delegation_id == "" ? 1 : 0
- name = "${var.prefix}-${var.cluster_name}-logicapp-delegation"
- resource_group_name = local.vnet_rg_name
- virtual_network_name = local.vnet_name
- address_prefixes = [var.logic_app_subnet_delegation_cidr]
- service_endpoints = ["Microsoft.KeyVault", "Microsoft.Web"]
- delegation {
- name = "logic-delegation"
- service_delegation {
- name = "Microsoft.Web/serverFarms"
- actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
- }
- }
+data "azurerm_client_config" "current" {}
+
+data "azurerm_storage_account" "logicapp" {
+ name = var.storage_account_name
+ resource_group_name = var.rg_name
}
resource "azurerm_service_plan" "logicapp_service_plan" {
name = "${var.prefix}-${var.cluster_name}-logic-app-service-plan"
- location = local.location
+ location = var.location
resource_group_name = var.rg_name
os_type = "Windows"
sku_name = "WS1"
@@ -33,25 +16,44 @@ resource "azurerm_service_plan" "logicapp_service_plan" {
}
}
+resource "azurerm_storage_share" "storage_share" {
+ count = var.use_secured_storage_account ? 1 : 0
+ name = "${var.prefix}-${var.cluster_name}-logic-app-content"
+ storage_account_name = data.azurerm_storage_account.logicapp.name
+ quota = 100
+}
+
+data "azurerm_storage_share" "storage_share" {
+ count = var.use_secured_storage_account ? 0 : 1
+ name = "${azurerm_logic_app_standard.logic_app_standard.name}-content"
+ storage_account_name = data.azurerm_storage_account.logicapp.name
+}
+
+locals {
+ storage_share_id = var.use_secured_storage_account ? azurerm_storage_share.storage_share[0].id : data.azurerm_storage_share.storage_share[0].id
+}
+
resource "azurerm_logic_app_standard" "logic_app_standard" {
name = "${var.prefix}-${var.cluster_name}-logic-app"
- location = local.location
+ location = var.location
resource_group_name = var.rg_name
app_service_plan_id = azurerm_service_plan.logicapp_service_plan.id
- storage_account_name = azurerm_storage_account.logicapp.name
- storage_account_access_key = azurerm_storage_account.logicapp.primary_access_key
+ storage_account_share_name = var.use_secured_storage_account ? azurerm_storage_share.storage_share[0].name : null
+ storage_account_name = data.azurerm_storage_account.logicapp.name
+ storage_account_access_key = data.azurerm_storage_account.logicapp.primary_access_key
version = "~4" # sets FUNCTIONS_EXTENSION_VERSION (should be same as for function app)
identity {
type = "UserAssigned"
- identity_ids = [local.logic_app_identity_id]
+ identity_ids = [var.logic_app_identity_id]
}
site_config {
- vnet_route_all_enabled = true
+ public_network_access_enabled = false
+ vnet_route_all_enabled = true
dynamic "ip_restriction" {
- for_each = range(local.create_private_function)
+ for_each = range(var.restricted_inbound_access ? 1 : 0)
content {
- virtual_network_subnet_id = data.azurerm_subnet.subnet.id
+ virtual_network_subnet_id = var.subnet_id
action = "Allow"
priority = 300
name = "VirtualNetwork"
@@ -59,57 +61,65 @@ resource "azurerm_logic_app_standard" "logic_app_standard" {
}
}
app_settings = {
+ "WEBSITE_CONTENTOVERVNET" = var.use_secured_storage_account ? 1 : 0
"FUNCTIONS_WORKER_RUNTIME" = "node"
"WEBSITE_NODE_DEFAULT_VERSION" = "~18"
- "function_app_key" = data.azurerm_function_app_host_keys.function_keys.default_function_key
- "keyVaultUri" = azurerm_key_vault.key_vault.vault_uri
+ "function_app_key" = var.function_app_key
+ "keyVaultUri" = var.key_vault_uri
}
- virtual_network_subnet_id = var.logic_app_subnet_delegation_id == "" ? azurerm_subnet.logicapp_subnet_delegation[0].id : var.logic_app_subnet_delegation_id
- depends_on = [azurerm_service_plan.logicapp_service_plan, azurerm_subnet.logicapp_subnet_delegation, azurerm_storage_account.logicapp]
+ https_only = true
+ virtual_network_subnet_id = var.logic_app_subnet_delegation_id
+
+ depends_on = [azurerm_service_plan.logicapp_service_plan]
}
resource "azurerm_key_vault_access_policy" "standard_logic_app_get_secret_permission" {
- key_vault_id = azurerm_key_vault.key_vault.id
+ key_vault_id = var.key_vault_id
tenant_id = data.azurerm_client_config.current.tenant_id
- object_id = local.logic_app_identity_principal
+ object_id = var.logic_app_identity_principal
secret_permissions = [
"Get",
]
- depends_on = [azurerm_key_vault.key_vault]
}
+resource "null_resource" "wait_for_logic_app" {
+ count = var.use_secured_storage_account ? 1 : 0
+ triggers = {
+ logic_app_id = azurerm_logic_app_standard.logic_app_standard.id
+ }
+
+ provisioner "local-exec" {
+ # wait for "site/wwwroot" to be created in file share
+ command = "sleep 60"
+ }
-resource "azurerm_storage_share_directory" "share_directory_scale_down" {
- name = "site/wwwroot/scale-down"
- share_name = "${azurerm_logic_app_standard.logic_app_standard.name}-content"
- storage_account_name = azurerm_storage_account.logicapp.name
- depends_on = [azurerm_storage_account.logicapp]
+ depends_on = [azurerm_logic_app_standard.logic_app_standard]
}
-resource "azurerm_storage_share_directory" "share_directory_scale_up" {
- name = "site/wwwroot/scale-up"
- share_name = "${azurerm_logic_app_standard.logic_app_standard.name}-content"
- storage_account_name = azurerm_storage_account.logicapp.name
- depends_on = [azurerm_storage_account.logicapp]
+resource "azurerm_storage_share_directory" "share_directory_scale_down" {
+ name = "site/wwwroot/scale-down"
+ storage_share_id = local.storage_share_id
+ depends_on = [null_resource.wait_for_logic_app]
}
-data "azurerm_storage_share" "storage_share" {
- name = "${azurerm_logic_app_standard.logic_app_standard.name}-content"
- storage_account_name = azurerm_storage_account.logicapp.name
+resource "azurerm_storage_share_directory" "share_directory_scale_up" {
+ name = "site/wwwroot/scale-up"
+ storage_share_id = local.storage_share_id
+ depends_on = [null_resource.wait_for_logic_app]
}
locals {
- connections_workflow_path = "${path.module}/logic_app/connections.json"
+ connections_workflow_path = "${path.module}/connections.json"
connections_workflow = templatefile(local.connections_workflow_path, {
- function_name = azurerm_linux_function_app.function_app.name
- function_id = azurerm_linux_function_app.function_app.id
+ function_name = var.function_app_name
+ function_id = var.function_app_id
})
connections_workflow_hash = md5(join("", [for f in fileset(local.connections_workflow, "**") : filemd5("${local.connections_workflow}/${f}")]))
connections_workflow_filename = "/tmp/${var.prefix}_${var.cluster_name}_connections_workflow_${local.connections_workflow_hash}"
- scale_up_workflow_path = "${path.module}/logic_app/scale_up.json"
+ scale_up_workflow_path = "${path.module}/scale_up.json"
scale_up_workflow_hash = md5(join("", [for f in fileset(local.scale_up_workflow_path, "**") : filemd5("${local.scale_up_workflow_path}/${f}")]))
scale_up_workflow_filename = "/tmp/${var.prefix}_${var.cluster_name}_scale_up_workflow_${local.scale_up_workflow_hash}"
- scale_down_workflow_path = "${path.module}/logic_app/scale_down.json"
+ scale_down_workflow_path = "${path.module}/scale_down.json"
scale_down_workflow_hash = md5(join("", [for f in fileset(local.scale_down_workflow_path, "**") : filemd5("${local.scale_down_workflow_path}/${f}")]))
scale_down_workflow_filename = "/tmp/${var.prefix}_${var.cluster_name}_scale_down_workflow_${local.scale_down_workflow_hash}"
}
@@ -132,23 +142,23 @@ resource "local_file" "scale_down_workflow_file" {
resource "azurerm_storage_share_file" "scale_down_share_file" {
name = "workflow.json"
path = azurerm_storage_share_directory.share_directory_scale_down.name
- storage_share_id = data.azurerm_storage_share.storage_share.id
+ storage_share_id = local.storage_share_id
source = local_file.scale_down_workflow_file.filename
- depends_on = [azurerm_storage_share_directory.share_directory_scale_down, data.azurerm_storage_share.storage_share, local_file.scale_down_workflow_file]
+ depends_on = [azurerm_storage_share_directory.share_directory_scale_down, azurerm_storage_share.storage_share, local_file.scale_down_workflow_file]
}
resource "azurerm_storage_share_file" "scale_up_share_file" {
name = "workflow.json"
path = azurerm_storage_share_directory.share_directory_scale_up.name
- storage_share_id = data.azurerm_storage_share.storage_share.id
+ storage_share_id = local.storage_share_id
source = local_file.scale_up_workflow_file.filename
- depends_on = [azurerm_storage_share_directory.share_directory_scale_up, data.azurerm_storage_share.storage_share, local_file.scale_up_workflow_file]
+ depends_on = [azurerm_storage_share_directory.share_directory_scale_up, azurerm_storage_share.storage_share, local_file.scale_up_workflow_file]
}
resource "azurerm_storage_share_file" "connections_share_file" {
name = "connections.json"
path = "site/wwwroot"
- storage_share_id = data.azurerm_storage_share.storage_share.id
+ storage_share_id = local.storage_share_id
source = local_file.connections_workflow_file.filename
- depends_on = [azurerm_storage_share_directory.share_directory_scale_down, data.azurerm_storage_share.storage_share, local_file.connections_workflow_file]
+ depends_on = [azurerm_storage_share_directory.share_directory_scale_down, azurerm_storage_share.storage_share, local_file.connections_workflow_file]
}
diff --git a/modules/logic_app/outputs.tf b/modules/logic_app/outputs.tf
new file mode 100644
index 00000000..e69de29b
diff --git a/logic_app/scale_down.json b/modules/logic_app/scale_down.json
similarity index 100%
rename from logic_app/scale_down.json
rename to modules/logic_app/scale_down.json
diff --git a/logic_app/scale_up.json b/modules/logic_app/scale_up.json
similarity index 100%
rename from logic_app/scale_up.json
rename to modules/logic_app/scale_up.json
diff --git a/modules/logic_app/variables.tf b/modules/logic_app/variables.tf
new file mode 100644
index 00000000..76411ea8
--- /dev/null
+++ b/modules/logic_app/variables.tf
@@ -0,0 +1,81 @@
+variable "prefix" {
+ type = string
+ description = "Prefix for all resources"
+}
+
+variable "cluster_name" {
+ type = string
+ description = "Cluster name"
+}
+
+variable "rg_name" {
+ type = string
+ description = "A predefined resource group in the Azure subscription."
+}
+
+variable "subnet_id" {
+ type = string
+ description = "The ID of the cluster subnet."
+}
+
+variable "location" {
+ type = string
+ description = "The Azure region to deploy all resources to."
+}
+
+variable "logic_app_subnet_delegation_id" {
+ type = string
+ description = "Required to specify if subnet_name were used to specify pre-defined subnets for weka. Logicapp subnet delegation requires an additional subnet, and in the case of pre-defined networking this one also should be pre-defined"
+}
+
+variable "storage_account_name" {
+ type = string
+ description = "The name of the storage account."
+}
+
+variable "logic_app_identity_id" {
+ type = string
+ description = "The ID of the managed identity for the logic app"
+}
+
+variable "logic_app_identity_principal" {
+ type = string
+ description = "The principal ID of the managed identity for the logic app"
+
+}
+
+variable "restricted_inbound_access" {
+ type = bool
+ description = "Restrict inbound access to internal VNet"
+}
+
+variable "function_app_name" {
+ type = string
+ description = "The name of the function app."
+}
+
+variable "function_app_id" {
+ type = string
+ description = "The ID of the function app."
+}
+
+variable "function_app_key" {
+ type = string
+ description = "The key of the function app."
+}
+
+variable "key_vault_id" {
+ type = string
+ description = "The id of the Azure Key Vault."
+}
+
+variable "key_vault_uri" {
+ type = string
+ description = "The URI of the Azure Key Vault."
+}
+
+variable "use_secured_storage_account" {
+ type = bool
+ description = "Use secured storage account with logic app."
+ default = false
+}
diff --git a/modules/logic_app/versions.tf b/modules/logic_app/versions.tf
new file mode 100644
index 00000000..8f93fa62
--- /dev/null
+++ b/modules/logic_app/versions.tf
@@ -0,0 +1,17 @@
+terraform {
+ required_version = ">= 1.4.6"
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "~>3.114.0"
+ }
+ local = {
+ source = "hashicorp/local"
+ version = "~>2.4.0"
+ }
+ null = {
+ source = "hashicorp/null"
+ version = "~>3.2.0"
+ }
+ }
+}
diff --git a/modules/network/README.md b/modules/network/README.md
index e5ddaa26..6caddf3b 100644
--- a/modules/network/README.md
+++ b/modules/network/README.md
@@ -64,13 +64,13 @@ No modules.
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
## Providers
| Name | Version |
|------|---------|
-| [azurerm](#provider\_azurerm) | ~>3.75.0 |
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
## Modules
@@ -108,6 +108,7 @@ No modules.
| [prefix](#input\_prefix) | The prefix for all the resource names. For example, the prefix for your system name. | `string` | `"weka"` | no |
| [private\_dns\_rg\_name](#input\_private\_dns\_rg\_name) | The private DNS zone resource group name. Required when private\_dns\_zone\_name is set. | `string` | `""` | no |
| [private\_dns\_zone\_name](#input\_private\_dns\_zone\_name) | The private DNS zone name. | `string` | `""` | no |
+| [private\_dns\_zone\_use](#input\_private\_dns\_zone\_use) | Determines whether to use private DNS zone. Required for LB dns name. | `bool` | `true` | no |
| [rg\_name](#input\_rg\_name) | A predefined resource group in the Azure subscription. | `string` | n/a | yes |
| [sg\_id](#input\_sg\_id) | The security group id. | `string` | `""` | no |
| [subnet\_name](#input\_subnet\_name) | Subnet name, if exist. | `string` | `""` | no |
diff --git a/modules/network/main.tf b/modules/network/main.tf
index 167009fd..1e5548ea 100644
--- a/modules/network/main.tf
+++ b/modules/network/main.tf
@@ -142,7 +142,7 @@ resource "azurerm_subnet_network_security_group_association" "sg_association" {
# ================== Private DNS ========================= #
resource "azurerm_private_dns_zone" "dns" {
- count = var.private_dns_zone_name == "" ? 1 : 0
+ count = var.private_dns_zone_name == "" && var.private_dns_zone_use ? 1 : 0
name = "${var.prefix}.private.net"
resource_group_name = local.private_dns_rg_name
tags = merge(var.tags_map)
@@ -152,7 +152,7 @@ resource "azurerm_private_dns_zone" "dns" {
}
resource "azurerm_private_dns_zone_virtual_network_link" "dns_vnet_link" {
- count = var.private_dns_zone_name == "" ? 1 : 0
+ count = var.private_dns_zone_name == "" && var.private_dns_zone_use ? 1 : 0
name = "${var.prefix}-private-network-link"
resource_group_name = data.azurerm_resource_group.rg.name
private_dns_zone_name = azurerm_private_dns_zone.dns[0].name
diff --git a/modules/network/outputs.tf b/modules/network/outputs.tf
index 3263ba16..3792121f 100644
--- a/modules/network/outputs.tf
+++ b/modules/network/outputs.tf
@@ -14,7 +14,7 @@ output "sg_id" {
}
output "private_dns_zone_name" {
- value = var.private_dns_zone_name == "" ? azurerm_private_dns_zone.dns[0].name : var.private_dns_zone_name
+ value = var.private_dns_zone_use ? var.private_dns_zone_name == "" ? azurerm_private_dns_zone.dns[0].name : var.private_dns_zone_name : null
description = "Displays the private DNS zone name."
}
diff --git a/modules/network/variables.tf b/modules/network/variables.tf
index 70d39ae0..63b1034f 100644
--- a/modules/network/variables.tf
+++ b/modules/network/variables.tf
@@ -69,6 +69,12 @@ variable "private_dns_zone_name" {
default = ""
}
+variable "private_dns_zone_use" {
+ type = bool
+ description = "Determines whether to use private DNS zone. Required for LB dns name."
+ default = true
+}
+
variable "sg_id" {
type = string
description = "The security group id."
diff --git a/modules/network/versions.tf b/modules/network/versions.tf
index 281dc878..202d92cc 100644
--- a/modules/network/versions.tf
+++ b/modules/network/versions.tf
@@ -3,7 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
+ version = "~>3.114.0"
}
}
}
diff --git a/modules/peering_vnets/README.md b/modules/peering_vnets/README.md
index b9aaec7f..46a4d696 100644
--- a/modules/peering_vnets/README.md
+++ b/modules/peering_vnets/README.md
@@ -42,13 +42,13 @@ No outputs.
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
## Providers
| Name | Version |
|------|---------|
-| [azurerm](#provider\_azurerm) | ~>3.75.0 |
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
## Modules
diff --git a/modules/peering_vnets/versions.tf b/modules/peering_vnets/versions.tf
index 281dc878..202d92cc 100644
--- a/modules/peering_vnets/versions.tf
+++ b/modules/peering_vnets/versions.tf
@@ -3,7 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
+ version = "~>3.114.0"
}
}
}
diff --git a/modules/protocol_gateways/README.md b/modules/protocol_gateways/README.md
index 2da41a71..6ff1bc04 100644
--- a/modules/protocol_gateways/README.md
+++ b/modules/protocol_gateways/README.md
@@ -4,13 +4,13 @@
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.4.6 |
-| [azurerm](#requirement\_azurerm) | ~>3.75.0 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
## Providers
| Name | Version |
|------|---------|
-| [azurerm](#provider\_azurerm) | ~>3.75.0 |
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
## Modules
diff --git a/modules/protocol_gateways/main.tf b/modules/protocol_gateways/main.tf
index ba3bc402..faa4c4d5 100644
--- a/modules/protocol_gateways/main.tf
+++ b/modules/protocol_gateways/main.tf
@@ -19,11 +19,11 @@ resource "azurerm_public_ip" "this" {
}
resource "azurerm_network_interface" "primary_gateway_nic_public" {
- count = var.assign_public_ip && var.protocol != "NFS" ? var.gateways_number : 0
- name = "${var.gateways_name}-primary-nic-${count.index}"
- location = var.location
- resource_group_name = var.rg_name
- enable_accelerated_networking = true
+ count = var.assign_public_ip && var.protocol != "NFS" ? var.gateways_number : 0
+ name = "${var.gateways_name}-primary-nic-${count.index}"
+ location = var.location
+ resource_group_name = var.rg_name
+ accelerated_networking_enabled = true
ip_configuration {
primary = true
@@ -51,11 +51,11 @@ resource "azurerm_network_interface_security_group_association" "primary_gateway
}
resource "azurerm_network_interface" "primary_gateway_nic_private" {
- count = var.assign_public_ip || var.protocol == "NFS" ? 0 : var.gateways_number
- name = "${var.gateways_name}-primary-nic-${count.index}"
- location = var.location
- resource_group_name = var.rg_name
- enable_accelerated_networking = true
+ count = var.assign_public_ip || var.protocol == "NFS" ? 0 : var.gateways_number
+ name = "${var.gateways_name}-primary-nic-${count.index}"
+ location = var.location
+ resource_group_name = var.rg_name
+ accelerated_networking_enabled = true
ip_configuration {
primary = true
@@ -86,11 +86,11 @@ locals {
}
resource "azurerm_network_interface" "secondary_gateway_nic" {
- count = var.protocol != "NFS" ? local.secondary_nics_num : 0
- name = "${var.gateways_name}-secondary-nic-${count.index + var.gateways_number}"
- location = var.location
- resource_group_name = var.rg_name
- enable_accelerated_networking = true
+ count = var.protocol != "NFS" ? local.secondary_nics_num : 0
+ name = "${var.gateways_name}-secondary-nic-${count.index + var.gateways_number}"
+ location = var.location
+ resource_group_name = var.rg_name
+ accelerated_networking_enabled = true
ip_configuration {
primary = true
@@ -115,7 +115,7 @@ locals {
init_script = templatefile("${path.module}/init.sh", {
apt_repo_server = var.apt_repo_server
nics_num = local.nics_numbers
- subnet_range = data.azurerm_subnet.subnet.address_prefix
+ subnet_range = data.azurerm_subnet.subnet.address_prefixes[0]
disk_size = local.disk_size
deploy_url = var.deploy_function_url
report_url = var.report_function_url
diff --git a/modules/protocol_gateways/versions.tf b/modules/protocol_gateways/versions.tf
index 281dc878..202d92cc 100644
--- a/modules/protocol_gateways/versions.tf
+++ b/modules/protocol_gateways/versions.tf
@@ -3,7 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
+ version = "~>3.114.0"
}
}
}
diff --git a/modules/subnet_delegation/README.md b/modules/subnet_delegation/README.md
new file mode 100644
index 00000000..92b58038
--- /dev/null
+++ b/modules/subnet_delegation/README.md
@@ -0,0 +1,43 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.4.6 |
+| [azurerm](#requirement\_azurerm) | ~>3.114.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | ~>3.114.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_subnet.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [cidr\_range](#input\_cidr\_range) | The address space that is used by the subnet. | `string` | n/a | yes |
+| [cluster\_name](#input\_cluster\_name) | Cluster name | `string` | n/a | yes |
+| [delegation\_name](#input\_delegation\_name) | The name of the subnet delegation. | `string` | `"subnet-delegation"` | no |
+| [prefix](#input\_prefix) | Prefix for all resources | `string` | n/a | yes |
+| [rg\_name](#input\_rg\_name) | A predefined resource group in the Azure subscription. | `string` | n/a | yes |
+| [service\_endpoints](#input\_service\_endpoints) | The list of service endpoints. | `list(string)` | [
"Microsoft.Storage",
"Microsoft.KeyVault",
"Microsoft.Web"
]
| no |
+| [vnet\_name](#input\_vnet\_name) | The name of the virtual network. | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [id](#output\_id) | n/a |
+| [name](#output\_name) | n/a |
+
diff --git a/modules/subnet_delegation/main.tf b/modules/subnet_delegation/main.tf
new file mode 100644
index 00000000..8018c542
--- /dev/null
+++ b/modules/subnet_delegation/main.tf
@@ -0,0 +1,14 @@
+resource "azurerm_subnet" "this" {
+ name = "${var.prefix}-${var.cluster_name}-${var.delegation_name}"
+ resource_group_name = var.rg_name
+ virtual_network_name = var.vnet_name
+ address_prefixes = [var.cidr_range]
+ service_endpoints = var.service_endpoints
+ delegation {
+ name = var.delegation_name
+ service_delegation {
+ name = "Microsoft.Web/serverFarms"
+ actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
+ }
+ }
+}
diff --git a/modules/subnet_delegation/outputs.tf b/modules/subnet_delegation/outputs.tf
new file mode 100644
index 00000000..a4468d1b
--- /dev/null
+++ b/modules/subnet_delegation/outputs.tf
@@ -0,0 +1,7 @@
+output "name" {
+ value = azurerm_subnet.this.name
+}
+
+output "id" {
+ value = azurerm_subnet.this.id
+}
diff --git a/modules/subnet_delegation/variables.tf b/modules/subnet_delegation/variables.tf
new file mode 100644
index 00000000..4e0cbc34
--- /dev/null
+++ b/modules/subnet_delegation/variables.tf
@@ -0,0 +1,36 @@
+variable "prefix" {
+ type = string
+ description = "Prefix for all resources"
+}
+
+variable "cluster_name" {
+ type = string
+ description = "Cluster name"
+}
+
+variable "rg_name" {
+ type = string
+ description = "A predefined resource group in the Azure subscription."
+}
+
+variable "vnet_name" {
+ type = string
+ description = "The name of the virtual network."
+}
+
+variable "cidr_range" {
+ type = string
+ description = "The address space that is used by the subnet."
+}
+
+variable "delegation_name" {
+ type = string
+ description = "The name of the subnet delegation."
+ default = "subnet-delegation"
+}
+
+variable "service_endpoints" {
+ type = list(string)
+ description = "The list of service endpoints."
+ default = ["Microsoft.Storage", "Microsoft.KeyVault", "Microsoft.Web"]
+}
diff --git a/modules/subnet_delegation/versions.tf b/modules/subnet_delegation/versions.tf
new file mode 100644
index 00000000..202d92cc
--- /dev/null
+++ b/modules/subnet_delegation/versions.tf
@@ -0,0 +1,9 @@
+terraform {
+ required_version = ">= 1.4.6"
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "~>3.114.0"
+ }
+ }
+}
diff --git a/outputs.tf b/outputs.tf
index deb022f5..ee767d48 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -1,7 +1,9 @@
locals {
vmss_name = "${var.prefix}-${var.cluster_name}-vmss"
+ clients_vmss_name = var.clients_number > 0 && var.clients_use_vmss ? module.clients[0].vmss_name : ""
key_vault_name = azurerm_key_vault.key_vault.name
vm_ips = local.assign_public_ip ? "az vmss list-instance-public-ips -g ${var.rg_name} --name ${local.vmss_name} --subscription ${var.subscription_id} --query \"[].ipAddress\" \n" : "az vmss nic list -g ${var.rg_name} --vmss-name ${local.vmss_name} --subscription ${var.subscription_id} --query \"[].ipConfigurations[]\" | jq -r '.[] | select(.name==\"ipconfig0\")'.privateIPAddress \n"
+ clients_vmss_ips = local.assign_public_ip ? "az vmss list-instance-public-ips -g ${var.rg_name} --name ${local.clients_vmss_name} --subscription ${var.subscription_id} --query \"[].ipAddress\" \n" : "az vmss nic list -g ${var.rg_name} --vmss-name ${local.clients_vmss_name} --subscription ${var.subscription_id} --query \"[].ipConfigurations[]\" | jq -r '.[] | select(.name==\"ipconfig0\")'.privateIPAddress \n"
ssh_keys_commands = "########################################## Download ssh keys command from blob ###########################################################\n az keyvault secret download --file private.pem --encoding utf-8 --vault-name ${local.key_vault_name} --name private-key --query \"value\" \n az keyvault secret download --file public.pub --encoding utf-8 --vault-name ${local.key_vault_name} --name public-key --query \"value\"\n"
blob_commands = var.ssh_public_key == null ? local.ssh_keys_commands : ""
private_ssh_key_path = var.ssh_public_key == null ? local.ssh_private_key_path : null
@@ -36,7 +38,6 @@ output "vmss_name" {
value = local.vmss_name
}
-
output "function_app_name" {
value = local.function_app_name
description = "Function app name"
@@ -57,8 +58,21 @@ output "backend_ips" {
description = "If 'assign_public_ip' is set to true, it will output the public ips, If no it will output the private ips"
}
+output "clients_vmss_name" {
+ value = local.clients_vmss_name != "" ? local.clients_vmss_name : null
+}
+
output "client_ips" {
- value = var.clients_number > 0 ? module.clients[0].client_ips : null
+ value = (
+ var.clients_number > 0 && !var.clients_use_vmss ? module.clients[0].client_ips :
+ var.clients_number > 0 && var.clients_use_vmss ? local.clients_vmss_ips :
+ null
+ )
+ description = "If 'private_network' is set to false, it will output clients public ips, otherwise private ips."
+}
+
+output "client_vmss_ips" {
+ value = var.clients_number > 0 && var.clients_use_vmss ? local.clients_vmss_ips : null
description = "If 'private_network' is set to false, it will output clients public ips, otherwise private ips."
}
@@ -112,6 +126,25 @@ output "ppg_id" {
description = "Placement proximity group id"
}
+output "weka_cluster_admin_password_secret_name" {
+ value = azurerm_key_vault_secret.weka_password_secret.name
+ description = "Weka cluster admin password secret name"
+}
+
+
+locals {
+ resize_helper_command = !local.create_logic_app ? "" : < --resource-group ${var.rg_name} --force-deletion true --subscription ${var.subscription_id}
EOT
description = "Useful commands and script to interact with weka cluster"
diff --git a/prerequisites.tf b/prerequisites.tf
index e460ac1e..e72d2777 100644
--- a/prerequisites.tf
+++ b/prerequisites.tf
@@ -15,6 +15,7 @@ module "network" {
allow_ssh_cidrs = var.allow_ssh_cidrs
allow_weka_api_cidrs = var.allow_weka_api_cidrs
private_dns_zone_name = var.private_dns_zone_name
+ private_dns_zone_use = var.private_dns_zone_use
sg_id = var.sg_id
create_nat_gateway = var.create_nat_gateway
}
@@ -24,10 +25,15 @@ module "iam" {
rg_name = var.rg_name
prefix = var.prefix
cluster_name = var.cluster_name
+ vnet_rg_name = local.vnet_rg_name
+ vnet_name = local.vnet_name
+ subnet_name = local.subnet_name
+ sg_id = var.sg_id
vmss_identity_name = var.vmss_identity_name
function_app_identity_name = var.function_app_identity_name
+ support_logic_app = local.create_logic_app
logic_app_identity_name = var.logic_app_identity_name
- logic_app_storage_account_id = azurerm_storage_account.logicapp.id
+ logic_app_storage_account_id = local.create_logic_app ? azurerm_storage_account.logicapp[0].id : ""
key_vault_id = azurerm_key_vault.key_vault.id
weka_tar_storage_account_id = var.weka_tar_storage_account_id
deployment_storage_account_id = local.deployment_storage_account_id
@@ -37,9 +43,12 @@ module "iam" {
tiering_enable_obs_integration = var.tiering_enable_obs_integration
tiering_obs_name = var.tiering_obs_name
obs_container_name = local.obs_container_name
+ obs_create_private_endpoint = var.create_storage_account_private_links && local.sa_public_access_disabled
+ depends_on = [module.network]
}
locals {
+ create_logic_app = local.create_sa_resources
vnet_name = var.vnet_name == "" ? module.network.vnet_name : var.vnet_name
vnet_rg_name = var.vnet_rg_name == "" ? module.network.vnet_rg_name : var.vnet_rg_name
subnet_name = var.subnet_name == "" ? module.network.subnet_name : var.subnet_name
@@ -65,6 +74,55 @@ module "peering" {
depends_on = [module.network]
}
+module "logic_app_subnet_delegation" {
+ count = var.logic_app_subnet_delegation_id == "" && local.create_logic_app ? 1 : 0
+ source = "./modules/subnet_delegation"
+ rg_name = local.vnet_rg_name
+ vnet_name = local.vnet_name
+ prefix = var.prefix
+ cluster_name = var.cluster_name
+ cidr_range = var.logic_app_subnet_delegation_cidr
+ delegation_name = "logic-app-delegation"
+
+ depends_on = [module.network]
+}
+
+module "function_app_subnet_delegation" {
+ count = var.function_app_subnet_delegation_id == "" ? 1 : 0
+ source = "./modules/subnet_delegation"
+ rg_name = local.vnet_rg_name
+ vnet_name = local.vnet_name
+ prefix = var.prefix
+ cluster_name = var.cluster_name
+ cidr_range = var.function_app_subnet_delegation_cidr
+ delegation_name = "function-app-delegation"
+
+ depends_on = [module.network]
+}
+
+module "logicapp" {
+ count = local.create_logic_app ? 1 : 0
+ source = "./modules/logic_app"
+ rg_name = var.rg_name
+ location = local.location
+ prefix = var.prefix
+ cluster_name = var.cluster_name
+ logic_app_subnet_delegation_id = var.logic_app_subnet_delegation_id == "" ? module.logic_app_subnet_delegation[0].id : var.logic_app_subnet_delegation_id
+ storage_account_name = azurerm_storage_account.logicapp[0].name
+ logic_app_identity_id = local.logic_app_identity_id
+ logic_app_identity_principal = local.logic_app_identity_principal
+ restricted_inbound_access = var.function_access_restriction_enabled
+ subnet_id = data.azurerm_subnet.subnet.id
+ function_app_id = azurerm_linux_function_app.function_app.id
+ function_app_name = azurerm_linux_function_app.function_app.name
+ function_app_key = data.azurerm_function_app_host_keys.function_keys.default_function_key
+ key_vault_id = azurerm_key_vault.key_vault.id
+ key_vault_uri = azurerm_key_vault.key_vault.vault_uri
+ use_secured_storage_account = local.sa_public_access_enabled ? false : true
+
+ depends_on = [azurerm_storage_account.logicapp, module.logic_app_subnet_delegation, module.iam]
+}
+
data "azurerm_subnet" "subnet" {
resource_group_name = local.vnet_rg_name
virtual_network_name = local.vnet_name
diff --git a/user-data.sh b/user-data.sh
deleted file mode 100644
index c2aa50c6..00000000
--- a/user-data.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-set -ex
-
-${user_data}
-
-${init_script}
diff --git a/utils/apt-repo/main.tf b/utils/apt-repo/main.tf
index 9efce0fb..54de1e31 100644
--- a/utils/apt-repo/main.tf
+++ b/utils/apt-repo/main.tf
@@ -105,10 +105,10 @@ resource "azurerm_virtual_machine" "apt_repo_vm_linux" {
}
resource "azurerm_network_interface" "vm_interface" {
- name = "${var.prefix}-vm-nic"
- location = azurerm_resource_group.rg.location
- resource_group_name = azurerm_resource_group.rg.name
- enable_accelerated_networking = false
+ name = "${var.prefix}-vm-nic"
+ location = azurerm_resource_group.rg.location
+ resource_group_name = azurerm_resource_group.rg.name
+ accelerated_networking_enabled = false
ip_configuration {
name = "ipconfig"
diff --git a/variables.tf b/variables.tf
index 9c1b2093..1e4737ed 100644
--- a/variables.tf
+++ b/variables.tf
@@ -195,6 +195,12 @@ variable "private_dns_rg_name" {
default = ""
}
+variable "private_dns_zone_use" {
+ type = bool
+ description = "Determines whether to use private DNS zone. Required for LB record creation."
+ default = true
+}
+
variable "vnets_to_peer_to_deployment_vnet" {
type = list(object({
vnet = string
@@ -387,13 +393,13 @@ variable "function_app_storage_account_container_prefix" {
variable "function_app_version" {
type = string
description = "Function app code version (hash)"
- default = "5464597f9be93b3c954324b1811ace7a"
+ default = "70129b9f8d813e6f87aeed9be4764327"
}
variable "function_app_dist" {
type = string
description = "Function app code dist"
- default = "release"
+ default = "dev"
validation {
condition = contains(["dev", "release"], var.function_app_dist)
@@ -552,6 +558,12 @@ variable "clients_custom_data" {
default = ""
}
+variable "clients_use_vmss" {
+ type = bool
+ default = false
+ description = "Use VMSS for clients"
+}
+
variable "placement_group_id" {
type = string
default = ""
@@ -576,10 +588,15 @@ variable "deployment_container_name" {
description = "Name of exising deployment container"
}
-variable "deployment_storage_account_access_key" {
+variable "deployment_file_share_name" {
type = string
- description = "The access key of the existing Blob object store container."
- sensitive = true
+ default = ""
+ description = "Name of exising deployment file share. Will use '-share' name if not provided."
+}
+
+variable "deployment_function_app_code_blob" {
+ type = string
+ description = "The path to the function app code blob file."
default = ""
}
@@ -643,12 +660,6 @@ variable "nfs_setup_protocol" {
default = false
}
-variable "nfs_client_group_name" {
- type = string
- description = "Client access group name."
- default = "weka-cg"
-}
-
variable "nfs_interface_group_name" {
type = string
description = "Interface group name."
@@ -828,3 +839,44 @@ variable "debug_down_backends_removal_timeout" {
default = "3h"
description = "Don't change this value without consulting weka support team. Timeout for removing down backends. Valid time units are ns, us (or µs), ms, s, m, h."
}
+
+variable "storage_account_public_network_access" {
+ type = string
+ description = "Public network access to the storage accounts."
+ default = "Enabled"
+
+ validation {
+ condition = contains(["Enabled", "Disabled", "EnabledForVnet"], var.storage_account_public_network_access)
+ error_message = "Allowed values: [\"Enabled\", \"Disabled\", \"EnabledForVnet\"]."
+ }
+}
+
+variable "storage_account_allowed_ips" {
+ type = list(string)
+ description = "IP ranges to allow access from the internet or your on-premises networks to storage accounts."
+ default = []
+}
+
+variable "create_storage_account_private_links" {
+ type = bool
+ default = false
+ description = "Create private links for storage accounts (needed in case if public network access for the storage account is disabled)."
+}
+
+variable "storage_blob_private_dns_zone_name" {
+ type = string
+ description = "The private DNS zone name for the storage account (blob)."
+ default = "privatelink.blob.core.windows.net"
+}
+
+variable "read_function_zip_from_storage_account" {
+ type = bool
+ default = false
+ description = "Read function app zip from storage account (is read from public distribution storage account by default)."
+}
+
+variable "key_vault_purge_protection_enabled" {
+ type = bool
+ default = false
+ description = "Enable purge protection for the key vault."
+}
diff --git a/versions.tf b/versions.tf
index 4e25ecb8..e5dc6e28 100644
--- a/versions.tf
+++ b/versions.tf
@@ -3,11 +3,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "~>3.75.0"
- }
- random = {
- source = "hashicorp/random"
- version = "~>3.5.1"
+ version = "~>3.114.0"
}
tls = {
source = "hashicorp/tls"
diff --git a/zip_function_app_creation/write_function_hash_to_variables.sh b/zip_function_app_creation/write_function_hash_to_variables.sh
index 52fbb0e4..efd9e911 100755
--- a/zip_function_app_creation/write_function_hash_to_variables.sh
+++ b/zip_function_app_creation/write_function_hash_to_variables.sh
@@ -12,6 +12,8 @@ old_function_app_zip_version=$(awk '/Function app code version/{getline;print $N
echo "Replacing '$old_function_app_zip_version' function_app_version to '$new_function_app_zip_version'"
if [ $os_name == "darwin" ]; then
sed -i '' "s/$old_function_app_zip_version/$new_function_app_zip_version/" variables.tf
+ sed -i '' "s/$old_function_app_zip_version/$new_function_app_zip_version/" README.md
else
sed -i "s/$old_function_app_zip_version/$new_function_app_zip_version/" variables.tf
+ sed -i "s/$old_function_app_zip_version/$new_function_app_zip_version/" README.md
fi