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

appinsights - migrate to go-azure-sdk #25376

Merged
merged 9 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,22 @@ import (
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/services/appinsights/mgmt/2020-02-02/insights" // nolint: staticcheck
"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
analyticsitems "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2015-05-01/analyticsitemsapis"
components "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-02-02/componentsapis"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/applicationinsights/migration"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/applicationinsights/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/applicationinsights/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

var (
userScopePath = "myAnalyticsItems"
sharedScopePath = "analyticsItems"
)

func resourceApplicationInsightsAnalyticsItem() *pluginsdk.Resource {
Expand All @@ -28,14 +34,12 @@ func resourceApplicationInsightsAnalyticsItem() *pluginsdk.Resource {
Delete: resourceApplicationInsightsAnalyticsItemDelete,

Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error {
if strings.Contains(id, "myAnalyticsItems") {
_, err := parse.AnalyticsUserItemID(id)
return err
} else {
strings.Contains(id, string(insights.ItemScopePathAnalyticsItems))
_, err := parse.AnalyticsSharedItemID(id)
return err
if strings.Contains(id, userScopePath) || strings.Contains(id, sharedScopePath) {
if _, err := analyticsitems.ParseProviderComponentID(id); err != nil {
return err
}
}
return nil
}),

SchemaVersion: 1,
Expand All @@ -62,7 +66,7 @@ func resourceApplicationInsightsAnalyticsItem() *pluginsdk.Resource {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.ComponentID,
ValidateFunc: components.ValidateComponentID,
},

"version": {
Expand All @@ -80,8 +84,8 @@ func resourceApplicationInsightsAnalyticsItem() *pluginsdk.Resource {
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
string(insights.ItemScopeShared),
string(insights.ItemScopeUser),
string(analyticsitems.ItemScopeShared),
string(analyticsitems.ItemScopeUser),
}, false),
},

Expand All @@ -90,10 +94,10 @@ func resourceApplicationInsightsAnalyticsItem() *pluginsdk.Resource {
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
string(insights.ItemTypeQuery),
string(insights.ItemTypeFunction),
string(insights.ItemTypeFolder),
string(insights.ItemTypeRecent),
string(analyticsitems.ItemTypeQuery),
string(analyticsitems.ItemTypeFunction),
string(analyticsitems.ItemTypeParameterFolder),
string(analyticsitems.ItemTypeRecent),
}, false),
},

Expand All @@ -116,129 +120,160 @@ func resourceApplicationInsightsAnalyticsItem() *pluginsdk.Resource {
}

func resourceApplicationInsightsAnalyticsItemCreate(d *pluginsdk.ResourceData, meta interface{}) error {
return resourceApplicationInsightsAnalyticsItemCreateUpdate(d, meta, false)
}

func resourceApplicationInsightsAnalyticsItemUpdate(d *pluginsdk.ResourceData, meta interface{}) error {
return resourceApplicationInsightsAnalyticsItemCreateUpdate(d, meta, true)
}

