Skip to content

Commit

Permalink
azurerm_log_analytics_cluster_customer_managed_key - fix create/upd…
Browse files Browse the repository at this point in the history
…ate/delete functions (#28862)

* fix bad request and deletion of CMK

* remove empty value errors so TF can recreate if CMK is missing during read

* Update internal/services/loganalytics/log_analytics_cluster_customer_managed_key_resource.go

Co-authored-by: stephybun <[email protected]>

* remove duplicated verbose comment

---------

Co-authored-by: stephybun <[email protected]>
  • Loading branch information
sreallymatt and stephybun authored Feb 27, 2025
1 parent 4a05d26 commit f481efb
Showing 1 changed file with 43 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"log"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2022-10-01/clusters"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
Expand All @@ -18,7 +19,6 @@ import (
"github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/migration"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func resourceLogAnalyticsClusterCustomerManagedKey() *pluginsdk.Resource {
Expand Down Expand Up @@ -86,12 +86,12 @@ func resourceLogAnalyticsClusterCustomerManagedKeyCreate(d *pluginsdk.ResourceDa

model := resp.Model
if model == nil {
return fmt.Errorf("retiring `azurerm_log_analytics_cluster` %s: `model` is nil", *id)
return fmt.Errorf("retrieving `azurerm_log_analytics_cluster` %s: `model` is nil", *id)
}

props := model.Properties
if props == nil {
return fmt.Errorf("retiring `azurerm_log_analytics_cluster` %s: `Properties` is nil", *id)
return fmt.Errorf("retrieving `azurerm_log_analytics_cluster` %s: `Properties` is nil", *id)
}

if props.KeyVaultProperties != nil {
Expand All @@ -100,19 +100,26 @@ func resourceLogAnalyticsClusterCustomerManagedKeyCreate(d *pluginsdk.ResourceDa
}
}

// Ensure `associatedWorkspaces` is not present in request, this is a read only property and cannot be sent to the API
// Error: updating Customer Managed Key for Cluster
// performing CreateOrUpdate: unexpected status 400 (400 Bad Request) with error:
// InvalidParameter: 'properties.associatedWorkspaces' is a read only property and cannot be set.
// Please refer to https://docs.microsoft.com/en-us/azure/azure-monitor/log-query/logs-dedicated-clusters#link-a-workspace-to-the-cluster for more information on how to associate a workspace to the cluster.
props.AssociatedWorkspaces = nil

keyId, err := keyVaultParse.ParseOptionallyVersionedNestedItemID(d.Get("key_vault_key_id").(string))
if err != nil {
return fmt.Errorf("parsing Key Vault Key ID: %+v", err)
}

model.Properties.KeyVaultProperties = &clusters.KeyVaultProperties{
KeyVaultUri: utils.String(keyId.KeyVaultBaseUrl),
KeyName: utils.String(keyId.Name),
KeyVersion: utils.String(keyId.Version),
KeyVaultUri: pointer.To(keyId.KeyVaultBaseUrl),
KeyName: pointer.To(keyId.Name),
KeyVersion: pointer.To(keyId.Version),
}

if err := client.CreateOrUpdateThenPoll(ctx, *id, *model); err != nil {
return fmt.Errorf("updating Customer Managed Key for %s: %+v", *id, err)
return fmt.Errorf("creating Customer Managed Key for %s: %+v", *id, err)
}

updateWait, err := logAnalyticsClusterWaitForState(ctx, client, *id)
Expand Down Expand Up @@ -156,17 +163,20 @@ func resourceLogAnalyticsClusterCustomerManagedKeyUpdate(d *pluginsdk.ResourceDa

model := resp.Model
if model == nil {
return fmt.Errorf("retiring `azurerm_log_analytics_cluster` %s: `model` is nil", *id)
return fmt.Errorf("retrieving `azurerm_log_analytics_cluster` %s: `model` is nil", *id)
}

if props := model.Properties; props == nil {
return fmt.Errorf("retiring `azurerm_log_analytics_cluster` %s: `Properties` is nil", *id)
return fmt.Errorf("retrieving `azurerm_log_analytics_cluster` %s: `Properties` is nil", *id)
}

// This is a read only property, please see comment in the create function.
model.Properties.AssociatedWorkspaces = nil

model.Properties.KeyVaultProperties = &clusters.KeyVaultProperties{
KeyVaultUri: utils.String(keyId.KeyVaultBaseUrl),
KeyName: utils.String(keyId.Name),
KeyVersion: utils.String(keyId.Version),
KeyVaultUri: pointer.To(keyId.KeyVaultBaseUrl),
KeyName: pointer.To(keyId.Name),
KeyVersion: pointer.To(keyId.Version),
}

if err := client.CreateOrUpdateThenPoll(ctx, *id, *model); err != nil {
Expand Down Expand Up @@ -200,31 +210,24 @@ func resourceLogAnalyticsClusterCustomerManagedKeyRead(d *pluginsdk.ResourceData
if model := resp.Model; model != nil {
if props := model.Properties; props != nil {
if kvProps := props.KeyVaultProperties; kvProps != nil {
var keyVaultUri, keyName, keyVersion string
if kvProps.KeyVaultUri != nil && *kvProps.KeyVaultUri != "" {
keyVaultUri = *kvProps.KeyVaultUri
} else {
return fmt.Errorf("empty value returned for Key Vault URI")
}
if kvProps.KeyName != nil && *kvProps.KeyName != "" {
keyName = *kvProps.KeyName
} else {
return fmt.Errorf("empty value returned for Key Vault Key Name")
keyVaultUri := pointer.From(kvProps.KeyVaultUri)
keyName := pointer.From(kvProps.KeyName)
keyVersion := pointer.From(kvProps.KeyVersion)

if keyVaultUri != "" && keyName != "" {
keyId, err := keyVaultParse.NewNestedItemID(keyVaultUri, keyVaultParse.NestedItemTypeKey, keyName, keyVersion)
if err != nil {
return err
}
keyVaultKeyId = keyId.ID()
}
if kvProps.KeyVersion != nil {
keyVersion = *kvProps.KeyVersion
}
keyId, err := keyVaultParse.NewNestedItemID(keyVaultUri, keyVaultParse.NestedItemTypeKey, keyName, keyVersion)
if err != nil {
return err
}
keyVaultKeyId = keyId.ID()
}
}
}

if keyVaultKeyId == "" {
log.Printf("[DEBUG] %s has no Customer Managed Key - removing from state", *id)
d.SetId("")
return nil
}

Expand Down Expand Up @@ -258,12 +261,12 @@ func resourceLogAnalyticsClusterCustomerManagedKeyDelete(d *pluginsdk.ResourceDa

model := resp.Model
if model == nil {
return fmt.Errorf("retiring `azurerm_log_analytics_cluster` %s: `model` is nil", *id)
return fmt.Errorf("retrieving `azurerm_log_analytics_cluster` %s: `model` is nil", *id)
}

props := model.Properties
if props == nil {
return fmt.Errorf("retiring `azurerm_log_analytics_cluster` %s: `Properties` is nil", *id)
return fmt.Errorf("retrieving `azurerm_log_analytics_cluster` %s: `Properties` is nil", *id)
}

if props.KeyVaultProperties == nil {
Expand All @@ -274,14 +277,18 @@ func resourceLogAnalyticsClusterCustomerManagedKeyDelete(d *pluginsdk.ResourceDa
return fmt.Errorf("deleting `azurerm_log_analytics_cluster_customer_managed_key` %s: `customer managed key does not exist!`", *id)
}

// This is a read only property, please see comment in the create function.
props.AssociatedWorkspaces = nil

// The API only removes the CMK when it is sent empty string values, sending nil for each property or an empty object does not work.
model.Properties.KeyVaultProperties = &clusters.KeyVaultProperties{
KeyVaultUri: nil,
KeyName: nil,
KeyVersion: nil,
KeyVaultUri: pointer.To(""),
KeyName: pointer.To(""),
KeyVersion: pointer.To(""),
}

if err = client.CreateOrUpdateThenPoll(ctx, *id, *model); err != nil {
return fmt.Errorf("updating Customer Managed Key for %s: %+v", *id, err)
return fmt.Errorf("deleting Customer Managed Key from %s: %+v", *id, err)
}

return nil
Expand Down

0 comments on commit f481efb

Please sign in to comment.