Skip to content
Open
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
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ require (
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
)

replace github.com/newrelic/newrelic-client-go/v2 => ../newrelic-client-go

require (
github.com/agext/levenshtein v1.2.2 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,6 @@ github.com/newrelic/go-agent/v3 v3.30.0 h1:ZXHCT/Cot4iIPwcegCZURuRQOsfmGA6wilW+S
github.com/newrelic/go-agent/v3 v3.30.0/go.mod h1:9utrgxlSryNqRrTvII2XBL+0lpofXbqXApvVWPpbzUg=
github.com/newrelic/go-insights v1.0.3 h1:zSNp1CEZnXktzSIEsbHJk8v6ZihdPFP2WsO/fzau3OQ=
github.com/newrelic/go-insights v1.0.3/go.mod h1:A20BoT8TNkqPGX2nS/Z2fYmKl3Cqa3iKZd4whzedCY4=
github.com/newrelic/newrelic-client-go/v2 v2.78.0 h1:RxQ0pkoFCW4U+a2olLh8z+kOG+q3gxnXMdU6z7vvM68=
github.com/newrelic/newrelic-client-go/v2 v2.78.0/go.mod h1:kROngr/zeNyxbdOI3zPK4Al+ze32XjLEVUDzjxsKW9g=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
Expand Down
24 changes: 18 additions & 6 deletions integration_test_utilities/integration_test_mappings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ resource_newrelic_alert_channel.go:
resource_newrelic_alert_channel_test.go:
test: true
product_mapping: ALERTS
resource_newrelic_alert_compound_condition.go:
test: false
product_mapping: ALERTS
resource_newrelic_alert_compound_condition_test.go:
test: true
product_mapping: ALERTS
resource_newrelic_alert_condition.go:
test: false
product_mapping: ALERTS
Expand All @@ -121,12 +127,6 @@ resource_newrelic_alert_condition_test.go:
resource_newrelic_alert_condition_unit_test.go:
test: true
product_mapping: ALERTS
resource_newrelic_alert_compound_condition.go:
test: false
product_mapping: ALERTS
resource_newrelic_alert_compound_condition_test.go:
test: true
product_mapping: ALERTS
resource_newrelic_alert_muting_rule.go:
test: false
product_mapping: ALERTS
Expand Down Expand Up @@ -163,6 +163,12 @@ resource_newrelic_application_settings.go:
resource_newrelic_application_settings_test.go:
test: true
product_mapping: APM
resource_newrelic_aws_connection.go:
test: false
product_mapping: NGEP
resource_newrelic_aws_connection_test.go:
test: true
product_mapping: NGEP
resource_newrelic_cloud_aws_eu_sovereign_integrations.go:
test: false
product_mapping: CLOUD
Expand Down Expand Up @@ -247,6 +253,12 @@ resource_newrelic_events_to_metrics_rule.go:
resource_newrelic_events_to_metrics_rule_test.go:
test: true
product_mapping: EVENTS
resource_newrelic_federated_log_partition.go:
test: false
product_mapping: NGEP
resource_newrelic_federated_log_setup.go:
test: false
product_mapping: NGEP
resource_newrelic_group_management.go:
test: false
product_mapping: AUTH
Expand Down
3 changes: 3 additions & 0 deletions newrelic/provider_newrelic.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ func Provider() *schema.Provider {
"newrelic_workflow": resourceNewRelicWorkflow(),
"newrelic_workload": resourceNewRelicWorkload(),
"newrelic_user": resourceNewRelicUser(),
"newrelic_federated_log_setup": resourceNewRelicFederatedLogSetup(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use federated_logs here and elsewhere instead, this will become newrelic_federated_logs_setup

"newrelic_federated_log_partition": resourceNewRelicFederatedLogPartition(),
"newrelic_aws_connection": resourceNewRelicAwsConnection(),
},
}

Expand Down
263 changes: 263 additions & 0 deletions newrelic/resource_newrelic_aws_connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
package newrelic

import (
"context"
"fmt"
"log"
"strconv"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/newrelic/newrelic-client-go/v2/pkg/pipelinecontrol"
)

func resourceNewRelicAwsConnection() *schema.Resource {
return &schema.Resource{
CreateContext: resourceNewRelicAwsConnectionCreate,
ReadContext: resourceNewRelicAwsConnectionRead,
UpdateContext: resourceNewRelicAwsConnectionUpdate,
DeleteContext: resourceNewRelicAwsConnectionDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
Computed: true,
Description: "The account ID where the AWS connection will be created. Used when scope_type is ACCOUNT.",
},
"scope_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
Description: "The scope ID (account ID or organization ID) for the AWS connection.",
},
"scope_type": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Default: "ACCOUNT",
Description: "The scope type for the AWS connection. Valid values are ACCOUNT and ORGANIZATION.",
},
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the AWS connection.",
},
"description": {
Type: schema.TypeString,
Optional: true,
Description: "The description of the AWS connection.",
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "Flag to indicate if the connection is enabled. True by default.",
},
"external_id": {
Type: schema.TypeString,
Optional: true,
Description: "Optional field representing an identifier managed by the consumer.",
},
"region": {
Type: schema.TypeString,
Optional: true,
Description: "Default region for this connection.",
},
"role_arn": {
Type: schema.TypeString,
Required: true,
Description: "The ARN of the IAM role to assume for this connection.",
},
"settings": {
Type: schema.TypeList,
Optional: true,
Description: "Optional list of connection settings.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
Description: "The key or name of the setting.",
},
"value": {
Type: schema.TypeString,
Required: true,
Description: "The value of the setting.",
},
},
},
},
},
}
}

func resourceNewRelicAwsConnectionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
providerConfig := meta.(*ProviderConfig)
client := providerConfig.NewClient

// Determine scope
scopeType := d.Get("scope_type").(string)
var scopeID string

if v, ok := d.GetOk("scope_id"); ok {
scopeID = v.(string)
} else {
accountID := selectAccountID(providerConfig, d)
scopeID = strconv.Itoa(accountID)
_ = d.Set("account_id", accountID)
}

input := pipelinecontrol.EntityManagementAwsConnectionEntityCreateInput{
Name: d.Get("name").(string),
Enabled: d.Get("enabled").(bool),
Credential: pipelinecontrol.EntityManagementAwsCredentialsCreateInput{
AssumeRole: pipelinecontrol.EntityManagementAwsAssumeRoleConfigCreateInput{
RoleArn: d.Get("role_arn").(string),
},
},
Scope: pipelinecontrol.EntityManagementScopedReferenceInput{
Type: pipelinecontrol.EntityManagementEntityScope(scopeType),
ID: scopeID,
},
}

if v, ok := d.GetOk("description"); ok {
input.Description = v.(string)
}
if v, ok := d.GetOk("external_id"); ok {
input.ExternalId = v.(string)
}
if v, ok := d.GetOk("region"); ok {
input.Region = v.(string)
}
if v, ok := d.GetOk("settings"); ok {
input.Settings = expandAwsConnectionSettings(v.([]interface{}))
}

resp, err := client.Pipelinecontrol.EntityManagementCreateAwsConnectionWithContext(ctx, input)
if err != nil {
return diag.FromErr(err)
}

d.SetId(resp.Entity.ID)

return resourceNewRelicAwsConnectionRead(ctx, d, meta)
}

func resourceNewRelicAwsConnectionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
providerConfig := meta.(*ProviderConfig)
client := providerConfig.NewClient

log.Printf("[INFO] Reading New Relic AWS Connection for %s", d.Id())

entityID := d.Id()

resp, err := client.Pipelinecontrol.GetEntityWithContext(ctx, entityID)
if err != nil {
return diag.FromErr(err)
}

if resp == nil {
d.SetId("")
return diag.FromErr(fmt.Errorf("entity with ID %s was nil", entityID))
}

switch entityType := (*resp).(type) {
case *pipelinecontrol.EntityManagementAwsConnectionEntity:
entity := (*resp).(*pipelinecontrol.EntityManagementAwsConnectionEntity)

accountIDStr := entity.Scope.ID
accountIDInt, accountIDIntErr := strconv.Atoi(accountIDStr)
if accountIDIntErr != nil {
log.Printf("[ERROR] Failed to convert account ID to integer: %v", accountIDIntErr)
accountIDInt = selectAccountID(providerConfig, d)
log.Printf("[INFO] Assigning the value of account_id from the state to prevent a panic: %d", accountIDInt)
}

if err := d.Set("account_id", accountIDInt); err != nil {
return diag.FromErr(err)
}
if err := d.Set("scope_id", entity.Scope.ID); err != nil {
return diag.FromErr(err)
}
if err := d.Set("scope_type", string(entity.Scope.Type)); err != nil {
return diag.FromErr(err)
}
if err := d.Set("name", entity.Name); err != nil {
return diag.FromErr(err)
}
if err := d.Set("description", entity.Description); err != nil {
return diag.FromErr(err)
}
if err := d.Set("enabled", entity.Enabled); err != nil {
return diag.FromErr(err)
}
if err := d.Set("external_id", entity.ExternalId); err != nil {
return diag.FromErr(err)
}
if err := d.Set("region", entity.Region); err != nil {
return diag.FromErr(err)
}
if err := d.Set("role_arn", entity.Credential.AssumeRole.RoleArn); err != nil {
return diag.FromErr(err)
}
if err := d.Set("settings", flattenAwsConnectionSettings(entity.Settings)); err != nil {
return diag.FromErr(err)
}
default:
return diag.Errorf("unexpected entity type %T for ID %s", entityType, d.Id())
}
return nil
}

func resourceNewRelicAwsConnectionUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// Update not yet supported for AwsConnectionEntity in the client
return resourceNewRelicAwsConnectionRead(ctx, d, meta)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we add it?

}

func resourceNewRelicAwsConnectionDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
providerConfig := meta.(*ProviderConfig)
client := providerConfig.NewClient

log.Printf("[INFO] Deleting New Relic AWS Connection entity with ID %s", d.Id())

entityID := d.Id()

result, err := client.Pipelinecontrol.EntityManagementDelete(entityID)
if err != nil {
return diag.FromErr(err)
}

if result.ID == "" {
return diag.FromErr(fmt.Errorf("error in deleting entity with ID %s", entityID))
}
return nil
}

func expandAwsConnectionSettings(settings []interface{}) []pipelinecontrol.EntityManagementConnectionSettingsCreateInput {
result := make([]pipelinecontrol.EntityManagementConnectionSettingsCreateInput, len(settings))
for i, s := range settings {
setting := s.(map[string]interface{})
result[i] = pipelinecontrol.EntityManagementConnectionSettingsCreateInput{
Key: setting["key"].(string),
Value: setting["value"].(string),
}
}
return result
}

func flattenAwsConnectionSettings(settings []pipelinecontrol.EntityManagementConnectionSettings) []map[string]interface{} {
result := make([]map[string]interface{}, len(settings))
for i, s := range settings {
result[i] = map[string]interface{}{
"key": s.Key,
"value": s.Value,
}
}
return result
}
Loading