Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new datasource azurerm_extended_location_custom_location #28066

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/labeler-issue-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ service/event-hubs:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_eventhub((.|\n)*)###'

service/extended-location:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_extended_custom_location((.|\n)*)###'
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_(extended_custom_location\W+|extended_location_custom_location\W+|extended_location_custom_location\W+)((.|\n)*)###'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why extended_location_custom_location\W+ twice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file is generated by the go generate ./internal/provider command. The duplicates should be handled within the internal/tools/generator-services/main.go file now.


service/firewall:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_firewall((.|\n)*)###'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package extendedlocation

import (
"context"
"fmt"
"regexp"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/go-azure-sdk/resource-manager/extendedlocation/2021-08-15/customlocations"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"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.DataSource = CustomLocationDataSource{}

type CustomLocationDataSource struct{}

type CustomLocationDataSourceModel struct {
Name string `tfschema:"name"`
ResourceGroupName string `tfschema:"resource_group_name"`
Location string `tfschema:"location"`
Authentication []AuthModel `tfschema:"authentication"`
ClusterExtensionIds []string `tfschema:"cluster_extension_ids"`
DisplayName string `tfschema:"display_name"`
HostResourceId string `tfschema:"host_resource_id"`
HostType string `tfschema:"host_type"`
Namespace string `tfschema:"namespace"`
}

func (r CustomLocationDataSource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*schema.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(
regexp.MustCompile(`^[A-Za-z\d.\-_]*[A-Za-z\d]$`),
"supported alphanumeric characters and periods, underscores, hyphens. Name should end with an alphanumeric character.",
),
},

"resource_group_name": commonschema.ResourceGroupNameForDataSource(),
}
}

func (r CustomLocationDataSource) Attributes() map[string]*pluginsdk.Schema {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could these be ordered alphabetically?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

return map[string]*schema.Schema{
"location": commonschema.LocationComputed(),

"namespace": {
Type: pluginsdk.TypeString,
Computed: true,
},

"host_resource_id": {
Type: pluginsdk.TypeString,
Computed: true,
},

"cluster_extension_ids": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},

"host_type": {
Type: pluginsdk.TypeString,
Computed: true,
},

"display_name": {
Type: pluginsdk.TypeString,
Computed: true,
},

"authentication": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"type": {
Type: pluginsdk.TypeString,
Computed: true,
},

"value": {
Type: pluginsdk.TypeString,
Computed: true,
},
},
},
},
}
}

func (r CustomLocationDataSource) ModelObject() interface{} {
return &CustomLocationDataSourceModel{}
}

func (r CustomLocationDataSource) ResourceType() string {
return "azurerm_extended_location_custom_location"
}

func (r CustomLocationDataSource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
var model CustomLocationResourceModel
if err := metadata.Decode(&model); err != nil {
return err
}

subscriptionId := metadata.Client.Account.SubscriptionId
client := metadata.Client.ExtendedLocation.CustomLocationsClient
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var model CustomLocationResourceModel
if err := metadata.Decode(&model); err != nil {
return err
}
subscriptionId := metadata.Client.Account.SubscriptionId
client := metadata.Client.ExtendedLocation.CustomLocationsClient
client := metadata.Client.ExtendedLocation.CustomLocationsClient
subscriptionId := metadata.Client.Account.SubscriptionId
var model CustomLocationResourceModel
if err := metadata.Decode(&model); err != nil {
return err
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


id := customlocations.NewCustomLocationID(subscriptionId, model.ResourceGroupName, model.Name)
resp, err := client.Get(ctx, id)
if err != nil {
return fmt.Errorf("reading %s: %+v", id, err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Errorf("reading %s: %+v", id, err)
return fmt.Errorf("retrieving %s: %+v", id, err)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}

state := CustomLocationDataSourceModel{
Name: id.CustomLocationName,
ResourceGroupName: id.ResourceGroupName,
}
if model := resp.Model; model != nil {
state.Location = model.Location
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
state.Location = model.Location
state.Location = location.Normalize(model.Location)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


if props := model.Properties; props != nil {
state.ClusterExtensionIds = pointer.From(props.ClusterExtensionIds)
state.DisplayName = pointer.From(props.DisplayName)
state.HostResourceId = pointer.From(props.HostResourceId)
state.HostType = string(pointer.From(props.HostType))
state.Namespace = pointer.From(props.Namespace)

// API always returns an empty `authentication` block even it's not specified. Tracing the bug: https://github.com/Azure/azure-rest-api-specs/issues/30101
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can remove this given that this is the datasource

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

if props.Authentication != nil && props.Authentication.Type != nil && props.Authentication.Value != nil {
state.Authentication = []AuthModel{
{
Type: pointer.From(props.Authentication.Type),
Value: pointer.From(props.Authentication.Value),
},
}
}
}
}

metadata.SetID(id)

return metadata.Encode(&state)
},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package extendedlocation_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
)

type CustomLocationDataSource struct{}

func TestAccCustomLocationDataSource_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_extended_location_custom_location", "test")
d := CustomLocationDataSource{}

credential, privateKey, publicKey := CustomLocationResource{}.getCredentials(t)

data.DataSourceTestInSequence(t, []acceptance.TestStep{
{
Config: d.basic(data, credential, privateKey, publicKey),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("location").IsNotEmpty(),
check.That(data.ResourceName).Key("host_type").HasValue("Kubernetes"),
check.That(data.ResourceName).Key("cluster_extension_ids.#").HasValue("1"),
check.That(data.ResourceName).Key("display_name").IsNotEmpty(),
check.That(data.ResourceName).Key("namespace").IsNotEmpty(),
check.That(data.ResourceName).Key("host_resource_id").IsNotEmpty(),
),
},
})
}

func (d CustomLocationDataSource) basic(data acceptance.TestData, credential string, privateKey string, publicKey string) string {
return fmt.Sprintf(`
%s

data "azurerm_extended_location_custom_location" "test" {
name = azurerm_extended_location_custom_location.test.name
resource_group_name = azurerm_extended_location_custom_location.test.resource_group_name
}
`, CustomLocationResource{}.complete(data, credential, privateKey, publicKey))
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,62 @@ import (
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)

var (
_ sdk.Resource = CustomLocationResource{}
_ sdk.ResourceWithUpdate = CustomLocationResource{}
)

type CustomLocationResource2 struct{}

func (r CustomLocationResource2) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return CustomLocationResource{}.IDValidationFunc()
}

func (r CustomLocationResource2) Arguments() map[string]*pluginsdk.Schema {
return CustomLocationResource{}.Arguments()
}

func (r CustomLocationResource2) Attributes() map[string]*pluginsdk.Schema {
return CustomLocationResource{}.Attributes()
}

func (r CustomLocationResource2) ModelObject() interface{} {
return &CustomLocationResourceModel{}
}

func (r CustomLocationResource2) Create() sdk.ResourceFunc {
return CustomLocationResource{}.Create()
}

func (r CustomLocationResource2) Update() sdk.ResourceFunc {
return CustomLocationResource{}.Update()
}

func (r CustomLocationResource2) Read() sdk.ResourceFunc {
return CustomLocationResource{}.Read()
}

func (r CustomLocationResource2) Delete() sdk.ResourceFunc {
return CustomLocationResource{}.Delete()
}

// The resource name should be `azurerm_extended_location_custom_location` as in the resource doc,
// but in source code it is named `azurerm_extended_custom_location`.
// we change the name to `azurerm_extended_location_custom_location` and keep the old name until 5.0
func (r CustomLocationResource2) ResourceType() string {
return "azurerm_extended_location_custom_location"
}

func (r CustomLocationResource) DeprecatedInFavourOfResource() string {
return "azurerm_extended_location_custom_location"
}

