From 14bac7ac9e8b586706e4e0511ad7487d326cf2be 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 | 21 +- ..._database_principal_assignment_resource.go | 267 ++++++++++++++++++ .../kusto_database_principal_resource.go | 2 + .../kusto_database_principal_assignment.go | 43 +++ ...usto_database_principal_assignment_test.go | 68 +++++ .../internal/services/kusto/registration.go | 1 + ...base_principal_assignment_resource_test.go | 183 ++++++++++++ website/azurerm.erb | 3 + ...atabase_principal_assignment.html.markdown | 99 +++++++ 9 files changed, 681 insertions(+), 6 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 3c3266934674..c2b37ac14470 100644 --- a/azurerm/internal/services/kusto/client/client.go +++ b/azurerm/internal/services/kusto/client/client.go @@ -6,22 +6,30 @@ import ( ) type Client struct { - ClustersClient *kusto.ClustersClient - DatabasesClient *kusto.DatabasesClient - DataConnectionsClient *kusto.DataConnectionsClient - ClusterPrincipalAssignmentsClient *kusto.ClusterPrincipalAssignmentsClient AttachedDatabaseConfigurationsClient *kusto.AttachedDatabaseConfigurationsClient + ClustersClient *kusto.ClustersClient + ClusterPrincipalAssignmentsClient *kusto.ClusterPrincipalAssignmentsClient + DatabasesClient *kusto.DatabasesClient + DataConnectionsClient *kusto.DataConnectionsClient + DatabasePrincipalAssignmentsClient *kusto.DatabasePrincipalAssignmentsClient } func NewClient(o *common.ClientOptions) *Client { ClustersClient := kusto.NewClustersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&ClustersClient.Client, o.ResourceManagerAuthorizer) + ClusterPrincipalAssignmentsClient := kusto.NewClusterPrincipalAssignmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&ClusterPrincipalAssignmentsClient.Client, o.ResourceManagerAuthorizer) + DatabasesClient := kusto.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&DatabasesClient.Client, o.ResourceManagerAuthorizer) + DatabasePrincipalAssignmentsClient := kusto.NewDatabasePrincipalAssignmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&DatabasePrincipalAssignmentsClient.Client, o.ResourceManagerAuthorizer) + DataConnectionsClient := kusto.NewDataConnectionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&DataConnectionsClient.Client, o.ResourceManagerAuthorizer) + ClusterPrincipalAssignmentsClient := kusto.NewClusterPrincipalAssignmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&ClusterPrincipalAssignmentsClient.Client, o.ResourceManagerAuthorizer) @@ -29,10 +37,11 @@ func NewClient(o *common.ClientOptions) *Client { o.ConfigureClient(&AttachedDatabaseConfigurationsClient.Client, o.ResourceManagerAuthorizer) return &Client{ + AttachedDatabaseConfigurationsClient: &AttachedDatabaseConfigurationsClient, ClustersClient: &ClustersClient, + ClusterPrincipalAssignmentsClient: &ClusterPrincipalAssignmentsClient, DatabasesClient: &DatabasesClient, DataConnectionsClient: &DataConnectionsClient, - ClusterPrincipalAssignmentsClient: &ClusterPrincipalAssignmentsClient, - AttachedDatabaseConfigurationsClient: &AttachedDatabaseConfigurationsClient, + 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 000000000000..bb547b88d9d4 --- /dev/null +++ b/azurerm/internal/services/kusto/kusto_database_principal_assignment_resource.go @@ -0,0 +1,267 @@ +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: resourceArmKustoDatabasePrincipalAssignmentCreate, + 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), + 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 resourceArmKustoDatabasePrincipalAssignmentCreate(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) + + existing, err := client.Get(ctx, resourceGroup, clusterName, databaseName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.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 existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_kusto_database_principal_assignment", *existing.ID) + } + + tenantID := d.Get("tenant_id").(string) + principalID := d.Get("principal_id").(string) + principalType := d.Get("principal_type").(string) + role := d.Get("role").(string) + + principalAssignment := kusto.DatabasePrincipalAssignment{ + DatabasePrincipalProperties: &kusto.DatabasePrincipalProperties{ + TenantID: utils.String(tenantID), + PrincipalID: utils.String(principalID), + PrincipalType: kusto.PrincipalType(principalType), + Role: kusto.DatabasePrincipalRole(role), + }, + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, clusterName, databaseName, name, principalAssignment) + if err != nil { + return fmt.Errorf("failed creating 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("failed 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("failed to retrieve Kusto Database Principal Assignment %q (Resource Group %q, Cluster %q, Database %q): %+v", name, resourceGroup, clusterName, databaseName, err) + } + + if resp.ID == nil || *resp.ID == "" { + 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("failed to retrieve 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) + + tenantID := "" + if resp.TenantID != nil { + tenantID = *resp.TenantID + } + + tenantName := "" + if resp.TenantName != nil { + tenantName = *resp.TenantName + } + + principalID := "" + if resp.PrincipalID != nil { + principalID = *resp.PrincipalID + } + + principalName := "" + if resp.PrincipalName != nil { + principalName = *resp.PrincipalName + } + + principalType := string(resp.PrincipalType) + role := string(resp.Role) + + d.Set("tenant_id", tenantID) + d.Set("tenant_name", tenantName) + d.Set("principal_id", principalID) + d.Set("principal_name", principalName) + d.Set("principal_type", principalType) + d.Set("role", 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/kusto_database_principal_resource.go b/azurerm/internal/services/kusto/kusto_database_principal_resource.go index 5ee58505b155..0a00d4a8854c 100644 --- a/azurerm/internal/services/kusto/kusto_database_principal_resource.go +++ b/azurerm/internal/services/kusto/kusto_database_principal_resource.go @@ -23,6 +23,8 @@ func resourceArmKustoDatabasePrincipal() *schema.Resource { Read: resourceArmKustoDatabasePrincipalRead, Delete: resourceArmKustoDatabasePrincipalDelete, + DeprecationMessage: "This resource has been superseded by `azurerm_kusto_database_principal_assignment` to reflects changes in the API/SDK and will be removed in version 3.0 of the provider.", + Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, 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 000000000000..a3d063a3c11e --- /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 000000000000..85b3589986d2 --- /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 61a6d8baba6e..2953caacb5f3 100644 --- a/azurerm/internal/services/kusto/registration.go +++ b/azurerm/internal/services/kusto/registration.go @@ -32,6 +32,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_kusto_cluster_principal_assignment": resourceArmKustoClusterPrincipalAssignment(), "azurerm_kusto_database": resourceArmKustoDatabase(), "azurerm_kusto_database_principal": resourceArmKustoDatabasePrincipal(), + "azurerm_kusto_database_principal_assignment": resourceArmKustoDatabasePrincipalAssignment(), "azurerm_kusto_eventhub_data_connection": resourceArmKustoEventHubDataConnection(), "azurerm_kusto_attached_database_configuration": resourceArmKustoAttachedDatabaseConfiguration(), } 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 000000000000..783eceb75649 --- /dev/null +++ b/azurerm/internal/services/kusto/tests/kusto_database_principal_assignment_resource_test.go @@ -0,0 +1,183 @@ +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 TestAccAzureRMKustoDatabasePrincipalAssignment_requiresImport(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.RequiresImportErrorStep(testAccAzureRMKustoDatabasePrincipalAssignment_requiresImport), + }, + }) +} + +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) +} + +func testAccAzureRMKustoDatabasePrincipalAssignment_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMKustoDatabasePrincipalAssignment_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_kusto_database_principal_assignment" "import" { + name = azurerm_kusto_database_principal_assignment.test.name + resource_group_name = azurerm_kusto_database_principal_assignment.test.resource_group_name + cluster_name = azurerm_kusto_database_principal_assignment.test.cluster_name + database_name = azurerm_kusto_database_principal_assignment.test.database_name + + tenant_id = azurerm_kusto_database_principal_assignment.test.tenant_id + principal_id = azurerm_kusto_database_principal_assignment.test.principal_id + principal_type = azurerm_kusto_database_principal_assignment.test.principal_type + role = azurerm_kusto_database_principal_assignment.test.role +} +`, template) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 55e037951634..dd0241488334 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -1433,6 +1433,9 @@
  • azurerm_kusto_database_principal
  • +
  • + azurerm_kusto_database_principal_assignment +
  • azurerm_kusto_eventhub_data_connection
  • 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 000000000000..7a4b73dc1147 --- /dev/null +++ b/website/docs/r/kusto_database_principal_assignment.html.markdown @@ -0,0 +1,99 @@ +--- +subcategory: "Data Explorer" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_kusto_database_principal_assignment" +description: |- + Manages a Kusto / Data Explorer Database Principal Assignment +--- + +# azurerm_kusto_database_principal_assignment + +Manages a Kusto (also known as Azure Data Explorer) 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 principal. 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 name of the principal. + +* `tenant_name` - The 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 Kusto Database Principal Assignment. +* `read` - (Defaults to 5 minutes) Used when retrieving the Kusto Database Principal Assignment. +* `delete` - (Defaults to 1 hour) Used when deleting the Kusto Database Principal Assignment. + +## Import + +Kusto Database Principal Assignment 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 +```