Skip to content

Commit

Permalink
r/kusto_database: support for principal permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
jrauschenbusch committed Nov 24, 2019
1 parent 0447ead commit dbf182d
Showing 1 changed file with 148 additions and 0 deletions.
148 changes: 148 additions & 0 deletions azurerm/resource_arm_kusto_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"fmt"
"log"
"regexp"
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/services/kusto/mgmt/2019-05-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/helpers/validate"
Expand All @@ -16,6 +18,10 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func createFqnPattern() *regexp.Regexp {
return regexp.MustCompile(`^aad(user|group|app)=([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}){1}(;([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})){0,1}$`)
}

func resourceArmKustoDatabase() *schema.Resource {
return &schema.Resource{
Create: resourceArmKustoDatabaseCreateUpdate,
Expand Down Expand Up @@ -69,6 +75,31 @@ func resourceArmKustoDatabase() *schema.Resource {
Type: schema.TypeFloat,
Computed: true,
},

"permission": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"role": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
string(kusto.Admin),
string(kusto.Viewer),
string(kusto.User),
string(kusto.Monitor),
string(kusto.Ingestor),
}, false),
},
"fqn": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(createFqnPattern(), "The fqn pattern must follow: aadapp=<app_guid> or aadapp=<app_guid>;<subscription_guid>"),
},
},
},
},
},
}
}
Expand Down Expand Up @@ -125,6 +156,24 @@ func resourceArmKustoDatabaseCreateUpdate(d *schema.ResourceData, meta interface
return fmt.Errorf("Cannot read ID for Kusto Cluster %q (Resource Group %q, Cluster %q)", name, resourceGroup, clusterName)
}

existingPrincipals, err := client.ListPrincipals(ctx, resourceGroup, clusterName, name)
if err != nil {
return fmt.Errorf("Error listing Kusto Database permissions (Resource Group %q, Cluster %q, Database: %q): %+v", resourceGroup, clusterName, name, err)
}

permissions := expandPermissions(d)

principalsToAdd, principalsToRemove := matchPrincipals((&existingPrincipals).Value, permissions)

_, err = client.AddPrincipals(ctx, resourceGroup, clusterName, name, *principalsToAdd)
if err != nil {
return fmt.Errorf("Error adding Kusto Database permissions (Resource Group %q, Cluster %q, Database: %q): %+v", resourceGroup, clusterName, name, err)
}
_, err = client.RemovePrincipals(ctx, resourceGroup, clusterName, name, *principalsToRemove)
if err != nil {
return fmt.Errorf("Error removing Kusto Database permissions (Resource Group %q, Cluster %q, Database %q): %+v", resourceGroup, clusterName, name, err)
}

d.SetId(*resp.ID)

return resourceArmKustoDatabaseRead(d, meta)
Expand Down Expand Up @@ -171,6 +220,14 @@ func resourceArmKustoDatabaseRead(d *schema.ResourceData, meta interface{}) erro
}
}

result, err := client.ListPrincipals(ctx, resourceGroup, clusterName, name)

flattenPerms := flattenPermissions(&result)

if err := d.Set("permission", flattenPerms); err != nil {
return fmt.Errorf("Error setting `permission`: %s", err)
}

return nil
}

Expand Down Expand Up @@ -231,3 +288,94 @@ func expandKustoDatabaseProperties(d *schema.ResourceData) *kusto.DatabaseProper

return databaseProperties
}

func expandPermissions(d *schema.ResourceData) *[]kusto.DatabasePrincipal {

permissions := d.Get("permission").([]interface{})

inferred := "" // Value is getting inferred in the Azure backend (FQN) but needs to be set in the kusto.DatabasePrincipal object.

perms := make([]kusto.DatabasePrincipal, 0)

for _, v := range permissions {
perm := v.(map[string]interface{})
principal := kusto.DatabasePrincipal{
Role: kusto.DatabasePrincipalRole(perm["role"].(string)),
Name: &inferred,
Type: kusto.DatabasePrincipalTypeUser, // Type is getting inferred in the Azure backend (FQN) but needs to be set.
Fqn: utils.String(perm["fqn"].(string)),
Email: &inferred,
AppID: &inferred,
}

perms = append(perms, principal)
}

return &perms
}

func flattenPermissions(result *kusto.DatabasePrincipalListResult) (flattenPerms []interface{}) {
flattenPerms = make([]interface{}, 0)

for _, principal := range *result.Value {
flattenPerm := flattenPermission(&principal)
flattenPerms = append(flattenPerms, flattenPerm)
}

return flattenPerms
}

func flattenPermission(principal *kusto.DatabasePrincipal) map[string]interface{} {
output := make(map[string]interface{})

if principal != nil {
if &principal.Role != nil {
output["role"] = string(principal.Role)
}

if &principal.Fqn != nil {
fqn := strings.Split(*principal.Fqn, ";")[0]
output["fqn"] = fqn
}
}

return output
}

func matchPrincipals(remotePrincipals *[]kusto.DatabasePrincipal, localPrincipals *[]kusto.DatabasePrincipal) (principalsToAdd *kusto.DatabasePrincipalListRequest, principalsToRemove *kusto.DatabasePrincipalListRequest) {
principalsToAdd = &kusto.DatabasePrincipalListRequest{
Value: &[]kusto.DatabasePrincipal{},
}
principalsToRemove = &kusto.DatabasePrincipalListRequest{
Value: &[]kusto.DatabasePrincipal{},
}

remote := make(map[string]*kusto.DatabasePrincipal)
local := make(map[string]*kusto.DatabasePrincipal)

for _, remotePrincipal := range *remotePrincipals {
fqn := strings.Split(*remotePrincipal.Fqn, ";")[0]
role := string(remotePrincipal.Role)
remote[fqn+role] = &remotePrincipal
}

for _, localPrincipal := range *localPrincipals {
fqn := *localPrincipal.Fqn
role := string(localPrincipal.Role)
local[fqn+role] = &localPrincipal
}

for key := range remote {
if local[key] == nil {
*principalsToRemove.Value = append(*principalsToRemove.Value, *remote[key])
}
}

for key := range local {
if remote[key] == nil {
*principalsToAdd.Value = append(*principalsToAdd.Value, *local[key])
}
}

return principalsToAdd, principalsToRemove
}

0 comments on commit dbf182d

Please sign in to comment.