From d2350ab59363b8ffc7ecf0410abacb7dbffdbb47 Mon Sep 17 00:00:00 2001 From: njucz Date: Mon, 20 Jul 2020 17:57:34 +0800 Subject: [PATCH] add support for setting aad admin --- .../services/synapse/client/client.go | 9 +- .../synapse/synapse_workspace_resource.go | 144 ++++++++++++++++-- .../tests/synapse_workspace_resource_test.go | 19 ++- .../docs/r/synapse_workspace.html.markdown | 22 +++ 4 files changed, 179 insertions(+), 15 deletions(-) diff --git a/azurerm/internal/services/synapse/client/client.go b/azurerm/internal/services/synapse/client/client.go index db695ad9682c6..508d5f66ee8a1 100644 --- a/azurerm/internal/services/synapse/client/client.go +++ b/azurerm/internal/services/synapse/client/client.go @@ -6,14 +6,19 @@ import ( ) type Client struct { - WorkspaceClient *synapse.WorkspacesClient + WorkspaceClient *synapse.WorkspacesClient + WorkspaceAadAdminsClient *synapse.WorkspaceAadAdminsClient } func NewClient(o *common.ClientOptions) *Client { workspaceClient := synapse.NewWorkspacesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&workspaceClient.Client, o.ResourceManagerAuthorizer) + workspaceAadAdminsClient := synapse.NewWorkspaceAadAdminsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&workspaceAadAdminsClient.Client, o.ResourceManagerAuthorizer) + return &Client{ - WorkspaceClient: &workspaceClient, + WorkspaceClient: &workspaceClient, + WorkspaceAadAdminsClient: &workspaceAadAdminsClient, } } diff --git a/azurerm/internal/services/synapse/synapse_workspace_resource.go b/azurerm/internal/services/synapse/synapse_workspace_resource.go index 8e1b3f73cda82..7d52cd6712d0a 100644 --- a/azurerm/internal/services/synapse/synapse_workspace_resource.go +++ b/azurerm/internal/services/synapse/synapse_workspace_resource.go @@ -10,6 +10,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/preview/synapse/mgmt/2019-06-01-preview/synapse" "github.com/hashicorp/go-azure-helpers/response" "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" @@ -78,6 +79,34 @@ func resourceArmSynapseWorkspace() *schema.Resource { ForceNew: true, }, + "aad_admin": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + ConfigMode: schema.SchemaConfigModeAttr, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "login": { + Type: schema.TypeString, + Required: true, + }, + + "object_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsUUID, + }, + + "tenant_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsUUID, + }, + }, + }, + }, + "connectivity_endpoints": { Type: schema.TypeMap, Computed: true, @@ -118,8 +147,10 @@ func resourceArmSynapseWorkspace() *schema.Resource { }, } } + func resourceArmSynapseWorkspaceCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Synapse.WorkspaceClient + aadAdminClient := meta.(*clients.Client).Synapse.WorkspaceAadAdminsClient ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -164,6 +195,18 @@ func resourceArmSynapseWorkspaceCreate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("waiting on creation for Synapse Workspace %q (Resource Group %q): %+v", name, resourceGroup, err) } + aadAdmin := expandArmWorkspaceAadAdmin(d.Get("aad_admin").([]interface{})) + if aadAdmin != nil { + workspaceAadAdminsCreateOrUpdateFuture, err := aadAdminClient.CreateOrUpdate(ctx, resourceGroup, name, *aadAdmin) + if err != nil { + return fmt.Errorf("updating Synapse Workspace %q Sql Admin (Resource Group %q): %+v", name, resourceGroup, err) + } + + if err = workspaceAadAdminsCreateOrUpdateFuture.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting on updating for Synapse Workspace %q Sql Admin (Resource Group %q): %+v", name, resourceGroup, err) + } + } + resp, err := client.Get(ctx, resourceGroup, name) if err != nil { return fmt.Errorf("retrieving Synapse Workspace %q (Resource Group %q): %+v", name, resourceGroup, err) @@ -179,6 +222,7 @@ func resourceArmSynapseWorkspaceCreate(d *schema.ResourceData, meta interface{}) func resourceArmSynapseWorkspaceRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Synapse.WorkspaceClient + aadAdminClient := meta.(*clients.Client).Synapse.WorkspaceAadAdminsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -196,6 +240,14 @@ func resourceArmSynapseWorkspaceRead(d *schema.ResourceData, meta interface{}) e } return fmt.Errorf("retrieving Synapse Workspace %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } + + aadAdmin, err := aadAdminClient.Get(ctx, id.ResourceGroup, id.Name) + if err != nil { + if !utils.ResponseWasNotFound(aadAdmin.Response) { + return fmt.Errorf("retrieving Synapse Workspace %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + } + d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) d.Set("location", location.NormalizeNilable(resp.Location)) @@ -213,11 +265,16 @@ func resourceArmSynapseWorkspaceRead(d *schema.ResourceData, meta interface{}) e d.Set("managed_resource_group_name", props.ManagedResourceGroupName) d.Set("connectivity_endpoints", utils.FlattenMapStringPtrString(props.ConnectivityEndpoints)) } + if err := d.Set("aad_admin", flattenArmWorkspaceAadAdmin(aadAdmin.AadAdminProperties)); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + return tags.FlattenAndSet(d, resp.Tags) } func resourceArmSynapseWorkspaceUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Synapse.WorkspaceClient + aadAdminClient := meta.(*clients.Client).Synapse.WorkspaceAadAdminsClient ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -226,22 +283,47 @@ func resourceArmSynapseWorkspaceUpdate(d *schema.ResourceData, meta interface{}) return err } - workspacePatchInfo := synapse.WorkspacePatchInfo{ - Tags: tags.Expand(d.Get("tags").(map[string]interface{})), - } - if d.HasChange("sql_administrator_login_password") { - workspacePatchInfo.WorkspacePatchProperties = &synapse.WorkspacePatchProperties{ - SQLAdministratorLoginPassword: utils.String(d.Get("sql_administrator_login_password").(string)), + if d.HasChanges("tags", "sql_administrator_login_password") { + workspacePatchInfo := synapse.WorkspacePatchInfo{ + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + } + if d.HasChange("sql_administrator_login_password") { + workspacePatchInfo.WorkspacePatchProperties = &synapse.WorkspacePatchProperties{ + SQLAdministratorLoginPassword: utils.String(d.Get("sql_administrator_login_password").(string)), + } } - } - future, err := client.Update(ctx, id.ResourceGroup, id.Name, workspacePatchInfo) - if err != nil { - return fmt.Errorf("updating Synapse Workspace %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + future, err := client.Update(ctx, id.ResourceGroup, id.Name, workspacePatchInfo) + if err != nil { + return fmt.Errorf("updating Synapse Workspace %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting on updating future for Synapse Workspace %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting on updating future for Synapse Workspace %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if d.HasChange("aad_admin") { + aadAdmin := expandArmWorkspaceAadAdmin(d.Get("aad_admin").([]interface{})) + if aadAdmin != nil { + workspaceAadAdminsCreateOrUpdateFuture, err := aadAdminClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, *aadAdmin) + if err != nil { + return fmt.Errorf("updating Synapse Workspace %q Sql Admin (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + if err = workspaceAadAdminsCreateOrUpdateFuture.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting on updating for Synapse Workspace %q Sql Admin (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + } else { + workspaceAadAdminsDeleteFuture, err := aadAdminClient.Delete(ctx, id.ResourceGroup, id.Name) + if err != nil { + return fmt.Errorf("setting empty Synapse Workspace %q Sql Admin (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + if err = workspaceAadAdminsDeleteFuture.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting on setting empty Synapse Workspace %q Sql Admin (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + } } return resourceArmSynapseWorkspaceRead(d, meta) } @@ -279,6 +361,21 @@ func expandArmWorkspaceDataLakeStorageAccountDetails(storageDataLakeGen2Filesyst } } +func expandArmWorkspaceAadAdmin(input []interface{}) *synapse.WorkspaceAadAdminInfo { + if input == nil || len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + return &synapse.WorkspaceAadAdminInfo{ + AadAdminProperties: &synapse.AadAdminProperties{ + TenantID: utils.String(v["tenant_id"].(string)), + Login: utils.String(v["login"].(string)), + AdministratorType: utils.String("ActiveDirectory"), + Sid: utils.String(v["object_id"].(string)), + }, + } +} + func flattenArmWorkspaceManagedIdentity(input *synapse.ManagedIdentity) []interface{} { if input == nil { return make([]interface{}, 0) @@ -307,3 +404,26 @@ func flattenArmWorkspaceDataLakeStorageAccountDetails(input *synapse.DataLakeSto } return "" } + +func flattenArmWorkspaceAadAdmin(input *synapse.AadAdminProperties) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + var tenantId, login, sid string + if input.TenantID != nil { + tenantId = *input.TenantID + } + if input.Login != nil { + login = *input.Login + } + if input.Sid != nil { + sid = *input.Sid + } + return []interface{}{ + map[string]interface{}{ + "tenant_id": tenantId, + "login": login, + "object_id": sid, + }, + } +} diff --git a/azurerm/internal/services/synapse/tests/synapse_workspace_resource_test.go b/azurerm/internal/services/synapse/tests/synapse_workspace_resource_test.go index 4369613070b8e..0271ee2ee8c42 100644 --- a/azurerm/internal/services/synapse/tests/synapse_workspace_resource_test.go +++ b/azurerm/internal/services/synapse/tests/synapse_workspace_resource_test.go @@ -50,7 +50,7 @@ func TestAccAzureRMSynapseWorkspace_requiresImport(t *testing.T) { func TestAccAzureRMSynapseWorkspace_complete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_synapse_workspace", "test") - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, CheckDestroy: testCheckAzureRMSynapseWorkspaceDestroy, @@ -87,6 +87,12 @@ func TestAccAzureRMSynapseWorkspace_update(t *testing.T) { ), }, data.ImportStep("sql_administrator_login_password"), + { + Config: testAccAzureRMSynapseWorkspace_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSynapseWorkspaceExists(data.ResourceName), + ), + }, }, }) } @@ -155,6 +161,7 @@ func testAccAzureRMSynapseWorkspace_requiresImport(data acceptance.TestData) str config := testAccAzureRMSynapseWorkspace_basic(data) return fmt.Sprintf(` %s + resource "azurerm_synapse_workspace" "import" { name = azurerm_synapse_workspace.test.name resource_group_name = azurerm_synapse_workspace.test.resource_group_name @@ -170,6 +177,7 @@ func testAccAzureRMSynapseWorkspace_complete(data acceptance.TestData) string { template := testAccAzureRMSynapseWorkspace_template(data) return fmt.Sprintf(` %s + resource "azurerm_synapse_workspace" "test" { name = "acctestsw%d" resource_group_name = azurerm_resource_group.test.name @@ -191,6 +199,9 @@ func testAccAzureRMSynapseWorkspace_withUpdateFields(data acceptance.TestData) s return fmt.Sprintf(` %s +data "azurerm_client_config" "current" { +} + resource "azurerm_synapse_workspace" "test" { name = "acctestsw%d" resource_group_name = azurerm_resource_group.test.name @@ -199,6 +210,12 @@ resource "azurerm_synapse_workspace" "test" { sql_administrator_login = "sqladminuser" sql_administrator_login_password = "H@Sh1CoR4!" + aad_admin { + login = "AzureAD Admin" + object_id = data.azurerm_client_config.current.object_id + tenant_id = data.azurerm_client_config.current.tenant_id + } + tags = { ENV = "Test" } diff --git a/website/docs/r/synapse_workspace.html.markdown b/website/docs/r/synapse_workspace.html.markdown index 87149e9859f6b..279a619c310fb 100644 --- a/website/docs/r/synapse_workspace.html.markdown +++ b/website/docs/r/synapse_workspace.html.markdown @@ -40,6 +40,16 @@ resource "azurerm_synapse_workspace" "example" { storage_data_lake_gen2_filesystem_id = azurerm_storage_data_lake_gen2_filesystem.example.id sql_administrator_login = "sqladminuser" sql_administrator_login_password = "H@Sh1CoR3!" + + aad_admin { + login = "AzureAD Admin" + object_id = "00000000-0000-0000-0000-000000000000" + tenant_id = "00000000-0000-0000-0000-000000000000" + } + + tags = { + Env = "production" + } } ``` @@ -61,8 +71,20 @@ The following arguments are supported: * `managed_virtual_network_enabled` - (Optional) Is Virtual Network enabled for all computes in this workspace. Changing this forces a new resource to be created. +* `aad_admin` - (Optional) An `aad_admin` block as defined below. + * `tags` - (Optional) A mapping of tags which should be assigned to the Synapse Workspace. +--- + +An `aad_admin` block supports the following: + +* `login` - (Required) The login name of the Azure AD Administrator of this Synapse Workspace. + +* `object_id` - (Required) The object id of the Azure AD Administrator of this Synapse Workspace. + +* `tenant_id` - (Required) The tenant id of the Azure AD Administrator of this Synapse Workspace. + ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: