diff --git a/docs/index.md b/docs/index.md index ad7faa9..8b4c6dd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,3 +25,4 @@ provider "abion" { - `apikey` (String, Sensitive) The Abion API key. Contact [Abion](https://abion.com) for help on how to create an account and an API key and whitelist IP addresses to be able to access the Abion API. This value can also be set using the `ABION_API_KEY` environment variable. The order of precedence: Terraform configuration value (highest priority) > environment variable (lowest priority). - `host` (String) The Abion API host URL. If not set, defaults to `https://api.abion.com`. This value can also be set using the `ABION_API_HOST` environment variable. The order of precedence: Terraform configuration value (highest priority) > environment variable > default value. +- `timeout` (Number) The Abion API timeout in seconds. If not set, defaults to `60`. This value can also be set using the `ABION_API_TIMEOUT` environment variable. The order of precedence: Terraform configuration value (highest priority) > environment variable > default value. diff --git a/examples/resources/test_multi_dev/import.sh b/examples/resources/test_multi_dev/import.sh new file mode 100755 index 0000000..ce59085 --- /dev/null +++ b/examples/resources/test_multi_dev/import.sh @@ -0,0 +1,2 @@ +# DNS TXT records can be imported by specifying the string identifier. The import ID should be in the format: "zone/name". The `@` character represents the root of the zone, E.g., "example.com/@" +terraform import abion_dns_txt_record.example "example.com/www" \ No newline at end of file diff --git a/examples/resources/test_multi_dev/resource.tf b/examples/resources/test_multi_dev/resource.tf new file mode 100644 index 0000000..2852b01 --- /dev/null +++ b/examples/resources/test_multi_dev/resource.tf @@ -0,0 +1,76 @@ +terraform { + required_providers { + abion = { + source = "abion/abion" + } + } +} + +provider "abion" { + #dev + # apikey = "+FOQDv1eG4BBFmYV3WwxtTI0pKZSK+g2rF+F9fmZGWJRZj/0qzM51ZYbcRl0vZuM1Hv9dbJj7eBmRG8ijNWASA==" + #demo + apikey = "p/cEqe8kBSF68Ft8+I7H39FmBALgaAswVXRog7Wo7ec=" +} + +resource "abion_dns_a_record" "example_x" { + zone = "pmapitest10.com" + name = "test20241203-1" + records = [ + { + ip_address = "203.0.113.0" + comments = "test comment" + ttl = "300" + } + ] +} + +resource "abion_dns_txt_record" "example_x" { + zone = "pmapitest10.com" + name = "test20241205" + records = [ + { + txt_data = "txt 1" + }, + { + txt_data = "txt 2" + comments = "test comment" + }, + { + txt_data = "txt 3" + ttl = "300" + }, + ] +} + +resource "abion_dns_cname_record" "example_x" { + zone = "pmapitest10.com" + name = "testcname20241205" + record = { + cname = "www.devabion.se." + ttl = "3600" + comments = "test comment" + } +} + + +resource "abion_dns_mx_record" "example_x" { + zone = "pmapitest10.com" + name = "testzone20241205" + records = [ + { + host = "mail1.example.com." + priority = "10" + }, + { + host = "mail2.example.com." + priority = "20" + comments = "test comment" + }, + { + host = "mail3.example.com." + priority = "30" + ttl = "300" + }, + ] +} \ No newline at end of file diff --git a/internal/client/client.go b/internal/client/client.go index 58c3583..f63b9fc 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -8,6 +8,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/hashicorp/terraform-plugin-log/tflog" "golang.org/x/net/html" "io" "net/http" @@ -35,7 +36,7 @@ type ApiClient interface { } // NewAbionClient Creates a new Client. -func NewAbionClient(host string, apiKey string) (*Client, error) { +func NewAbionClient(host string, apiKey string, timeout int) (*Client, error) { baseURL, err := url.Parse(host) if err != nil { @@ -45,7 +46,7 @@ func NewAbionClient(host string, apiKey string) (*Client, error) { return &Client{ apiKey: apiKey, baseURL: baseURL, - HTTPClient: &http.Client{Timeout: 10 * time.Second}, + HTTPClient: &http.Client{Timeout: time.Duration(timeout) * time.Second}, }, nil } @@ -69,6 +70,11 @@ func (c *Client) GetZone(ctx context.Context, name string) (*APIResponse[*Zone], // PatchZone Updates a zone by patching it according to JSON Merge Patch format (RFC 7396). func (c *Client) PatchZone(ctx context.Context, name string, patch ZoneRequest) (*APIResponse[*Zone], error) { + + ctx = tflog.SetField(ctx, "key", c.apiKey) + ctx = tflog.SetField(ctx, "url", c.baseURL) + tflog.Debug(ctx, "Sending patch request") + endpoint := c.baseURL.JoinPath("v1", "zones", name) req, err := newJSONRequest(ctx, http.MethodPatch, endpoint, patch) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 2ed323d..93b509b 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "os" + "strconv" abionclient "terraform-provider-abion/internal/client" ) @@ -31,8 +32,9 @@ type AbionDnsProvider struct { // AbionProviderModel describes the provider data model. type AbionProviderModel struct { - Host types.String `tfsdk:"host"` - Apikey types.String `tfsdk:"apikey"` + Host types.String `tfsdk:"host"` + Apikey types.String `tfsdk:"apikey"` + Timeout types.Int32 `tfsdk:"timeout"` } // Metadata returns the provider type name. @@ -61,6 +63,13 @@ func (p *AbionDnsProvider) Schema(ctx context.Context, req provider.SchemaReques Optional: true, Sensitive: true, }, + "timeout": schema.Int32Attribute{ + MarkdownDescription: "The Abion API timeout in seconds. If not set, defaults to `60`. " + + "This value can also be set using the `ABION_API_TIMEOUT` environment variable. " + + "The order of precedence: Terraform configuration value (highest priority) > " + + "environment variable > default value.", + Optional: true, + }, }, } } @@ -82,7 +91,16 @@ func (p *AbionDnsProvider) Configure(ctx context.Context, req provider.Configure path.Root("host"), "Unknown Abion API Host", "The provider cannot create the Abion API client as there is an unknown configuration value for the Abion API host. "+ - "Either target apply the source of the value first, set the value statically in the configuration, or use the ABION_API_KEY environment variable.", + "Either target apply the source of the value first, set the value statically in the configuration, or use the ABION_API_HOST environment variable.", + ) + } + + if config.Timeout.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("timeout"), + "Unknown Abion API timeout", + "The provider cannot create the Abion API client as there is an unknown configuration value for the Abion API timeout. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or use the ABION_API_TIMEOUT environment variable.", ) } @@ -110,6 +128,29 @@ func (p *AbionDnsProvider) Configure(ctx context.Context, req provider.Configure host = "https://api.abion.com" } + // Environment variable ABION_API_TIMEOUT + timeoutEnv := os.Getenv("ABION_API_TIMEOUT") + + var timeout int + if !config.Timeout.IsNull() { + // If Terraform configuration is set, use it + timeout = int(config.Timeout.ValueInt32()) + } else if timeoutEnv != "" { + // If ABION_API_TIMEOUT environment variable is set, convert it + timeoutInt, err := strconv.Atoi(timeoutEnv) + if err != nil { + resp.Diagnostics.AddAttributeError( + path.Root("timeout"), + "Invalid ABION_API_TIMEOUT value in environment", + "Must be an integer.", + ) + } + timeout = timeoutInt + } else { + // Use the default value + timeout = 60 + } + apikey := os.Getenv("ABION_API_KEY") if !config.Apikey.IsNull() { @@ -132,12 +173,13 @@ func (p *AbionDnsProvider) Configure(ctx context.Context, req provider.Configure ctx = tflog.SetField(ctx, "abion_host", host) ctx = tflog.SetField(ctx, "abion_apikey", apikey) + ctx = tflog.SetField(ctx, "timeout", timeout) ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "abion_apikey") tflog.Debug(ctx, "Creating Abion client") // Create a new Abion client using the configuration values - client, err := abionclient.NewAbionClient(host, apikey) + client, err := abionclient.NewAbionClient(host, apikey, timeout) if err != nil { resp.Diagnostics.AddError(