diff --git a/azurerm/internal/services/logic/client/client.go b/azurerm/internal/services/logic/client/client.go index 789f0354586d..f808857045f5 100644 --- a/azurerm/internal/services/logic/client/client.go +++ b/azurerm/internal/services/logic/client/client.go @@ -6,14 +6,19 @@ import ( ) type Client struct { - WorkflowsClient *logic.WorkflowsClient + IntegrationAccountClient *logic.IntegrationAccountsClient + WorkflowsClient *logic.WorkflowsClient } func NewClient(o *common.ClientOptions) *Client { + integrationAccountClient := logic.NewIntegrationAccountsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&integrationAccountClient.Client, o.ResourceManagerAuthorizer) + WorkflowsClient := logic.NewWorkflowsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&WorkflowsClient.Client, o.ResourceManagerAuthorizer) return &Client{ - WorkflowsClient: &WorkflowsClient, + WorkflowsClient: &WorkflowsClient, + IntegrationAccountClient: &integrationAccountClient, } } diff --git a/azurerm/internal/services/logic/logic_app_integration_account_data_source.go b/azurerm/internal/services/logic/logic_app_integration_account_data_source.go new file mode 100644 index 000000000000..f4f11ba24095 --- /dev/null +++ b/azurerm/internal/services/logic/logic_app_integration_account_data_source.go @@ -0,0 +1,70 @@ +package logic + +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/location" + "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 dataSourceLogicAppIntegrationAccount() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmLogicAppIntegrationAccountRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "location": azure.SchemaLocationForDataSource(), + + "sku_name": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceArmLogicAppIntegrationAccountRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Logic.IntegrationAccountClient + 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("Logic App Integration Account Account %q does not exist in Resource Group %q", name, resourceGroup) + } + return fmt.Errorf("retrieving Logic App Integration Account Account %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + if resp.ID == nil || *resp.ID == "" { + return fmt.Errorf("reading Logic App Integration Account Account %q (Resource Group %q): ID is empty or nil", name, resourceGroup) + } + + d.SetId(*resp.ID) + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("sku_name", string(resp.Sku.Name)) + return tags.FlattenAndSet(d, resp.Tags) +} diff --git a/azurerm/internal/services/logic/logic_app_integration_account_resource.go b/azurerm/internal/services/logic/logic_app_integration_account_resource.go new file mode 100644 index 000000000000..5d6ae6c17889 --- /dev/null +++ b/azurerm/internal/services/logic/logic_app_integration_account_resource.go @@ -0,0 +1,151 @@ +package logic + +import ( + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/logic/mgmt/2019-05-01/logic" + "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/location" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/logic/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/logic/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmLogicAppIntegrationAccount() *schema.Resource { + return &schema.Resource{ + Create: resourceArmLogicAppIntegrationAccountCreateUpdate, + Read: resourceArmLogicAppIntegrationAccountRead, + Update: resourceArmLogicAppIntegrationAccountCreateUpdate, + Delete: resourceArmLogicAppIntegrationAccountDelete, + + 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), + }, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.IntegrationAccountID(id) + return err + }), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.IntegrationAccountName(), + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "location": azure.SchemaLocation(), + + "sku_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(logic.IntegrationAccountSkuNameBasic), + string(logic.IntegrationAccountSkuNameFree), + string(logic.IntegrationAccountSkuNameStandard), + }, false), + }, + + "tags": tags.Schema(), + }, + } +} +func resourceArmLogicAppIntegrationAccountCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Logic.IntegrationAccountClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + if d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for present of existing Integration Account %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_logic_app_integration_account", *existing.ID) + } + } + + account := logic.IntegrationAccount{ + IntegrationAccountProperties: &logic.IntegrationAccountProperties{}, + Location: utils.String(location.Normalize(d.Get("location").(string))), + Sku: &logic.IntegrationAccountSku{ + Name: logic.IntegrationAccountSkuName(d.Get("sku_name").(string)), + }, + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + } + + if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, account); err != nil { + return fmt.Errorf("creating Integration Account %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("retrieving Integration Account %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + if resp.ID == nil || *resp.ID == "" { + return fmt.Errorf("reading Integration Account %q (Resource Group %q): ID is empty or nil", name, resourceGroup) + } + + d.SetId(*resp.ID) + + return resourceArmLogicAppIntegrationAccountRead(d, meta) +} + +func resourceArmLogicAppIntegrationAccountRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Logic.IntegrationAccountClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.IntegrationAccountID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + if err != nil { + return fmt.Errorf("retrieving Integration Account %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)) + d.Set("sku_name", string(resp.Sku.Name)) + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceArmLogicAppIntegrationAccountDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Logic.IntegrationAccountClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.IntegrationAccountID(d.Id()) + if err != nil { + return err + } + + if _, err := client.Delete(ctx, id.ResourceGroup, id.Name); err != nil { + return fmt.Errorf("deleting Integration Account %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + return nil +} diff --git a/azurerm/internal/services/logic/logic_app_workflow_data_source.go b/azurerm/internal/services/logic/logic_app_workflow_data_source.go index 5312ecccdcfe..81b8bf726538 100644 --- a/azurerm/internal/services/logic/logic_app_workflow_data_source.go +++ b/azurerm/internal/services/logic/logic_app_workflow_data_source.go @@ -32,6 +32,11 @@ func dataSourceArmLogicAppWorkflow() *schema.Resource { "location": azure.SchemaLocationForDataSource(), + "logic_app_integration_account_id": { + Type: schema.TypeString, + Computed: true, + }, + // TODO: should Parameters be split out into their own object to allow validation on the different sub-types? "parameters": { Type: schema.TypeMap, @@ -134,6 +139,10 @@ func dataSourceArmLogicAppWorkflowRead(d *schema.ResourceData, meta interface{}) d.Set("workflow_version", v["contentVersion"].(string)) } } + + if props.IntegrationAccount != nil && props.IntegrationAccount.ID != nil { + d.Set("logic_app_integration_account_id", props.IntegrationAccount.ID) + } } return tags.FlattenAndSet(d, resp.Tags) diff --git a/azurerm/internal/services/logic/logic_app_workflow_resource.go b/azurerm/internal/services/logic/logic_app_workflow_resource.go index 8a4b91556be8..fe1544a6e0f0 100644 --- a/azurerm/internal/services/logic/logic_app_workflow_resource.go +++ b/azurerm/internal/services/logic/logic_app_workflow_resource.go @@ -12,6 +12,7 @@ import ( "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/locks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/logic/validate" "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" @@ -47,6 +48,12 @@ func resourceArmLogicAppWorkflow() *schema.Resource { "resource_group_name": azure.SchemaResourceGroupName(), + "logic_app_integration_account_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.IntegrationAccountID, + }, + // TODO: should Parameters be split out into their own object to allow validation on the different sub-types? "parameters": { Type: schema.TypeMap, @@ -145,6 +152,12 @@ func resourceArmLogicAppWorkflowCreate(d *schema.ResourceData, meta interface{}) Tags: tags.Expand(t), } + if v, ok := d.GetOk("logic_app_integration_account_id"); ok { + properties.WorkflowProperties.IntegrationAccount = &logic.ResourceReference{ + ID: utils.String(v.(string)), + } + } + if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, properties); err != nil { return fmt.Errorf("[ERROR] Error creating Logic App Workflow %q (Resource Group %q): %+v", name, resourceGroup, err) } @@ -206,6 +219,12 @@ func resourceArmLogicAppWorkflowUpdate(d *schema.ResourceData, meta interface{}) Tags: tags.Expand(t), } + if v, ok := d.GetOk("logic_app_integration_account_id"); ok { + properties.WorkflowProperties.IntegrationAccount = &logic.ResourceReference{ + ID: utils.String(v.(string)), + } + } + if _, err = client.CreateOrUpdate(ctx, resourceGroup, name, properties); err != nil { return fmt.Errorf("Error updating Logic App Workspace %q (Resource Group %q): %+v", name, resourceGroup, err) } @@ -271,6 +290,10 @@ func resourceArmLogicAppWorkflowRead(d *schema.ResourceData, meta interface{}) e d.Set("workflow_version", v["contentVersion"].(string)) } } + + if props.IntegrationAccount != nil && props.IntegrationAccount.ID != nil { + d.Set("logic_app_integration_account_id", props.IntegrationAccount.ID) + } } return tags.FlattenAndSet(d, resp.Tags) diff --git a/azurerm/internal/services/logic/parse/logic.go b/azurerm/internal/services/logic/parse/logic.go new file mode 100644 index 000000000000..4ff050e81d3f --- /dev/null +++ b/azurerm/internal/services/logic/parse/logic.go @@ -0,0 +1,31 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type IntegrationAccountId struct { + ResourceGroup string + Name string +} + +func IntegrationAccountID(input string) (*IntegrationAccountId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("parsing Integration Account ID %q: %+v", input, err) + } + + IntegrationAccount := IntegrationAccountId{ + ResourceGroup: id.ResourceGroup, + } + if IntegrationAccount.Name, err = id.PopSegment("integrationAccounts"); err != nil { + return nil, err + } + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &IntegrationAccount, nil +} diff --git a/azurerm/internal/services/logic/parse/logic_test.go b/azurerm/internal/services/logic/parse/logic_test.go new file mode 100644 index 000000000000..d1ca561b5b15 --- /dev/null +++ b/azurerm/internal/services/logic/parse/logic_test.go @@ -0,0 +1,70 @@ +package parse + +import "testing" + +func TestIntegrationAccountID(t *testing.T) { + testData := []struct { + Name string + Input string + Expected *IntegrationAccountId + }{ + { + Name: "Empty", + Input: "", + Expected: nil, + }, + { + Name: "No Resource Groups Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Expected: nil, + }, + { + Name: "No Resource Groups Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + Expected: nil, + }, + { + Name: "Resource Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/", + Expected: nil, + }, + { + Name: "Missing Account Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Logic/integrationAccounts/", + Expected: nil, + }, + { + Name: "Integration account ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Logic/integrationAccounts/account1", + Expected: &IntegrationAccountId{ + Name: "account1", + ResourceGroup: "resGroup1", + }, + }, + { + Name: "Wrong Casing", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Logic/IntegrationAccounts/account1", + Expected: nil, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q..", v.Name) + + actual, err := IntegrationAccountID(v.Input) + if err != nil { + if v.Expected == nil { + continue + } + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/logic/registration.go b/azurerm/internal/services/logic/registration.go index 7aca0d65af47..4fbd69f3a879 100644 --- a/azurerm/internal/services/logic/registration.go +++ b/azurerm/internal/services/logic/registration.go @@ -21,7 +21,8 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_logic_app_workflow": dataSourceArmLogicAppWorkflow(), + "azurerm_logic_app_workflow": dataSourceArmLogicAppWorkflow(), + "azurerm_logic_app_integration_account": dataSourceLogicAppIntegrationAccount(), } } @@ -30,6 +31,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ "azurerm_logic_app_action_custom": resourceArmLogicAppActionCustom(), "azurerm_logic_app_action_http": resourceArmLogicAppActionHTTP(), + "azurerm_logic_app_integration_account": resourceArmLogicAppIntegrationAccount(), "azurerm_logic_app_trigger_custom": resourceArmLogicAppTriggerCustom(), "azurerm_logic_app_trigger_http_request": resourceArmLogicAppTriggerHttpRequest(), "azurerm_logic_app_trigger_recurrence": resourceArmLogicAppTriggerRecurrence(), diff --git a/azurerm/internal/services/logic/tests/logic_app_integration_account_data_source_test.go b/azurerm/internal/services/logic/tests/logic_app_integration_account_data_source_test.go new file mode 100644 index 000000000000..559742d729bb --- /dev/null +++ b/azurerm/internal/services/logic/tests/logic_app_integration_account_data_source_test.go @@ -0,0 +1,42 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" +) + +func TestAccDataSourceAzureRMLogicAppIntegrationAccount_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_logic_app_integration_account", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogicAppIntegrationAccountDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceLogicAppIntegrationAccount_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppIntegrationAccountExists(data.ResourceName), + resource.TestCheckResourceAttrSet(data.ResourceName, "location"), + resource.TestCheckResourceAttrSet(data.ResourceName, "sku_name"), + resource.TestCheckResourceAttrSet(data.ResourceName, "tags.%"), + resource.TestCheckResourceAttrSet(data.ResourceName, "tags.ENV"), + ), + }, + }, + }) +} + +func testAccDataSourceLogicAppIntegrationAccount_basic(data acceptance.TestData) string { + config := testAccAzureRMLogicAppIntegrationAccount_complete(data) + return fmt.Sprintf(` +%s + +data "azurerm_logic_app_integration_account" "test" { + name = azurerm_logic_app_integration_account.test.name + resource_group_name = azurerm_resource_group.test.name +} +`, config) +} diff --git a/azurerm/internal/services/logic/tests/logic_app_integration_account_resource_test.go b/azurerm/internal/services/logic/tests/logic_app_integration_account_resource_test.go new file mode 100644 index 000000000000..434d598c74de --- /dev/null +++ b/azurerm/internal/services/logic/tests/logic_app_integration_account_resource_test.go @@ -0,0 +1,228 @@ +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/services/logic/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMLogicAppIntegrationAccount_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_logic_app_integration_account", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogicAppIntegrationAccountDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogicAppIntegrationAccount_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppIntegrationAccountExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMLogicAppIntegrationAccount_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_logic_app_integration_account", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogicAppIntegrationAccountDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogicAppIntegrationAccount_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppIntegrationAccountExists(data.ResourceName), + ), + }, + data.RequiresImportErrorStep(testAccAzureRMLogicAppIntegrationAccount_requiresImport), + }, + }) +} + +func TestAccAzureRMLogicAppIntegrationAccount_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_logic_app_integration_account", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogicAppIntegrationAccountDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogicAppIntegrationAccount_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppIntegrationAccountExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMLogicAppIntegrationAccount_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_logic_app_integration_account", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogicAppIntegrationAccountDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogicAppIntegrationAccount_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppIntegrationAccountExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMLogicAppIntegrationAccount_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppIntegrationAccountExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMLogicAppIntegrationAccount_update(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppIntegrationAccountExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMLogicAppIntegrationAccount_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppIntegrationAccountExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func testCheckAzureRMLogicAppIntegrationAccountExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Logic.IntegrationAccountClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Integration Account not found: %s", resourceName) + } + id, err := parse.IntegrationAccountID(rs.Primary.ID) + if err != nil { + return err + } + if resp, err := client.Get(ctx, id.ResourceGroup, id.Name); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("bad: integration account %q does not exist", id.Name) + } + return fmt.Errorf("bad: Get on LogicAppIntegrationAccountClient: %+v", err) + } + return nil + } +} + +func testCheckAzureRMLogicAppIntegrationAccountDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Logic.IntegrationAccountClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_logic_app_integration_account" { + continue + } + id, err := parse.IntegrationAccountID(rs.Primary.ID) + if err != nil { + return err + } + if resp, err := client.Get(ctx, id.ResourceGroup, id.Name); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("bad: Get on integration.accountClient: %+v", err) + } + } + return nil + } + return nil +} + +func testAccAzureRMLogicAppIntegrationAccount_template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-logic-%d" + location = "%s" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func testAccAzureRMLogicAppIntegrationAccount_basic(data acceptance.TestData) string { + template := testAccAzureRMLogicAppIntegrationAccount_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_logic_app_integration_account" "test" { + name = "acctest-IA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" +} +`, template, data.RandomInteger) +} + +func testAccAzureRMLogicAppIntegrationAccount_requiresImport(data acceptance.TestData) string { + config := testAccAzureRMLogicAppIntegrationAccount_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_logic_app_integration_account" "import" { + name = azurerm_logic_app_integration_account.test.name + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = azurerm_logic_app_integration_account.test.sku_name +} +`, config) +} + +func testAccAzureRMLogicAppIntegrationAccount_complete(data acceptance.TestData) string { + template := testAccAzureRMLogicAppIntegrationAccount_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_logic_app_integration_account" "test" { + name = "acctest-IA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" + tags = { + ENV = "Test" + } +} +`, template, data.RandomInteger) +} + +func testAccAzureRMLogicAppIntegrationAccount_update(data acceptance.TestData) string { + template := testAccAzureRMLogicAppIntegrationAccount_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_logic_app_integration_account" "test" { + name = "acctest-IA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Standard" + tags = { + ENV = "Stage" + } +} +`, template, data.RandomInteger) +} diff --git a/azurerm/internal/services/logic/tests/logic_app_workflow_resource_test.go b/azurerm/internal/services/logic/tests/logic_app_workflow_resource_test.go index 47aa45c0657d..3c05dd4505dc 100644 --- a/azurerm/internal/services/logic/tests/logic_app_workflow_resource_test.go +++ b/azurerm/internal/services/logic/tests/logic_app_workflow_resource_test.go @@ -89,6 +89,46 @@ func TestAccAzureRMLogicAppWorkflow_tags(t *testing.T) { }) } +func TestAccAzureRMLogicAppWorkflow_integrationAccount(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_logic_app_workflow", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogicAppWorkflowDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogicAppWorkflow_empty(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppWorkflowExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMLogicAppWorkflow_integrationAccount(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppWorkflowExists(data.ResourceName), + ), + }, + data.ImportStep("logic_app_integration_account_id"), + { + Config: testAccAzureRMLogicAppWorkflow_integrationAccountUpdated(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppWorkflowExists(data.ResourceName), + ), + }, + data.ImportStep("logic_app_integration_account_id"), + { + Config: testAccAzureRMLogicAppWorkflow_empty(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogicAppWorkflowExists(data.ResourceName), + ), + }, + data.ImportStep("logic_app_integration_account_id"), + }, + }) +} + func testCheckAzureRMLogicAppWorkflowExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Logic.WorkflowsClient @@ -151,7 +191,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" + name = "acctestRG-logic-%d" location = "%s" } @@ -198,3 +238,71 @@ resource "azurerm_logic_app_workflow" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func testAccAzureRMLogicAppWorkflow_integrationAccount(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-logic-%[1]d" + location = "%[2]s" +} + +resource "azurerm_logic_app_integration_account" "test" { + name = "acctest-IA-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" +} + +resource "azurerm_logic_app_integration_account" "test2" { + name = "acctest-IA2-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" +} + +resource "azurerm_logic_app_workflow" "test" { + name = "acctestlaw-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + logic_app_integration_account_id = azurerm_logic_app_integration_account.test.id +} +`, data.RandomInteger, data.Locations.Primary) +} + +func testAccAzureRMLogicAppWorkflow_integrationAccountUpdated(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-logic-%[1]d" + location = "%[2]s" +} + +resource "azurerm_logic_app_integration_account" "test" { + name = "acctest-IA-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" +} + +resource "azurerm_logic_app_integration_account" "test2" { + name = "acctest-IA2-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" +} + +resource "azurerm_logic_app_workflow" "test" { + name = "acctestlaw-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + logic_app_integration_account_id = azurerm_logic_app_integration_account.test2.id +} +`, data.RandomInteger, data.Locations.Primary) +} diff --git a/azurerm/internal/services/logic/validate/logic.go b/azurerm/internal/services/logic/validate/logic.go new file mode 100644 index 000000000000..9c61b191fc82 --- /dev/null +++ b/azurerm/internal/services/logic/validate/logic.go @@ -0,0 +1,30 @@ +package validate + +import ( + "fmt" + "regexp" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/logic/parse" +) + +func IntegrationAccountName() schema.SchemaValidateFunc { + return validation.StringMatch( + regexp.MustCompile(`^[\w-().]{1,80}$`), `Integration name can contain only letters, numbers, '_','-', '(', ')' or '.'`, + ) +} + +func IntegrationAccountID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return warnings, errors + } + + if _, err := parse.IntegrationAccountID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a Integration Account resource id: %v", k, err)) + } + + return warnings, errors +} diff --git a/azurerm/internal/services/logic/validate/logic_test.go b/azurerm/internal/services/logic/validate/logic_test.go new file mode 100644 index 000000000000..ce0f8f37051c --- /dev/null +++ b/azurerm/internal/services/logic/validate/logic_test.go @@ -0,0 +1,62 @@ +package validate + +import "testing" + +func TestIntegrationAccountName(t *testing.T) { + tests := []struct { + name string + input string + valid bool + }{ + { + name: "Empty", + input: "", + valid: false, + }, + { + name: "1", + input: "1", + valid: true, + }, + { + name: "abs_def", + input: "abs_def", + valid: true, + }, + { + name: "abs.def", + input: "abs.def", + valid: true, + }, + { + name: "abs def", + input: "abs def", + valid: false, + }, + { + name: "abs-def", + input: "abs-def", + valid: true, + }, + { + name: "AA-bb-", + input: "AA-bb-", + valid: true, + }, + { + name: "-1-A-b", + input: "-1-A-b", + valid: true, + }, + } + var validationFunction = IntegrationAccountName() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := validationFunction(tt.input, "") + valid := err == nil + if valid != tt.valid { + t.Errorf("Expected valid status %t but got %t for input %s", tt.valid, valid, tt.input) + } + }) + } +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 0ce801bf38ad..f9eb37d17a6e 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -310,6 +310,10 @@ azurerm_log_analytics_workspace +
  • + azurerm_logic_app_integration_account +
  • +
  • azurerm_logic_app_workflow
  • @@ -1712,6 +1716,10 @@ azurerm_logic_app_action_http +
  • + azurerm_logic_app_integration_account +
  • +
  • azurerm_logic_app_trigger_custom
  • diff --git a/website/docs/d/logic_app_integration_account.html.markdown b/website/docs/d/logic_app_integration_account.html.markdown new file mode 100644 index 000000000000..16b70dffd341 --- /dev/null +++ b/website/docs/d/logic_app_integration_account.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "Logic App" +layout: "azurerm" +page_title: "Azure Resource Manager: Data Source: azurerm_logic_app_integration_account" +description: |- + Gets information about an existing Logic App Integration Account. +--- + +# Data Source: azurerm_logic_app_integration_account + +Use this data source to access information about an existing Logic App Integration Account. + +## Example Usage + +```hcl +data "azurerm_logic_app_integration_account" "example" { + name = "example-account" + resource_group_name = "example-resource-group" +} + +output "id" { + value = data.azurerm_logic_app_integration_account.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name of this Logic App Integration Account. + +* `resource_group_name` - (Required) The name of the Resource Group where the Logic App Integration Account exists. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Logic App Integration Account. + +* `location` - The Azure Region where the Logic App Integration Account exists. + +* `sku_name` - The sku name of the Logic App Integration Account. + +* `tags` - A mapping of tags assigned to the Logic App Integration Account. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the Logic App Integration Account. diff --git a/website/docs/d/logic_app_workflow.html.markdown b/website/docs/d/logic_app_workflow.html.markdown index 0da4bb97eb55..7995c4705b9a 100644 --- a/website/docs/d/logic_app_workflow.html.markdown +++ b/website/docs/d/logic_app_workflow.html.markdown @@ -39,6 +39,8 @@ The following attributes are exported: * `location` - The Azure location where the Logic App Workflow exists. +* `logic_app_integration_account_id` - The ID of the integration account linked by this Logic App Workflow. + * `workflow_schema` - The Schema used for this Logic App Workflow. * `workflow_version` - The version of the Schema used for this Logic App Workflow. Defaults to `1.0.0.0`. diff --git a/website/docs/r/logic_app_integration_account.html.markdown b/website/docs/r/logic_app_integration_account.html.markdown new file mode 100644 index 000000000000..31835940e612 --- /dev/null +++ b/website/docs/r/logic_app_integration_account.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: "Logic App" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_logic_app_integration_account" +description: |- + Manages a Logic App Integration Account. +--- + +# azurerm_logic_app_integration_account + +Manages a Logic App Integration Account. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_logic_app_integration_account" "example" { + name = "example-ia" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + sku_name = "Standard" + tags = { + foo = "bar" + } +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Logic App Integration Account. Changing this forces a new Logic App Integration Account to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the Logic App Integration Account should exist. Changing this forces a new Logic App Integration Account to be created. + +* `location` - (Required) The Azure Region where the Logic App Integration Account should exist. Changing this forces a new Logic App Integration Account to be created. + +* `sku_name` - (Required) The sku name of the Logic App Integration Account. Possible Values are `Basic`, `Free` and `Standard`. + +--- + +* `tags` - (Optional) A mapping of tags which should be assigned to the Logic App Integration Account. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Logic App Integration Account. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Logic App Integration Account. +* `read` - (Defaults to 5 minutes) Used when retrieving the Logic App Integration Account. +* `update` - (Defaults to 30 minutes) Used when updating the Logic App Integration Account. +* `delete` - (Defaults to 30 minutes) Used when deleting the Logic App Integration Account. + +## Import + +Logic App Integration Accounts can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_logic_app_integration_account.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Logic/integrationAccounts/account1 +``` diff --git a/website/docs/r/logic_app_workflow.html.markdown b/website/docs/r/logic_app_workflow.html.markdown index 3d959438cb08..d3b68dd36c54 100644 --- a/website/docs/r/logic_app_workflow.html.markdown +++ b/website/docs/r/logic_app_workflow.html.markdown @@ -35,6 +35,8 @@ The following arguments are supported: * `location` - (Required) Specifies the supported Azure location where the Logic App Workflow exists. Changing this forces a new resource to be created. +* `logic_app_integration_account_id` - (Optional) The ID of the integration account linked by this Logic App Workflow. + * `workflow_schema` - (Optional) Specifies the Schema to use for this Logic App Workflow. Defaults to `https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#`. Changing this forces a new resource to be created. * `workflow_version` - (Optional) Specifies the version of the Schema used for this Logic App Workflow. Defaults to `1.0.0.0`. Changing this forces a new resource to be created.