Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
4 changes: 3 additions & 1 deletion internal/services/managedidentity/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,7 @@ func (r Registration) EphemeralResources() []func() ephemeral.EphemeralResource
}

func (r Registration) ListResources() []sdk.FrameworkListWrappedResource {
return []sdk.FrameworkListWrappedResource{}
return []sdk.FrameworkListWrappedResource{
UserAssignedIdentityListResource{},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"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-helpers/resourcemanager/resourceids"
"github.com/hashicorp/go-azure-helpers/resourcemanager/tags"
"github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2024-11-30/identities"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
Expand All @@ -21,13 +22,20 @@ import (
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)

//go:generate go run ../../tools/generator-tests resourceidentity -resource-name user_assigned_identity -service-package-name managedidentity -properties "name,resource_group_name" -known-values "subscription_id:data.Subscriptions.Primary"

var (
_ sdk.Resource = UserAssignedIdentityResource{}
_ sdk.ResourceWithIdentity = UserAssignedIdentityResource{}
_ sdk.ResourceWithStateMigration = UserAssignedIdentityResource{}
)

type UserAssignedIdentityResource struct{}

func (r UserAssignedIdentityResource) Identity() resourceids.ResourceId {
return &commonids.UserAssignedIdentityId{}
}

func (r UserAssignedIdentityResource) StateUpgraders() sdk.StateUpgradeData {
return sdk.StateUpgradeData{
SchemaVersion: 1,
Expand Down Expand Up @@ -144,6 +152,9 @@ func (r UserAssignedIdentityResource) Create() sdk.ResourceFunc {
}

metadata.SetID(id)
if err := pluginsdk.SetResourceIdentityData(metadata.ResourceData, &id); err != nil {
return err
}
return nil
},
}
Expand All @@ -154,7 +165,6 @@ func (r UserAssignedIdentityResource) Read() sdk.ResourceFunc {
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.ManagedIdentity.V20241130.Identities
schema := UserAssignedIdentityResourceSchema{}

id, err := commonids.ParseUserAssignedIdentityID(metadata.ResourceData.Id())
if err != nil {
Expand All @@ -169,24 +179,7 @@ func (r UserAssignedIdentityResource) Read() sdk.ResourceFunc {
return fmt.Errorf("retrieving %s: %+v", *id, err)
}

if model := resp.Model; model != nil {
schema.Name = id.UserAssignedIdentityName
schema.ResourceGroupName = id.ResourceGroupName
schema.Location = location.Normalize(model.Location)
schema.Tags = tags.Flatten(model.Tags)

if model.Properties != nil {
schema.ClientId = pointer.From(model.Properties.ClientId)
schema.PrincipalId = pointer.From(model.Properties.PrincipalId)
schema.TenantId = pointer.From(model.Properties.TenantId)

if isolationScope := pointer.FromEnum(model.Properties.IsolationScope); isolationScope != string(identities.IsolationScopeNone) {
schema.IsolationScope = isolationScope
}
}
}

return metadata.Encode(&schema)
return r.flatten(metadata, id, resp.Model)
},
}
}
Expand Down Expand Up @@ -248,3 +241,31 @@ func (r UserAssignedIdentityResource) Update() sdk.ResourceFunc {
},
}
}

