diff --git a/azurerm/internal/services/kusto/kusto_cluster_resource.go b/azurerm/internal/services/kusto/kusto_cluster_resource.go index db50517de0a60..ebeee85f4f8ab 100644 --- a/azurerm/internal/services/kusto/kusto_cluster_resource.go +++ b/azurerm/internal/services/kusto/kusto_cluster_resource.go @@ -110,6 +110,31 @@ func resourceArmKustoCluster() *schema.Resource { Optional: true, }, + "virtual_network_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + "engine_public_ip_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + "data_management_public_ip_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + }, + }, + }, + "uri": { Type: schema.TypeString, Computed: true, @@ -161,6 +186,11 @@ func resourceArmKustoClusterCreateUpdate(d *schema.ResourceData, meta interface{ EnablePurge: utils.Bool(d.Get("enable_purge").(bool)), } + if v, ok := d.GetOk("virtual_network_configuration"); ok { + vnet := expandKustoClusterVNET(v.([]interface{})) + clusterProperties.VirtualNetworkConfiguration = vnet + } + t := d.Get("tags").(map[string]interface{}) kustoCluster := kusto.Cluster{ @@ -239,6 +269,7 @@ func resourceArmKustoClusterRead(d *schema.ResourceData, meta interface{}) error d.Set("enable_disk_encryption", clusterProperties.EnableDiskEncryption) d.Set("enable_streaming_ingest", clusterProperties.EnableStreamingIngest) d.Set("enable_purge", clusterProperties.EnablePurge) + d.Set("virtual_network_configuration", flatteKustoClusterVNET(clusterProperties.VirtualNetworkConfiguration)) d.Set("uri", clusterProperties.URI) d.Set("data_ingestion_uri", clusterProperties.DataIngestionURI) } @@ -309,6 +340,23 @@ func expandKustoClusterSku(d *schema.ResourceData) (*kusto.AzureSku, error) { return azureSku, nil } +func expandKustoClusterVNET(input []interface{}) *kusto.VirtualNetworkConfiguration { + if len(input) == 0 || input[0] == nil { + return nil + } + + vnet := input[0].(map[string]interface{}) + subnetID := vnet["subnet_id"].(string) + enginePublicIPID := vnet["engine_public_ip_id"].(string) + dataManagementPublicIPID := vnet["data_management_public_ip_id"].(string) + + return &kusto.VirtualNetworkConfiguration{ + SubnetID: &subnetID, + EnginePublicIPID: &enginePublicIPID, + DataManagementPublicIPID: &dataManagementPublicIPID, + } +} + func flattenKustoClusterSku(sku *kusto.AzureSku) []interface{} { if sku == nil { return []interface{}{} @@ -324,3 +372,32 @@ func flattenKustoClusterSku(sku *kusto.AzureSku) []interface{} { return []interface{}{s} } + +func flatteKustoClusterVNET(vnet *kusto.VirtualNetworkConfiguration) []interface{} { + if vnet == nil { + return []interface{}{} + } + + subnetID := "" + if vnet.SubnetID != nil { + subnetID = *vnet.SubnetID + } + + enginePublicIPID := "" + if vnet.EnginePublicIPID != nil { + enginePublicIPID = *vnet.EnginePublicIPID + } + + dataManagementPublicIPID := "" + if vnet.DataManagementPublicIPID != nil { + dataManagementPublicIPID = *vnet.DataManagementPublicIPID + } + + output := map[string]interface{}{ + "subnet_id": subnetID, + "engine_public_ip_id": enginePublicIPID, + "data_management_public_ip_id": dataManagementPublicIPID, + } + + return []interface{}{output} +} diff --git a/azurerm/internal/services/kusto/tests/kusto_cluster_resource_test.go b/azurerm/internal/services/kusto/tests/kusto_cluster_resource_test.go index 3c6128c93e159..5413375cf756e 100644 --- a/azurerm/internal/services/kusto/tests/kusto_cluster_resource_test.go +++ b/azurerm/internal/services/kusto/tests/kusto_cluster_resource_test.go @@ -152,6 +152,29 @@ func TestAccAzureRMKustoCluster_identitySystemAssigned(t *testing.T) { }) } +func TestAccAzureRMKustoCluster_vnet(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kusto_cluster", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKustoClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKustoCluster_vnet(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKustoClusterExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "virtual_network_configuration.#", "1"), + resource.TestCheckResourceAttrSet(data.ResourceName, "virtual_network_configuration.0.subnet_id"), + resource.TestCheckResourceAttrSet(data.ResourceName, "virtual_network_configuration.0.engine_public_ip_id"), + resource.TestCheckResourceAttrSet(data.ResourceName, "virtual_network_configuration.0.data_management_public_ip_id"), + ), + }, + data.ImportStep(), + }, + }) +} + func testAccAzureRMKustoCluster_basic(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -339,6 +362,91 @@ func testCheckAzureRMKustoClusterDestroy(s *terraform.State) error { return nil } +func testAccAzureRMKustoCluster_vnet(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestkc%s-vnet" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "acctestkc%s-subnet" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] +} + +resource "azurerm_network_security_group" "test" { + name = "acctestkc%s-nsg" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_network_security_rule" "test_allow_management_inbound" { + name = "AllowAzureDataExplorerManagement" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "AzureDataExplorerManagement" + destination_address_prefix = "VirtualNetwork" + resource_group_name = azurerm_resource_group.test.name + network_security_group_name = azurerm_network_security_group.test.name +} + +resource "azurerm_subnet_network_security_group_association" "test" { + subnet_id = azurerm_subnet.test.id + network_security_group_id = azurerm_network_security_group.test.id +} + +resource "azurerm_public_ip" "engine_pip" { + name = "acctestkc%s-engine-pip" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" + allocation_method = "Static" +} + +resource "azurerm_public_ip" "management_pip" { + name = "acctestkc%s-management-pip" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Basic" + allocation_method = "Static" +} + +resource "azurerm_kusto_cluster" "test" { + name = "acctestkc%s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + name = "Dev(No SLA)_Standard_D11_v2" + capacity = 1 + } + + virtual_network_configuration { + subnet_id = azurerm_subnet.test.id + engine_public_ip_id = azurerm_public_ip.engine_pip.id + data_management_public_ip_id = azurerm_public_ip.management_pip.id + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString, data.RandomString, data.RandomString, data.RandomString, data.RandomString) +} + func testCheckAzureRMKustoClusterExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Kusto.ClustersClient diff --git a/website/docs/r/kusto_cluster.html.markdown b/website/docs/r/kusto_cluster.html.markdown index a73e9198c0890..ca9dd527db0ab 100644 --- a/website/docs/r/kusto_cluster.html.markdown +++ b/website/docs/r/kusto_cluster.html.markdown @@ -54,6 +54,8 @@ The following arguments are supported: * `enable_purge` - (Optional) Specifies if the purge operations are enabled. +* `virtual_network_configuration`- (Optional) A `virtual_network_configuration` block as defined below. + * `tags` - (Optional) A mapping of tags to assign to the resource. --- @@ -66,6 +68,16 @@ A `sku` block supports the following: --- +A `virtual_network_configuration` block supports the following: + +* `subnet_id` - (Required) The subnet resource id. + +* `engine_public_ip_id` - (Required) Engine service's public IP address resource id. + +* `data_management_public_ip_id` - (Required) Data management's service public IP address resource id. + +--- + An `identity` block supports the following: * `type` - (Required) Specifies the type of Managed Service Identity that is configured on this Kusto Cluster. Possible values are: `SystemAssigned` (where Azure will generate a Service Principal for you).