var (
_ sdk.Resource = CustomLocationResource{}
_ sdk.ResourceWithUpdate = CustomLocationResource{}
_ sdk.ResourceWithDeprecationReplacedBy = CustomLocationResource{}
)

type CustomLocationResource struct{}

type CustomLocationResourceModel struct {
Expand Down Expand Up @@ -91,7 +147,6 @@ func (r CustomLocationResource) Arguments() map[string]*pluginsdk.Schema {
"display_name": {
Type: pluginsdk.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
},

Expand Down Expand Up @@ -294,11 +349,15 @@ func (r CustomLocationResource) Update() sdk.ResourceFunc {
model.Properties.Authentication = nil
}

if d.HasChange("display_name") {
model.Properties.DisplayName = pointer.To(state.DisplayName)
}

if d.HasChange("cluster_extension_ids") {
model.Properties.ClusterExtensionIds = pointer.To(state.ClusterExtensionIds)
}

if _, err := client.CreateOrUpdate(ctx, *id, *model); err != nil {
if err := client.CreateOrUpdateThenPoll(ctx, *id, *model); err != nil {
return fmt.Errorf("updating %s: %+v", *id, err)
}
return nil
Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we retain the original tests in addition to new ones so we can ensure the original resource is still working as expected?

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (r CustomLocationResource) Exists(ctx context.Context, client *clients.Clie
}

func TestAccExtendedLocationCustomLocations_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_extended_custom_location", "test")
data := acceptance.BuildTestData(t, "azurerm_extended_location_custom_location", "test")
r := CustomLocationResource{}
credential, privateKey, publicKey := r.getCredentials(t)

Expand All @@ -58,7 +58,7 @@ func TestAccExtendedLocationCustomLocations_basic(t *testing.T) {
}

func TestAccExtendedLocationCustomLocations_complete(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_extended_custom_location", "test")
data := acceptance.BuildTestData(t, "azurerm_extended_location_custom_location", "test")
r := CustomLocationResource{}
credential, privateKey, publicKey := r.getCredentials(t)

Expand All @@ -74,7 +74,7 @@ func TestAccExtendedLocationCustomLocations_complete(t *testing.T) {
}

func TestAccExtendedLocationCustomLocations_update(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_extended_custom_location", "test")
data := acceptance.BuildTestData(t, "azurerm_extended_location_custom_location", "test")
r := CustomLocationResource{}
credential, privateKey, publicKey := r.getCredentials(t)

Expand All @@ -101,7 +101,7 @@ func (r CustomLocationResource) basic(data acceptance.TestData, credential strin
return fmt.Sprintf(`
%s

resource "azurerm_extended_custom_location" "test" {
resource "azurerm_extended_location_custom_location" "test" {
name = "acctestcustomlocation%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
Expand All @@ -119,7 +119,7 @@ func (r CustomLocationResource) update(data acceptance.TestData, credential stri
return fmt.Sprintf(`
%s

resource "azurerm_extended_custom_location" "test" {
resource "azurerm_extended_location_custom_location" "test" {
name = "acctestcustomlocation%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
Expand All @@ -139,7 +139,7 @@ func (r CustomLocationResource) complete(data acceptance.TestData, credential st
return fmt.Sprintf(`
%s

resource "azurerm_extended_custom_location" "test" {
resource "azurerm_extended_location_custom_location" "test" {
name = "acctestcustomlocation%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
Expand Down
5 changes: 4 additions & 1 deletion internal/services/extendedlocation/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ func (r Registration) WebsiteCategories() []string {
}

func (r Registration) DataSources() []sdk.DataSource {
return []sdk.DataSource{}
return []sdk.DataSource{
CustomLocationDataSource{},
}
}

func (r Registration) Resources() []sdk.Resource {
return []sdk.Resource{
CustomLocationResource{},
CustomLocationResource2{},
}
}

Expand Down
Loading
Loading