From da2d226efe8332ed666e52005df2cdce9e6a0c48 Mon Sep 17 00:00:00 2001 From: Tao <104055472+teowa@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:53:57 +0800 Subject: [PATCH 1/6] wip --- .../stack_hci_cluster_resource.go | 78 ++++++++++- .../stack_hci_cluster_resource_test.go | 125 ++++++++++++++++++ 2 files changed, 202 insertions(+), 1 deletion(-) diff --git a/internal/services/azurestackhci/stack_hci_cluster_resource.go b/internal/services/azurestackhci/stack_hci_cluster_resource.go index 5a73997ee9a2..cd6cfe567129 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_resource.go +++ b/internal/services/azurestackhci/stack_hci_cluster_resource.go @@ -8,10 +8,13 @@ import ( "log" "time" + "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + clusterSdk "github.com/hashicorp/go-azure-sdk/resource-manager/azurestackhci/2023-08-01/cluster" "github.com/hashicorp/go-azure-sdk/resource-manager/azurestackhci/2023-08-01/clusters" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -77,6 +80,14 @@ func resourceArmStackHCICluster() *pluginsdk.Resource { ValidateFunc: autoVal.AutomanageConfigurationID, }, + "software_assurance_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "identity": commonschema.SystemAssignedIdentityOptional(), + "tags": commonschema.Tags(), }, } @@ -108,6 +119,14 @@ func resourceArmStackHCIClusterCreate(d *pluginsdk.ResourceData, meta interface{ Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } + if v, ok := d.GetOk("identity"); ok { + expandedIdentity, err := identity.ExpandSystemAndUserAssignedMap(v.([]interface{})) + if err != nil { + return fmt.Errorf("expanding identity: %+v", err) + } + cluster.Identity = expandedIdentity + } + if v, ok := d.GetOk("tenant_id"); ok { cluster.Properties.AadTenantId = utils.String(v.(string)) } else { @@ -153,6 +172,16 @@ func resourceArmStackHCIClusterCreate(d *pluginsdk.ResourceData, meta interface{ } } + if v, ok := d.GetOk("software_assurance_enabled"); ok { + clusterClient := meta.(*clients.Client).AzureStackHCI.Cluster + clusterId := clusterSdk.NewClusterID(id.SubscriptionId, id.ResourceGroupName, id.ClusterName) + softwareAssurance := ExpandClusterSoftwareAssurance(v.(bool)) + + if err := clusterClient.ExtendSoftwareAssuranceBenefitThenPoll(ctx, clusterId, softwareAssurance); err != nil { + return fmt.Errorf("setting software assurance for %s: %+v", id, err) + } + } + d.SetId(id.ID()) return resourceArmStackHCIClusterRead(d, meta) @@ -186,10 +215,20 @@ func resourceArmStackHCIClusterRead(d *pluginsdk.ResourceData, meta interface{}) if model := resp.Model; model != nil { d.Set("location", location.Normalize(model.Location)) + flattenedIdentity, err := identity.FlattenSystemAndUserAssignedMap(model.Identity) + if err != nil { + return fmt.Errorf("flattening identity: %+v", err) + } + d.Set("identity", flattenedIdentity) + if props := model.Properties; props != nil { d.Set("client_id", props.AadClientId) d.Set("tenant_id", props.AadTenantId) + if props.SoftwareAssuranceProperties != nil { + d.Set("software_assurance_enabled", FlattenClusterSoftwareAssurance(props.SoftwareAssuranceProperties.SoftwareAssuranceIntent)) + } + assignmentResp, err := hciAssignmentClient.Get(ctx, id.ResourceGroupName, id.ClusterName, "default") if err != nil && !utils.ResponseWasNotFound(assignmentResp.Response) { return err @@ -231,10 +270,28 @@ func resourceArmStackHCIClusterUpdate(d *pluginsdk.ResourceData, meta interface{ cluster.Tags = tags.Expand(d.Get("tags").(map[string]interface{})) } + if d.HasChange("identity") { + expandedIdentity, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) + if err != nil { + return fmt.Errorf("expanding identity: %+v", err) + } + cluster.Identity = expandedIdentity + } + if _, err := client.Update(ctx, *id, cluster); err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } + if d.HasChange("software_assurance_enabled") { + clusterClient := meta.(*clients.Client).AzureStackHCI.Cluster + clusterId := clusterSdk.NewClusterID(id.SubscriptionId, id.ResourceGroupName, id.ClusterName) + softwareAssurance := ExpandClusterSoftwareAssurance(d.Get("software_assurance_enabled").(bool)) + + if err := clusterClient.ExtendSoftwareAssuranceBenefitThenPoll(ctx, clusterId, softwareAssurance); err != nil { + return fmt.Errorf("setting software assurance for %s: %+v", id, err) + } + } + if d.HasChange("automanage_configuration_id") { if v, ok := d.GetOk("automanage_configuration_id"); ok { hciAssignmentClient := meta.(*clients.Client).Automanage.HCIAssignmentClient @@ -274,7 +331,6 @@ func resourceArmStackHCIClusterUpdate(d *pluginsdk.ResourceData, meta interface{ } } } - } return resourceArmStackHCIClusterRead(d, meta) @@ -308,3 +364,23 @@ func resourceArmStackHCIClusterDelete(d *pluginsdk.ResourceData, meta interface{ return nil } + +func ExpandClusterSoftwareAssurance(input bool) clusterSdk.SoftwareAssuranceChangeRequest { + enabled := clusterSdk.SoftwareAssuranceIntentDisable + if input { + enabled = clusterSdk.SoftwareAssuranceIntentEnable + } + + return clusterSdk.SoftwareAssuranceChangeRequest{ + Properties: &clusterSdk.SoftwareAssuranceChangeRequestProperties{ + SoftwareAssuranceIntent: pointer.To(enabled), + }, + } +} + +func FlattenClusterSoftwareAssurance(input *clusters.SoftwareAssuranceIntent) bool { + if input == nil { + return false + } + return *input == clusters.SoftwareAssuranceIntentEnable +} diff --git a/internal/services/azurestackhci/stack_hci_cluster_resource_test.go b/internal/services/azurestackhci/stack_hci_cluster_resource_test.go index fcd11d945efd..0aca64afec6e 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_resource_test.go +++ b/internal/services/azurestackhci/stack_hci_cluster_resource_test.go @@ -49,6 +49,94 @@ func TestAccStackHCICluster_requiresImport(t *testing.T) { }) } +func TestAccStackHCICluster_systemAssignedIdentity(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_stack_hci_cluster", "test") + r := StackHCIClusterResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.systemAssignedIdentity(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccStackHCICluster_systemAssignedIdentityUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_stack_hci_cluster", "test") + r := StackHCIClusterResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.systemAssignedIdentity(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccStackHCICluster_softwareAssurance(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_stack_hci_cluster", "test") + r := StackHCIClusterResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.softwareAssurance(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccStackHCICluster_softwareAssuranceUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_stack_hci_cluster", "test") + r := StackHCIClusterResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.softwareAssurance(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccStackHCICluster_complete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_stack_hci_cluster", "test") r := StackHCIClusterResource{} @@ -158,6 +246,40 @@ resource "azurerm_stack_hci_cluster" "import" { `, config) } +func (r StackHCIClusterResource) systemAssignedIdentity(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_stack_hci_cluster" "test" { + name = "acctest-StackHCICluster-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + client_id = azuread_application.test.application_id + tenant_id = data.azurerm_client_config.current.tenant_id + identity { + type = "SystemAssigned" + } +} +`, template, data.RandomInteger) +} + +func (r StackHCIClusterResource) softwareAssurance(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_stack_hci_cluster" "test" { + name = "acctest-StackHCICluster-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + client_id = azuread_application.test.application_id + tenant_id = data.azurerm_client_config.current.tenant_id + softwareAssuranceEnabled = true +} +`, template, data.RandomInteger) +} + func (r StackHCIClusterResource) complete(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` @@ -169,6 +291,9 @@ resource "azurerm_stack_hci_cluster" "test" { location = azurerm_resource_group.test.location client_id = azuread_application.test.application_id tenant_id = data.azurerm_client_config.current.tenant_id + identity { + type = "SystemAssigned" + } tags = { ENV = "Test" From 4c6a6d79d63ee48a9b99979c7aefea284ed460a1 Mon Sep 17 00:00:00 2001 From: Tao <104055472+teowa@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:43:37 +0800 Subject: [PATCH 2/6] support for identity, export cloud_id, service_endpoint, resource_provider_object_id --- .../stack_hci_cluster_data_source.go | 58 ++++++++++-- .../stack_hci_cluster_data_source_test.go | 30 ++++++ .../stack_hci_cluster_resource.go | 91 +++++++++---------- .../stack_hci_cluster_resource_test.go | 66 ++------------ .../docs/d/stack_hci_cluster.html.markdown | 22 ++++- .../docs/r/stack_hci_cluster.html.markdown | 32 ++++++- 6 files changed, 179 insertions(+), 120 deletions(-) diff --git a/internal/services/azurestackhci/stack_hci_cluster_data_source.go b/internal/services/azurestackhci/stack_hci_cluster_data_source.go index 2c7ed6bd8943..cc0a49b211b6 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_data_source.go +++ b/internal/services/azurestackhci/stack_hci_cluster_data_source.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" "github.com/hashicorp/go-azure-sdk/resource-manager/azurestackhci/2023-08-01/clusters" @@ -35,13 +36,17 @@ func (r StackHCIClusterDataSource) ModelObject() interface{} { } type StackHCIClusterDataSourceModel struct { - Name string `tfschema:"name"` - ResourceGroupName string `tfschema:"resource_group_name"` - Location string `tfschema:"location"` - ClientId string `tfschema:"client_id"` - TenantId string `tfschema:"tenant_id"` - AutomanageConfigurationId string `tfschema:"automanage_configuration_id"` - Tags map[string]interface{} `tfschema:"tags"` + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + Location string `tfschema:"location"` + ClientId string `tfschema:"client_id"` + TenantId string `tfschema:"tenant_id"` + AutomanageConfigurationId string `tfschema:"automanage_configuration_id"` + CloudId string `tfschema:"cloud_id"` + ServiceEndpoint string `tfschema:"service_endpoint"` + ResourceProviderObjectId string `tfschema:"resource_provider_object_id"` + Identity []identity.ModelSystemAssigned `tfschema:"identity"` + Tags map[string]interface{} `tfschema:"tags"` } func (r StackHCIClusterDataSource) Arguments() map[string]*schema.Schema { @@ -75,6 +80,23 @@ func (r StackHCIClusterDataSource) Attributes() map[string]*schema.Schema { Computed: true, }, + "cloud_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "service_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "resource_provider_object_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "identity": commonschema.SystemAssignedIdentityComputed(), + "tags": commonschema.TagsDataSource(), } } @@ -108,6 +130,10 @@ func (r StackHCIClusterDataSource) Read() sdk.ResourceFunc { if props := model.Properties; props != nil { cluster.ClientId = pointer.From(props.AadClientId) + cluster.CloudId = pointer.From(props.CloudId) + cluster.Identity = flattenSystemAssignedToModel(model.Identity) + cluster.ResourceProviderObjectId = pointer.From(props.ResourceProviderObjectId) + cluster.ServiceEndpoint = pointer.From(props.ServiceEndpoint) cluster.TenantId = pointer.From(props.AadTenantId) assignmentResp, err := hciAssignmentClient.Get(ctx, id.ResourceGroupName, id.ClusterName, "default") @@ -132,3 +158,21 @@ func (r StackHCIClusterDataSource) Read() sdk.ResourceFunc { }, } } + +func flattenSystemAssignedToModel(input *identity.SystemAndUserAssignedMap) []identity.ModelSystemAssigned { + if input == nil { + return []identity.ModelSystemAssigned{} + } + + if input.Type == identity.TypeNone { + return []identity.ModelSystemAssigned{} + } + + return []identity.ModelSystemAssigned{ + { + Type: input.Type, + PrincipalId: input.PrincipalId, + TenantId: input.TenantId, + }, + } +} diff --git a/internal/services/azurestackhci/stack_hci_cluster_data_source_test.go b/internal/services/azurestackhci/stack_hci_cluster_data_source_test.go index 9fbe1b820be4..ad7c772ad288 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_data_source_test.go +++ b/internal/services/azurestackhci/stack_hci_cluster_data_source_test.go @@ -24,6 +24,25 @@ func TestAccStackHCIClusterDataSource_basic(t *testing.T) { check.That(data.ResourceName).Key("location").IsNotEmpty(), check.That(data.ResourceName).Key("client_id").IsNotEmpty(), check.That(data.ResourceName).Key("tenant_id").IsNotEmpty(), + check.That(data.ResourceName).Key("cloud_id").IsNotEmpty(), + check.That(data.ResourceName).Key("service_endpoint").IsNotEmpty(), + check.That(data.ResourceName).Key("resource_provider_object_id").IsNotEmpty(), + ), + }, + }) +} + +func TestAccStackHCIClusterDataSource_identity(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_stack_hci_cluster", "test") + r := StackHCIClusterDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("identity.0.type").HasValue("SystemAssigned"), + check.That(data.ResourceName).Key("identity.0.principal_id").IsNotEmpty(), + check.That(data.ResourceName).Key("identity.0.tenant_id").IsNotEmpty(), ), }, }) @@ -39,3 +58,14 @@ data "azurerm_stack_hci_cluster" "test" { } `, StackHCIClusterResource{}.basic(data)) } + +func (d StackHCIClusterDataSource) identity(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_stack_hci_cluster" "test" { + name = azurerm_stack_hci_cluster.test.name + resource_group_name = azurerm_stack_hci_cluster.test.resource_group_name +} +`, StackHCIClusterResource{}.systemAssignedIdentity(data)) +} diff --git a/internal/services/azurestackhci/stack_hci_cluster_resource.go b/internal/services/azurestackhci/stack_hci_cluster_resource.go index cd6cfe567129..17321afa76ae 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_resource.go +++ b/internal/services/azurestackhci/stack_hci_cluster_resource.go @@ -8,13 +8,11 @@ import ( "log" "time" - "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" - clusterSdk "github.com/hashicorp/go-azure-sdk/resource-manager/azurestackhci/2023-08-01/cluster" "github.com/hashicorp/go-azure-sdk/resource-manager/azurestackhci/2023-08-01/clusters" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -80,10 +78,19 @@ func resourceArmStackHCICluster() *pluginsdk.Resource { ValidateFunc: autoVal.AutomanageConfigurationID, }, - "software_assurance_enabled": { - Type: pluginsdk.TypeBool, - Optional: true, - Default: false, + "cloud_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "service_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "resource_provider_object_id": { + Type: pluginsdk.TypeString, + Computed: true, }, "identity": commonschema.SystemAssignedIdentityOptional(), @@ -120,7 +127,7 @@ func resourceArmStackHCIClusterCreate(d *pluginsdk.ResourceData, meta interface{ } if v, ok := d.GetOk("identity"); ok { - expandedIdentity, err := identity.ExpandSystemAndUserAssignedMap(v.([]interface{})) + expandedIdentity, err := expandSystemAssigned(v.([]interface{})) if err != nil { return fmt.Errorf("expanding identity: %+v", err) } @@ -172,16 +179,6 @@ func resourceArmStackHCIClusterCreate(d *pluginsdk.ResourceData, meta interface{ } } - if v, ok := d.GetOk("software_assurance_enabled"); ok { - clusterClient := meta.(*clients.Client).AzureStackHCI.Cluster - clusterId := clusterSdk.NewClusterID(id.SubscriptionId, id.ResourceGroupName, id.ClusterName) - softwareAssurance := ExpandClusterSoftwareAssurance(v.(bool)) - - if err := clusterClient.ExtendSoftwareAssuranceBenefitThenPoll(ctx, clusterId, softwareAssurance); err != nil { - return fmt.Errorf("setting software assurance for %s: %+v", id, err) - } - } - d.SetId(id.ID()) return resourceArmStackHCIClusterRead(d, meta) @@ -214,20 +211,14 @@ func resourceArmStackHCIClusterRead(d *pluginsdk.ResourceData, meta interface{}) if model := resp.Model; model != nil { d.Set("location", location.Normalize(model.Location)) - - flattenedIdentity, err := identity.FlattenSystemAndUserAssignedMap(model.Identity) - if err != nil { - return fmt.Errorf("flattening identity: %+v", err) - } - d.Set("identity", flattenedIdentity) + d.Set("identity", flattenSystemAssigned(model.Identity)) if props := model.Properties; props != nil { d.Set("client_id", props.AadClientId) d.Set("tenant_id", props.AadTenantId) - - if props.SoftwareAssuranceProperties != nil { - d.Set("software_assurance_enabled", FlattenClusterSoftwareAssurance(props.SoftwareAssuranceProperties.SoftwareAssuranceIntent)) - } + d.Set("cloud_id", props.CloudId) + d.Set("service_endpoint", props.ServiceEndpoint) + d.Set("resource_provider_object_id", props.ResourceProviderObjectId) assignmentResp, err := hciAssignmentClient.Get(ctx, id.ResourceGroupName, id.ClusterName, "default") if err != nil && !utils.ResponseWasNotFound(assignmentResp.Response) { @@ -271,7 +262,7 @@ func resourceArmStackHCIClusterUpdate(d *pluginsdk.ResourceData, meta interface{ } if d.HasChange("identity") { - expandedIdentity, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) + expandedIdentity, err := expandSystemAssigned(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding identity: %+v", err) } @@ -282,16 +273,6 @@ func resourceArmStackHCIClusterUpdate(d *pluginsdk.ResourceData, meta interface{ return fmt.Errorf("updating %s: %+v", *id, err) } - if d.HasChange("software_assurance_enabled") { - clusterClient := meta.(*clients.Client).AzureStackHCI.Cluster - clusterId := clusterSdk.NewClusterID(id.SubscriptionId, id.ResourceGroupName, id.ClusterName) - softwareAssurance := ExpandClusterSoftwareAssurance(d.Get("software_assurance_enabled").(bool)) - - if err := clusterClient.ExtendSoftwareAssuranceBenefitThenPoll(ctx, clusterId, softwareAssurance); err != nil { - return fmt.Errorf("setting software assurance for %s: %+v", id, err) - } - } - if d.HasChange("automanage_configuration_id") { if v, ok := d.GetOk("automanage_configuration_id"); ok { hciAssignmentClient := meta.(*clients.Client).Automanage.HCIAssignmentClient @@ -365,22 +346,32 @@ func resourceArmStackHCIClusterDelete(d *pluginsdk.ResourceData, meta interface{ return nil } -func ExpandClusterSoftwareAssurance(input bool) clusterSdk.SoftwareAssuranceChangeRequest { - enabled := clusterSdk.SoftwareAssuranceIntentDisable - if input { - enabled = clusterSdk.SoftwareAssuranceIntentEnable +func expandSystemAssigned(input []interface{}) (*identity.SystemAndUserAssignedMap, error) { + if len(input) == 0 || input[0] == nil { + return &identity.SystemAndUserAssignedMap{ + Type: identity.TypeNone, + }, nil } - return clusterSdk.SoftwareAssuranceChangeRequest{ - Properties: &clusterSdk.SoftwareAssuranceChangeRequestProperties{ - SoftwareAssuranceIntent: pointer.To(enabled), - }, - } + return &identity.SystemAndUserAssignedMap{ + Type: identity.TypeSystemAssigned, + }, nil } -func FlattenClusterSoftwareAssurance(input *clusters.SoftwareAssuranceIntent) bool { +func flattenSystemAssigned(input *identity.SystemAndUserAssignedMap) []interface{} { if input == nil { - return false + return []interface{}{} + } + + if input.Type == identity.TypeNone { + return []interface{}{} + } + + return []interface{}{ + map[string]interface{}{ + "type": input.Type, + "principal_id": input.PrincipalId, + "tenant_id": input.TenantId, + }, } - return *input == clusters.SoftwareAssuranceIntentEnable } diff --git a/internal/services/azurestackhci/stack_hci_cluster_resource_test.go b/internal/services/azurestackhci/stack_hci_cluster_resource_test.go index 0aca64afec6e..51ae137d96cf 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_resource_test.go +++ b/internal/services/azurestackhci/stack_hci_cluster_resource_test.go @@ -28,6 +28,9 @@ func TestAccStackHCICluster_basic(t *testing.T) { Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("cloud_id").IsNotEmpty(), + check.That(data.ResourceName).Key("service_endpoint").IsNotEmpty(), + check.That(data.ResourceName).Key("resource_provider_object_id").IsNotEmpty(), ), }, data.ImportStep(), @@ -58,6 +61,9 @@ func TestAccStackHCICluster_systemAssignedIdentity(t *testing.T) { Config: r.systemAssignedIdentity(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("identity.0.type").HasValue("SystemAssigned"), + check.That(data.ResourceName).Key("identity.0.principal_id").IsNotEmpty(), + check.That(data.ResourceName).Key("identity.0.tenant_id").IsNotEmpty(), ), }, data.ImportStep(), @@ -93,50 +99,6 @@ func TestAccStackHCICluster_systemAssignedIdentityUpdate(t *testing.T) { }) } -func TestAccStackHCICluster_softwareAssurance(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_stack_hci_cluster", "test") - r := StackHCIClusterResource{} - - data.ResourceTest(t, r, []acceptance.TestStep{ - { - Config: r.softwareAssurance(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - }) -} - -func TestAccStackHCICluster_softwareAssuranceUpdate(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_stack_hci_cluster", "test") - r := StackHCIClusterResource{} - - data.ResourceTest(t, r, []acceptance.TestStep{ - { - Config: r.basic(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - { - Config: r.softwareAssurance(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - { - Config: r.basic(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - }) -} - func TestAccStackHCICluster_complete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_stack_hci_cluster", "test") r := StackHCIClusterResource{} @@ -264,22 +226,6 @@ resource "azurerm_stack_hci_cluster" "test" { `, template, data.RandomInteger) } -func (r StackHCIClusterResource) softwareAssurance(data acceptance.TestData) string { - template := r.template(data) - return fmt.Sprintf(` -%s - -resource "azurerm_stack_hci_cluster" "test" { - name = "acctest-StackHCICluster-%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - client_id = azuread_application.test.application_id - tenant_id = data.azurerm_client_config.current.tenant_id - softwareAssuranceEnabled = true -} -`, template, data.RandomInteger) -} - func (r StackHCIClusterResource) complete(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` diff --git a/website/docs/d/stack_hci_cluster.html.markdown b/website/docs/d/stack_hci_cluster.html.markdown index 774bee7794a2..7e9fd45a6011 100644 --- a/website/docs/d/stack_hci_cluster.html.markdown +++ b/website/docs/d/stack_hci_cluster.html.markdown @@ -47,15 +47,33 @@ In addition to the Arguments listed above - the following Attributes are exporte * `id` - The ID of the Azure Stack HCI Cluster. -* `location` - The Azure Region where the Azure Stack HCI Cluster exists. +* `automanage_configuration_id` - The ID of the Automanage Configuration assigned to the Azure Stack HCI Cluster. * `client_id` - The Client ID of the Azure Active Directory used by the Azure Stack HCI Cluster. +* `cloud_id` - An immutable UUID for the Azure Stack HCI Cluster. + +* `identity` - An `identity` block as defined below. + +* `location` - The Azure Region where the Azure Stack HCI Cluster exists. + +* `resource_provider_object_id` - The object ID of the Resource Provider Service Principal. + +* `service_endpoint` - The region specific Data Path Endpoint of the Azure Stack HCI Cluster. + * `tenant_id` - The Tenant ID of the Azure Active Directory used by the Azure Stack HCI Cluster. * `tags` - A mapping of tags assigned to the Azure Stack HCI Cluster. -* `automanage_configuration_id` - The ID of the Automanage Configuration assigned to the Azure Stack HCI Cluster. +--- + +An `identity` block exports the following: + +* `type` - (Required) The type of Managed Service Identity that configured on the Azure Stack HCI Cluster. + +* `principal_id` - The Principal ID associated with this Managed Service Identity. + +* `tenant_id` - The Tenant ID associated with this Managed Service Identity. ## Timeouts diff --git a/website/docs/r/stack_hci_cluster.html.markdown b/website/docs/r/stack_hci_cluster.html.markdown index b5550481859a..5219529098b3 100644 --- a/website/docs/r/stack_hci_cluster.html.markdown +++ b/website/docs/r/stack_hci_cluster.html.markdown @@ -30,6 +30,9 @@ resource "azurerm_stack_hci_cluster" "example" { location = azurerm_resource_group.example.location client_id = data.azuread_application.example.application_id tenant_id = data.azurerm_client_config.current.tenant_id + identity { + type = "SystemAssigned" + } } ``` @@ -45,6 +48,8 @@ The following arguments are supported: * `client_id` - (Required) The Client ID of the Azure Active Directory which is used by the Azure Stack HCI Cluster. Changing this forces a new resource to be created. +* `identity` - (Optional) An `identity` block as defined below. + * `tenant_id` - (Optional) The Tenant ID of the Azure Active Directory which is used by the Azure Stack HCI Cluster. Changing this forces a new resource to be created. ~> **NOTE** If unspecified the Tenant ID of the Provider will be used. @@ -53,11 +58,36 @@ The following arguments are supported: * `automanage_configuration_id` - (Optional) The ID of the Automanage Configuration assigned to the Azure Stack HCI Cluster. +--- + +An `identity` block supports the following: + +* `type` - (Required) Specifies the type of Managed Service Identity that should be configured on the Azure Stack HCI Cluster. Possible value is `SystemAssigned`. + ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: -* `id` - The ID of the Azure Stack HCI Cluster. +* `id` - The resource ID of the Azure Stack HCI Cluster. + +* `cloud_id` - An immutable UUID for the Azure Stack HCI Cluster. + + +* `resource_provider_object_id` - The object ID of the Resource Provider Service Principal. + +* `identity` - An `identity` block as defined below. + +* `service_endpoint` - The region specific Data Path Endpoint of the Azure Stack HCI Cluster. + +--- + +An `identity` block exports the following: + +* `principal_id` - The Principal ID associated with this Managed Service Identity. + +* `tenant_id` - The Tenant ID associated with this Managed Service Identity. + +-> You can access the Principal ID via `azurerm_stack_hci_cluster.example.identity.0.principal_id` ## Timeouts From 23934aca85935bd8b32859d4c57279ef7762edac Mon Sep 17 00:00:00 2001 From: Tao <104055472+teowa@users.noreply.github.com> Date: Tue, 27 Feb 2024 13:23:42 +0800 Subject: [PATCH 3/6] fix --- .../azurestackhci/stack_hci_cluster_data_source_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/azurestackhci/stack_hci_cluster_data_source_test.go b/internal/services/azurestackhci/stack_hci_cluster_data_source_test.go index ad7c772ad288..b802041dffaa 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_data_source_test.go +++ b/internal/services/azurestackhci/stack_hci_cluster_data_source_test.go @@ -38,7 +38,7 @@ func TestAccStackHCIClusterDataSource_identity(t *testing.T) { data.DataSourceTest(t, []acceptance.TestStep{ { - Config: r.basic(data), + Config: r.identity(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).Key("identity.0.type").HasValue("SystemAssigned"), check.That(data.ResourceName).Key("identity.0.principal_id").IsNotEmpty(), From dc956ea228de7b35eff11d87fde09f8eb7e86730 Mon Sep 17 00:00:00 2001 From: Tao <104055472+teowa@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:22:26 +0800 Subject: [PATCH 4/6] fix golangci-lint error --- .../stack_hci_cluster_resource.go | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/internal/services/azurestackhci/stack_hci_cluster_resource.go b/internal/services/azurestackhci/stack_hci_cluster_resource.go index 17321afa76ae..4a5572c04446 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_resource.go +++ b/internal/services/azurestackhci/stack_hci_cluster_resource.go @@ -127,11 +127,7 @@ func resourceArmStackHCIClusterCreate(d *pluginsdk.ResourceData, meta interface{ } if v, ok := d.GetOk("identity"); ok { - expandedIdentity, err := expandSystemAssigned(v.([]interface{})) - if err != nil { - return fmt.Errorf("expanding identity: %+v", err) - } - cluster.Identity = expandedIdentity + cluster.Identity = expandSystemAssigned(v.([]interface{})) } if v, ok := d.GetOk("tenant_id"); ok { @@ -262,11 +258,7 @@ func resourceArmStackHCIClusterUpdate(d *pluginsdk.ResourceData, meta interface{ } if d.HasChange("identity") { - expandedIdentity, err := expandSystemAssigned(d.Get("identity").([]interface{})) - if err != nil { - return fmt.Errorf("expanding identity: %+v", err) - } - cluster.Identity = expandedIdentity + cluster.Identity = expandSystemAssigned(d.Get("identity").([]interface{})) } if _, err := client.Update(ctx, *id, cluster); err != nil { @@ -346,16 +338,16 @@ func resourceArmStackHCIClusterDelete(d *pluginsdk.ResourceData, meta interface{ return nil } -func expandSystemAssigned(input []interface{}) (*identity.SystemAndUserAssignedMap, error) { +func expandSystemAssigned(input []interface{}) *identity.SystemAndUserAssignedMap { if len(input) == 0 || input[0] == nil { return &identity.SystemAndUserAssignedMap{ Type: identity.TypeNone, - }, nil + } } return &identity.SystemAndUserAssignedMap{ Type: identity.TypeSystemAssigned, - }, nil + } } func flattenSystemAssigned(input *identity.SystemAndUserAssignedMap) []interface{} { From d04e2f5d6dcff044eafca94511975f0f4310f3a0 Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Thu, 14 Mar 2024 07:44:51 +0000 Subject: [PATCH 5/6] link swagger issue --- internal/services/azurestackhci/stack_hci_cluster_resource.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/services/azurestackhci/stack_hci_cluster_resource.go b/internal/services/azurestackhci/stack_hci_cluster_resource.go index 4a5572c04446..413d978b20fb 100644 --- a/internal/services/azurestackhci/stack_hci_cluster_resource.go +++ b/internal/services/azurestackhci/stack_hci_cluster_resource.go @@ -338,6 +338,7 @@ func resourceArmStackHCIClusterDelete(d *pluginsdk.ResourceData, meta interface{ return nil } +// API does not accept userAssignedIdentity as in swagger https://github.com/Azure/azure-rest-api-specs/issues/28260 func expandSystemAssigned(input []interface{}) *identity.SystemAndUserAssignedMap { if len(input) == 0 || input[0] == nil { return &identity.SystemAndUserAssignedMap{ From 0b19be3e85a56db486b313c7015c885acf35fee0 Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Thu, 14 Mar 2024 08:34:09 +0000 Subject: [PATCH 6/6] fix doc --- website/docs/d/stack_hci_cluster.html.markdown | 2 +- website/docs/r/stack_hci_cluster.html.markdown | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/d/stack_hci_cluster.html.markdown b/website/docs/d/stack_hci_cluster.html.markdown index 7e9fd45a6011..43637878ff38 100644 --- a/website/docs/d/stack_hci_cluster.html.markdown +++ b/website/docs/d/stack_hci_cluster.html.markdown @@ -69,7 +69,7 @@ In addition to the Arguments listed above - the following Attributes are exporte An `identity` block exports the following: -* `type` - (Required) The type of Managed Service Identity that configured on the Azure Stack HCI Cluster. +* `type` - (Required) The type of Managed Service Identity configured on the Azure Stack HCI Cluster. * `principal_id` - The Principal ID associated with this Managed Service Identity. diff --git a/website/docs/r/stack_hci_cluster.html.markdown b/website/docs/r/stack_hci_cluster.html.markdown index 5219529098b3..e5bd9734d3ce 100644 --- a/website/docs/r/stack_hci_cluster.html.markdown +++ b/website/docs/r/stack_hci_cluster.html.markdown @@ -72,7 +72,6 @@ In addition to the Arguments listed above - the following Attributes are exporte * `cloud_id` - An immutable UUID for the Azure Stack HCI Cluster. - * `resource_provider_object_id` - The object ID of the Resource Provider Service Principal. * `identity` - An `identity` block as defined below.