-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
function/parse_duration: Add duration parsing function
- Loading branch information
1 parent
e284774
commit 95b6f62
Showing
6 changed files
with
325 additions
and
0 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,54 @@ | ||
--- | ||
page_title: "parse_duration function - terraform-provider-time" | ||
subcategory: "" | ||
description: |- | ||
Parse a duration string into an object | ||
--- | ||
|
||
# function: parse_duration | ||
|
||
Given a duration string, will parse and return an object representation of that duration. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
# Configuration using provider functions must include required_providers configuration. | ||
terraform { | ||
required_providers { | ||
time = { | ||
source = "hashicorp/time" | ||
# Setting the provider version is a strongly recommended practice | ||
# version = "..." | ||
} | ||
} | ||
# Provider functions require Terraform 1.8 and later. | ||
required_version = ">= 1.8.0" | ||
} | ||
output "example_output" { | ||
value = provider::time::parse_duration("1h") | ||
} | ||
``` | ||
|
||
## Signature | ||
|
||
<!-- signature generated by tfplugindocs --> | ||
```text | ||
parse_duration(duration string) object | ||
``` | ||
|
||
## Arguments | ||
|
||
<!-- arguments generated by tfplugindocs --> | ||
1. `duration` (String) Go time package duration string to parse | ||
|
||
|
||
## Return Type | ||
|
||
The `object` returned from `parse_duration` has the following attributes: | ||
- `hours` (Number) The duration as a floating point number of hours. | ||
- `minutes` (Number) The duration as a floating point number of minutes. | ||
- `seconds` (Number) The duration as a floating point number of seconds. | ||
- `milliseconds` (Number) The duration as an integer number of milliseconds. | ||
- `microseconds` (Number) The duration as an integer number of microseconds. | ||
- `nanoseconds` (Number) The duration as an integer number of nanoseconds. |
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,16 @@ | ||
# Configuration using provider functions must include required_providers configuration. | ||
terraform { | ||
required_providers { | ||
time = { | ||
source = "hashicorp/time" | ||
# Setting the provider version is a strongly recommended practice | ||
# version = "..." | ||
} | ||
} | ||
# Provider functions require Terraform 1.8 and later. | ||
required_version = ">= 1.8.0" | ||
} | ||
|
||
output "example_output" { | ||
value = provider::time::parse_duration("1h") | ||
} |
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,91 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package provider | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/attr" | ||
"github.com/hashicorp/terraform-plugin-framework/function" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/hashicorp/terraform-plugin-log/tflog" | ||
) | ||
|
||
var parseDurationReturnAttrTypes = map[string]attr.Type{ | ||
"hours": types.Float64Type, | ||
"minutes": types.Float64Type, | ||
"seconds": types.Float64Type, | ||
"milliseconds": types.Int64Type, | ||
"microseconds": types.Int64Type, | ||
"nanoseconds": types.Int64Type, | ||
} | ||
|
||
var _ function.Function = &ParseDurationFunction{} | ||
|
||
type ParseDurationFunction struct{} | ||
|
||
func NewParseDurationFunction() function.Function { | ||
return &ParseDurationFunction{} | ||
} | ||
|
||
func (f *ParseDurationFunction) Metadata(ctx context.Context, req function.MetadataRequest, resp *function.MetadataResponse) { | ||
resp.Name = "parse_duration" | ||
} | ||
|
||
func (f *ParseDurationFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) { | ||
resp.Definition = function.Definition{ | ||
Summary: "Parse a duration string into an object", | ||
Description: "Given a duration string, will parse and return an object representation of that duration.", | ||
|
||
Parameters: []function.Parameter{ | ||
function.StringParameter{ | ||
Name: "duration", | ||
Description: "Go time package duration string to parse", | ||
}, | ||
}, | ||
Return: function.ObjectReturn{ | ||
AttributeTypes: parseDurationReturnAttrTypes, | ||
}, | ||
} | ||
} | ||
|
||
func (f *ParseDurationFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) { | ||
var input string | ||
|
||
resp.Error = req.Arguments.Get(ctx, &input) | ||
if resp.Error != nil { | ||
return | ||
} | ||
|
||
duration, err := time.ParseDuration(input) | ||
if err != nil { | ||
// Intentionally not including the Go parse error in the return diagnostic, as the message is based on a Go-specific | ||
// reference time that may be unfamiliar to practitioners | ||
tflog.Error(ctx, fmt.Sprintf("failed to parse duration string, underlying time.Duration error: %s", err.Error())) | ||
|
||
resp.Error = function.NewArgumentFuncError(0, fmt.Sprintf("Error parsing duration string: %q is not a valid duration string", input)) | ||
return | ||
} | ||
|
||
durationObj, diags := types.ObjectValue( | ||
parseDurationReturnAttrTypes, | ||
map[string]attr.Value{ | ||
"hours": types.Float64Value(duration.Hours()), | ||
"minutes": types.Float64Value(duration.Minutes()), | ||
"seconds": types.Float64Value(duration.Seconds()), | ||
"milliseconds": types.Int64Value(duration.Milliseconds()), | ||
"microseconds": types.Int64Value(duration.Microseconds()), | ||
"nanoseconds": types.Int64Value(duration.Nanoseconds()), | ||
}, | ||
) | ||
|
||
resp.Error = function.FuncErrorFromDiags(ctx, diags) | ||
if resp.Error != nil { | ||
return | ||
} | ||
|
||
resp.Error = resp.Result.Set(ctx, &durationObj) | ||
} |
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,126 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package provider | ||
|
||
import ( | ||
"regexp" | ||
"testing" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-testing/knownvalue" | ||
"github.com/hashicorp/terraform-plugin-testing/plancheck" | ||
"github.com/hashicorp/terraform-plugin-testing/tfversion" | ||
) | ||
|
||
func TestParseDuration_valid(t *testing.T) { | ||
resource.UnitTest(t, resource.TestCase{ | ||
TerraformVersionChecks: []tfversion.TerraformVersionCheck{ | ||
tfversion.SkipBelow(tfversion.Version1_8_0), | ||
}, | ||
ProtoV5ProviderFactories: protoV5ProviderFactories(), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: ` | ||
output "test" { | ||
value = provider::time::parse_duration("1h") | ||
} | ||
`, | ||
ConfigPlanChecks: resource.ConfigPlanChecks{ | ||
PreApply: []plancheck.PlanCheck{ | ||
plancheck.ExpectKnownOutputValue("test", knownvalue.ObjectExact( | ||
map[string]knownvalue.Check{ | ||
"hours": knownvalue.Float64Exact(time.Hour.Hours()), | ||
"minutes": knownvalue.Float64Exact(time.Hour.Minutes()), | ||
"seconds": knownvalue.Float64Exact(time.Hour.Seconds()), | ||
"milliseconds": knownvalue.Int64Exact(time.Hour.Milliseconds()), | ||
"microseconds": knownvalue.Int64Exact(time.Hour.Microseconds()), | ||
"nanoseconds": knownvalue.Int64Exact(time.Hour.Nanoseconds()), | ||
}, | ||
)), | ||
}, | ||
}, | ||
}, | ||
{ | ||
Config: ` | ||
output "test" { | ||
value = provider::time::parse_duration("60m") | ||
} | ||
`, | ||
ConfigPlanChecks: resource.ConfigPlanChecks{ | ||
PreApply: []plancheck.PlanCheck{ | ||
plancheck.ExpectEmptyPlan(), | ||
}, | ||
}, | ||
}, | ||
{ | ||
Config: ` | ||
output "test" { | ||
value = provider::time::parse_duration("3600s") | ||
} | ||
`, | ||
ConfigPlanChecks: resource.ConfigPlanChecks{ | ||
PreApply: []plancheck.PlanCheck{ | ||
plancheck.ExpectEmptyPlan(), | ||
}, | ||
}, | ||
}, | ||
{ | ||
Config: ` | ||
output "test" { | ||
value = provider::time::parse_duration("3600000ms") | ||
} | ||
`, | ||
ConfigPlanChecks: resource.ConfigPlanChecks{ | ||
PreApply: []plancheck.PlanCheck{ | ||
plancheck.ExpectEmptyPlan(), | ||
}, | ||
}, | ||
}, | ||
{ | ||
Config: ` | ||
output "test" { | ||
value = provider::time::parse_duration("3600000000us") | ||
} | ||
`, | ||
ConfigPlanChecks: resource.ConfigPlanChecks{ | ||
PreApply: []plancheck.PlanCheck{ | ||
plancheck.ExpectEmptyPlan(), | ||
}, | ||
}, | ||
}, | ||
{ | ||
Config: ` | ||
output "test" { | ||
value = provider::time::parse_duration("3600000000000ns") | ||
} | ||
`, | ||
ConfigPlanChecks: resource.ConfigPlanChecks{ | ||
PreApply: []plancheck.PlanCheck{ | ||
plancheck.ExpectEmptyPlan(), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestParseDuration_invalid(t *testing.T) { | ||
resource.UnitTest(t, resource.TestCase{ | ||
TerraformVersionChecks: []tfversion.TerraformVersionCheck{ | ||
tfversion.SkipBelow(tfversion.Version1_8_0), | ||
}, | ||
ProtoV5ProviderFactories: protoV5ProviderFactories(), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: ` | ||
output "test" { | ||
value = provider::time::parse_duration("abcdef") | ||
} | ||
`, | ||
ExpectError: regexp.MustCompile(`"abcdef" is not a valid duration string.`), | ||
}, | ||
}, | ||
}) | ||
} |
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,37 @@ | ||
--- | ||
page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" | ||
subcategory: "" | ||
description: |- | ||
{{ .Summary | plainmarkdown | trimspace | prefixlines " " }} | ||
--- | ||
|
||
# {{.Type}}: {{.Name}} | ||
|
||
{{ .Description | trimspace }} | ||
|
||
{{ if .HasExample -}} | ||
## Example Usage | ||
|
||
{{tffile .ExampleFile }} | ||
{{- end }} | ||
|
||
## Signature | ||
|
||
{{ .FunctionSignatureMarkdown }} | ||
|
||
## Arguments | ||
|
||
{{ .FunctionArgumentsMarkdown }} | ||
{{ if .HasVariadic -}} | ||
{{ .FunctionVariadicArgumentMarkdown }} | ||
{{- end }} | ||
|
||
## Return Type | ||
|
||
The `object` returned from `parse_duration` has the following attributes: | ||
- `hours` (Number) The duration as a floating point number of hours. | ||
- `minutes` (Number) The duration as a floating point number of minutes. | ||
- `seconds` (Number) The duration as a floating point number of seconds. | ||
- `milliseconds` (Number) The duration as an integer number of milliseconds. | ||
- `microseconds` (Number) The duration as an integer number of microseconds. | ||
- `nanoseconds` (Number) The duration as an integer number of nanoseconds. |