-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into msg/no-fail-code-cov
- Loading branch information
Showing
6 changed files
with
362 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Copyright Splunk, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package provider | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/hashicorp/go-retryablehttp" | ||
"github.com/hashicorp/terraform-plugin-log/tflog" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/signalfx/signalfx-go" | ||
|
||
"github.com/splunk-terraform/terraform-provider-signalfx/internal/definition/team" | ||
pmeta "github.com/splunk-terraform/terraform-provider-signalfx/internal/providermeta" | ||
tfext "github.com/splunk-terraform/terraform-provider-signalfx/internal/tfextension" | ||
"github.com/splunk-terraform/terraform-provider-signalfx/version" | ||
) | ||
|
||
func New() *schema.Provider { | ||
return &schema.Provider{ | ||
Schema: map[string]*schema.Schema{ | ||
"auth_token": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
DefaultFunc: schema.EnvDefaultFunc("SFX_AUTH_TOKEN", ""), | ||
Description: "Splunk Observability Cloud auth token", | ||
}, | ||
"api_url": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
DefaultFunc: schema.EnvDefaultFunc("SFX_API_URL", "https://api.signalfx.com"), | ||
Description: "API URL for your Splunk Observability Cloud org, may include a realm", | ||
}, | ||
"custom_app_url": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
DefaultFunc: schema.EnvDefaultFunc("SFX_CUSTOM_APP_URL", "https://app.signalfx.com"), | ||
Description: "Application URL for your Splunk Observability Cloud org, often customized for organizations using SSO", | ||
}, | ||
"timeout_seconds": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 120, | ||
Description: "Timeout duration for a single HTTP call in seconds. Defaults to 120", | ||
}, | ||
"retry_max_attempts": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 4, | ||
Description: "Max retries for a single HTTP call. Defaults to 4", | ||
}, | ||
"retry_wait_min_seconds": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 1, | ||
Description: "Minimum retry wait for a single HTTP call in seconds. Defaults to 1", | ||
}, | ||
"retry_wait_max_seconds": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 30, | ||
Description: "Maximum retry wait for a single HTTP call in seconds. Defaults to 30", | ||
}, | ||
}, | ||
ResourcesMap: map[string]*schema.Resource{ | ||
"signalfx_team": team.NewResource(), | ||
}, | ||
DataSourcesMap: map[string]*schema.Resource{}, | ||
ConfigureContextFunc: configureProvider, | ||
} | ||
} | ||
|
||
func configureProvider(ctx context.Context, data *schema.ResourceData) (any, diag.Diagnostics) { | ||
var meta pmeta.Meta | ||
for _, lookup := range pmeta.NewDefaultProviderLookups() { | ||
if err := lookup.Do(ctx, &meta); err != nil { | ||
tflog.Debug( | ||
ctx, | ||
"Issue trying to load external provider configuration, skipping", | ||
tfext.ErrorLogFields(err), | ||
) | ||
} | ||
} | ||
|
||
if token, ok := data.GetOk("auth_token"); ok { | ||
meta.AuthToken = token.(string) | ||
} | ||
if url, ok := data.GetOk("api_url"); ok { | ||
meta.APIURL = url.(string) | ||
} | ||
if url, ok := data.GetOk("custom_app_url"); ok { | ||
meta.CustomAppURL = url.(string) | ||
} | ||
|
||
err := meta.Validate() | ||
if err != nil { | ||
return nil, tfext.AsErrorDiagnostics(err) | ||
} | ||
|
||
var ( | ||
attempts = data.Get("retry_max_attempts").(int) | ||
timeout = time.Duration(int64(data.Get("timeout_seconds").(int))) * time.Second | ||
waitmin = time.Duration(int64(data.Get("retry_wait_min_seconds").(int))) * time.Second | ||
waitmax = time.Duration(int64((data.Get("retry_wait_max_seconds").(int)))) * time.Second | ||
) | ||
|
||
rc := retryablehttp.NewClient() | ||
rc.RetryMax = attempts | ||
rc.RetryWaitMin = waitmin | ||
rc.RetryWaitMax = waitmax | ||
rc.HTTPClient.Timeout = timeout | ||
rc.HTTPClient.Transport = logging.NewSubsystemLoggingHTTPTransport("signalfx", &http.Transport{ | ||
Proxy: http.ProxyFromEnvironment, | ||
DialContext: (&net.Dialer{Timeout: 5 * time.Second}).DialContext, | ||
TLSHandshakeTimeout: 5 * time.Second, | ||
MaxIdleConns: 100, | ||
MaxIdleConnsPerHost: 100, | ||
}) | ||
|
||
meta.Client, err = signalfx.NewClient(meta.AuthToken, | ||
signalfx.APIUrl(meta.APIURL), | ||
signalfx.HTTPClient(rc.StandardClient()), | ||
signalfx.UserAgent(fmt.Sprintf("Terraform terraform-provider-signalfx/%s", version.ProviderVersion)), | ||
) | ||
|
||
if err != nil { | ||
return nil, tfext.AsErrorDiagnostics(err) | ||
} | ||
|
||
tflog.Debug(ctx, "Configured settings for http client", tfext.NewLogFields(). | ||
Field("attempts", attempts). | ||
Duration("timeout", timeout). | ||
Duration("wait_min", waitmin). | ||
Duration("wait_max", waitmax), | ||
) | ||
|
||
return &meta, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright Splunk, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package provider | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestProviderValidation(t *testing.T) { | ||
t.Parallel() | ||
|
||
assert.NoError(t, New().InternalValidate(), "Must not error loading provider") | ||
} | ||
|
||
func TestProviderHasResource(t *testing.T) { | ||
t.Parallel() | ||
|
||
p := New() | ||
|
||
expected := []string{ | ||
"signalfx_team", | ||
} | ||
|
||
for name := range p.ResourcesMap { | ||
assert.Contains(t, expected, name, "Must have the resource defined as part of provider") | ||
} | ||
|
||
for _, name := range expected { | ||
assert.Contains(t, p.ResourcesMap, name, "Must have the expected resource defined in provider") | ||
} | ||
} | ||
|
||
func TestProviderConfiguration(t *testing.T) { | ||
t.Parallel() | ||
|
||
for _, tc := range []struct { | ||
name string | ||
details map[string]any | ||
expect diag.Diagnostics | ||
}{ | ||
{ | ||
name: "no details provided", | ||
details: make(map[string]any), | ||
expect: diag.Diagnostics{ | ||
{Severity: diag.Error, Summary: "auth token not set"}, | ||
}, | ||
}, | ||
{ | ||
name: "setting min required fields", | ||
details: map[string]any{ | ||
"auth_token": "hunter2", | ||
"api_url": "api.us.signalfx.com", | ||
}, | ||
expect: nil, | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
actual := New().Configure( | ||
context.Background(), | ||
terraform.NewResourceConfigRaw(tc.details), | ||
) | ||
|
||
assert.Equal(t, tc.expect, actual, "Must match the expected details") | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright Splunk, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package tfext | ||
|
||
import "time" | ||
|
||
// LogFields is an extension to logging fields parameter | ||
// to help as a convience and provides some level of standards. | ||
type LogFields map[string]any | ||
|
||
// NewLogFields creates an empty [LogFields] that be used | ||
// as part of the `tflog` fields parameter. | ||
func NewLogFields() LogFields { | ||
return make(LogFields) | ||
} | ||
|
||
// ErrorLogFields is a convience function that allows | ||
// for a [LogFields] to be created with the error entry set. | ||
func ErrorLogFields(err error) LogFields { | ||
return NewLogFields().Error(err) | ||
} | ||
|
||
// Error appends the field name `error` if the error value is not nil | ||
func (lf LogFields) Error(err error) LogFields { | ||
if err != nil { | ||
lf["error"] = err.Error() | ||
} | ||
return lf | ||
} | ||
|
||
// Duration is a convience function to ensure the key is correctly set. | ||
func (lf LogFields) Duration(key string, val time.Duration) LogFields { | ||
return lf.Field(key, val.String()) | ||
} | ||
|
||
// Field appends any type to be set as the key's value. | ||
// if the field already exists, it is overwritten. | ||
func (lf LogFields) Field(key string, val any) LogFields { | ||
lf[key] = val | ||
return lf | ||
} |
Oops, something went wrong.