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

Feature/add sumologic #91

Merged
merged 3 commits into from
Jan 19, 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
13 changes: 12 additions & 1 deletion docs/resources/metrics_exporter.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ resource "ybm_metrics_exporter" "grafana" {

- `datadog_spec` (Attributes) Configuration for Datadog metrics sink. (see [below for nested schema](#nestedatt--datadog_spec))
- `grafana_spec` (Attributes) Configuration for Grafana metrics sink. (see [below for nested schema](#nestedatt--grafana_spec))
- `sumologic_spec` (Attributes) Configuration for Sumologic metrics sink. (see [below for nested schema](#nestedatt--sumologic_spec))

### Read-Only

Expand All @@ -72,4 +73,14 @@ Required:
- `access_policy_token` (String, Sensitive) Grafana Access Policy Token
- `instance_id` (String) Grafana InstanceID.
- `org_slug` (String) Grafana OrgSlug.
- `zone` (String) Grafana Zone.
- `zone` (String) Grafana Zone.


<a id="nestedatt--sumologic_spec"></a>
### Nested Schema for `sumologic_spec`

Required:

- `access_id` (String, Sensitive) Sumo Logic Access Key ID
- `access_key` (String, Sensitive) Sumo Logic Access Key
- `installation_token` (String, Sensitive) A SumoLogic installation token to export metrics
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/hashicorp/terraform-plugin-framework-validators v0.4.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/sethvargo/go-retry v0.2.3
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20231030163130-9268a00de50c
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240116030641-973390683b73
)

require (
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20230915211221-361825bc5618 h1:ubU9s9gJPqDVcl9ZFd6sXZWhvRWJtcgdG5WtVVn4WE4=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20230915211221-361825bc5618/go.mod h1:5vW0xIzIZw+1djkiWKx0qqNmqbRBSf4mjc4qw8lIMik=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20231030163130-9268a00de50c h1:MzOpYz9LCniKMUhWZOnp6kn8bda5zq8vQ0oI58akrtc=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20231030163130-9268a00de50c/go.mod h1:5vW0xIzIZw+1djkiWKx0qqNmqbRBSf4mjc4qw8lIMik=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240116030641-973390683b73 h1:FWFFiWGqOjKxXay6ycDmVXZPX6oYFyvPGa+TSXYPm3k=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240116030641-973390683b73/go.mod h1:5vW0xIzIZw+1djkiWKx0qqNmqbRBSf4mjc4qw8lIMik=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240117020629-6fbf564e7278 h1:1qDNJO7TUYYNK+E7BiHLoVrpSvftNkPUo51fvh0Vtyk=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240117020629-6fbf564e7278/go.mod h1:5vW0xIzIZw+1djkiWKx0qqNmqbRBSf4mjc4qw8lIMik=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
36 changes: 28 additions & 8 deletions managed/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,14 @@ type ApiKey struct {
}

type MetricsExporter struct {
AccountID types.String `tfsdk:"account_id"`
ProjectID types.String `tfsdk:"project_id"`
ConfigID types.String `tfsdk:"config_id"`
ConfigName types.String `tfsdk:"config_name"`
Type types.String `tfsdk:"type"`
DataDogSpec *DataDogSpec `tfsdk:"datadog_spec"`
GrafanaSpec *GrafanaSpec `tfsdk:"grafana_spec"`
AccountID types.String `tfsdk:"account_id"`
ProjectID types.String `tfsdk:"project_id"`
ConfigID types.String `tfsdk:"config_id"`
ConfigName types.String `tfsdk:"config_name"`
Type types.String `tfsdk:"type"`
DataDogSpec *DataDogSpec `tfsdk:"datadog_spec"`
GrafanaSpec *GrafanaSpec `tfsdk:"grafana_spec"`
SumoLogicSpec *SumoLogicSpec `tfsdk:"sumologic_spec"`
}

type DataDogSpec struct {
Expand All @@ -277,12 +278,31 @@ type GrafanaSpec struct {
OrgSlug types.String `tfsdk:"org_slug"`
}

type SumoLogicSpec struct {
AccessKey types.String `tfsdk:"access_key"`
AccessId types.String `tfsdk:"access_id"`
InstallationToken types.String `tfsdk:"installation_token"`
}

func (d DataDogSpec) EncryptedKey() string {
return obfuscateString(d.ApiKey.Value)
}

func (g GrafanaSpec) EncryptedKey() string {
return obfuscateString(g.AccessTokenPolicy.Value)
return obfuscateStringLenght(g.AccessTokenPolicy.Value, 5)
}

func (s SumoLogicSpec) EncryptedKey(key string) string {
switch key {

case "access_key":
return obfuscateString(s.AccessKey.Value)
case "access_id":
return obfuscateString(s.AccessId.Value)
case "installation_token":
return obfuscateString(s.InstallationToken.Value)
}
return ""
}

type AssociateMetricsExporterCluster struct {
Expand Down
89 changes: 82 additions & 7 deletions managed/resource_metrics_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@ func (r resourceMetricsExporterType) GetSchema(_ context.Context) (tfsdk.Schema,
Description: "The type of third party metrics sink. ",
Type: types.StringType,
Required: true,
Validators: []tfsdk.AttributeValidator{stringvalidator.OneOf("DATADOG", "GRAFANA")},
Validators: []tfsdk.AttributeValidator{stringvalidator.OneOf("DATADOG", "GRAFANA", "SUMOLOGIC")},
},
"datadog_spec": {
Description: "Configuration for Datadog metrics sink.",
Optional: true,
Validators: []tfsdk.AttributeValidator{
schemavalidator.ConflictsWith(path.MatchRoot("grafana_spec")),
schemavalidator.ConflictsWith(path.MatchRoot("sumologic_spec")),
},
Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{
"api_key": {
Expand All @@ -74,6 +75,10 @@ func (r resourceMetricsExporterType) GetSchema(_ context.Context) (tfsdk.Schema,
"grafana_spec": {
Description: "Configuration for Grafana metrics sink.",
Optional: true,
Validators: []tfsdk.AttributeValidator{
schemavalidator.ConflictsWith(path.MatchRoot("datadog_spec")),
schemavalidator.ConflictsWith(path.MatchRoot("sumologic_spec")),
},
Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{
"access_policy_token": {
Description: "Grafana Access Policy Token",
Expand All @@ -98,6 +103,34 @@ func (r resourceMetricsExporterType) GetSchema(_ context.Context) (tfsdk.Schema,
},
}),
},
"sumologic_spec": {
Description: "Configuration for Sumologic metrics sink.",
Optional: true,
Validators: []tfsdk.AttributeValidator{
schemavalidator.ConflictsWith(path.MatchRoot("datadog_spec")),
schemavalidator.ConflictsWith(path.MatchRoot("grafana_spec")),
},
Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{
"access_id": {
Description: "Sumo Logic Access Key ID",
Type: types.StringType,
Required: true,
Sensitive: true,
},
"access_key": {
Description: "Sumo Logic Access Key",
Type: types.StringType,
Required: true,
Sensitive: true,
},
"installation_token": {
Description: "A SumoLogic installation token to export metrics",
Type: types.StringType,
Required: true,
Sensitive: true,
},
}),
},
},
}, nil
}
Expand All @@ -118,6 +151,7 @@ func getMetricsExporterPlan(ctx context.Context, plan tfsdk.Plan, me *MetricsExp
diags.Append(plan.GetAttribute(ctx, path.Root("type"), &me.Type)...)
diags.Append(plan.GetAttribute(ctx, path.Root("datadog_spec"), &me.DataDogSpec)...)
diags.Append(plan.GetAttribute(ctx, path.Root("grafana_spec"), &me.GrafanaSpec)...)
diags.Append(plan.GetAttribute(ctx, path.Root("sumologic_spec"), &me.SumoLogicSpec)...)
return diags
}

Expand All @@ -131,6 +165,8 @@ func getIDsFromMetricsExporterState(ctx context.Context, state tfsdk.State, me *
state.GetAttribute(ctx, path.Root("datadog_spec"), &me.DataDogSpec)
case string(openapiclient.METRICSEXPORTERCONFIGTYPEENUM_GRAFANA):
state.GetAttribute(ctx, path.Root("grafana_spec"), &me.GrafanaSpec)
case string(openapiclient.METRICSEXPORTERCONFIGTYPEENUM_SUMOLOGIC):
state.GetAttribute(ctx, path.Root("sumologic_spec"), &me.SumoLogicSpec)
}
}

Expand Down Expand Up @@ -186,6 +222,7 @@ func (r resourceMetricsExporter) Create(ctx context.Context, req tfsdk.CreateRes

metricsExporterConfigSpec := openapiclient.NewMetricsExporterConfigurationSpec(configName, *metricsSinkTypeEnum)
apiKey := ""
var sumoSpec *SumoLogicSpec
switch *metricsSinkTypeEnum {
case openapiclient.METRICSEXPORTERCONFIGTYPEENUM_DATADOG:
if plan.DataDogSpec == nil {
Expand All @@ -209,10 +246,21 @@ func (r resourceMetricsExporter) Create(ctx context.Context, req tfsdk.CreateRes
grafanaSpec := openapiclient.NewGrafanaMetricsExporterConfigurationSpec(plan.GrafanaSpec.AccessTokenPolicy.Value, plan.GrafanaSpec.Zone.Value, plan.GrafanaSpec.InstanceId.Value, plan.GrafanaSpec.OrgSlug.Value)
metricsExporterConfigSpec.SetGrafanaSpec(*grafanaSpec)
apiKey = plan.GrafanaSpec.AccessTokenPolicy.Value
case openapiclient.METRICSEXPORTERCONFIGTYPEENUM_SUMOLOGIC:
if plan.SumoLogicSpec == nil {
resp.Diagnostics.AddError(
"sumologic_spec is required for type SUMOLOGIC",
"sumologic_spec is required when third party sink is SUMOLOGIC. Please include this field in the resource",
)
return
}
sumoLogicSpec := openapiclient.NewSumologicMetricsExporterConfigurationSpec(plan.SumoLogicSpec.InstallationToken.Value, plan.SumoLogicSpec.AccessId.Value, plan.SumoLogicSpec.AccessKey.Value)
metricsExporterConfigSpec.SetSumologicSpec(*sumoLogicSpec)
sumoSpec = plan.SumoLogicSpec
default:
//We should never go there normally
resp.Diagnostics.AddError(
"Only DATADOG and GRAFANA is currently supported as a third party sink",
"Only DATADOG,GRAFANA,SUMOLOGIC are currently supported as a third party sink",
"",
)
return
Expand All @@ -226,7 +274,7 @@ func (r resourceMetricsExporter) Create(ctx context.Context, req tfsdk.CreateRes

metricsExporterId := CreateResp.GetData().Info.Id

config, readOK, message := resourceMetricsExporterRead(accountId, projectId, metricsExporterId, "", apiKey, apiClient)
config, readOK, message := resourceMetricsExporterRead(accountId, projectId, metricsExporterId, "", apiKey, apiClient, sumoSpec)
if !readOK {
resp.Diagnostics.AddError("Unable to read the state of the metrics exporter config ", message)
return
Expand All @@ -246,6 +294,7 @@ func (r resourceMetricsExporter) Read(ctx context.Context, req tfsdk.ReadResourc
getIDsFromMetricsExporterState(ctx, req.State, &state)
configID := state.ConfigID.Value
apiKey := ""
var sumoSpec *SumoLogicSpec

// We cannot use the api return as the apikey return by the api is masked.
// We need to use the one provided by the user which should be in the state
Expand All @@ -254,6 +303,8 @@ func (r resourceMetricsExporter) Read(ctx context.Context, req tfsdk.ReadResourc
apiKey = state.DataDogSpec.ApiKey.Value
case string(openapiclient.METRICSEXPORTERCONFIGTYPEENUM_GRAFANA):
apiKey = state.GrafanaSpec.AccessTokenPolicy.Value
case string(openapiclient.METRICSEXPORTERCONFIGTYPEENUM_SUMOLOGIC):
sumoSpec = state.SumoLogicSpec
}

apiClient := r.p.client
Expand All @@ -270,7 +321,7 @@ func (r resourceMetricsExporter) Read(ctx context.Context, req tfsdk.ReadResourc
return
}

config, readOK, message := resourceMetricsExporterRead(accountId, projectId, configID, "", apiKey, apiClient)
config, readOK, message := resourceMetricsExporterRead(accountId, projectId, configID, "", apiKey, apiClient, sumoSpec)
if !readOK {
resp.Diagnostics.AddError("Unable to read the state of the metrics exporter config ", message)
return
Expand All @@ -287,6 +338,16 @@ func (r resourceMetricsExporter) Read(ctx context.Context, req tfsdk.ReadResourc
if config.GrafanaSpec.AccessTokenPolicy.Value == state.GrafanaSpec.EncryptedKey() {
config.GrafanaSpec.AccessTokenPolicy.Value = apiKey
}
case string(openapiclient.METRICSEXPORTERCONFIGTYPEENUM_SUMOLOGIC):
if config.SumoLogicSpec.AccessKey.Value == state.SumoLogicSpec.EncryptedKey("access_key") {
config.SumoLogicSpec.AccessKey.Value = sumoSpec.AccessKey.Value
}
if config.SumoLogicSpec.AccessId.Value == state.SumoLogicSpec.EncryptedKey("access_id") {
config.SumoLogicSpec.AccessId.Value = sumoSpec.AccessId.Value
}
if config.SumoLogicSpec.InstallationToken.Value == state.SumoLogicSpec.EncryptedKey("installation_token") {
config.SumoLogicSpec.InstallationToken.Value = sumoSpec.InstallationToken.Value
}
}

diags := resp.State.Set(ctx, &config)
Expand Down Expand Up @@ -320,6 +381,7 @@ func (r resourceMetricsExporter) Update(ctx context.Context, req tfsdk.UpdateRes

metricsExporterConfigSpec := openapiclient.NewMetricsExporterConfigurationSpec(configName, *metricsSinkTypeEnum)
apiKey := ""
var sumoSpec *SumoLogicSpec
switch *metricsSinkTypeEnum {
case openapiclient.METRICSEXPORTERCONFIGTYPEENUM_DATADOG:
if plan.DataDogSpec == nil {
Expand All @@ -343,10 +405,21 @@ func (r resourceMetricsExporter) Update(ctx context.Context, req tfsdk.UpdateRes
grafanaSpec := openapiclient.NewGrafanaMetricsExporterConfigurationSpec(plan.GrafanaSpec.AccessTokenPolicy.Value, plan.GrafanaSpec.Zone.Value, plan.GrafanaSpec.InstanceId.Value, plan.GrafanaSpec.OrgSlug.Value)
metricsExporterConfigSpec.SetGrafanaSpec(*grafanaSpec)
apiKey = plan.GrafanaSpec.AccessTokenPolicy.Value
case openapiclient.METRICSEXPORTERCONFIGTYPEENUM_SUMOLOGIC:
if plan.SumoLogicSpec == nil {
resp.Diagnostics.AddError(
"sumologic_spec is required for type SUMOLOGIC",
"sumologic_spec is required when third party sink is SUMOLOGIC. Please include this field in the resource",
)
return
}
sumoLogicSpec := openapiclient.NewSumologicMetricsExporterConfigurationSpec(plan.SumoLogicSpec.InstallationToken.Value, plan.SumoLogicSpec.AccessId.Value, plan.SumoLogicSpec.AccessKey.Value)
metricsExporterConfigSpec.SetSumologicSpec(*sumoLogicSpec)
sumoSpec = plan.SumoLogicSpec
default:
//We should never go there normally
resp.Diagnostics.AddError(
"Only DATADOG and GRAFANA is currently supported as a third party sink",
"Only DATADOG, GRAFANA and SUMOLOGIC are currently supported as a third party sink",
"",
)
return
Expand All @@ -360,7 +433,7 @@ func (r resourceMetricsExporter) Update(ctx context.Context, req tfsdk.UpdateRes

metricsExporterId := updateResp.GetData().Info.Id

config, readOK, message := resourceMetricsExporterRead(accountId, projectId, metricsExporterId, "", apiKey, apiClient)
config, readOK, message := resourceMetricsExporterRead(accountId, projectId, metricsExporterId, "", apiKey, apiClient, sumoSpec)
if !readOK {
resp.Diagnostics.AddError("Unable to read the state of the metrics exporter config ", message)
return
Expand All @@ -386,7 +459,7 @@ func (r resourceMetricsExporter) Update(ctx context.Context, req tfsdk.UpdateRes

}

func resourceMetricsExporterRead(accountId string, projectId string, configID string, configName string, apiKey string, apiClient *openapiclient.APIClient) (me MetricsExporter, readOK bool, errorMessage string) {
func resourceMetricsExporterRead(accountId string, projectId string, configID string, configName string, apiKey string, apiClient *openapiclient.APIClient, sumoSpec *SumoLogicSpec) (me MetricsExporter, readOK bool, errorMessage string) {

config, err := GetConfigByNameorID(accountId, projectId, configID, configName, apiClient)
if err != nil {
Expand Down Expand Up @@ -415,6 +488,8 @@ func resourceMetricsExporterRead(accountId string, projectId string, configID st
InstanceId: types.String{Value: string(config.GetSpec().GrafanaSpec.Get().InstanceId)},
OrgSlug: types.String{Value: string(config.GetSpec().GrafanaSpec.Get().OrgSlug)},
}
case openapiclient.METRICSEXPORTERCONFIGTYPEENUM_SUMOLOGIC:
me.SumoLogicSpec = sumoSpec
}

return me, true, ""
Expand Down
6 changes: 5 additions & 1 deletion managed/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,14 @@ func SliceStringToSliceTypesString(slice []string) []types.String {
}

func obfuscateString(s string) string {
return obfuscateStringLenght(s, 2)
}

func obfuscateStringLenght(s string, l int) string {
if len(s) < 6 {
return "X"
}
substring := s[2 : len(s)-2]
substring := s[l : len(s)-l]
replaced := strings.Replace(s, substring, strings.Repeat("X", len(substring)), 1)
return replaced
}
Loading