func resourceApplicationInsightsAnalyticsItemCreateUpdate(d *pluginsdk.ResourceData, meta interface{}, overwrite bool) error {
client := meta.(*clients.Client).AppInsights.AnalyticsItemsClient
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

appInsightsId, err := parse.ComponentID(d.Get("application_insights_id").(string))
appInsightsId, err := components.ParseComponentID(d.Get("application_insights_id").(string))
if err != nil {
return err
}

var itemID string
var id string
if id, _, _, _, itemID, err = ResourcesArmApplicationInsightsAnalyticsItemParseID(d.Id()); d.Id() != "" {
if err != nil {
return fmt.Errorf("parsing Application Insights Analytics Item ID %s: %+v", d.Id(), err)
}
}

name := d.Get("name").(string)
content := d.Get("content").(string)
scopeName := d.Get("scope").(string)
typeName := d.Get("type").(string)
functionAlias := d.Get("function_alias").(string)

itemType := insights.ItemType(typeName)
itemScope := insights.ItemScope(scopeName)
itemType := analyticsitems.ItemType(typeName)
itemScope := analyticsitems.ItemScope(scopeName)

var itemScopePath insights.ItemScopePath
if itemScope == insights.ItemScopeUser {
itemScopePath = insights.ItemScopePathMyanalyticsItems
} else {
itemScopePath = insights.ItemScopePathAnalyticsItems
itemScopePath := sharedScopePath
if itemScope == analyticsitems.ItemScopeUser {
itemScopePath = userScopePath
}

includeContent := false

if d.IsNewResource() {
// We cannot get specific analytics items without their itemID which is why we need to list all the
// available items of a certain type and scope in order to check whether a resource already exists and needs
// to be imported first
// https://github.com/Azure/azure-rest-api-specs/issues/20712 itemScopePath should be set to insights.ItemScopePathAnalyticsItems in List method
existing, err := client.List(ctx, appInsightsId.ResourceGroup, appInsightsId.Name, insights.ItemScopePathAnalyticsItems, itemScope, insights.ItemTypeParameter(typeName), &includeContent)
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("checking for presence of existing Application Insights Analytics Items %+v", err)
}
id := analyticsitems.NewProviderComponentID(appInsightsId.SubscriptionId, appInsightsId.ResourceGroupName, appInsightsId.ComponentName, itemScopePath)

// We cannot get specific analytics items without their itemID which is why we need to list all the
// available items of a certain type and scope in order to check whether a resource already exists and needs
// to be imported first
// https://github.com/Azure/azure-rest-api-specs/issues/20712 itemScopePath should be set to insights.ItemScopePathAnalyticsItems in List method
listId := analyticsitems.NewProviderComponentID(appInsightsId.SubscriptionId, appInsightsId.ResourceGroupName, appInsightsId.ComponentName, "analyticsItems")
existing, err := client.AnalyticsItemsList(ctx, listId, analyticsitems.DefaultAnalyticsItemsListOperationOptions())
if err != nil {
if !response.WasNotFound(existing.HttpResponse) {
return fmt.Errorf("checking for presence of existing %s: %+v", id, err)
}
if existing.Value != nil {
values := *existing.Value
for _, v := range values {
if *v.Name == name {
return tf.ImportAsExistsError("azurerm_application_insights_analytics_item", *v.ID)
}
}

if model := existing.Model; model != nil {
for _, value := range *model {
if v := value.Name; v != nil && *v == name {
return tf.ImportAsExistsError("azurerm_application_insights_analytics_item", *value.Id)
}
}
}

properties := insights.ApplicationInsightsComponentAnalyticsItem{
ID: &itemID,
Name: &name,
Type: itemType,
Scope: itemScope,
Content: &content,
properties := analyticsitems.ApplicationInsightsComponentAnalyticsItem{
Name: pointer.To(name),
Type: pointer.To(itemType),
Scope: pointer.To(itemScope),
Content: pointer.To(d.Get("content").(string)),
}
if functionAlias != "" {
properties.Properties = &insights.ApplicationInsightsComponentAnalyticsItemProperties{
FunctionAlias: &functionAlias,
if v := d.Get("function_alias").(string); v != "" {
properties.Properties = &analyticsitems.ApplicationInsightsComponentAnalyticsItemProperties{
FunctionAlias: &v,
}
}

result, err := client.Put(ctx, appInsightsId.ResourceGroup, appInsightsId.Name, itemScopePath, properties, &overwrite)
resp, err := client.AnalyticsItemsPut(ctx, id, properties, analyticsitems.DefaultAnalyticsItemsPutOperationOptions())
if err != nil {
return fmt.Errorf("creating %s: %+v", id, err)
}

if resp.Model == nil && resp.Model.Id == nil {
return fmt.Errorf("model and model ID for %s are nil", id)
}

generatedId := parse.NewAnalyticsSharedItemID(id.SubscriptionId, id.ResourceGroupName, id.ComponentName, *resp.Model.Id).ID()
if itemScope == analyticsitems.ItemScopeUser {
generatedId = parse.NewAnalyticsUserItemID(id.SubscriptionId, id.ResourceGroupName, id.ComponentName, *resp.Model.Id).ID()
}

d.SetId(generatedId)

return resourceApplicationInsightsAnalyticsItemRead(d, meta)
}

func resourceApplicationInsightsAnalyticsItemUpdate(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).AppInsights.AnalyticsItemsClient
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

id, itemId, err := ParseGeneratedAnalyticsItemId(d.Id())
if err != nil {
return err
}

getOptions := analyticsitems.AnalyticsItemsGetOperationOptions{
Id: pointer.To(itemId),
}

existing, err := client.AnalyticsItemsGet(ctx, *id, getOptions)
if err != nil {
return fmt.Errorf("putting Application Insights Analytics Item %s: %+v", id, err)
return fmt.Errorf("retrieving %s: %+v", id, err)
}

payload := existing.Model

if d.HasChange("content") {
payload.Content = pointer.To(d.Get("content").(string))
}

// See comments in ResourcesArmApplicationInsightsAnalyticsItemParseID method about ID format
generatedID := resourcesArmApplicationInsightsAnalyticsItemGenerateID(itemScope, *result.ID, appInsightsId)
if d.HasChange("function_alias") {
if payload.Properties == nil {
payload.Properties = &analyticsitems.ApplicationInsightsComponentAnalyticsItemProperties{}
}
payload.Properties.FunctionAlias = pointer.To(d.Get("function_alias").(string))
}

d.SetId(generatedID)
putOptions := analyticsitems.AnalyticsItemsPutOperationOptions{
OverrideItem: pointer.To(true),
}

if _, err = client.AnalyticsItemsPut(ctx, *id, *payload, putOptions); err != nil {
return fmt.Errorf("updating %s: %+v", id, err)
}

return resourceApplicationInsightsAnalyticsItemRead(d, meta)
}

func resourceApplicationInsightsAnalyticsItemRead(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).AppInsights.AnalyticsItemsClient
subscriptionId := meta.(*clients.Client).AppInsights.AnalyticsItemsClient.SubscriptionID
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, resourceGroupName, appInsightsName, itemScopePath, itemID, err := ResourcesArmApplicationInsightsAnalyticsItemParseID(d.Id())
id, itemId, err := ParseGeneratedAnalyticsItemId(d.Id())
if err != nil {
return fmt.Errorf("parsing Application Insights Analytics Item ID %s: %s", d.Id(), err)
return err
}

options := analyticsitems.AnalyticsItemsGetOperationOptions{
Id: pointer.To(itemId),
}

result, err := client.Get(ctx, resourceGroupName, appInsightsName, itemScopePath, itemID, "")
resp, err := client.AnalyticsItemsGet(ctx, *id, options)
if err != nil {
if utils.ResponseWasNotFound(result.Response) {
if response.WasNotFound(resp.HttpResponse) {
d.SetId("")
return nil
}
return fmt.Errorf("getting Application Insights Analytics Item %s: %+v", id, err)
return fmt.Errorf("retrieving %s: %+v", id, err)
}

appInsightsId := parse.NewComponentID(subscriptionId, resourceGroupName, appInsightsName)
appInsightsId := components.NewComponentID(id.SubscriptionId, id.ResourceGroupName, id.ComponentName)

d.Set("application_insights_id", appInsightsId.ID())
d.Set("name", result.Name)
d.Set("version", result.Version)
d.Set("content", result.Content)
d.Set("scope", string(result.Scope))
d.Set("type", string(result.Type))
d.Set("time_created", result.TimeCreated)
d.Set("time_modified", result.TimeModified)

if result.Properties != nil {
d.Set("function_alias", result.Properties.FunctionAlias)
if model := resp.Model; model != nil {
d.Set("name", model.Name)
d.Set("version", model.Version)
d.Set("content", model.Content)
d.Set("scope", pointer.From(model.Scope))
d.Set("type", pointer.From(model.Type))
d.Set("time_created", model.TimeCreated)
d.Set("time_modified", model.TimeModified)
if props := model.Properties; props != nil {
d.Set("function_alias", pointer.From(props.FunctionAlias))
}
}

return nil
Expand All @@ -249,46 +284,34 @@ func resourceApplicationInsightsAnalyticsItemDelete(d *pluginsdk.ResourceData, m
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, resourceGroupName, appInsightsName, itemScopePath, itemID, err := ResourcesArmApplicationInsightsAnalyticsItemParseID(d.Id())
id, itemId, err := ParseGeneratedAnalyticsItemId(d.Id())
if err != nil {
return fmt.Errorf("parsing Application Insights Analytics Item ID %s: %+v", d.Id(), err)
return err
}

options := analyticsitems.AnalyticsItemsDeleteOperationOptions{
Id: pointer.To(itemId),
}

if _, err = client.Delete(ctx, resourceGroupName, appInsightsName, itemScopePath, itemID, ""); err != nil {
return fmt.Errorf("deleting Application Insights Analytics Item %s: %+v", id, err)
if _, err = client.AnalyticsItemsDelete(ctx, *id, options); err != nil {
return fmt.Errorf("deleting %s: %+v", id, err)
}

return nil
}

func ResourcesArmApplicationInsightsAnalyticsItemParseID(id string) (string, string, string, insights.ItemScopePath, string, error) {
func ParseGeneratedAnalyticsItemId(input string) (*analyticsitems.ProviderComponentId, string, error) {
// The generated ID format differs depending on scope
// <appinsightsID>/analyticsItems/<itemID> [for shared scope items]
// <appinsightsID>/myAnalyticsItems/<itemID> [for user scope items]
switch {
case strings.Contains(id, "myAnalyticsItems"):
id, err := parse.AnalyticsUserItemID(id)
if err != nil {
return "", "", "", "", "", err
}
return id.String(), id.ResourceGroup, id.ComponentName, insights.ItemScopePathMyanalyticsItems, id.MyAnalyticsItemName, nil
case strings.Contains(id, string(insights.ItemScopePathAnalyticsItems)):
id, err := parse.AnalyticsSharedItemID(id)
if err != nil {
return "", "", "", "", "", err
}
return id.String(), id.ResourceGroup, id.ComponentName, insights.ItemScopePathAnalyticsItems, id.AnalyticsItemName, nil
default:
return "", "", "", "", "", fmt.Errorf("parsing Application Insights Analytics Item ID %s", id)
generatedId, err := analyticsitems.ParseProviderComponentID(input)
if err != nil {
return nil, "", err
}
}

func resourcesArmApplicationInsightsAnalyticsItemGenerateID(itemScope insights.ItemScope, itemID string, appInsightsId *parse.ComponentId) string {
if itemScope == insights.ItemScopeShared {
id := parse.NewAnalyticsSharedItemID(appInsightsId.SubscriptionId, appInsightsId.ResourceGroup, appInsightsId.Name, itemID)
return id.ID()
} else {
id := parse.NewAnalyticsUserItemID(appInsightsId.SubscriptionId, appInsightsId.ResourceGroup, appInsightsId.Name, itemID)
return id.ID()
}
scope := strings.Split(generatedId.ScopePath, "/")

id := analyticsitems.NewProviderComponentID(generatedId.SubscriptionId, generatedId.ResourceGroupName, generatedId.ComponentName, scope[1])

return &id, scope[2], nil
}
Loading
Loading