diff --git a/azurerm/internal/services/eventgrid/client/client.go b/azurerm/internal/services/eventgrid/client/client.go index 2e74b0c0f3c0..4ed958b3b7e7 100644 --- a/azurerm/internal/services/eventgrid/client/client.go +++ b/azurerm/internal/services/eventgrid/client/client.go @@ -7,6 +7,7 @@ import ( type Client struct { DomainsClient *eventgrid.DomainsClient + DomainTopicsClient *eventgrid.DomainTopicsClient EventSubscriptionsClient *eventgrid.EventSubscriptionsClient TopicsClient *eventgrid.TopicsClient } @@ -15,6 +16,9 @@ func NewClient(o *common.ClientOptions) *Client { DomainsClient := eventgrid.NewDomainsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&DomainsClient.Client, o.ResourceManagerAuthorizer) + DomainTopicsClient := eventgrid.NewDomainTopicsClient(o.SubscriptionId) + o.ConfigureClient(&DomainTopicsClient.Client, o.ResourceManagerAuthorizer) + EventSubscriptionsClient := eventgrid.NewEventSubscriptionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&EventSubscriptionsClient.Client, o.ResourceManagerAuthorizer) @@ -24,6 +28,7 @@ func NewClient(o *common.ClientOptions) *Client { return &Client{ DomainsClient: &DomainsClient, EventSubscriptionsClient: &EventSubscriptionsClient, + DomainTopicsClient: &DomainTopicsClient, TopicsClient: &TopicsClient, } } diff --git a/azurerm/internal/services/eventgrid/eventgrid_domain_topic_resource.go b/azurerm/internal/services/eventgrid/eventgrid_domain_topic_resource.go new file mode 100644 index 000000000000..0e3fa23e47b2 --- /dev/null +++ b/azurerm/internal/services/eventgrid/eventgrid_domain_topic_resource.go @@ -0,0 +1,153 @@ +package eventgrid + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/go-azure-helpers/response" + "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/helpers/tf" + "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/services/eventgrid/parse" + 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 resourceArmEventGridDomainTopic() *schema.Resource { + return &schema.Resource{ + Create: resourceArmEventGridDomainTopicCreate, + Read: resourceArmEventGridDomainTopicRead, + Delete: resourceArmEventGridDomainTopicDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.EventGridDomainTopicID(id) + return err + }), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + }, + } +} + +func resourceArmEventGridDomainTopicCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).EventGrid.DomainTopicsClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + domainName := d.Get("domain_name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, domainName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing EventGrid Domain Topic %q (Resource Group %q): %s", name, resourceGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_eventgrid_domain_topic", *existing.ID) + } + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, domainName, name) + if err != nil { + return fmt.Errorf("Error creating/updating EventGrid Domain Topic %q (Resource Group %q): %s", name, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for EventGrid Domain Topic %q (Resource Group %q) to become available: %s", name, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, domainName, name) + if err != nil { + return fmt.Errorf("Error retrieving EventGrid Domain Topic %q (Resource Group %q): %s", name, resourceGroup, err) + } + if read.ID == nil { + return fmt.Errorf("Cannot read EventGrid Domain Topic %q (resource group %s) ID", name, resourceGroup) + } + + d.SetId(*read.ID) + + return resourceArmEventGridDomainTopicRead(d, meta) +} + +func resourceArmEventGridDomainTopicRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).EventGrid.DomainTopicsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.EventGridDomainTopicID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.Domain, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[WARN] EventGrid Domain Topic %q was not found (Resource Group %q)", id.Name, id.ResourceGroup) + d.SetId("") + return nil + } + + return fmt.Errorf("Error making Read request on EventGrid Domain Topic %q: %+v", id.Name, err) + } + + d.Set("name", resp.Name) + d.Set("domain_name", id.Domain) + d.Set("resource_group_name", id.ResourceGroup) + + return nil +} + +func resourceArmEventGridDomainTopicDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).EventGrid.DomainTopicsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.EventGridDomainTopicID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.Domain, id.Name) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error deleting EventGrid Domain Topic %q: %+v", id.Name, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error deleting EventGrid Domain Topic %q: %+v", id.Name, err) + } + + return nil +} diff --git a/azurerm/internal/services/eventgrid/parse/eventgrid_domain_topic.go b/azurerm/internal/services/eventgrid/parse/eventgrid_domain_topic.go new file mode 100644 index 000000000000..f11961171e95 --- /dev/null +++ b/azurerm/internal/services/eventgrid/parse/eventgrid_domain_topic.go @@ -0,0 +1,38 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type EventGridDomainTopicId struct { + ResourceGroup string + Name string + Domain string +} + +func EventGridDomainTopicID(input string) (*EventGridDomainTopicId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse EventGrid Domain Topic ID %q: %+v", input, err) + } + + domainTopic := EventGridDomainTopicId{ + ResourceGroup: id.ResourceGroup, + } + + if domainTopic.Name, err = id.PopSegment("topics"); err != nil { + return nil, err + } + + if domainTopic.Domain, err = id.PopSegment("domains"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &domainTopic, nil +} diff --git a/azurerm/internal/services/eventgrid/registration.go b/azurerm/internal/services/eventgrid/registration.go index f1b2feda1dc8..7ea4410b7d24 100644 --- a/azurerm/internal/services/eventgrid/registration.go +++ b/azurerm/internal/services/eventgrid/registration.go @@ -29,6 +29,7 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ "azurerm_eventgrid_domain": resourceArmEventGridDomain(), + "azurerm_eventgrid_domain_topic": resourceArmEventGridDomainTopic(), "azurerm_eventgrid_event_subscription": resourceArmEventGridEventSubscription(), "azurerm_eventgrid_topic": resourceArmEventGridTopic(), } diff --git a/azurerm/internal/services/eventgrid/tests/eventgrid_domain_topic_resource_test.go b/azurerm/internal/services/eventgrid/tests/eventgrid_domain_topic_resource_test.go new file mode 100644 index 000000000000..62eef498b5a9 --- /dev/null +++ b/azurerm/internal/services/eventgrid/tests/eventgrid_domain_topic_resource_test.go @@ -0,0 +1,149 @@ +package tests + +import ( + "fmt" + "net/http" + "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/utils" +) + +func TestAccAzureRMEventGridDomainTopic_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_domain_topic", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMEventGridDomainTopicDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMEventGridDomainTopic_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMEventGridDomainTopicExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMEventGridDomainTopic_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_domain_topic", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMEventGridTopicDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMEventGridDomainTopic_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMEventGridDomainTopicExists(data.ResourceName), + ), + }, + { + Config: testAccAzureRMEventGridDomainTopic_requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_eventgrid_domain_topic"), + }, + }, + }) +} + +func testCheckAzureRMEventGridDomainTopicDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).EventGrid.DomainTopicsClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_eventgrid_domain_topic" { + continue + } + + name := rs.Primary.Attributes["name"] + domainName := rs.Primary.Attributes["domain_name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := client.Get(ctx, resourceGroup, domainName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return err + } + + if resp.StatusCode != http.StatusNotFound { + return fmt.Errorf("EventGrid Domain Topic still exists:\n%#v", resp) + } + } + + return nil +} + +func testCheckAzureRMEventGridDomainTopicExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).EventGrid.DomainTopicsClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + domainName := rs.Primary.Attributes["domain_name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for EventGrid Domain Topic: %s", name) + } + + resp, err := client.Get(ctx, resourceGroup, domainName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: EventGrid Domain Topic %q (resource group: %s) does not exist", name, resourceGroup) + } + + return fmt.Errorf("Bad: Get on EventGrid.DomainTopicsClient: %s", err) + } + + return nil + } +} + +func testAccAzureRMEventGridDomainTopic_basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} +resource "azurerm_eventgrid_domain" "test" { + name = "acctestegdomain-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} +resource "azurerm_eventgrid_domain_topic" "test" { + name = "acctestegtopic-%d" + domain_name = azurerm_eventgrid_domain.test.name + resource_group_name = azurerm_resource_group.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMEventGridDomainTopic_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMEventGridDomainTopic_basic(data) + return fmt.Sprintf(` +%s +resource "azurerm_eventgrid_domain_topic" "import" { + name = azurerm_eventgrid_domain_topic.test.name + domain_name = azurerm_eventgrid_domain_topic.test.domain_name + resource_group_name = azurerm_eventgrid_domain_topic.test.resource_group_name +} +`, template) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 685e43574374..0ce801bf38ad 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -1793,6 +1793,10 @@
  • azurerm_eventgrid_domain
  • + +
  • + azurerm_eventgrid_domain_topic +
  • azurerm_eventgrid_event_subscription diff --git a/website/docs/r/eventgrid_domain_topic.html.markdown b/website/docs/r/eventgrid_domain_topic.html.markdown new file mode 100644 index 000000000000..1a1f45ede7dc --- /dev/null +++ b/website/docs/r/eventgrid_domain_topic.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: "Messaging" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_eventgrid_domain_topic" +description: |- + Manages an EventGrid Domain Topic +--- + +# azurerm_eventgrid_domain_topic + +Manages an EventGrid Domain Topic + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "resourceGroup1" + location = "West US 2" +} +resource "azurerm_eventgrid_domain" "example" { + name = "my-eventgrid-domain" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + tags = { + environment = "Production" + } +} +resource "azurerm_eventgrid_domain_topic" "example" { + name = "my-eventgrid-domain-topic" + domain_name = azurerm_eventgrid_domain.example.name + resource_group_name = azurerm_resource_group.example.name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of the EventGrid Domain Topic resource. Changing this forces a new resource to be created. + +* `domain_name` - (Required) Specifies the name of the EventGrid Domain. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group in which the EventGrid Domain exists. Changing this forces a new resource to be created. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the EventGrid Domain Topic. + +## 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 EventGrid Domain Topic. +* `update` - (Defaults to 30 minutes) Used when updating the EventGrid Domain Topic. +* `read` - (Defaults to 5 minutes) Used when retrieving the EventGrid Domain Topic. +* `delete` - (Defaults to 30 minutes) Used when deleting the EventGrid Domain Topic. + +## Import + +EventGrid Domain Topics can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_eventgrid_domain_topic.topic1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.EventGrid/domains/domain1/topics/topic1 +``` \ No newline at end of file