func (r UserAssignedIdentityResource) flatten(metadata sdk.ResourceMetaData, id *commonids.UserAssignedIdentityId, model *identities.Identity) error {
state := UserAssignedIdentityResourceSchema{
Name: id.UserAssignedIdentityName,
ResourceGroupName: id.ResourceGroupName,
}

if model != nil {
state.Location = location.Normalize(model.Location)
state.Tags = tags.Flatten(model.Tags)

if model.Properties != nil {
state.ClientId = pointer.From(model.Properties.ClientId)
state.PrincipalId = pointer.From(model.Properties.PrincipalId)
state.TenantId = pointer.From(model.Properties.TenantId)

if isolationScope := pointer.FromEnum(model.Properties.IsolationScope); isolationScope != string(identities.IsolationScopeNone) {
state.IsolationScope = isolationScope
}
}
}

if err := pluginsdk.SetResourceIdentityData(metadata.ResourceData, id); err != nil {
return err
}

return metadata.Encode(&state)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: MPL-2.0

package managedidentity

import (
"context"
"fmt"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/terraform-plugin-framework/list"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
)

type UserAssignedIdentityListResource struct{}

var _ sdk.FrameworkListWrappedResource = new(UserAssignedIdentityListResource)

func (UserAssignedIdentityListResource) Metadata(_ context.Context, _ resource.MetadataRequest, response *resource.MetadataResponse) {
response.TypeName = UserAssignedIdentityResource{}.ResourceType()
}

func (UserAssignedIdentityListResource) ResourceFunc() *pluginsdk.Resource {
return sdk.WrappedResource(UserAssignedIdentityResource{})
}

func (UserAssignedIdentityListResource) List(ctx context.Context, request list.ListRequest, stream *list.ListResultsStream, metadata sdk.ResourceMetadata) {
client := metadata.Client.ManagedIdentity.V20241130.Identities

var data sdk.DefaultListModel
diags := request.Config.Get(ctx, &data)
if diags.HasError() {
stream.Results = list.ListResultsStreamDiagnostics(diags)
return
}

subscriptionID := metadata.SubscriptionId
if !data.SubscriptionId.IsNull() {
subscriptionID = data.SubscriptionId.ValueString()
}

r := UserAssignedIdentityResource{}

switch {
case !data.ResourceGroupName.IsNull():
resp, err := client.UserAssignedIdentitiesListByResourceGroupComplete(ctx, commonids.NewResourceGroupID(subscriptionID, data.ResourceGroupName.ValueString()))
if err != nil {
sdk.SetResponseErrorDiagnostic(stream, fmt.Sprintf("listing `%s`", r.ResourceType()), err)
return
}

stream.Results = func(push func(list.ListResult) bool) {
for _, item := range resp.Items {
result := request.NewListResult(ctx)
result.DisplayName = pointer.From(item.Name)

id, err := commonids.ParseUserAssignedIdentityIDInsensitively(pointer.From(item.Id))
if err != nil {
sdk.SetErrorDiagnosticAndPushListResult(result, push, "parsing User Assigned Identity ID", err)
return
}

meta := sdk.NewResourceMetaData(metadata.Client, r)
meta.SetID(id)

if err := r.flatten(meta, id, &item); err != nil {
sdk.SetErrorDiagnosticAndPushListResult(result, push, fmt.Sprintf("encoding `%s` resource data", r.ResourceType()), err)
return
}
Comment thread
Copilot marked this conversation as resolved.

sdk.EncodeListResult(ctx, meta.ResourceData, &result)
if result.Diagnostics.HasError() {
push(result)
return
}

if !push(result) {
return
}
}
}
default:
resp, err := client.UserAssignedIdentitiesListBySubscriptionComplete(ctx, commonids.NewSubscriptionID(subscriptionID))
if err != nil {
sdk.SetResponseErrorDiagnostic(stream, fmt.Sprintf("listing `%s`", r.ResourceType()), err)
return
}

stream.Results = func(push func(list.ListResult) bool) {
for _, item := range resp.Items {
result := request.NewListResult(ctx)
result.DisplayName = pointer.From(item.Name)

id, err := commonids.ParseUserAssignedIdentityIDInsensitively(pointer.From(item.Id))
if err != nil {
sdk.SetErrorDiagnosticAndPushListResult(result, push, "parsing User Assigned Identity ID", err)
return
}

meta := sdk.NewResourceMetaData(metadata.Client, r)
meta.SetID(id)

if err := r.flatten(meta, id, &item); err != nil {
sdk.SetErrorDiagnosticAndPushListResult(result, push, fmt.Sprintf("encoding `%s` resource data", r.ResourceType()), err)
return
}
Comment thread
Copilot marked this conversation as resolved.

sdk.EncodeListResult(ctx, meta.ResourceData, &result)
if result.Diagnostics.HasError() {
push(result)
return
}

if !push(result) {
return
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: MPL-2.0

package managedidentity_test

import (
"context"
"fmt"
"testing"
"time"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/querycheck"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/provider/framework"
)

func TestAccUserAssignedIdentity_list(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_user_assigned_identity", "test")
r := UserAssignedIdentityTestResource{}
resourceName := fmt.Sprintf("acctestuai-0-%d", data.RandomInteger)
resourceGroupName := fmt.Sprintf("acctestrg-%d", data.RandomInteger)

resource.Test(t, resource.TestCase{
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(tfversion.Version1_14_0),
},
ProtoV5ProviderFactories: framework.ProtoV5ProviderFactoriesInit(context.Background(), "azurerm"),
Steps: []resource.TestStep{
{
Config: r.basicList(data),
},
{
PreConfig: func() { time.Sleep(2 * time.Minute) },
Comment thread
aayushsingh2502 marked this conversation as resolved.
Outdated
Query: true,
Config: r.subscriptionListQuery(),
QueryResultChecks: []querycheck.QueryResultCheck{
querycheck.ExpectLengthAtLeast("azurerm_user_assigned_identity.list", 3),
querycheck.ExpectIdentity("azurerm_user_assigned_identity.list", map[string]knownvalue.Check{
"name": knownvalue.StringExact(resourceName),
"resource_group_name": knownvalue.StringExact(resourceGroupName),
"subscription_id": knownvalue.StringExact(data.Subscriptions.Primary),
}),
},
},
{
Query: true,
Config: r.resourceGroupListQuery(data),
QueryResultChecks: []querycheck.QueryResultCheck{
querycheck.ExpectLength("azurerm_user_assigned_identity.list", 3),
querycheck.ExpectIdentity("azurerm_user_assigned_identity.list", map[string]knownvalue.Check{
"name": knownvalue.StringExact(resourceName),
"resource_group_name": knownvalue.StringExact(resourceGroupName),
"subscription_id": knownvalue.StringExact(data.Subscriptions.Primary),
}),
},
},
},
})
}

func (UserAssignedIdentityTestResource) basicList(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
name = "acctestrg-%[1]d"
location = "%[2]s"
}

resource "azurerm_user_assigned_identity" "test" {
count = 3

name = "acctestuai-${count.index}-%[1]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
}
`, data.RandomInteger, data.Locations.Primary)
}

func (UserAssignedIdentityTestResource) subscriptionListQuery() string {
return `
list "azurerm_user_assigned_identity" "list" {
provider = azurerm
}
`
}

func (UserAssignedIdentityTestResource) resourceGroupListQuery(data acceptance.TestData) string {
return fmt.Sprintf(`
list "azurerm_user_assigned_identity" "list" {
provider = azurerm
config {
resource_group_name = "acctestrg-%[1]d"
}
}
`, data.RandomInteger)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
subcategory: "Authorization"
layout: "azurerm"
page_title: "Azure Resource Manager: azurerm_user_assigned_identity"
description: |-
Lists User Assigned Identity resources.
---

# List resource: azurerm_user_assigned_identity

Lists User Assigned Identity resources.

## Example Usage

### List all User Assigned Identities in the subscription

```hcl
list "azurerm_user_assigned_identity" "example" {
provider = azurerm
}
Comment thread
Copilot marked this conversation as resolved.
```

### List all User Assigned Identities in a Resource Group

```hcl
list "azurerm_user_assigned_identity" "example" {
provider = azurerm
config {
resource_group_name = "example-rg"
}
}
```

## Argument Reference

This list resource supports the following arguments:

* `subscription_id` - (Optional) The ID of the Subscription to query. Defaults to the value specified in the Provider Configuration.

* `resource_group_name` - (Optional) The name of the Resource Group to query.
Loading