diff --git a/azurerm/internal/clients/client.go b/azurerm/internal/clients/client.go index a5c93d96aa5f..94b63e0e6b7d 100644 --- a/azurerm/internal/clients/client.go +++ b/azurerm/internal/clients/client.go @@ -35,6 +35,7 @@ import ( kusto "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/kusto/client" loganalytics "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/client" logic "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/logic/client" + managedapplication "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/managedapplication/client" managementgroup "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/managementgroup/client" maps "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/maps/client" mariadb "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mariadb/client" @@ -75,67 +76,68 @@ type Client struct { Account *ResourceManagerAccount Features features.UserFeatures - AnalysisServices *analysisServices.Client - ApiManagement *apiManagement.Client - AppConfiguration *appConfiguration.Client - AppInsights *applicationInsights.Client - Authorization *authorization.Client - Automation *automation.Client - Batch *batch.Client - Bot *bot.Client - Cdn *cdn.Client - Cognitive *cognitiveServices.Client - Compute *compute.Client - Containers *containerServices.Client - Cosmos *cosmosdb.Client - DataBricks *databricks.Client - DataFactory *datafactory.Client - Datalake *datalake.Client - DevSpace *devspace.Client - DevTestLabs *devtestlabs.Client - Dns *dns.Client - EventGrid *eventgrid.Client - Eventhub *eventhub.Client - Frontdoor *frontdoor.Client - Graph *graph.Client - HDInsight *hdinsight.Client - HealthCare *healthcare.Client - IoTHub *iothub.Client - KeyVault *keyvault.Client - Kusto *kusto.Client - LogAnalytics *loganalytics.Client - Logic *logic.Client - ManagementGroups *managementgroup.Client - Maps *maps.Client - MariaDB *mariadb.Client - Media *media.Client - Monitor *monitor.Client - MSI *msi.Client - MSSQL *mssql.Client - MySQL *mysql.Client - NetApp *netapp.Client - Network *network.Client - NotificationHubs *notificationhub.Client - Policy *policy.Client - Portal *portal.Client - Postgres *postgres.Client - PrivateDns *privatedns.Client - RecoveryServices *recoveryServices.Client - Redis *redis.Client - Relay *relay.Client - Resource *resource.Client - Scheduler *scheduler.Client - Search *search.Client - SecurityCenter *securityCenter.Client - ServiceBus *serviceBus.Client - ServiceFabric *serviceFabric.Client - SignalR *signalr.Client - Storage *storage.Client - StreamAnalytics *streamAnalytics.Client - Subscription *subscription.Client - Sql *sql.Client - TrafficManager *trafficManager.Client - Web *web.Client + AnalysisServices *analysisServices.Client + ApiManagement *apiManagement.Client + AppConfiguration *appConfiguration.Client + AppInsights *applicationInsights.Client + Authorization *authorization.Client + Automation *automation.Client + Batch *batch.Client + Bot *bot.Client + Cdn *cdn.Client + Cognitive *cognitiveServices.Client + Compute *compute.Client + Containers *containerServices.Client + Cosmos *cosmosdb.Client + DataBricks *databricks.Client + DataFactory *datafactory.Client + Datalake *datalake.Client + DevSpace *devspace.Client + DevTestLabs *devtestlabs.Client + Dns *dns.Client + EventGrid *eventgrid.Client + Eventhub *eventhub.Client + Frontdoor *frontdoor.Client + Graph *graph.Client + HDInsight *hdinsight.Client + HealthCare *healthcare.Client + IoTHub *iothub.Client + KeyVault *keyvault.Client + Kusto *kusto.Client + LogAnalytics *loganalytics.Client + Logic *logic.Client + ManagedApplication *managedapplication.Client + ManagementGroups *managementgroup.Client + Maps *maps.Client + MariaDB *mariadb.Client + Media *media.Client + Monitor *monitor.Client + MSI *msi.Client + MSSQL *mssql.Client + MySQL *mysql.Client + NetApp *netapp.Client + Network *network.Client + NotificationHubs *notificationhub.Client + Policy *policy.Client + Portal *portal.Client + Postgres *postgres.Client + PrivateDns *privatedns.Client + RecoveryServices *recoveryServices.Client + Redis *redis.Client + Relay *relay.Client + Resource *resource.Client + Scheduler *scheduler.Client + Search *search.Client + SecurityCenter *securityCenter.Client + ServiceBus *serviceBus.Client + ServiceFabric *serviceFabric.Client + SignalR *signalr.Client + Storage *storage.Client + StreamAnalytics *streamAnalytics.Client + Subscription *subscription.Client + Sql *sql.Client + TrafficManager *trafficManager.Client + Web *web.Client } // NOTE: it should be possible for this method to become Private once the top level Client's removed @@ -174,6 +176,7 @@ func (client *Client) Build(ctx context.Context, o *common.ClientOptions) error client.Kusto = kusto.NewClient(o) client.LogAnalytics = loganalytics.NewClient(o) client.Logic = logic.NewClient(o) + client.ManagedApplication = managedapplication.NewClient(o) client.ManagementGroups = managementgroup.NewClient(o) client.Maps = maps.NewClient(o) client.MariaDB = mariadb.NewClient(o) diff --git a/azurerm/internal/provider/services.go b/azurerm/internal/provider/services.go index 4a052e204d13..22c831de6475 100644 --- a/azurerm/internal/provider/services.go +++ b/azurerm/internal/provider/services.go @@ -32,6 +32,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/kusto" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/logic" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/managedapplication" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/managementgroup" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/maps" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mariadb" @@ -97,6 +98,7 @@ func SupportedServices() []common.ServiceRegistration { kusto.Registration{}, loganalytics.Registration{}, logic.Registration{}, + managedapplication.Registration{}, managementgroup.Registration{}, maps.Registration{}, mariadb.Registration{}, diff --git a/azurerm/internal/services/managedapplication/client/client.go b/azurerm/internal/services/managedapplication/client/client.go new file mode 100644 index 000000000000..2fac84201466 --- /dev/null +++ b/azurerm/internal/services/managedapplication/client/client.go @@ -0,0 +1,19 @@ +package client + +import ( + "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/managedapplications" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/common" +) + +type Client struct { + ApplicationDefinitionClient *managedapplications.ApplicationDefinitionsClient +} + +func NewClient(o *common.ClientOptions) *Client { + applicationDefinitionClient := managedapplications.NewApplicationDefinitionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&applicationDefinitionClient.Client, o.ResourceManagerAuthorizer) + + return &Client{ + ApplicationDefinitionClient: &applicationDefinitionClient, + } +} diff --git a/azurerm/internal/services/managedapplication/data_source_managed_application_definition.go b/azurerm/internal/services/managedapplication/data_source_managed_application_definition.go new file mode 100644 index 000000000000..654fc5fd3a98 --- /dev/null +++ b/azurerm/internal/services/managedapplication/data_source_managed_application_definition.go @@ -0,0 +1,134 @@ +package managedapplication + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmManagedApplicationDefinition() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmManagedApplicationDefinitionRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: ValidateManagedAppDefinitionName, + }, + + "location": azure.SchemaLocationForDataSource(), + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "authorization": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_principal_id": { + Type: schema.TypeString, + Computed: true, + }, + "role_definition_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "create_ui_definition": { + Type: schema.TypeString, + Computed: true, + }, + + "description": { + Type: schema.TypeString, + Computed: true, + }, + + "display_name": { + Type: schema.TypeString, + Computed: true, + }, + + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + + "lock_level": { + Type: schema.TypeString, + Computed: true, + }, + + "main_template": { + Type: schema.TypeString, + Computed: true, + }, + + "package_file_uri": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceArmManagedApplicationDefinitionRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ManagedApplication.ApplicationDefinitionClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: Managed Application Definition (Managed Application Definition Name %q / Resource Group %q) was not found", name, resourceGroup) + } + return fmt.Errorf("Error reading Managed Application Definition (Managed Application Definition Name %q / Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + d.Set("resource_group_name", resourceGroup) + d.Set("name", name) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if props := resp.ApplicationDefinitionProperties; props != nil { + if err := d.Set("authorization", flattenArmManagedApplicationDefinitionAuthorization(props.Authorizations)); err != nil { + return fmt.Errorf("Error setting `authorization`: %+v", err) + } + d.Set("description", props.Description) + d.Set("display_name", props.DisplayName) + d.Set("enabled", props.IsEnabled) + d.Set("lock_level", string(props.LockLevel)) + } + if v, ok := d.GetOk("create_ui_definition"); ok { + d.Set("create_ui_definition", v.(string)) + } + if v, ok := d.GetOk("main_template"); ok { + d.Set("main_template", v.(string)) + } + if v, ok := d.GetOk("package_file_uri"); ok { + d.Set("package_file_uri", v.(string)) + } + + return nil +} diff --git a/azurerm/internal/services/managedapplication/registration.go b/azurerm/internal/services/managedapplication/registration.go new file mode 100644 index 000000000000..cd2759946b7b --- /dev/null +++ b/azurerm/internal/services/managedapplication/registration.go @@ -0,0 +1,26 @@ +package managedapplication + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +type Registration struct{} + +// Name is the name of this Service +func (r Registration) Name() string { + return "ManagedApplication" +} + +// SupportedDataSources returns the supported Data Sources supported by this Service +func (r Registration) SupportedDataSources() map[string]*schema.Resource { + return map[string]*schema.Resource{ + "azurerm_managed_application_definition": dataSourceArmManagedApplicationDefinition(), + } +} + +// SupportedResources returns the supported Resources supported by this Service +func (r Registration) SupportedResources() map[string]*schema.Resource { + return map[string]*schema.Resource{ + "azurerm_managed_application_definition": resourceArmManagedApplicationDefinition(), + } +} diff --git a/azurerm/internal/services/managedapplication/resource_arm_managed_application_definition.go b/azurerm/internal/services/managedapplication/resource_arm_managed_application_definition.go new file mode 100644 index 000000000000..b8fd2e925092 --- /dev/null +++ b/azurerm/internal/services/managedapplication/resource_arm_managed_application_definition.go @@ -0,0 +1,312 @@ +package managedapplication + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/managedapplications" + "github.com/hashicorp/go-azure-helpers/response" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/structure" + "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" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmManagedApplicationDefinition() *schema.Resource { + return &schema.Resource{ + Create: resourceArmManagedApplicationDefinitionCreateUpdate, + Read: resourceArmManagedApplicationDefinitionRead, + Update: resourceArmManagedApplicationDefinitionCreateUpdate, + Delete: resourceArmManagedApplicationDefinitionDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: ValidateManagedAppDefinitionName, + }, + + "location": azure.SchemaLocation(), + + "resource_group_name": azure.SchemaResourceGroupName(), + + "authorization": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_principal_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.GUID, + }, + "role_definition_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.GUID, + }, + }, + }, + }, + + "display_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: ValidateManagedAppDefinitionDisplayName, + }, + + "lock_level": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(managedapplications.CanNotDelete), + string(managedapplications.None), + string(managedapplications.ReadOnly), + }, false), + }, + + "create_ui_definition": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: structure.SuppressJsonDiff, + ConflictsWith: []string{"package_file_uri"}, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: ValidateManagedAppDefinitionDescription, + }, + + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + + "main_template": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: structure.SuppressJsonDiff, + ConflictsWith: []string{"package_file_uri"}, + }, + + "package_file_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.URLIsHTTPS, + }, + + "tags": tags.Schema(), + }, + } +} + +func resourceArmManagedApplicationDefinitionCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ManagedApplication.ApplicationDefinitionClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroupName := d.Get("resource_group_name").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroupName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for present of existing Managed Application Definition (Managed Application Definition Name %q / Resource Group %q): %+v", name, resourceGroupName, err) + } + } + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_managed_application_definition", *existing.ID) + } + } + + location := azure.NormalizeLocation(d.Get("location").(string)) + authorizations := d.Get("authorization").(*schema.Set).List() + displayName := d.Get("display_name").(string) + description := d.Get("description").(string) + enabled := d.Get("enabled").(bool) + lockLevel := d.Get("lock_level").(string) + t := d.Get("tags").(map[string]interface{}) + + parameters := managedapplications.ApplicationDefinition{ + Location: utils.String(location), + ApplicationDefinitionProperties: &managedapplications.ApplicationDefinitionProperties{ + Authorizations: expandArmManagedApplicationDefinitionAuthorization(authorizations), + Description: utils.String(description), + DisplayName: utils.String(displayName), + IsEnabled: utils.Bool(enabled), + LockLevel: managedapplications.ApplicationLockLevel(lockLevel), + }, + Tags: tags.Expand(t), + } + + if v, ok := d.GetOk("create_ui_definition"); ok { + parameters.CreateUIDefinition = utils.String(v.(string)) + } + + if v, ok := d.GetOk("main_template"); ok { + parameters.MainTemplate = utils.String(v.(string)) + } + + if v, ok := d.GetOk("package_file_uri"); ok { + parameters.PackageFileURI = utils.String(v.(string)) + } + + future, err := client.CreateOrUpdate(ctx, resourceGroupName, name, parameters) + if err != nil { + return fmt.Errorf("Error creating Managed Application Definition (Managed Application Definition Name %q / Resource Group %q): %+v", name, resourceGroupName, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for creation of Managed Application Definition (Managed Application Definition Name %q / Resource Group %q): %+v", name, resourceGroupName, err) + } + + resp, err := client.Get(ctx, resourceGroupName, name) + if err != nil { + return fmt.Errorf("Error retrieving Managed Application Definition (Managed Application Definition Name %q / Resource Group %q): %+v", name, resourceGroupName, err) + } + if resp.ID == nil || *resp.ID == "" { + return fmt.Errorf("Cannot read Managed Application Definition (Managed Application Definition Name %q / Resource Group %q) ID", name, resourceGroupName) + } + d.SetId(*resp.ID) + + return resourceArmManagedApplicationDefinitionRead(d, meta) +} + +func resourceArmManagedApplicationDefinitionRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ManagedApplication.ApplicationDefinitionClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroupName := id.ResourceGroup + name := id.Path["applicationDefinitions"] + + resp, err := client.Get(ctx, resourceGroupName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Managed Application Definition %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("Error reading Managed Application Definition (Managed Application Definition Name %q / Resource Group %q): %+v", name, resourceGroupName, err) + } + + d.Set("name", name) + d.Set("resource_group_name", resourceGroupName) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if props := resp.ApplicationDefinitionProperties; props != nil { + if err := d.Set("authorization", flattenArmManagedApplicationDefinitionAuthorization(props.Authorizations)); err != nil { + return fmt.Errorf("Error setting `authorization`: %+v", err) + } + d.Set("description", props.Description) + d.Set("display_name", props.DisplayName) + d.Set("enabled", props.IsEnabled) + d.Set("lock_level", string(props.LockLevel)) + } + if v, ok := d.GetOk("create_ui_definition"); ok { + d.Set("create_ui_definition", v.(string)) + } + if v, ok := d.GetOk("main_template"); ok { + d.Set("main_template", v.(string)) + } + if v, ok := d.GetOk("package_file_uri"); ok { + d.Set("package_file_uri", v.(string)) + } + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceArmManagedApplicationDefinitionDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ManagedApplication.ApplicationDefinitionClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroupName := id.ResourceGroup + name := id.Path["applicationDefinitions"] + + future, err := client.Delete(ctx, resourceGroupName, name) + if err != nil { + return fmt.Errorf("Error deleting Managed Application Definition (Managed Application Definition Name %q / Resource Group %q): %+v", name, resourceGroupName, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("Error waiting for deleting Managed Application Definition (Managed Application Definition Name %q / Resource Group %q): %+v", name, resourceGroupName, err) + } + } + + return nil +} + +func expandArmManagedApplicationDefinitionAuthorization(input []interface{}) *[]managedapplications.ApplicationAuthorization { + results := make([]managedapplications.ApplicationAuthorization, 0) + for _, item := range input { + v := item.(map[string]interface{}) + result := managedapplications.ApplicationAuthorization{ + RoleDefinitionID: utils.String(v["role_definition_id"].(string)), + PrincipalID: utils.String(v["service_principal_id"].(string)), + } + + results = append(results, result) + } + return &results +} + +func flattenArmManagedApplicationDefinitionAuthorization(input *[]managedapplications.ApplicationAuthorization) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + servicePrincipalId := "" + if item.PrincipalID != nil { + servicePrincipalId = *item.PrincipalID + } + + roleDefinitionId := "" + if item.RoleDefinitionID != nil { + roleDefinitionId = *item.RoleDefinitionID + } + + results = append(results, map[string]interface{}{ + "role_definition_id": roleDefinitionId, + "service_principal_id": servicePrincipalId, + }) + } + + return results +} diff --git a/azurerm/internal/services/managedapplication/tests/data_source_managed_application_definition_test.go b/azurerm/internal/services/managedapplication/tests/data_source_managed_application_definition_test.go new file mode 100644 index 000000000000..229b63ae2530 --- /dev/null +++ b/azurerm/internal/services/managedapplication/tests/data_source_managed_application_definition_test.go @@ -0,0 +1,38 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" +) + +func TestAccDataSourceAzureRMManagedApplicationDefinition_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_managed_application_definition", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceManagedApplicationDefinition_basic(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(data.ResourceName, "name"), + ), + }, + }, + }) +} + +func testAccDataSourceManagedApplicationDefinition_basic(data acceptance.TestData) string { + config := testAccAzureRMManagedApplicationDefinition_basic(data) + return fmt.Sprintf(` +%s + +data "azurerm_managed_application_definition" "test" { + resource_group_name = "${azurerm_managed_application_definition.test.resource_group_name}" + name = "${azurerm_managed_application_definition.test.name}" +} +`, config) +} diff --git a/azurerm/internal/services/managedapplication/tests/resource_arm_managed_application_definition_test.go b/azurerm/internal/services/managedapplication/tests/resource_arm_managed_application_definition_test.go new file mode 100644 index 000000000000..4718ead8dae1 --- /dev/null +++ b/azurerm/internal/services/managedapplication/tests/resource_arm_managed_application_definition_test.go @@ -0,0 +1,323 @@ +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/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMManagedApplicationDefinition_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_managed_application_definition", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMManagedApplicationDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMManagedApplicationDefinition_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMManagedApplicationDefinitionExists(data.ResourceName), + ), + }, + data.ImportStep("package_file_uri"), + }, + }) +} + +func TestAccAzureRMManagedApplicationDefinition_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + data := acceptance.BuildTestData(t, "azurerm_managed_application_definition", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMManagedApplicationDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMManagedApplicationDefinition_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMManagedApplicationDefinitionExists(data.ResourceName), + ), + }, + { + Config: testAccAzureRMManagedApplicationDefinition_requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_managed_application_definition"), + }, + }, + }) +} + +func TestAccAzureRMManagedApplicationDefinition_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_managed_application_definition", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMManagedApplicationDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMManagedApplicationDefinition_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMManagedApplicationDefinitionExists(data.ResourceName), + ), + }, + data.ImportStep("create_ui_definition", "main_template"), + }, + }) +} + +func TestAccAzureRMManagedApplicationDefinition_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_managed_application_definition", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMManagedApplicationDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMManagedApplicationDefinition_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMManagedApplicationDefinitionExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "display_name", "TestManagedApplicationDefinition"), + resource.TestCheckResourceAttr(data.ResourceName, "description", "Test Managed Application Definition"), + resource.TestCheckResourceAttr(data.ResourceName, "enabled", "false"), + resource.TestCheckResourceAttr(data.ResourceName, "tags.%", "0"), + ), + }, + data.ImportStep("package_file_uri"), + { + Config: testAccAzureRMManagedApplicationDefinition_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMManagedApplicationDefinitionExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "display_name", "UpdatedTestManagedApplicationDefinition"), + resource.TestCheckResourceAttr(data.ResourceName, "description", "Updated Test Managed Application Definition"), + resource.TestCheckResourceAttr(data.ResourceName, "enabled", "true"), + resource.TestCheckResourceAttr(data.ResourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(data.ResourceName, "tags.ENV", "Test"), + ), + }, + data.ImportStep("create_ui_definition", "main_template", "package_file_uri"), + }, + }) +} + +func testCheckAzureRMManagedApplicationDefinitionExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Managed Application Definition not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + client := acceptance.AzureProvider.Meta().(*clients.Client).ManagedApplication.ApplicationDefinitionClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + if resp, err := client.Get(ctx, resourceGroup, name); err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Managed Application Definition %q (Resource Group %q) does not exist", name, resourceGroup) + } + return fmt.Errorf("Bad: Get on ManagedApplication.ApplicationDefinitionClient: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMManagedApplicationDefinitionDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).ManagedApplication.ApplicationDefinitionClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_managed_application_definition" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + if resp, err := client.Get(ctx, resourceGroup, name); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Get on ManagedApplication.ApplicationDefinitionClient: %+v", err) + } + } + + return nil + } + + return nil +} + +func testAccAzureRMManagedApplicationDefinition_basic(data acceptance.TestData) string { + template := testAccAzureRMManagedApplicationDefinition_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_managed_application_definition" "test" { + name = "acctestAppDef%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + lock_level = "ReadOnly" + package_file_uri = "https://github.com/Azure/azure-managedapp-samples/raw/master/Managed Application Sample Packages/201-managed-storage-account/managedstorage.zip" + display_name = "TestManagedApplicationDefinition" + description = "Test Managed Application Definition" + enabled = false + + authorization { + service_principal_id = "${data.azurerm_client_config.current.object_id}" + role_definition_id = "b24988ac-6180-42a0-ab88-20f7382dd24c" + } +} +`, template, data.RandomInteger) +} + +func testAccAzureRMManagedApplicationDefinition_requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_managed_application_definition" "import" { + name = "${azurerm_managed_application_definition.test.name}" + location = "${azurerm_managed_application_definition.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, testAccAzureRMManagedApplicationDefinition_basic(data)) +} + +func testAccAzureRMManagedApplicationDefinition_complete(data acceptance.TestData) string { + template := testAccAzureRMManagedApplicationDefinition_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_managed_application_definition" "test" { + name = "acctestAppDef%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + lock_level = "ReadOnly" + display_name = "UpdatedTestManagedApplicationDefinition" + description = "Updated Test Managed Application Definition" + enabled = true + + create_ui_definition = <azurerm_managed_disk +
  • + azurerm_managed_application_definition +
  • +
  • azurerm_management_group
  • @@ -1518,6 +1522,9 @@
  • azurerm_management_group
  • +
  • + azurerm_managed_application_definition +
  • diff --git a/website/docs/d/managed_application_definition.html.markdown b/website/docs/d/managed_application_definition.html.markdown new file mode 100644 index 000000000000..ba58c891d145 --- /dev/null +++ b/website/docs/d/managed_application_definition.html.markdown @@ -0,0 +1,64 @@ +--- +subcategory: "Solutions" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_managed_application_definition" +description: |- + Gets information about an existing Managed Application Definition +--- + +# Data Source: azurerm_managed_application_definition + +Uses this data source to access information about an existing Managed Application Definition. + +## Managed Application Definition Usage + +```hcl +data "azurerm_managed_application_definition" "example" { + resource_group_name = "acctestRG" + name = "acctestmanagedapplicationdefinition" +} + +output "managed_application_definition_id" { + value = "${data.azurerm_managed_application_definition.example.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Managed Application Definition. + +* `resource_group_name` - (Required) The Name of the Resource Group where the Managed Application Definition exists. + +## Attributes Reference + +The following attributes are exported: + +* `location` - The Azure Region where the Managed Application Definition exists. + +* `authorization` - One or more `authorization` block defined below. + +* `display_name` - The managed application definition display name. + +* `lock_level` - The managed application lock level. Valid values include `CanNotDelete`, `None`, `ReadOnly`. Changing this forces a new resource to be created. + +* `create_ui_definition` - The createUiDefinition json for the backing template with Microsoft.Solutions/applications resource. + +* `description` - The managed application definition description. + +* `enabled` - The value indicating whether the package is enabled or not. + +* `main_template` - The inline main template json which has resources to be provisioned. + +* `package_file_uri` - The managed application definition package file Uri. + +* `tags` - A mapping of tags to assign to the resource. + +--- + +An `authorization` block supports the following: + +* `service_principal_id` - The provider's principal identifier. This is the identity that the provider will use to call ARM to manage the managed application resources. + +* `role_definition_id` - The provider's role definition identifier. This role will define all the permissions that the provider must have on the managed application's container resource group. This role definition cannot have permission to delete the resource group. diff --git a/website/docs/r/managed_application_definition.html.markdown b/website/docs/r/managed_application_definition.html.markdown new file mode 100644 index 000000000000..2055b3b9f448 --- /dev/null +++ b/website/docs/r/managed_application_definition.html.markdown @@ -0,0 +1,85 @@ +--- +subcategory: "Solutions" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_managed_application_definition" +description: |- + Manages a Managed Application Definition. +--- + +# azurerm_managed_application_definition + +Manages a Managed Application Definition. + +## Managed Application Definition Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} +resource "azurerm_managed_application_definition" "example" { + name = "example-managedapplicationdefinition" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + lock_level = "ReadOnly" + package_file_uri = "https://github.com/Azure/azure-managedapp-samples/raw/master/Managed Application Sample Packages/201-managed-storage-account/managedstorage.zip" + display_name = "TestManagedApplicationDefinition" + description = "Test Managed Application Definition" + authorization { + service_principal_id = "a1ac7e8c-14d3-432d-8c9b-0f780f99ef1e" + role_definition_id = "a094b430-dad3-424d-ae58-13f72fd72591" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Managed Application Definition. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group where the Managed Application Definition should be created. Changing this forces a new resource to be created. + +* `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. + +* `authorization` - (Required) One or more `authorization` block defined below. + +* `display_name` - (Optional) The managed application definition display name. + +* `lock_level` - (Optional) The managed application lock level. Valid values include `CanNotDelete`, `None`, `ReadOnly`. Changing this forces a new resource to be created. + +* `create_ui_definition` - (Optional) The createUiDefinition json for the backing template with Microsoft.Solutions/applications resource. + +* `description` - (Optional) The managed application definition description. + +* `enabled` - (Optional) The value indicating whether the package is enabled or not. + +* `main_template` - (Optional) The inline main template json which has resources to be provisioned. + +* `package_file_uri` - (Optional) The managed application definition package file Uri. + +* `tags` - (Optional) A mapping of tags to assign to the resource. + +--- + +An `authorization` block supports the following: + +* `service_principal_id` - (Required) The provider's principal identifier. This is the identity that the provider will use to call ARM to manage the managed application resources. + +* `role_definition_id` - (Required) The provider's role definition identifier. This role will define all the permissions that the provider must have on the managed application's container resource group. This role definition cannot have permission to delete the resource group. + +--- + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Managed Application Definition. + +## Import + +Managed Application Definition can be imported using the `resource id`, e.g. + +```shell +$ terraform import azurerm_managed_application_definition.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Solutions/applicationDefinitions/appDefinition1 +```