Skip to content

Commit

Permalink
New resource: azurerm_log_analytics_workspace_table (#24229)
Browse files Browse the repository at this point in the history
Fixes #10573
Fixes #6199
  • Loading branch information
favoretti committed Dec 18, 2023
1 parent 102e9ba commit f411200
Show file tree
Hide file tree
Showing 27 changed files with 1,707 additions and 0 deletions.
9 changes: 9 additions & 0 deletions internal/services/loganalytics/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches"
"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights"
"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces"
"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2022-10-01/tables"
featureWorkspaces "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2022-10-01/workspaces"
"github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution"
"github.com/hashicorp/terraform-provider-azurerm/internal/common"
Expand All @@ -33,6 +34,7 @@ type Client struct {
StorageInsightsClient *storageinsights.StorageInsightsClient
QueryPackQueriesClient *querypackqueries.QueryPackQueriesClient
SharedKeyWorkspacesClient *workspaces.WorkspacesClient
TablesClient *tables.TablesClient
WorkspaceClient *featureWorkspaces.WorkspacesClient // 2022-10-01 API version does not contain sharedkeys related API, so we keep two versions SDK of this API
}

Expand Down Expand Up @@ -109,6 +111,12 @@ func NewClient(o *common.ClientOptions) (*Client, error) {
}
o.Configure(queryPackQueriesClient.Client, o.Authorizers.ResourceManager)

tablesClient, err := tables.NewTablesClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building Tables client: %+v", err)
}
o.Configure(tablesClient.Client, o.Authorizers.ResourceManager)

return &Client{
ClusterClient: clusterClient,
DataExportClient: dataExportClient,
Expand All @@ -121,6 +129,7 @@ func NewClient(o *common.ClientOptions) (*Client, error) {
SolutionsClient: solutionsClient,
StorageInsightsClient: storageInsightsClient,
SharedKeyWorkspacesClient: workspacesClient,
TablesClient: tablesClient,
WorkspaceClient: featureWorkspaceClient,
}, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package loganalytics

import (
"context"
"fmt"
"log"
"time"

"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2022-10-01/tables"
"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2022-10-01/workspaces"
"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"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

type LogAnalyticsWorkspaceTableResource struct {
}

var _ sdk.ResourceWithUpdate = LogAnalyticsWorkspaceTableResource{}

type LogAnalyticsWorkspaceTableResourceModel struct {
Name string `tfschema:"name"`
WorkspaceId string `tfschema:"workspace_id"`
RetentionInDays int64 `tfschema:"retention_in_days"`
}

func (r LogAnalyticsWorkspaceTableResource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"workspace_id": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: workspaces.ValidateWorkspaceID,
},

"name": {
Type: pluginsdk.TypeString,
Required: true,
},

"retention_in_days": {
Type: pluginsdk.TypeInt,
Required: true,
ValidateFunc: validation.Any(validation.IntBetween(30, 730), validation.IntInSlice([]int{7})),
},
}
}

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

func (r LogAnalyticsWorkspaceTableResource) ModelObject() interface{} {
return &LogAnalyticsWorkspaceTableResourceModel{}
}

func (r LogAnalyticsWorkspaceTableResource) ResourceType() string {
return "azurerm_log_analytics_workspace_table"
}

func (r LogAnalyticsWorkspaceTableResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return tables.ValidateTableID
}

func (r LogAnalyticsWorkspaceTableResource) Create() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
var model LogAnalyticsWorkspaceTableResourceModel
if err := metadata.Decode(&model); err != nil {
return fmt.Errorf("decoding %+v", err)
}
client := metadata.Client.LogAnalytics.TablesClient
subscriptionId := metadata.Client.Account.SubscriptionId

tableName := model.Name
log.Printf("[INFO] preparing arguments for AzureRM Log Analytics Workspace Table %s update.", tableName)

workspaceId, err := workspaces.ParseWorkspaceID(model.WorkspaceId)
if err != nil {
return fmt.Errorf("invalid workspace object ID for table %s: %s", tableName, err)
}

id := tables.NewTableID(subscriptionId, workspaceId.ResourceGroupName, workspaceId.WorkspaceName, tableName)

retentionInDays := model.RetentionInDays
updateInput := tables.Table{
Properties: &tables.TableProperties{
RetentionInDays: &retentionInDays,
},
}
if err := client.CreateOrUpdateThenPoll(ctx, id, updateInput); err != nil {
return fmt.Errorf("failed to update table %s in workspace %s in resource group %s: %s", tableName, workspaceId.WorkspaceName, workspaceId.ResourceGroupName, err)
}

metadata.SetID(id)
return nil
},
}
}

