From 3cb35736ea18812921c3a6be253782c21b8b6b47 Mon Sep 17 00:00:00 2001 From: Neil Ye Date: Thu, 17 Oct 2024 11:41:09 +0800 Subject: [PATCH] New Resource: `azurerm_dev_center_attached_network` (#27638) * New Resource: azurerm_dev_center_attached_network * update registration * update tc --- .../dev_center_attached_network_resource.go | 161 ++++++++++++++++++ ...v_center_attached_network_resource_test.go | 136 +++++++++++++++ internal/services/devcenter/registration.go | 1 + .../dev_center_attached_network.html.markdown | 93 ++++++++++ 4 files changed, 391 insertions(+) create mode 100644 internal/services/devcenter/dev_center_attached_network_resource.go create mode 100644 internal/services/devcenter/dev_center_attached_network_resource_test.go create mode 100644 website/docs/r/dev_center_attached_network.html.markdown diff --git a/internal/services/devcenter/dev_center_attached_network_resource.go b/internal/services/devcenter/dev_center_attached_network_resource.go new file mode 100644 index 000000000000..97c167f8f9f4 --- /dev/null +++ b/internal/services/devcenter/dev_center_attached_network_resource.go @@ -0,0 +1,161 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package devcenter + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-sdk/resource-manager/devcenter/2023-04-01/attachednetworkconnections" + "github.com/hashicorp/go-azure-sdk/resource-manager/devcenter/2023-04-01/devcenters" + "github.com/hashicorp/go-azure-sdk/resource-manager/devcenter/2023-04-01/networkconnections" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +var _ sdk.Resource = DevCenterAttachedNetworkResource{} + +type DevCenterAttachedNetworkResource struct{} + +func (r DevCenterAttachedNetworkResource) ModelObject() interface{} { + return &DevCenterAttachedNetworkResourceModel{} +} + +type DevCenterAttachedNetworkResourceModel struct { + Name string `tfschema:"name"` + DevCenterId string `tfschema:"dev_center_id"` + NetworkConnectionId string `tfschema:"network_connection_id"` +} + +func (r DevCenterAttachedNetworkResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return attachednetworkconnections.ValidateDevCenterAttachedNetworkID +} + +func (r DevCenterAttachedNetworkResource) ResourceType() string { + return "azurerm_dev_center_attached_network" +} + +func (r DevCenterAttachedNetworkResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "dev_center_id": commonschema.ResourceIDReferenceRequiredForceNew(&devcenters.DevCenterId{}), + + "network_connection_id": commonschema.ResourceIDReferenceRequiredForceNew(&networkconnections.NetworkConnectionId{}), + } +} + +func (r DevCenterAttachedNetworkResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r DevCenterAttachedNetworkResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.DevCenter.V20230401.AttachedNetworkConnections + subscriptionId := metadata.Client.Account.SubscriptionId + + var model DevCenterAttachedNetworkResourceModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + devCenterId, err := devcenters.ParseDevCenterID(model.DevCenterId) + if err != nil { + return err + } + + id := attachednetworkconnections.NewDevCenterAttachedNetworkID(subscriptionId, devCenterId.ResourceGroupName, devCenterId.DevCenterName, model.Name) + + existing, err := client.AttachedNetworksGetByDevCenter(ctx, id) + if err != nil { + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for the presence of an existing %s: %+v", id, err) + } + } + + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + parameters := attachednetworkconnections.AttachedNetworkConnection{ + Properties: &attachednetworkconnections.AttachedNetworkConnectionProperties{ + NetworkConnectionId: model.NetworkConnectionId, + }, + } + + if err := client.AttachedNetworksCreateOrUpdateThenPoll(ctx, id, parameters); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r DevCenterAttachedNetworkResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.DevCenter.V20230401.AttachedNetworkConnections + + id, err := attachednetworkconnections.ParseDevCenterAttachedNetworkID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.AttachedNetworksGetByDevCenter(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(*id) + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + state := DevCenterAttachedNetworkResourceModel{ + Name: id.AttachedNetworkName, + DevCenterId: attachednetworkconnections.NewDevCenterID(id.SubscriptionId, id.ResourceGroupName, id.DevCenterName).ID(), + } + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + state.NetworkConnectionId = props.NetworkConnectionId + } + } + + return metadata.Encode(&state) + }, + } +} + +func (r DevCenterAttachedNetworkResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.DevCenter.V20230401.AttachedNetworkConnections + + id, err := attachednetworkconnections.ParseDevCenterAttachedNetworkID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if err := client.AttachedNetworksDeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + return nil + }, + } +} diff --git a/internal/services/devcenter/dev_center_attached_network_resource_test.go b/internal/services/devcenter/dev_center_attached_network_resource_test.go new file mode 100644 index 000000000000..13b5c89988f6 --- /dev/null +++ b/internal/services/devcenter/dev_center_attached_network_resource_test.go @@ -0,0 +1,136 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package devcenter_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-sdk/resource-manager/devcenter/2023-04-01/attachednetworkconnections" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type DevCenterAttachedNetworkTestResource struct{} + +func TestAccDevCenterAttachedNetwork_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dev_center_attached_network", "test") + r := DevCenterAttachedNetworkTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccDevCenterAttachedNetwork_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dev_center_attached_network", "test") + r := DevCenterAttachedNetworkTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (r DevCenterAttachedNetworkTestResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := attachednetworkconnections.ParseDevCenterAttachedNetworkID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.DevCenter.V20230401.AttachedNetworkConnections.AttachedNetworksGetByDevCenter(ctx, *id) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) + } + + return pointer.To(resp.Model != nil), nil +} + +func (r DevCenterAttachedNetworkTestResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +provider "azurerm" { + features {} +} + +resource "azurerm_dev_center_attached_network" "test" { + name = "acctest-dcet-%d" + dev_center_id = azurerm_dev_center.test.id + network_connection_id = azurerm_dev_center_network_connection.test.id +} +`, r.template(data), data.RandomInteger) +} + +func (r DevCenterAttachedNetworkTestResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_dev_center_attached_network" "import" { + name = azurerm_dev_center_attached_network.test.name + dev_center_id = azurerm_dev_center_attached_network.test.dev_center_id + network_connection_id = azurerm_dev_center_attached_network.test.network_connection_id +} +`, r.basic(data)) +} + +func (r DevCenterAttachedNetworkTestResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-dcan-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest-vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] +} + +resource "azurerm_dev_center" "test" { + name = "acctest-dc-%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + identity { + type = "SystemAssigned" + } + + depends_on = [azurerm_subnet.test] +} + +resource "azurerm_dev_center_network_connection" "test" { + name = "acctest-dcnc-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + domain_join_type = "AzureADJoin" + subnet_id = azurerm_subnet.test.id + + depends_on = [azurerm_dev_center.test] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomString, data.RandomInteger) +} diff --git a/internal/services/devcenter/registration.go b/internal/services/devcenter/registration.go index 4d14e520bfad..2ae90d91f86e 100644 --- a/internal/services/devcenter/registration.go +++ b/internal/services/devcenter/registration.go @@ -31,6 +31,7 @@ func (r Registration) DataSources() []sdk.DataSource { func (r Registration) Resources() []sdk.Resource { resources := []sdk.Resource{ + DevCenterAttachedNetworkResource{}, DevCenterGalleryResource{}, DevCenterCatalogsResource{}, DevCenterDevBoxDefinitionResource{}, diff --git a/website/docs/r/dev_center_attached_network.html.markdown b/website/docs/r/dev_center_attached_network.html.markdown new file mode 100644 index 000000000000..4f896563847b --- /dev/null +++ b/website/docs/r/dev_center_attached_network.html.markdown @@ -0,0 +1,93 @@ +--- +subcategory: "Dev Center" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_dev_center_attached_network" +description: |- + Manages a Dev Center Attached Network. +--- + +# azurerm_dev_center_attached_network + +Manages a Dev Center Attached Network. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-dcan" + location = "West Europe" +} + +resource "azurerm_virtual_network" "example" { + name = "example-vnet" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_subnet" "example" { + name = "internal" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name + address_prefixes = ["10.0.2.0/24"] +} + +resource "azurerm_dev_center" "example" { + name = "example-dc" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_dev_center_network_connection" "example" { + name = "example-dcnc" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + domain_join_type = "AzureADJoin" + subnet_id = azurerm_subnet.example.id +} + +resource "azurerm_dev_center_attached_network" "example" { + name = "example-dcet" + dev_center_id = azurerm_dev_center.example.id + network_connection_id = azurerm_dev_center_network_connection.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of this Dev Center Attached Network. Changing this forces a new resource to be created. + +* `dev_center_id` - (Required) The ID of the associated Dev Center. Changing this forces a new resource to be created. + +* `network_connection_id` - (Required) The ID of the Dev Center Network Connection you want to attach. Changing this forces a new resource to be created. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Dev Center Attached Network. + +--- + +## 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 this Dev Center Attached Network. +* `delete` - (Defaults to 30 minutes) Used when deleting this Dev Center Attached Network. +* `read` - (Defaults to 5 minutes) Used when retrieving this Dev Center Attached Network. +* `update` - (Defaults to 30 minutes) Used when updating this Dev Center Attached Network. + +## Import + +An existing Dev Center Attached Network can be imported into Terraform using the `resource id`, e.g. + +```shell +terraform import azurerm_dev_center_attached_network.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.DevCenter/devCenters/dc1/attachedNetworks/et1 +```