From dc4ed942ffeb9990e18c6a366414280cb59d8d10 Mon Sep 17 00:00:00 2001 From: Yuping Wei <56525716+yupwei68@users.noreply.github.com> Date: Thu, 3 Dec 2020 10:47:41 +0800 Subject: [PATCH] Partial fix for #9211 * update azure-sdk-for-go to v47.0.0 * Updated to v47.1.0 * Update SDK to v48.0.0 * update * update * update * update * update * update * update * update * update * update * update * update * review * Resolve conflicts * Rename and move tests * Fixed test case * gofmt registration Co-authored-by: arcturusZhang Co-authored-by: Dapeng Zhang Co-authored-by: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> --- .../services/digitaltwins/client/client.go | 5 + ...gital_twins_endpoint_eventgrid_resource.go | 184 ++++++++++++ ..._twins_endpoint_eventgrid_resource_test.go | 262 ++++++++++++++++++ .../parse/digital_twins_endpoint.go | 55 ++++ .../parse/digital_twins_endpoint_test.go | 128 +++++++++ .../services/digitaltwins/registration.go | 3 +- .../services/digitaltwins/resourceids.go | 1 + .../validate/digital_twins_instance_name.go | 16 ++ ...tal_twins_endpoint_eventgrid.html.markdown | 83 ++++++ 9 files changed, 736 insertions(+), 1 deletion(-) create mode 100644 azurerm/internal/services/digitaltwins/digital_twins_endpoint_eventgrid_resource.go create mode 100644 azurerm/internal/services/digitaltwins/digital_twins_endpoint_eventgrid_resource_test.go create mode 100644 azurerm/internal/services/digitaltwins/parse/digital_twins_endpoint.go create mode 100644 azurerm/internal/services/digitaltwins/parse/digital_twins_endpoint_test.go create mode 100644 website/docs/r/digital_twins_endpoint_eventgrid.html.markdown diff --git a/azurerm/internal/services/digitaltwins/client/client.go b/azurerm/internal/services/digitaltwins/client/client.go index 30efe3c8be83..041d8e512655 100644 --- a/azurerm/internal/services/digitaltwins/client/client.go +++ b/azurerm/internal/services/digitaltwins/client/client.go @@ -6,14 +6,19 @@ import ( ) type Client struct { + EndpointClient *digitaltwins.EndpointClient InstanceClient *digitaltwins.Client } func NewClient(o *common.ClientOptions) *Client { + endpointClient := digitaltwins.NewEndpointClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&endpointClient.Client, o.ResourceManagerAuthorizer) + InstanceClient := digitaltwins.NewClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&InstanceClient.Client, o.ResourceManagerAuthorizer) return &Client{ + EndpointClient: &endpointClient, InstanceClient: &InstanceClient, } } diff --git a/azurerm/internal/services/digitaltwins/digital_twins_endpoint_eventgrid_resource.go b/azurerm/internal/services/digitaltwins/digital_twins_endpoint_eventgrid_resource.go new file mode 100644 index 000000000000..5f7aa6eda783 --- /dev/null +++ b/azurerm/internal/services/digitaltwins/digital_twins_endpoint_eventgrid_resource.go @@ -0,0 +1,184 @@ +package digitaltwins + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/digitaltwins/mgmt/2020-10-31/digitaltwins" + "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/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/digitaltwins/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/digitaltwins/validate" + 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 resourceDigitalTwinsEndpointEventGrid() *schema.Resource { + return &schema.Resource{ + Create: resourceDigitalTwinsEndpointEventGridCreateUpdate, + Read: resourceDigitalTwinsEndpointEventGridRead, + Update: resourceDigitalTwinsEndpointEventGridCreateUpdate, + Delete: resourceDigitalTwinsEndpointEventGridDelete, + + 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.DigitalTwinsEndpointID(id) + return err + }), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DigitalTwinsInstanceName, + }, + + "digital_twins_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DigitalTwinsInstanceID, + }, + + "eventgrid_topic_endpoint": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + + "eventgrid_topic_primary_access_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "eventgrid_topic_secondary_access_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "dead_letter_storage_secret": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + } +} +func resourceDigitalTwinsEndpointEventGridCreateUpdate(d *schema.ResourceData, meta interface{}) error { + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + client := meta.(*clients.Client).DigitalTwins.EndpointClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + digitalTwinsId, err := parse.DigitalTwinsInstanceID(d.Get("digital_twins_id").(string)) + if err != nil { + return err + } + + id := parse.NewDigitalTwinsEndpointID(subscriptionId, digitalTwinsId.ResourceGroup, digitalTwinsId.Name, name).ID("") + + if d.IsNewResource() { + existing, err := client.Get(ctx, digitalTwinsId.ResourceGroup, digitalTwinsId.Name, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for present of existing Digital Twins Endpoint %q (Resource Group %q / Instance %q): %+v", name, digitalTwinsId.ResourceGroup, digitalTwinsId.Name, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_digital_twins_endpoint_eventgrid", id) + } + } + + properties := digitaltwins.EndpointResource{ + Properties: &digitaltwins.EventGrid{ + EndpointType: digitaltwins.EndpointTypeEventGrid, + TopicEndpoint: utils.String(d.Get("eventgrid_topic_endpoint").(string)), + AccessKey1: utils.String(d.Get("eventgrid_topic_primary_access_key").(string)), + AccessKey2: utils.String(d.Get("eventgrid_topic_secondary_access_key").(string)), + DeadLetterSecret: utils.String(d.Get("dead_letter_storage_secret").(string)), + }, + } + + future, err := client.CreateOrUpdate(ctx, digitalTwinsId.ResourceGroup, digitalTwinsId.Name, name, properties) + if err != nil { + return fmt.Errorf("creating/updating Digital Twins EventGrid Endpoint %q (Resource Group %q / Instance %q): %+v", name, digitalTwinsId.ResourceGroup, digitalTwinsId.Name, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation/update of the Digital Twins EventGrid Endpoint %q (Resource Group %q / Instance %q): %+v", name, digitalTwinsId.ResourceGroup, digitalTwinsId.Name, err) + } + + if _, err := client.Get(ctx, digitalTwinsId.ResourceGroup, digitalTwinsId.Name, name); err != nil { + return fmt.Errorf("retrieving Digital Twins EventGrid Endpoint %q (Resource Group %q / Instance %q): %+v", name, digitalTwinsId.ResourceGroup, digitalTwinsId.Name, err) + } + + d.SetId(id) + + return resourceDigitalTwinsEndpointEventGridRead(d, meta) +} + +func resourceDigitalTwinsEndpointEventGridRead(d *schema.ResourceData, meta interface{}) error { + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + client := meta.(*clients.Client).DigitalTwins.EndpointClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.DigitalTwinsEndpointID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.DigitalTwinsInstanceName, id.EndpointName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Digital Twins EventGrid Endpoint %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("retrieving Digital Twins EventGrid Endpoint %q (Resource Group %q / Instance %q): %+v", id.EndpointName, id.ResourceGroup, id.DigitalTwinsInstanceName, err) + } + d.Set("name", id.EndpointName) + d.Set("digital_twins_id", parse.NewDigitalTwinsInstanceID(subscriptionId, id.ResourceGroup, id.DigitalTwinsInstanceName).ID("")) + if resp.Properties != nil { + if _, ok := resp.Properties.AsEventGrid(); !ok { + return fmt.Errorf("retrieving Digital Twins Endpoint %q (Resource Group %q / Instance %q) is not type Event Grid", id.EndpointName, id.ResourceGroup, id.DigitalTwinsInstanceName) + } + } + + return nil +} + +func resourceDigitalTwinsEndpointEventGridDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).DigitalTwins.EndpointClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.DigitalTwinsEndpointID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.DigitalTwinsInstanceName, id.EndpointName) + if err != nil { + return fmt.Errorf("deleting Digital Twins EventGrid Endpoint %q (Resource Group %q / Instance %q): %+v", id.EndpointName, id.ResourceGroup, id.DigitalTwinsInstanceName, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for deletion of the Digital Twins EventGrid Endpoint %q (Resource Group %q / Instance %q): %+v", id.EndpointName, id.ResourceGroup, id.DigitalTwinsInstanceName, err) + } + return nil +} diff --git a/azurerm/internal/services/digitaltwins/digital_twins_endpoint_eventgrid_resource_test.go b/azurerm/internal/services/digitaltwins/digital_twins_endpoint_eventgrid_resource_test.go new file mode 100644 index 000000000000..35eeb8be10e1 --- /dev/null +++ b/azurerm/internal/services/digitaltwins/digital_twins_endpoint_eventgrid_resource_test.go @@ -0,0 +1,262 @@ +package digitaltwins_test + +import ( + "context" + "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/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/digitaltwins/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type DigitalTwinsEndpointEventGridResource struct{} + +func TestAccDigitalTwinsEndpointEventGrid_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_digital_twins_endpoint_eventgrid", "test") + r := DigitalTwinsEndpointEventGridResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("eventgrid_topic_endpoint", "eventgrid_topic_primary_access_key", "eventgrid_topic_secondary_access_key"), + }) +} + +func TestAccDigitalTwinsEndpointEventGrid_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_digital_twins_endpoint_eventgrid", "test") + r := DigitalTwinsEndpointEventGridResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccDigitalTwinsEndpointEventGrid_updateEventGrid(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_digital_twins_endpoint_eventgrid", "test") + r := DigitalTwinsEndpointEventGridResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("eventgrid_topic_endpoint", "eventgrid_topic_primary_access_key", "eventgrid_topic_secondary_access_key"), + { + Config: r.updateEventGrid(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("eventgrid_topic_endpoint", "eventgrid_topic_primary_access_key", "eventgrid_topic_secondary_access_key"), + { + Config: r.updateEventGridRestore(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("eventgrid_topic_endpoint", "eventgrid_topic_primary_access_key", "eventgrid_topic_secondary_access_key"), + }) +} + +func TestAccDigitalTwinsEndpointEventGrid_updateDeadLetter(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_digital_twins_endpoint_eventgrid", "test") + r := DigitalTwinsEndpointEventGridResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("eventgrid_topic_endpoint", "eventgrid_topic_primary_access_key", "eventgrid_topic_secondary_access_key"), + { + Config: r.updateDeadLetter(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("eventgrid_topic_endpoint", "eventgrid_topic_primary_access_key", "eventgrid_topic_secondary_access_key", "dead_letter_storage_secret"), + { + Config: r.updateDeadLetterRestore(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("eventgrid_topic_endpoint", "eventgrid_topic_primary_access_key", "eventgrid_topic_secondary_access_key", "dead_letter_storage_secret"), + }) +} + +func (r DigitalTwinsEndpointEventGridResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.DigitalTwinsEndpointID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.DigitalTwins.EndpointClient.Get(ctx, id.ResourceGroup, id.DigitalTwinsInstanceName, id.EndpointName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving Digital Twins EventGrid Endpoint %q (Resource Group %q / Digital Twins Instance Name %q): %+v", id.EndpointName, id.ResourceGroup, id.DigitalTwinsInstanceName, err) + } + + return utils.Bool(true), nil +} + +func (r DigitalTwinsEndpointEventGridResource) template(data acceptance.TestData) string { + iR := DigitalTwinsInstanceResource{} + digitalTwinsInstance := iR.basic(data) + return fmt.Sprintf(` +%[1]s + +resource "azurerm_eventgrid_topic" "test" { + name = "acctesteg-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} +`, digitalTwinsInstance, data.RandomInteger) +} + +func (r DigitalTwinsEndpointEventGridResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_digital_twins_endpoint_eventgrid" "test" { + name = "acctest-EG-%d" + digital_twins_id = azurerm_digital_twins_instance.test.id + eventgrid_topic_endpoint = azurerm_eventgrid_topic.test.endpoint + eventgrid_topic_primary_access_key = azurerm_eventgrid_topic.test.primary_access_key + eventgrid_topic_secondary_access_key = azurerm_eventgrid_topic.test.secondary_access_key +} +`, r.template(data), data.RandomInteger) +} + +func (r DigitalTwinsEndpointEventGridResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_digital_twins_endpoint_eventgrid" "import" { + name = azurerm_digital_twins_endpoint_eventgrid.test.name + digital_twins_id = azurerm_digital_twins_endpoint_eventgrid.test.digital_twins_id + eventgrid_topic_endpoint = azurerm_digital_twins_endpoint_eventgrid.test.eventgrid_topic_endpoint + eventgrid_topic_primary_access_key = azurerm_digital_twins_endpoint_eventgrid.test.eventgrid_topic_primary_access_key + eventgrid_topic_secondary_access_key = azurerm_digital_twins_endpoint_eventgrid.test.eventgrid_topic_secondary_access_key +} +`, r.basic(data)) +} + +func (r DigitalTwinsEndpointEventGridResource) updateEventGrid(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_eventgrid_topic" "test_alt" { + name = "acctesteg-alt-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_digital_twins_endpoint_eventgrid" "test" { + name = "acctest-EG-%[2]d" + digital_twins_id = azurerm_digital_twins_instance.test.id + eventgrid_topic_endpoint = azurerm_eventgrid_topic.test_alt.endpoint + eventgrid_topic_primary_access_key = azurerm_eventgrid_topic.test_alt.primary_access_key + eventgrid_topic_secondary_access_key = azurerm_eventgrid_topic.test_alt.secondary_access_key +} +`, r.template(data), data.RandomInteger) +} + +func (r DigitalTwinsEndpointEventGridResource) updateEventGridRestore(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_eventgrid_topic" "test_alt" { + name = "acctesteg-alt-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_digital_twins_endpoint_eventgrid" "test" { + name = "acctest-EG-%[2]d" + digital_twins_id = azurerm_digital_twins_instance.test.id + eventgrid_topic_endpoint = azurerm_eventgrid_topic.test.endpoint + eventgrid_topic_primary_access_key = azurerm_eventgrid_topic.test.primary_access_key + eventgrid_topic_secondary_access_key = azurerm_eventgrid_topic.test.secondary_access_key +} +`, r.template(data), data.RandomInteger) +} + +func (r DigitalTwinsEndpointEventGridResource) updateDeadLetter(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_storage_account" "test" { + name = "acctestacc%[2]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "test" { + name = "vhds" + storage_account_name = azurerm_storage_account.test.name + container_access_type = "private" +} + +resource "azurerm_digital_twins_endpoint_eventgrid" "test" { + name = "acctest-EG-%[3]d" + digital_twins_id = azurerm_digital_twins_instance.test.id + eventgrid_topic_endpoint = azurerm_eventgrid_topic.test.endpoint + eventgrid_topic_primary_access_key = azurerm_eventgrid_topic.test.primary_access_key + eventgrid_topic_secondary_access_key = azurerm_eventgrid_topic.test.secondary_access_key + dead_letter_storage_secret = "${azurerm_storage_container.test.id}?${azurerm_storage_account.test.primary_access_key}" + +} +`, r.template(data), data.RandomString, data.RandomInteger) +} + +func (r DigitalTwinsEndpointEventGridResource) updateDeadLetterRestore(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_storage_account" "test" { + name = "acctestacc%[2]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "test" { + name = "vhds" + storage_account_name = azurerm_storage_account.test.name + container_access_type = "private" +} + +resource "azurerm_digital_twins_endpoint_eventgrid" "test" { + name = "acctest-EG-%[3]d" + digital_twins_id = azurerm_digital_twins_instance.test.id + eventgrid_topic_endpoint = azurerm_eventgrid_topic.test.endpoint + eventgrid_topic_primary_access_key = azurerm_eventgrid_topic.test.primary_access_key + eventgrid_topic_secondary_access_key = azurerm_eventgrid_topic.test.secondary_access_key + +} +`, r.template(data), data.RandomString, data.RandomInteger) +} diff --git a/azurerm/internal/services/digitaltwins/parse/digital_twins_endpoint.go b/azurerm/internal/services/digitaltwins/parse/digital_twins_endpoint.go new file mode 100644 index 000000000000..0957e4f25ed0 --- /dev/null +++ b/azurerm/internal/services/digitaltwins/parse/digital_twins_endpoint.go @@ -0,0 +1,55 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type DigitalTwinsEndpointId struct { + SubscriptionId string + ResourceGroup string + DigitalTwinsInstanceName string + EndpointName string +} + +func NewDigitalTwinsEndpointID(subscriptionId, resourceGroup, digitalTwinsInstanceName, endpointName string) DigitalTwinsEndpointId { + return DigitalTwinsEndpointId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + DigitalTwinsInstanceName: digitalTwinsInstanceName, + EndpointName: endpointName, + } +} + +func (id DigitalTwinsEndpointId) ID(_ string) string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DigitalTwins/digitalTwinsInstances/%s/endpoints/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DigitalTwinsInstanceName, id.EndpointName) +} + +func DigitalTwinsEndpointID(input string) (*DigitalTwinsEndpointId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := DigitalTwinsEndpointId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.DigitalTwinsInstanceName, err = id.PopSegment("digitalTwinsInstances"); err != nil { + return nil, err + } + if resourceId.EndpointName, err = id.PopSegment("endpoints"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/digitaltwins/parse/digital_twins_endpoint_test.go b/azurerm/internal/services/digitaltwins/parse/digital_twins_endpoint_test.go new file mode 100644 index 000000000000..bf67233317f7 --- /dev/null +++ b/azurerm/internal/services/digitaltwins/parse/digital_twins_endpoint_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = DigitalTwinsEndpointId{} + +func TestDigitalTwinsEndpointIDFormatter(t *testing.T) { + actual := NewDigitalTwinsEndpointID("12345678-1234-9876-4563-123456789012", "group1", "instance1", "endpoint1").ID("") + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.DigitalTwins/digitalTwinsInstances/instance1/endpoints/endpoint1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestDigitalTwinsEndpointID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *DigitalTwinsEndpointId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing DigitalTwinsInstanceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.DigitalTwins/", + Error: true, + }, + + { + // missing value for DigitalTwinsInstanceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.DigitalTwins/digitalTwinsInstances/", + Error: true, + }, + + { + // missing EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.DigitalTwins/digitalTwinsInstances/instance1/", + Error: true, + }, + + { + // missing value for EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.DigitalTwins/digitalTwinsInstances/instance1/endpoints/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.DigitalTwins/digitalTwinsInstances/instance1/endpoints/endpoint1", + Expected: &DigitalTwinsEndpointId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "group1", + DigitalTwinsInstanceName: "instance1", + EndpointName: "endpoint1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.DIGITALTWINS/DIGITALTWINSINSTANCES/INSTANCE1/ENDPOINTS/ENDPOINT1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := DigitalTwinsEndpointID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.DigitalTwinsInstanceName != v.Expected.DigitalTwinsInstanceName { + t.Fatalf("Expected %q but got %q for DigitalTwinsInstanceName", v.Expected.DigitalTwinsInstanceName, actual.DigitalTwinsInstanceName) + } + if actual.EndpointName != v.Expected.EndpointName { + t.Fatalf("Expected %q but got %q for EndpointName", v.Expected.EndpointName, actual.EndpointName) + } + } +} diff --git a/azurerm/internal/services/digitaltwins/registration.go b/azurerm/internal/services/digitaltwins/registration.go index 3fb019f3bae6..0eb1c5f38559 100644 --- a/azurerm/internal/services/digitaltwins/registration.go +++ b/azurerm/internal/services/digitaltwins/registration.go @@ -28,6 +28,7 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_digital_twins_instance": resourceDigitalTwinsInstance(), + "azurerm_digital_twins_instance": resourceDigitalTwinsInstance(), + "azurerm_digital_twins_endpoint_eventgrid": resourceDigitalTwinsEndpointEventGrid(), } } diff --git a/azurerm/internal/services/digitaltwins/resourceids.go b/azurerm/internal/services/digitaltwins/resourceids.go index f67d9d9b382a..84e431bd1eb5 100644 --- a/azurerm/internal/services/digitaltwins/resourceids.go +++ b/azurerm/internal/services/digitaltwins/resourceids.go @@ -2,3 +2,4 @@ package digitaltwins // leaving the DigitalTwins prefix here to avoid stuttering the property name for now //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DigitalTwinsInstance -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.DigitalTwins/digitalTwinsInstances/instance1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DigitalTwinsEndpoint -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.DigitalTwins/digitalTwinsInstances/instance1/endpoints/endpoint1 diff --git a/azurerm/internal/services/digitaltwins/validate/digital_twins_instance_name.go b/azurerm/internal/services/digitaltwins/validate/digital_twins_instance_name.go index 4259cdb26830..9ed6b953626f 100644 --- a/azurerm/internal/services/digitaltwins/validate/digital_twins_instance_name.go +++ b/azurerm/internal/services/digitaltwins/validate/digital_twins_instance_name.go @@ -3,6 +3,8 @@ package validate import ( "fmt" "regexp" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/digitaltwins/parse" ) func DigitalTwinsInstanceName(i interface{}, k string) (warnings []string, errors []error) { @@ -28,3 +30,17 @@ func DigitalTwinsInstanceName(i interface{}, k string) (warnings []string, error } return } + +func DigitalTwinsInstanceID(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.DigitalTwinsInstanceID(v); err != nil { + errors = append(errors, fmt.Errorf("can not parse %q as a Digital Twins Instance resource id: %v", k, err)) + } + + return warnings, errors +} diff --git a/website/docs/r/digital_twins_endpoint_eventgrid.html.markdown b/website/docs/r/digital_twins_endpoint_eventgrid.html.markdown new file mode 100644 index 000000000000..582f92024ac0 --- /dev/null +++ b/website/docs/r/digital_twins_endpoint_eventgrid.html.markdown @@ -0,0 +1,83 @@ +--- +subcategory: "Digital Twins" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_digital_twins_endpoint_eventgrid" +description: |- + Manages a Digital Twins Event Grid Endpoint. +--- + +# azurerm_digital_twins_endpoint_eventgrid + +Manages a Digital Twins Event Grid Endpoint. + +## Example Usage + +```hcl +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "example" { + name = "example_resources" + location = "West Europe" +} + +resource "azurerm_digital_twins_instance" "example" { + name = "example-DT" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location +} + +resource "azurerm_eventgrid_topic" "example" { + name = "example-topic" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_digital_twins_endpoint_eventgrid" "example" { + name = "example-EG" + digital_twins_id = azurerm_digital_twins_instance.example.id + eventgrid_topic_endpoint = azurerm_eventgrid_topic.example.endpoint + eventgrid_topic_primary_access_key = azurerm_eventgrid_topic.example.primary_access_key + eventgrid_topic_secondary_access_key = azurerm_eventgrid_topic.example.secondary_access_key +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Digital Twins Eventgrid Endpoint. Changing this forces a new Digital Twins Eventgrid Endpoint to be created. + +* `digital_twins_id` - (Required) The resource ID of the Digital Twins Instance. Changing this forces a new Digital Twins Eventgrid Endpoint to be created. + +* `eventgrid_topic_endpoint` - (Required) The endpoint of the Event Grid Topic. + +* `eventgrid_topic_primary_access_key` - (Required) The primary access key of the Event Grid Topic. + +* `eventgrid_topic_secondary_access_key` - (Required) The secondary access key of the Event Grid Topic. + +* `dead_letter_storage_secret` - (Optional) The storage secret of the dead-lettering, whose format is `https://.blob.core.windows.net/?`. When an endpoint can't deliver an event within a certain time period or after trying to deliver the event a certain number of times, it can send the undelivered event to a storage account. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Digital Twins Event Grid Endpoint. + +## 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 Digital Twins Eventgrid Endpoint. +* `read` - (Defaults to 5 minutes) Used when retrieving the Digital Twins Eventgrid Endpoint. +* `update` - (Defaults to 30 minutes) Used when updating the Digital Twins Eventgrid Endpoint. +* `delete` - (Defaults to 30 minutes) Used when deleting the Digital Twins Eventgrid Endpoint. + +## Import + +Digital Twins Eventgrid Endpoints can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_digital_twins_endpoint_eventgrid.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.DigitalTwins/digitalTwinsInstances/dt1/endpoints/ep1 +```