func (r LogAnalyticsWorkspaceTableResource) Update() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.LogAnalytics.TablesClient
id, err := tables.ParseTableID(metadata.ResourceData.Id())
if err != nil {
return err
}

var state LogAnalyticsWorkspaceTableResourceModel
if err := metadata.Decode(&state); err != nil {
return fmt.Errorf("decoding: %+v", err)
}

existing, err := client.Get(ctx, *id)
if err != nil {
return fmt.Errorf("reading Log Analytics Workspace Table %s: %v", id, err)
}

updateInput := tables.Table{
Properties: &tables.TableProperties{
RetentionInDays: existing.Model.Properties.RetentionInDays,
},
}

if metadata.ResourceData.HasChange("retention_in_days") {
updateInput.Properties.RetentionInDays = &state.RetentionInDays
}
if err := client.CreateOrUpdateThenPoll(ctx, *id, updateInput); err != nil {
return fmt.Errorf("failed to update table: %s: %+v", id.TableName, err)
}

return nil
},
}
}

func (r LogAnalyticsWorkspaceTableResource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
id, err := tables.ParseTableID(metadata.ResourceData.Id())
if err != nil {
return fmt.Errorf("while parsing resource ID: %+v", err)
}

workspaceId, err := workspaces.ParseWorkspaceID(metadata.ResourceData.Get("workspace_id").(string))
if err != nil {
return fmt.Errorf("while parsing resource ID: %+v", err)
}

client := metadata.Client.LogAnalytics.TablesClient

resp, err := client.Get(ctx, *id)
if err != nil {
if response.WasNotFound(resp.HttpResponse) {
return metadata.MarkAsGone(id)
}
return fmt.Errorf("retrieving Log Analytics Workspace Table %s: %+v", *id, err)
}

state := LogAnalyticsWorkspaceTableResourceModel{
Name: id.TableName,
WorkspaceId: workspaceId.ID(),
}

if model := resp.Model; model != nil {
if model.Properties.RetentionInDays != nil {
state.RetentionInDays = *model.Properties.RetentionInDays
}
}

return metadata.Encode(&state)
},
}
}

func (r LogAnalyticsWorkspaceTableResource) Delete() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 30 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
var model LogAnalyticsWorkspaceTableResourceModel
if err := metadata.Decode(&model); err != nil {
return fmt.Errorf("decoding %+v", err)
}
client := metadata.Client.LogAnalytics.TablesClient
id, err := tables.ParseTableID(metadata.ResourceData.Id())
if err != nil {
return fmt.Errorf("while parsing resource ID: %+v", err)
}

// We do not delete the resource here, just set the retention to workspace default value, which is
// achieved by setting the value to `-1`
retentionInDays := utils.Int64(-1)

updateInput := tables.Table{
Properties: &tables.TableProperties{
RetentionInDays: retentionInDays,
},
}

if err := client.CreateOrUpdateThenPoll(ctx, *id, updateInput); err != nil {
return fmt.Errorf("failed to update table %s in workspace %s in resource group %s: %s", id.TableName, id.WorkspaceName, id.ResourceGroupName, err)
}

return nil
},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package loganalytics_test

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2022-10-01/tables"
"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"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

type LogAnalyticsWorkspaceTableResource struct{}

func TestAccLogAnalyticsWorkspaceTable_updateTableRetention(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_log_analytics_workspace_table", "test")
r := LogAnalyticsWorkspaceTableResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.updateRetention(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("id").Exists(),
check.That(data.ResourceName).Key("name").HasValue("AppEvents"),
check.That(data.ResourceName).Key("retention_in_days").HasValue("7"),
),
},
})
}

func (t LogAnalyticsWorkspaceTableResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := tables.ParseTableID(state.ID)
if err != nil {
return nil, err
}

resp, err := clients.LogAnalytics.TablesClient.Get(ctx, *id)
if err != nil {
return nil, fmt.Errorf("reading Log Analytics Workspace Table (%s): %+v", id.ID(), err)
}

return utils.Bool(resp.Model.Id != nil), nil
}

func (LogAnalyticsWorkspaceTableResource) updateRetention(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}
resource "azurerm_log_analytics_workspace" "test" {
name = "acctestLAW-%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
retention_in_days = 30
}
resource "azurerm_log_analytics_workspace_table" "test" {
name = "AppEvents"
workspace_id = azurerm_log_analytics_workspace.test.id
retention_in_days = 7
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}
1 change: 1 addition & 0 deletions internal/services/loganalytics/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func (r Registration) Resources() []sdk.Resource {
LogAnalyticsQueryPackResource{},
LogAnalyticsQueryPackQueryResource{},
LogAnalyticsSolutionResource{},
LogAnalyticsWorkspaceTableResource{},
}
}

Expand Down
Loading

0 comments on commit f411200

Please sign in to comment.