diff --git a/internal/services/devcenter/dev_center_network_connection_resource.go b/internal/services/devcenter/dev_center_network_connection_resource.go new file mode 100644 index 000000000000..f730b41a82d7 --- /dev/null +++ b/internal/services/devcenter/dev_center_network_connection_resource.go @@ -0,0 +1,285 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package devcenter + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "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/services/devcenter/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +var _ sdk.Resource = DevCenterNetworkConnectionResource{} +var _ sdk.ResourceWithUpdate = DevCenterNetworkConnectionResource{} + +type DevCenterNetworkConnectionResource struct{} + +func (r DevCenterNetworkConnectionResource) ModelObject() interface{} { + return &DevCenterNetworkConnectionResourceModel{} +} + +type DevCenterNetworkConnectionResourceModel struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + Location string `tfschema:"location"` + DomainJoinType string `tfschema:"domain_join_type"` + SubnetId string `tfschema:"subnet_id"` + DomainName string `tfschema:"domain_name"` + DomainPassword string `tfschema:"domain_password"` + DomainUsername string `tfschema:"domain_username"` + OrganizationUnit string `tfschema:"organization_unit"` + Tags map[string]string `tfschema:"tags"` +} + +func (r DevCenterNetworkConnectionResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return networkconnections.ValidateNetworkConnectionID +} + +func (r DevCenterNetworkConnectionResource) ResourceType() string { + return "azurerm_dev_center_network_connection" +} + +func (r DevCenterNetworkConnectionResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DevCenterNetworkConnectionName, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "domain_join_type": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(networkconnections.PossibleValuesForDomainJoinType(), false), + }, + + "subnet_id": commonschema.ResourceIDReferenceRequired(&commonids.SubnetId{}), + + "domain_name": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validate.DevCenterNetworkConnectionDomainName, + }, + + "domain_password": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "domain_username": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validate.DevCenterNetworkConnectionDomainUsername, + }, + + "organization_unit": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "tags": commonschema.Tags(), + } +} + +func (r DevCenterNetworkConnectionResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r DevCenterNetworkConnectionResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.DevCenter.V20230401.NetworkConnections + subscriptionId := metadata.Client.Account.SubscriptionId + + var model DevCenterNetworkConnectionResourceModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + id := networkconnections.NewNetworkConnectionID(subscriptionId, model.ResourceGroupName, model.Name) + + existing, err := client.Get(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 := networkconnections.NetworkConnection{ + Location: location.Normalize(model.Location), + Properties: &networkconnections.NetworkProperties{ + DomainJoinType: networkconnections.DomainJoinType(model.DomainJoinType), + SubnetId: pointer.To(model.SubnetId), + }, + Tags: pointer.To(model.Tags), + } + + if v := model.DomainName; v != "" { + parameters.Properties.DomainName = pointer.To(v) + } + + if v := model.DomainPassword; v != "" { + parameters.Properties.DomainPassword = pointer.To(v) + } + + if v := model.DomainUsername; v != "" { + parameters.Properties.DomainUsername = pointer.To(v) + } + + if v := model.OrganizationUnit; v != "" { + parameters.Properties.OrganizationUnit = pointer.To(v) + } + + if err := client.CreateOrUpdateThenPoll(ctx, id, parameters); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r DevCenterNetworkConnectionResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.DevCenter.V20230401.NetworkConnections + + id, err := networkconnections.ParseNetworkConnectionID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(*id) + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + state := DevCenterNetworkConnectionResourceModel{ + Name: id.NetworkConnectionName, + ResourceGroupName: id.ResourceGroupName, + DomainPassword: metadata.ResourceData.Get("domain_password").(string), + } + + if model := resp.Model; model != nil { + state.Location = location.Normalize(model.Location) + state.Tags = pointer.From(model.Tags) + + if props := model.Properties; props != nil { + state.SubnetId = pointer.From(props.SubnetId) + state.DomainName = pointer.From(props.DomainName) + state.DomainUsername = pointer.From(props.DomainUsername) + state.OrganizationUnit = pointer.From(props.OrganizationUnit) + + if v := props.DomainJoinType; v != "" { + state.DomainJoinType = string(v) + } + } + } + + return metadata.Encode(&state) + }, + } +} + +func (r DevCenterNetworkConnectionResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.DevCenter.V20230401.NetworkConnections + + id, err := networkconnections.ParseNetworkConnectionID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if err := client.DeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (r DevCenterNetworkConnectionResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.DevCenter.V20230401.NetworkConnections + + id, err := networkconnections.ParseNetworkConnectionID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var model DevCenterNetworkConnectionResourceModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + parameters := networkconnections.NetworkConnectionUpdate{ + Properties: &networkconnections.NetworkConnectionUpdateProperties{}, + } + + if metadata.ResourceData.HasChange("subnet_id") { + parameters.Properties.SubnetId = pointer.To(model.SubnetId) + } + + if metadata.ResourceData.HasChange("domain_name") { + parameters.Properties.DomainName = pointer.To(model.DomainName) + } + + if metadata.ResourceData.HasChange("domain_password") { + parameters.Properties.DomainPassword = pointer.To(model.DomainPassword) + } + + if metadata.ResourceData.HasChange("domain_username") { + parameters.Properties.DomainUsername = pointer.To(model.DomainUsername) + } + + if metadata.ResourceData.HasChange("organization_unit") { + parameters.Properties.OrganizationUnit = pointer.To(model.OrganizationUnit) + } + + if metadata.ResourceData.HasChange("tags") { + parameters.Tags = pointer.To(model.Tags) + } + + if err := client.UpdateThenPoll(ctx, *id, parameters); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + return nil + }, + } +} diff --git a/internal/services/devcenter/dev_center_network_connection_resource_test.go b/internal/services/devcenter/dev_center_network_connection_resource_test.go new file mode 100644 index 000000000000..5f5d3ef78916 --- /dev/null +++ b/internal/services/devcenter/dev_center_network_connection_resource_test.go @@ -0,0 +1,238 @@ +// 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/networkconnections" + "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 DevCenterNetworkConnectionTestResource struct{} + +func TestAccDevCenterNetworkConnection_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dev_center_network_connection", "test") + r := DevCenterNetworkConnectionTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccDevCenterNetworkConnection_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dev_center_network_connection", "test") + r := DevCenterNetworkConnectionTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccDevCenterNetworkConnection_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dev_center_network_connection", "test") + r := DevCenterNetworkConnectionTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("domain_password"), + }) +} + +func TestAccDevCenterNetworkConnection_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dev_center_network_connection", "test") + r := DevCenterNetworkConnectionTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("domain_password"), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("domain_password"), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r DevCenterNetworkConnectionTestResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := networkconnections.ParseNetworkConnectionID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.DevCenter.V20230401.NetworkConnections.Get(ctx, *id) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) + } + + return pointer.To(resp.Model != nil), nil +} + +func (r DevCenterNetworkConnectionTestResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +provider "azurerm" { + features {} +} + +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 +} +`, r.template(data), data.RandomInteger) +} + +func (r DevCenterNetworkConnectionTestResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_dev_center_network_connection" "import" { + name = azurerm_dev_center_network_connection.test.name + resource_group_name = azurerm_dev_center_network_connection.test.resource_group_name + location = azurerm_dev_center_network_connection.test.location + domain_join_type = azurerm_dev_center_network_connection.test.domain_join_type + subnet_id = azurerm_dev_center_network_connection.test.subnet_id +} +`, r.basic(data)) +} + +func (r DevCenterNetworkConnectionTestResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "network" { + name = "acctestrg-dcncn-%d" + location = "%s" +} + +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 = "HybridAzureADJoin" + subnet_id = azurerm_subnet.test.id + domain_name = "never.gonna.shut.you.down" + domain_username = "tfuser@microsoft.com" + domain_password = "P@ssW0RD7890" + organization_unit = "OU=Sales,DC=Fabrikam,DC=com" + + tags = { + ENV = "Test" + } +} +`, r.template(data), data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (r DevCenterNetworkConnectionTestResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "network" { + name = "acctestrg-dcncn-%d" + location = "%s" +} + +resource "azurerm_subnet" "test2" { + name = "internal2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.3.0/24"] +} + +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 = "HybridAzureADJoin" + subnet_id = azurerm_subnet.test2.id + domain_name = "never2.gonna.shut.you.down" + domain_username = "tfuser2@microsoft.com" + domain_password = "P@ssW0RD7891" + organization_unit = "OU=SaleStores,DC=Fabrikam,DC=com" + + tags = { + ENV = "Test2" + } +} +`, r.template(data), data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (r DevCenterNetworkConnectionTestResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-dcnc-%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"] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/devcenter/registration.go b/internal/services/devcenter/registration.go index c880c3f757f5..5a16d408433d 100644 --- a/internal/services/devcenter/registration.go +++ b/internal/services/devcenter/registration.go @@ -35,6 +35,7 @@ func (r Registration) Resources() []sdk.Resource { DevCenterCatalogsResource{}, DevCenterDevBoxDefinitionResource{}, DevCenterEnvironmentTypeResource{}, + DevCenterNetworkConnectionResource{}, } return append(resources, r.autoRegistration.Resources()...) } diff --git a/internal/services/devcenter/validate/dev_center_network_connection_domain_name.go b/internal/services/devcenter/validate/dev_center_network_connection_domain_name.go new file mode 100644 index 000000000000..2aaf185fb6a0 --- /dev/null +++ b/internal/services/devcenter/validate/dev_center_network_connection_domain_name.go @@ -0,0 +1,23 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validate + +import ( + "fmt" + "regexp" +) + +func DevCenterNetworkConnectionDomainName(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 + } + + if !regexp.MustCompile("^[a-zA-Z0-9-]([a-zA-Z0-9-.]{0,253}[a-zA-Z0-9-])?$").MatchString(v) { + errors = append(errors, fmt.Errorf("%q must start or end with an alphanumeric character or dashes, may contain alphanumeric characters, dashes or periods and must be between 1 and 255 characters long", k)) + } + + return warnings, errors +} diff --git a/internal/services/devcenter/validate/dev_center_network_connection_domain_name_test.go b/internal/services/devcenter/validate/dev_center_network_connection_domain_name_test.go new file mode 100644 index 000000000000..c4462b857493 --- /dev/null +++ b/internal/services/devcenter/validate/dev_center_network_connection_domain_name_test.go @@ -0,0 +1,65 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validate + +import ( + "strings" + "testing" +) + +func TestDevCenterNetworkConnectionDomainName(t *testing.T) { + testCases := []struct { + Input string + Expected bool + }{ + { + Input: "", + Expected: false, + }, + { + Input: "a", + Expected: true, + }, + { + Input: "aa", + Expected: true, + }, + { + Input: "Aa-", + Expected: true, + }, + { + Input: "a.a", + Expected: true, + }, + { + Input: "aa.", + Expected: false, + }, + { + Input: ".aa", + Expected: false, + }, + { + Input: strings.Repeat("s", 254), + Expected: true, + }, + { + Input: strings.Repeat("s", 255), + Expected: true, + }, + { + Input: strings.Repeat("s", 256), + Expected: false, + }, + } + + for _, v := range testCases { + _, errors := DevCenterNetworkConnectionDomainName(v.Input, "domain_name") + result := len(errors) == 0 + if result != v.Expected { + t.Fatalf("Expected the result to be %t but got %t (and %d errors)", v.Expected, result, len(errors)) + } + } +} diff --git a/internal/services/devcenter/validate/dev_center_network_connection_domain_username.go b/internal/services/devcenter/validate/dev_center_network_connection_domain_username.go new file mode 100644 index 000000000000..027b17acc875 --- /dev/null +++ b/internal/services/devcenter/validate/dev_center_network_connection_domain_username.go @@ -0,0 +1,23 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validate + +import ( + "fmt" + "regexp" +) + +func DevCenterNetworkConnectionDomainUsername(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 + } + + if !regexp.MustCompile(`^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$`).MatchString(v) { + errors = append(errors, fmt.Errorf("%q is not a valid email", k)) + } + + return warnings, errors +} diff --git a/internal/services/devcenter/validate/dev_center_network_connection_domain_username_test.go b/internal/services/devcenter/validate/dev_center_network_connection_domain_username_test.go new file mode 100644 index 000000000000..e62f382ca6f6 --- /dev/null +++ b/internal/services/devcenter/validate/dev_center_network_connection_domain_username_test.go @@ -0,0 +1,52 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validate + +import ( + "testing" +) + +func TestDevCenterNetworkConnectionDomainUsername(t *testing.T) { + testCases := []struct { + Input string + Expected bool + }{ + { + Input: "a", + Expected: false, + }, + { + Input: "abc", + Expected: false, + }, + { + Input: "123", + Expected: false, + }, + { + Input: "test.com", + Expected: false, + }, + { + Input: "test@.com", + Expected: false, + }, + { + Input: "test.com", + Expected: false, + }, + { + Input: "tfuser@test.com", + Expected: true, + }, + } + + for _, v := range testCases { + _, errors := DevCenterNetworkConnectionDomainUsername(v.Input, "domain_username") + result := len(errors) == 0 + if result != v.Expected { + t.Fatalf("Expected the result to be %t but got %t (and %d errors)", v.Expected, result, len(errors)) + } + } +} diff --git a/internal/services/devcenter/validate/dev_center_network_connection_name.go b/internal/services/devcenter/validate/dev_center_network_connection_name.go new file mode 100644 index 000000000000..a919f5c706f1 --- /dev/null +++ b/internal/services/devcenter/validate/dev_center_network_connection_name.go @@ -0,0 +1,23 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validate + +import ( + "fmt" + "regexp" +) + +func DevCenterNetworkConnectionName(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 + } + + if !regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9-_.]{2,62}$").MatchString(v) { + errors = append(errors, fmt.Errorf("%q must start with an alphanumeric character, may contain alphanumeric characters, dashes, underscores or periods and must be between 3 and 63 characters long", k)) + } + + return warnings, errors +} diff --git a/internal/services/devcenter/validate/dev_center_network_connection_name_test.go b/internal/services/devcenter/validate/dev_center_network_connection_name_test.go new file mode 100644 index 000000000000..490ebd600c5b --- /dev/null +++ b/internal/services/devcenter/validate/dev_center_network_connection_name_test.go @@ -0,0 +1,61 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validate + +import ( + "strings" + "testing" +) + +func TestDevCenterNetworkConnectionName(t *testing.T) { + testCases := []struct { + Input string + Expected bool + }{ + { + Input: "", + Expected: false, + }, + { + Input: "a", + Expected: false, + }, + { + Input: "a8a", + Expected: true, + }, + { + Input: "a-8.a", + Expected: true, + }, + { + Input: "aa-", + Expected: true, + }, + { + Input: "aa.", + Expected: true, + }, + { + Input: strings.Repeat("s", 62), + Expected: true, + }, + { + Input: strings.Repeat("s", 63), + Expected: true, + }, + { + Input: strings.Repeat("s", 64), + Expected: false, + }, + } + + for _, v := range testCases { + _, errors := DevCenterNetworkConnectionName(v.Input, "name") + result := len(errors) == 0 + if result != v.Expected { + t.Fatalf("Expected the result to be %t but got %t (and %d errors)", v.Expected, result, len(errors)) + } + } +} diff --git a/website/docs/r/dev_center_network_connection.html.markdown b/website/docs/r/dev_center_network_connection.html.markdown new file mode 100644 index 000000000000..e8a5c4d212eb --- /dev/null +++ b/website/docs/r/dev_center_network_connection.html.markdown @@ -0,0 +1,89 @@ +--- +subcategory: "Dev Center" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_dev_center_network_connection" +description: |- + Manages a Dev Center Network Connection. +--- + +# azurerm_dev_center_network_connection + +Manages a Dev Center Network Connection. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + 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_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 +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of this Dev Center Network Connection. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) Specifies the name of the Resource Group within which this Dev Center Network Connection should exist. Changing this forces a new resource to be created. + +* `location` - (Required) The Azure Region where the Dev Center Network Connection should exist. Changing this forces a new resource to be created. + +* `domain_join_type` - (Required) The Azure Active Directory Join type. Possible values are `AzureADJoin` and `HybridAzureADJoin`. Changing this forces a new resource to be created. + +* `subnet_id` - (Required) The ID of the Subnet that is used to attach Virtual Machines. + +* `domain_name` - (Optional) The name of the Azure Active Directory domain. + +* `domain_password` - (Optional) The password for the account used to join domain. + +* `domain_username` - (Optional) The username of the Azure Active Directory account (user or service account) that has permissions to create computer objects in Active Directory. + +* `organization_unit` - (Optional) The Azure Active Directory domain Organization Unit (OU). + +* `tags` - (Optional) A mapping of tags which should be assigned to the Dev Center Network Connection. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Dev Center Network Connection. + +## 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 Network Connection. +* `delete` - (Defaults to 30 minutes) Used when deleting this Dev Center Network Connection. +* `read` - (Defaults to 5 minutes) Used when retrieving this Dev Center Network Connection. +* `update` - (Defaults to 30 minutes) Used when updating this Dev Center Network Connection. + +## Import + +An existing Dev Center Network Connection can be imported into Terraform using the `resource id`, e.g. + +```shell +terraform import azurerm_dev_center_network_connection.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.DevCenter/networkConnections/networkConnection1 +```