From a7c9fa6735fb053b69644bf3823c6eca3b0539e9 Mon Sep 17 00:00:00 2001 From: Jochen Rauschenbusch Date: Thu, 25 Jun 2020 10:11:07 +0200 Subject: [PATCH] Kusto Database Principal Assignment Support --- .../internal/services/kusto/client/client.go | 17 +- ..._database_principal_assignment_resource.go | 248 ++++++++++++++++++ .../kusto_database_principal_assignment.go | 43 +++ ...usto_database_principal_assignment_test.go | 68 +++++ .../internal/services/kusto/registration.go | 9 +- ...base_principal_assignment_resource_test.go | 145 ++++++++++ ...atabase_principal_assignment.html.markdown | 100 +++++++ 7 files changed, 620 insertions(+), 10 deletions(-) create mode 100644 azurerm/internal/services/kusto/kusto_database_principal_assignment_resource.go create mode 100644 azurerm/internal/services/kusto/parse/kusto_database_principal_assignment.go create mode 100644 azurerm/internal/services/kusto/parse/kusto_database_principal_assignment_test.go create mode 100644 azurerm/internal/services/kusto/tests/kusto_database_principal_assignment_resource_test.go create mode 100644 website/docs/r/kusto_database_principal_assignment.html.markdown diff --git a/azurerm/internal/services/kusto/client/client.go b/azurerm/internal/services/kusto/client/client.go index 7d48fb8ba1a26..82ddd24ed0d33 100644 --- a/azurerm/internal/services/kusto/client/client.go +++ b/azurerm/internal/services/kusto/client/client.go @@ -6,9 +6,10 @@ import ( ) type Client struct { - ClustersClient *kusto.ClustersClient - DatabasesClient *kusto.DatabasesClient - DataConnectionsClient *kusto.DataConnectionsClient + ClustersClient *kusto.ClustersClient + DatabasesClient *kusto.DatabasesClient + DataConnectionsClient *kusto.DataConnectionsClient + DatabasePrincipalAssignmentsClient *kusto.DatabasePrincipalAssignmentsClient } func NewClient(o *common.ClientOptions) *Client { @@ -21,9 +22,13 @@ func NewClient(o *common.ClientOptions) *Client { DataConnectionsClient := kusto.NewDataConnectionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&DataConnectionsClient.Client, o.ResourceManagerAuthorizer) + DatabasePrincipalAssignmentsClient := kusto.NewDatabasePrincipalAssignmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&DatabasePrincipalAssignmentsClient.Client, o.ResourceManagerAuthorizer) + return &Client{ - ClustersClient: &ClustersClient, - DatabasesClient: &DatabasesClient, - DataConnectionsClient: &DataConnectionsClient, + ClustersClient: &ClustersClient, + DatabasesClient: &DatabasesClient, + DataConnectionsClient: &DataConnectionsClient, + DatabasePrincipalAssignmentsClient: &DatabasePrincipalAssignmentsClient, } } diff --git a/azurerm/internal/services/kusto/kusto_database_principal_assignment_resource.go b/azurerm/internal/services/kusto/kusto_database_principal_assignment_resource.go new file mode 100644 index 0000000000000..9af45dca09014 --- /dev/null +++ b/azurerm/internal/services/kusto/kusto_database_principal_assignment_resource.go @@ -0,0 +1,248 @@ +package kusto + +import ( + "fmt" + "log" + "regexp" + "time" + + "github.com/Azure/azure-sdk-for-go/services/kusto/mgmt/2020-02-15/kusto" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/kusto/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmKustoDatabasePrincipalAssignment() *schema.Resource { + return &schema.Resource{ + Create: resourceArmKustoDatabasePrincipalAssignmentCreateUpdate, + Read: resourceArmKustoDatabasePrincipalAssignmentRead, + Delete: resourceArmKustoDatabasePrincipalAssignmentDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "resource_group_name": azure.SchemaResourceGroupName(), + + "cluster_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateAzureRMKustoClusterName, + }, + + "database_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateAzureRMKustoDatabaseName, + }, + + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateAzureRMKustoDatabasePrincipalAssignmentName, + }, + + "tenant_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "tenant_name": { + Type: schema.TypeString, + Computed: true, + }, + + "principal_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "principal_name": { + Type: schema.TypeString, + Computed: true, + }, + + "principal_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(kusto.PrincipalTypeApp), + string(kusto.PrincipalTypeGroup), + string(kusto.PrincipalTypeUser), + }, false), + }, + + "role": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(kusto.Admin), + string(kusto.Ingestor), + string(kusto.Monitor), + string(kusto.User), + string(kusto.UnrestrictedViewers), + string(kusto.Viewer), + }, false), + }, + }, + } +} + +func resourceArmKustoDatabasePrincipalAssignmentCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Kusto.DatabasePrincipalAssignmentsClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for Azure Kusto Database Principal Assignment creation.") + + resourceGroup := d.Get("resource_group_name").(string) + clusterName := d.Get("cluster_name").(string) + databaseName := d.Get("database_name").(string) + name := d.Get("name").(string) + + if d.IsNewResource() { + principalAssignment, err := client.Get(ctx, resourceGroup, clusterName, databaseName, name) + if err != nil { + if !utils.ResponseWasNotFound(principalAssignment.Response) { + return fmt.Errorf("Error checking for presence of existing Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q): %+v", name, resourceGroup, clusterName, databaseName, err) + } + } + + if principalAssignment.ID != nil && *principalAssignment.ID != "" { + return tf.ImportAsExistsError("azurerm_kusto_database_principal_assignment", *principalAssignment.ID) + } + } + + tenantID := d.Get("tenant_id").(string) + principalID := d.Get("principal_id").(string) + principalType := d.Get("principal_type").(string) + role := d.Get("role").(string) + + props := kusto.DatabasePrincipalProperties{ + TenantID: utils.String(tenantID), + PrincipalID: utils.String(principalID), + PrincipalType: kusto.PrincipalType(principalType), + Role: kusto.DatabasePrincipalRole(role), + } + + principalAssignment := kusto.DatabasePrincipalAssignment{ + DatabasePrincipalProperties: &props, + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, clusterName, databaseName, name, principalAssignment) + if err != nil { + return fmt.Errorf("Error creating or updating Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q): %+v", name, resourceGroup, clusterName, databaseName, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for completion of Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q): %+v", name, resourceGroup, clusterName, databaseName, err) + } + + resp, err := client.Get(ctx, resourceGroup, clusterName, databaseName, name) + if err != nil { + return fmt.Errorf("Error retrieving Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q): %+v", name, resourceGroup, clusterName, databaseName, err) + } + + if resp.ID == nil { + return fmt.Errorf("Cannot read ID for Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q)", name, resourceGroup, clusterName, databaseName) + } + + d.SetId(*resp.ID) + + return resourceArmKustoDatabasePrincipalAssignmentRead(d, meta) +} + +func resourceArmKustoDatabasePrincipalAssignmentRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Kusto.DatabasePrincipalAssignmentsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.KustoDatabasePrincipalAssignmentID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.Cluster, id.Database, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q): %+v", id.Name, id.ResourceGroup, id.Cluster, id.Database, err) + } + + d.Set("resource_group_name", id.ResourceGroup) + d.Set("cluster_name", id.Cluster) + d.Set("database_name", id.Database) + d.Set("name", id.Name) + d.Set("tenant_id", *resp.TenantID) + d.Set("tenant_name", *resp.TenantName) + d.Set("principal_id", *resp.PrincipalID) + d.Set("principal_name", *resp.PrincipalName) + d.Set("principal_type", string(resp.PrincipalType)) + d.Set("role", string(resp.Role)) + + return nil +} + +func resourceArmKustoDatabasePrincipalAssignmentDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Kusto.DatabasePrincipalAssignmentsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.KustoDatabasePrincipalAssignmentID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.Cluster, id.Database, id.Name) + if err != nil { + return fmt.Errorf("Error deleting Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q): %+v", id.Name, id.ResourceGroup, id.Cluster, id.Database, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for deletion of Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q): %+v", id.Name, id.ResourceGroup, id.Cluster, id.Database, err) + } + + return nil +} + +func validateAzureRMKustoDatabasePrincipalAssignmentName(v interface{}, k string) (warnings []string, errors []error) { + name := v.(string) + + if regexp.MustCompile(`^[\s]+$`).MatchString(name) { + errors = append(errors, fmt.Errorf("%q must not consist of whitespaces only", k)) + } + + if !regexp.MustCompile(`^[a-zA-Z0-9\s.-]+$`).MatchString(name) { + errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters, whitespaces, dashes and dots: %q", k, name)) + } + + if len(name) > 260 { + errors = append(errors, fmt.Errorf("%q must be (inclusive) between 4 and 22 characters long but is %d", k, len(name))) + } + + return warnings, errors +} diff --git a/azurerm/internal/services/kusto/parse/kusto_database_principal_assignment.go b/azurerm/internal/services/kusto/parse/kusto_database_principal_assignment.go new file mode 100644 index 0000000000000..a3d063a3c11e2 --- /dev/null +++ b/azurerm/internal/services/kusto/parse/kusto_database_principal_assignment.go @@ -0,0 +1,43 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type KustoDatabasePrincipalAssignmentId struct { + ResourceGroup string + Cluster string + Database string + Name string +} + +func KustoDatabasePrincipalAssignmentID(input string) (*KustoDatabasePrincipalAssignmentId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse Kusto Database Principal ID %q: %+v", input, err) + } + + principal := KustoDatabasePrincipalAssignmentId{ + ResourceGroup: id.ResourceGroup, + } + + if principal.Cluster, err = id.PopSegment("Clusters"); err != nil { + return nil, err + } + + if principal.Database, err = id.PopSegment("Databases"); err != nil { + return nil, err + } + + if principal.Name, err = id.PopSegment("PrincipalAssignments"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &principal, nil +} diff --git a/azurerm/internal/services/kusto/parse/kusto_database_principal_assignment_test.go b/azurerm/internal/services/kusto/parse/kusto_database_principal_assignment_test.go new file mode 100644 index 0000000000000..85b3589986d27 --- /dev/null +++ b/azurerm/internal/services/kusto/parse/kusto_database_principal_assignment_test.go @@ -0,0 +1,68 @@ +package parse + +import ( + "testing" +) + +func TestKustoDatabasePrincipalAssignmentId(t *testing.T) { + testData := []struct { + Name string + Input string + Expected *KustoDatabasePrincipalAssignmentId + }{ + { + Name: "Empty", + Input: "", + Expected: nil, + }, + { + Name: "Missing Cluster", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Kusto/Databases/database1/PrincipalAssignments/assignment1", + Expected: nil, + }, + { + Name: "Missing Database", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Kusto/Clusters/cluster1/PrincipalAssignments/assignment1", + Expected: nil, + }, + { + Name: "Database Principal Assignment ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Kusto/Clusters/cluster1/Databases/database1/PrincipalAssignments/assignment1", + Expected: &KustoDatabasePrincipalAssignmentId{ + Name: "assignment1", + Database: "database1", + Cluster: "cluster1", + ResourceGroup: "group1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := KustoDatabasePrincipalAssignmentID(v.Input) + if err != nil { + if v.Expected == nil { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + + if actual.Database != v.Expected.Database { + t.Fatalf("Expected %q but got %q for Database", v.Expected.Database, actual.Database) + } + + if actual.Cluster != v.Expected.Cluster { + t.Fatalf("Expected %q but got %q for Cluster", v.Expected.Cluster, actual.Cluster) + } + + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for Resource Group", v.Expected.ResourceGroup, actual.ResourceGroup) + } + } +} diff --git a/azurerm/internal/services/kusto/registration.go b/azurerm/internal/services/kusto/registration.go index 6a0414cffb4ef..318ba73b49e52 100644 --- a/azurerm/internal/services/kusto/registration.go +++ b/azurerm/internal/services/kusto/registration.go @@ -28,9 +28,10 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_kusto_cluster": resourceArmKustoCluster(), - "azurerm_kusto_database": resourceArmKustoDatabase(), - "azurerm_kusto_database_principal": resourceArmKustoDatabasePrincipal(), - "azurerm_kusto_eventhub_data_connection": resourceArmKustoEventHubDataConnection(), + "azurerm_kusto_cluster": resourceArmKustoCluster(), + "azurerm_kusto_database": resourceArmKustoDatabase(), + "azurerm_kusto_database_principal": resourceArmKustoDatabasePrincipal(), + "azurerm_kusto_database_principal_assignment": resourceArmKustoDatabasePrincipalAssignment(), + "azurerm_kusto_eventhub_data_connection": resourceArmKustoEventHubDataConnection(), } } diff --git a/azurerm/internal/services/kusto/tests/kusto_database_principal_assignment_resource_test.go b/azurerm/internal/services/kusto/tests/kusto_database_principal_assignment_resource_test.go new file mode 100644 index 0000000000000..534017e1897c5 --- /dev/null +++ b/azurerm/internal/services/kusto/tests/kusto_database_principal_assignment_resource_test.go @@ -0,0 +1,145 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMKustoDatabasePrincipalAssignment_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kusto_database_principal_assignment", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKustoDatabasePrincipalAssignmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKustoDatabasePrincipalAssignment_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKustoDatabasePrincipalAssignmentExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func testCheckAzureRMKustoDatabasePrincipalAssignmentDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Kusto.DatabasePrincipalAssignmentsClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_kusto_database_principal_assignment" { + continue + } + + resourceGroup := rs.Primary.Attributes["resource_group_name"] + clusterName := rs.Primary.Attributes["cluster_name"] + databaseName := rs.Primary.Attributes["database_name"] + name := rs.Primary.Attributes["name"] + + resp, err := client.Get(ctx, resourceGroup, clusterName, databaseName, name) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + return err + } + + return nil + } + + return nil +} + +func testCheckAzureRMKustoDatabasePrincipalAssignmentExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Kusto.DatabasePrincipalAssignmentsClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for Kusto Database Principal Assignment: %s", name) + } + + clusterName, hasClusterName := rs.Primary.Attributes["cluster_name"] + if !hasClusterName { + return fmt.Errorf("Bad: no cluster found in state for Kusto Database Principal Assignment: %s", name) + } + + databaseName, hasDatabaseName := rs.Primary.Attributes["database_name"] + if !hasDatabaseName { + return fmt.Errorf("Bad: no database found in state for Kusto Database Principal Assignment: %s", name) + } + + resp, err := client.Get(ctx, resourceGroup, clusterName, databaseName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q) does not exist", name, resourceGroup, clusterName, databaseName) + } + + return fmt.Errorf("Bad: Get on DatabasePrincipalAssignmentsClient: %+v", err) + } + + return nil + } +} + +func testAccAzureRMKustoDatabasePrincipalAssignment_basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "rg" { + name = "acctestRG-kusto-%d" + location = "%s" +} + +resource "azurerm_kusto_cluster" "test" { + name = "acctestkc%s" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + sku { + name = "Dev(No SLA)_Standard_D11_v2" + capacity = 1 + } +} + +resource "azurerm_kusto_database" "test" { + name = "acctestkd-%d" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + cluster_name = azurerm_kusto_cluster.test.name +} + +resource "azurerm_kusto_database_principal_assignment" "test" { + name = "acctestkdpa%d" + resource_group_name = azurerm_resource_group.rg.name + cluster_name = azurerm_kusto_cluster.test.name + database_name = azurerm_kusto_database.test.name + + tenant_id = data.azurerm_client_config.current.tenant_id + principal_id = data.azurerm_client_config.current.client_id + principal_type = "App" + role = "Viewer" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomInteger, data.RandomInteger) +} diff --git a/website/docs/r/kusto_database_principal_assignment.html.markdown b/website/docs/r/kusto_database_principal_assignment.html.markdown new file mode 100644 index 0000000000000..12983ea871824 --- /dev/null +++ b/website/docs/r/kusto_database_principal_assignment.html.markdown @@ -0,0 +1,100 @@ +--- +subcategory: "Data Explorer" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_kusto_database_principal_assignment" +description: |- + Manages a Kusto Database Principal Assignment. +--- + +# azurerm_kusto_database_principal_assignment + +Manages a Kusto Database Principal Assignment. + +## Example Usage + +```hcl +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "rg" { + name = "KustoRG" + location = "East US" +} + +resource "azurerm_kusto_cluster" "example" { + name = "KustoCluster" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + sku { + name = "Standard_D13_v2" + capacity = 2 + } +} + +resource "azurerm_kusto_database" "example" { + name = "KustoDatabase" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + cluster_name = azurerm_kusto_cluster.example.name + + hot_cache_period = "P7D" + soft_delete_period = "P31D" +} + +resource "azurerm_kusto_database_principal_assignment" "example" { + name = "KustoPrincipalAssignment" + resource_group_name = azurerm_resource_group.rg.name + cluster_name = azurerm_kusto_cluster.example.name + database_name = azurerm_kusto_database.example.name + + tenant_id = data.azurerm_client_config.current.tenant_id + principal_id = data.azurerm_client_config.current.client_id + principal_type = "App" + role = "Viewer" +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `resource_group_name` - (Required) The name of the resource group in which to create the resource. Changing this forces a new resource to be created. + +* `cluster_name` - (Required) The name of the cluster in which to create the resource. Changing this forces a new resource to be created. + +* `database_name` - (Required) The name of the database in which to create the resource. Changing this forces a new resource to be created. + +* `principal_id` - (Required) The object id of the principal. Changing this forces a new resource to be created. + +* `principal_type` - (Required) The type of the principal. Valid values include `App`, `Group`, `User`. Changing this forces a new resource to be created. + +* `role` - (Required) The database role assigned to the pricipal. Valid values include `Admin`, `Ingestor`, `Monitor`, `UnrestrictedViewers`, `User` and `Viewer`. Changing this forces a new resource to be created. + +* `tenant_id` - (Required) The tenant id in which the principal resides. Changing this forces a new resource to be created. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Kusto Database Principal Assignment. + +* `principal_name` - The computed name of the principal. + +* `tenant_name` - The computed name of the tenant. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 1 hour) Used when creating the Data Explorer. +* `read` - (Defaults to 5 minutes) Used when retrieving the Data Explorer. +* `update` - (Defaults to 1 hour) Used when updating the Data Explorer. +* `delete` - (Defaults to 1 hour) Used when deleting the Data Explorer. + +## Import + +Data Explorers can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_kusto_database_principal_assignment.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Kusto/Clusters/cluster1/Databases/database1/PrincipalAssignments/assignment1 +``` \ No newline at end of file