-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Kusto Cluster Principal Assignment Support
- Loading branch information
1 parent
3c26dd0
commit 8474e01
Showing
8 changed files
with
573 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
235 changes: 235 additions & 0 deletions
235
azurerm/internal/services/kusto/kusto_cluster_principal_assignment_resource.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
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 resourceArmKustoClusterPrincipalAssignment() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceArmKustoClusterPrincipalAssignmentCreateUpdate, | ||
Read: resourceArmKustoClusterPrincipalAssignmentRead, | ||
Delete: resourceArmKustoClusterPrincipalAssignmentDelete, | ||
|
||
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, | ||
}, | ||
|
||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validateAzureRMKustoClusterPrincipalAssignmentName, | ||
}, | ||
|
||
"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.AllDatabasesAdmin), | ||
string(kusto.AllDatabasesViewer), | ||
}, false), | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceArmKustoClusterPrincipalAssignmentCreateUpdate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*clients.Client).Kusto.ClusterPrincipalAssignmentsClient | ||
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) | ||
defer cancel() | ||
|
||
log.Printf("[INFO] preparing arguments for Azure Kusto Cluster Principal Assignment creation.") | ||
|
||
resourceGroup := d.Get("resource_group_name").(string) | ||
clusterName := d.Get("cluster_name").(string) | ||
name := d.Get("name").(string) | ||
|
||
if d.IsNewResource() { | ||
principalAssignment, err := client.Get(ctx, resourceGroup, clusterName, name) | ||
if err != nil { | ||
if !utils.ResponseWasNotFound(principalAssignment.Response) { | ||
return fmt.Errorf("Error checking for presence of existing Kusto Cluster Principal Assignment %q (Resource Group %q, Cluster %q): %+v", name, resourceGroup, clusterName, err) | ||
} | ||
} | ||
|
||
if principalAssignment.ID != nil && *principalAssignment.ID != "" { | ||
return tf.ImportAsExistsError("azurerm_kusto_cluster_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.ClusterPrincipalProperties{ | ||
TenantID: utils.String(tenantID), | ||
PrincipalID: utils.String(principalID), | ||
PrincipalType: kusto.PrincipalType(principalType), | ||
Role: kusto.ClusterPrincipalRole(role), | ||
} | ||
|
||
principalAssignment := kusto.ClusterPrincipalAssignment{ | ||
ClusterPrincipalProperties: &props, | ||
} | ||
|
||
future, err := client.CreateOrUpdate(ctx, resourceGroup, clusterName, name, principalAssignment) | ||
if err != nil { | ||
return fmt.Errorf("Error creating or updating Kusto Cluster Principal Assignment %q (Resource Group %q, Cluster %q): %+v", name, resourceGroup, clusterName, err) | ||
} | ||
|
||
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { | ||
return fmt.Errorf("Error waiting for completion of Kusto Cluster Principal Assignment %q (Resource Group %q, Cluster %q): %+v", name, resourceGroup, clusterName, err) | ||
} | ||
|
||
resp, err := client.Get(ctx, resourceGroup, clusterName, name) | ||
if err != nil { | ||
return fmt.Errorf("Error retrieving Kusto Cluster Principal Assignment %q (Resource Group %q, Cluster %q): %+v", name, resourceGroup, clusterName, err) | ||
} | ||
|
||
if resp.ID == nil { | ||
return fmt.Errorf("Cannot read ID for Kusto Cluster Principal Assignment %q (Resource Group %q, Cluster %q)", name, resourceGroup, clusterName) | ||
} | ||
|
||
d.SetId(*resp.ID) | ||
|
||
return resourceArmKustoClusterPrincipalAssignmentRead(d, meta) | ||
} | ||
|
||
func resourceArmKustoClusterPrincipalAssignmentRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*clients.Client).Kusto.ClusterPrincipalAssignmentsClient | ||
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) | ||
defer cancel() | ||
|
||
id, err := parse.KustoClusterPrincipalAssignmentID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
resp, err := client.Get(ctx, id.ResourceGroup, id.Cluster, id.Name) | ||
if err != nil { | ||
if utils.ResponseWasNotFound(resp.Response) { | ||
d.SetId("") | ||
return nil | ||
} | ||
return fmt.Errorf("Error retrieving Kusto Cluster Principal Assignment %q (Resource Group %q, Cluster %q): %+v", id.Name, id.ResourceGroup, id.Cluster, err) | ||
} | ||
|
||
d.Set("resource_group_name", id.ResourceGroup) | ||
d.Set("cluster_name", id.Cluster) | ||
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 resourceArmKustoClusterPrincipalAssignmentDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*clients.Client).Kusto.ClusterPrincipalAssignmentsClient | ||
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) | ||
defer cancel() | ||
|
||
id, err := parse.KustoClusterPrincipalAssignmentID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
future, err := client.Delete(ctx, id.ResourceGroup, id.Cluster, id.Name) | ||
if err != nil { | ||
return fmt.Errorf("Error deleting Kusto Cluster Principal Assignment %q (Resource Group %q, Cluster %q): %+v", id.Name, id.ResourceGroup, id.Cluster, err) | ||
} | ||
|
||
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { | ||
return fmt.Errorf("Error waiting for deletion of Kusto Cluster Principal Assignment %q (Resource Group %q, Cluster %q): %+v", id.Name, id.ResourceGroup, id.Cluster, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func validateAzureRMKustoClusterPrincipalAssignmentName(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 | ||
} |
38 changes: 38 additions & 0 deletions
38
azurerm/internal/services/kusto/parse/kusto_cluster_principal_assignment.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package parse | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" | ||
) | ||
|
||
type KustoClusterPrincipalAssignmentId struct { | ||
ResourceGroup string | ||
Cluster string | ||
Name string | ||
} | ||
|
||
func KustoClusterPrincipalAssignmentID(input string) (*KustoClusterPrincipalAssignmentId, error) { | ||
id, err := azure.ParseAzureResourceID(input) | ||
if err != nil { | ||
return nil, fmt.Errorf("[ERROR] Unable to parse Kusto Cluster Principal ID %q: %+v", input, err) | ||
} | ||
|
||
principal := KustoClusterPrincipalAssignmentId{ | ||
ResourceGroup: id.ResourceGroup, | ||
} | ||
|
||
if principal.Cluster, err = id.PopSegment("Clusters"); 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 | ||
} |
63 changes: 63 additions & 0 deletions
63
azurerm/internal/services/kusto/parse/kusto_cluster_principal_assignment_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package parse | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestKustoClusterPrincipalAssignmentId(t *testing.T) { | ||
testData := []struct { | ||
Name string | ||
Input string | ||
Expected *KustoClusterPrincipalAssignmentId | ||
}{ | ||
{ | ||
Name: "Empty", | ||
Input: "", | ||
Expected: nil, | ||
}, | ||
{ | ||
Name: "Missing Cluster", | ||
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Kusto/PrincipalAssignments/assignment1", | ||
Expected: nil, | ||
}, | ||
{ | ||
Name: "Missing PrincipalAssignment", | ||
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Kusto/Clusters/cluster1/", | ||
Expected: nil, | ||
}, | ||
{ | ||
Name: "Cluster Principal Assignment ID", | ||
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Kusto/Clusters/cluster1/PrincipalAssignments/assignment1", | ||
Expected: &KustoClusterPrincipalAssignmentId{ | ||
Name: "assignment1", | ||
Cluster: "cluster1", | ||
ResourceGroup: "group1", | ||
}, | ||
}, | ||
} | ||
|
||
for _, v := range testData { | ||
t.Logf("[DEBUG] Testing %q", v.Name) | ||
|
||
actual, err := KustoClusterPrincipalAssignmentID(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.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) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.