Skip to content

Commit d436f6e

Browse files
authored
use standard timetypes (#21)
Use `github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes` for durations.
1 parent 5105d40 commit d436f6e

File tree

9 files changed

+217
-147
lines changed

9 files changed

+217
-147
lines changed

example/main.tf

+7-6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ resource "pomerium_settings" "settings" {
3636
api_key = "key"
3737
url = "http://localhost"
3838
}
39+
timeout_idle = "5m"
3940
}
4041

4142
resource "pomerium_policy" "test_policy" {
@@ -74,18 +75,18 @@ data "pomerium_namespace" "existing_namespace" {
7475
id = pomerium_namespace.test_namespace.id
7576
}
7677

77-
data "pomerium_route" "existing_route" {
78-
id = pomerium_route.test_route.id
79-
}
78+
# data "pomerium_route" "existing_route" {
79+
# id = pomerium_route.test_route.id
80+
# }
8081

8182
# Output examples
8283
output "namespace_name" {
8384
value = data.pomerium_namespace.existing_namespace.name
8485
}
8586

86-
output "route_from" {
87-
value = data.pomerium_route.existing_route.from
88-
}
87+
# output "route_from" {
88+
# value = data.pomerium_route.existing_route.from
89+
# }
8990

9091
output "all_namespaces" {
9192
value = data.pomerium_namespaces.all_namespaces.namespaces

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ require (
3838
github.com/hashicorp/go-set/v3 v3.0.0 // indirect
3939
github.com/hashicorp/go-uuid v1.0.3 // indirect
4040
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
41+
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0 // indirect
4142
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
4243
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
4344
github.com/hashicorp/yamux v0.1.1 // indirect

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
134134
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
135135
github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw=
136136
github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU=
137+
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0 h1:v3DapR8gsp3EM8fKMh6up9cJUFQ2iRaFsYLP8UJnCco=
138+
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0/go.mod h1:c3PnGE9pHBDfdEVG9t1S1C9ia5LW+gkFR0CygXlM8ak=
137139
github.com/hashicorp/terraform-plugin-framework-validators v0.16.0 h1:O9QqGoYDzQT7lwTXUsZEtgabeWW96zUBh47Smn2lkFA=
138140
github.com/hashicorp/terraform-plugin-framework-validators v0.16.0/go.mod h1:Bh89/hNmqsEWug4/XWKYBwtnw3tbz5BAy1L1OgvbIaY=
139141
github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks=

internal/provider/convert.go

+13-13
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import (
44
"context"
55
"fmt"
66
"reflect"
7-
"time"
87

8+
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
99
"github.com/hashicorp/terraform-plugin-framework/attr"
1010
"github.com/hashicorp/terraform-plugin-framework/diag"
1111
"github.com/hashicorp/terraform-plugin-framework/path"
@@ -50,7 +50,6 @@ func FromStringMap(m map[string]string) types.Map {
5050

5151
// ToStringList converts a types.List to Settings_StringList and handles diagnostics internally
5252
func ToStringList(ctx context.Context, dst **pb.Settings_StringList, list types.List, diagnostics *diag.Diagnostics) {
53-
// Handle null list case first
5453
if list.IsNull() {
5554
*dst = nil
5655
return
@@ -89,26 +88,27 @@ func ToStringSlice(ctx context.Context, dst *[]string, list types.List, diagnost
8988
}
9089
}
9190

92-
// ToDuration converts a types.String containing a duration to a durationpb.Duration and handles diagnostics internally
93-
func ToDuration(dst **durationpb.Duration, src types.String, field string, diagnostics *diag.Diagnostics) {
94-
if src.IsNull() {
91+
// ToDuration converts a timetypes.Duration to durationpb.Duration
92+
func ToDuration(dst **durationpb.Duration, src timetypes.GoDuration, diagnostics *diag.Diagnostics) {
93+
if src.IsNull() || src.IsUnknown() {
9594
*dst = nil
9695
return
9796
}
9897

99-
if d, err := time.ParseDuration(src.ValueString()); err == nil {
100-
*dst = durationpb.New(d)
101-
} else {
102-
diagnostics.AddError("invalid "+field, err.Error())
98+
d, diags := src.ValueGoDuration()
99+
diagnostics.Append(diags...)
100+
if diagnostics.HasError() {
101+
return
103102
}
103+
*dst = durationpb.New(d)
104104
}
105105

106-
// FromDuration converts a durationpb.Duration to a types.String
107-
func FromDuration(d *durationpb.Duration) types.String {
106+
// FromDuration converts a durationpb.Duration to a timetypes.GoDuration
107+
func FromDuration(d *durationpb.Duration) timetypes.GoDuration {
108108
if d == nil {
109-
return types.StringNull()
109+
return timetypes.NewGoDurationNull()
110110
}
111-
return types.StringValue(d.AsDuration().String())
111+
return timetypes.NewGoDurationValue(d.AsDuration())
112112
}
113113

114114
// GoStructToPB converts a Go struct to a protobuf Struct.

internal/provider/convert_test.go

+55-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"github.com/google/go-cmp/cmp"
9+
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
910
"github.com/hashicorp/terraform-plugin-framework/attr"
1011
"github.com/hashicorp/terraform-plugin-framework/diag"
1112
"github.com/hashicorp/terraform-plugin-framework/types"
@@ -58,22 +59,22 @@ func TestFromDurationP(t *testing.T) {
5859
tests := []struct {
5960
name string
6061
input *durationpb.Duration
61-
expected types.String
62+
expected timetypes.GoDuration
6263
}{
6364
{
6465
name: "nil duration",
6566
input: nil,
66-
expected: types.StringNull(),
67+
expected: timetypes.NewGoDurationNull(),
6768
},
6869
{
6970
name: "zero duration",
7071
input: durationpb.New(0),
71-
expected: types.StringValue("0s"),
72+
expected: timetypes.NewGoDurationValueFromStringMust("0s"),
7273
},
7374
{
7475
name: "normal duration",
7576
input: durationpb.New(time.Hour + time.Minute),
76-
expected: types.StringValue("1h1m0s"),
77+
expected: timetypes.NewGoDurationValueFromStringMust("1h1m0s"),
7778
},
7879
}
7980

@@ -85,6 +86,56 @@ func TestFromDurationP(t *testing.T) {
8586
}
8687
}
8788

89+
func TestToDuration(t *testing.T) {
90+
tests := []struct {
91+
name string
92+
input timetypes.GoDuration
93+
expected *durationpb.Duration
94+
expectError bool
95+
}{
96+
{
97+
name: "null duration",
98+
input: timetypes.NewGoDurationNull(),
99+
expected: nil,
100+
},
101+
{
102+
name: "unknown duration",
103+
input: timetypes.NewGoDurationUnknown(),
104+
expected: nil,
105+
},
106+
{
107+
name: "zero duration",
108+
input: timetypes.NewGoDurationValueFromStringMust("0s"),
109+
expected: durationpb.New(0),
110+
},
111+
{
112+
name: "normal duration",
113+
input: timetypes.NewGoDurationValueFromStringMust("1h1m0s"),
114+
expected: durationpb.New(time.Hour + time.Minute),
115+
},
116+
}
117+
118+
for _, tt := range tests {
119+
t.Run(tt.name, func(t *testing.T) {
120+
var result *durationpb.Duration
121+
diagnostics := diag.Diagnostics{}
122+
provider.ToDuration(&result, tt.input, &diagnostics)
123+
124+
if tt.expectError {
125+
assert.True(t, diagnostics.HasError())
126+
return
127+
}
128+
129+
assert.False(t, diagnostics.HasError())
130+
if tt.expected == nil {
131+
assert.Nil(t, result)
132+
} else {
133+
assert.Equal(t, tt.expected.AsDuration(), result.AsDuration())
134+
}
135+
})
136+
}
137+
}
138+
88139
func TestToStringList(t *testing.T) {
89140
ctx := context.Background()
90141
tests := []struct {

internal/provider/route.go

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66

7+
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
78
"github.com/hashicorp/terraform-plugin-framework/path"
89
"github.com/hashicorp/terraform-plugin-framework/resource"
910
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
@@ -123,10 +124,12 @@ func (r *RouteResource) Schema(_ context.Context, _ resource.SchemaRequest, resp
123124
"timeout": schema.StringAttribute{
124125
Description: "Timeout.",
125126
Optional: true,
127+
CustomType: timetypes.GoDurationType{},
126128
},
127129
"idle_timeout": schema.StringAttribute{
128130
Description: "Idle timeout.",
129131
Optional: true,
132+
CustomType: timetypes.GoDurationType{},
130133
},
131134
"allow_websockets": schema.BoolAttribute{
132135
Description: "Allow websockets.",

internal/provider/route_model.go

+40-39
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package provider
33
import (
44
"context"
55

6+
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
67
"github.com/hashicorp/terraform-plugin-framework/attr"
78
"github.com/hashicorp/terraform-plugin-framework/diag"
89
"github.com/hashicorp/terraform-plugin-framework/types"
@@ -11,41 +12,41 @@ import (
1112

1213
// RouteModel represents the shared model for route resources and data sources
1314
type RouteModel struct {
14-
ID types.String `tfsdk:"id"`
15-
Name types.String `tfsdk:"name"`
16-
From types.String `tfsdk:"from"`
17-
To types.List `tfsdk:"to"`
18-
NamespaceID types.String `tfsdk:"namespace_id"`
19-
Policies types.List `tfsdk:"policies"`
20-
StatName types.String `tfsdk:"stat_name"`
21-
Prefix types.String `tfsdk:"prefix"`
22-
Path types.String `tfsdk:"path"`
23-
Regex types.String `tfsdk:"regex"`
24-
PrefixRewrite types.String `tfsdk:"prefix_rewrite"`
25-
RegexRewritePattern types.String `tfsdk:"regex_rewrite_pattern"`
26-
RegexRewriteSubstitution types.String `tfsdk:"regex_rewrite_substitution"`
27-
HostRewrite types.String `tfsdk:"host_rewrite"`
28-
HostRewriteHeader types.String `tfsdk:"host_rewrite_header"`
29-
HostPathRegexRewritePattern types.String `tfsdk:"host_path_regex_rewrite_pattern"`
30-
HostPathRegexRewriteSubstitution types.String `tfsdk:"host_path_regex_rewrite_substitution"`
31-
RegexPriorityOrder types.Int64 `tfsdk:"regex_priority_order"`
32-
Timeout types.String `tfsdk:"timeout"`
33-
IdleTimeout types.String `tfsdk:"idle_timeout"`
34-
AllowWebsockets types.Bool `tfsdk:"allow_websockets"`
35-
AllowSPDY types.Bool `tfsdk:"allow_spdy"`
36-
TLSSkipVerify types.Bool `tfsdk:"tls_skip_verify"`
37-
TLSUpstreamServerName types.String `tfsdk:"tls_upstream_server_name"`
38-
TLSDownstreamServerName types.String `tfsdk:"tls_downstream_server_name"`
39-
TLSUpstreamAllowRenegotiation types.Bool `tfsdk:"tls_upstream_allow_renegotiation"`
40-
SetRequestHeaders types.Map `tfsdk:"set_request_headers"`
41-
RemoveRequestHeaders types.List `tfsdk:"remove_request_headers"`
42-
SetResponseHeaders types.Map `tfsdk:"set_response_headers"`
43-
PreserveHostHeader types.Bool `tfsdk:"preserve_host_header"`
44-
PassIdentityHeaders types.Bool `tfsdk:"pass_identity_headers"`
45-
KubernetesServiceAccountToken types.String `tfsdk:"kubernetes_service_account_token"`
46-
IDPClientID types.String `tfsdk:"idp_client_id"`
47-
IDPClientSecret types.String `tfsdk:"idp_client_secret"`
48-
ShowErrorDetails types.Bool `tfsdk:"show_error_details"`
15+
ID types.String `tfsdk:"id"`
16+
Name types.String `tfsdk:"name"`
17+
From types.String `tfsdk:"from"`
18+
To types.List `tfsdk:"to"`
19+
NamespaceID types.String `tfsdk:"namespace_id"`
20+
Policies types.List `tfsdk:"policies"`
21+
StatName types.String `tfsdk:"stat_name"`
22+
Prefix types.String `tfsdk:"prefix"`
23+
Path types.String `tfsdk:"path"`
24+
Regex types.String `tfsdk:"regex"`
25+
PrefixRewrite types.String `tfsdk:"prefix_rewrite"`
26+
RegexRewritePattern types.String `tfsdk:"regex_rewrite_pattern"`
27+
RegexRewriteSubstitution types.String `tfsdk:"regex_rewrite_substitution"`
28+
HostRewrite types.String `tfsdk:"host_rewrite"`
29+
HostRewriteHeader types.String `tfsdk:"host_rewrite_header"`
30+
HostPathRegexRewritePattern types.String `tfsdk:"host_path_regex_rewrite_pattern"`
31+
HostPathRegexRewriteSubstitution types.String `tfsdk:"host_path_regex_rewrite_substitution"`
32+
RegexPriorityOrder types.Int64 `tfsdk:"regex_priority_order"`
33+
Timeout timetypes.GoDuration `tfsdk:"timeout"`
34+
IdleTimeout timetypes.GoDuration `tfsdk:"idle_timeout"`
35+
AllowWebsockets types.Bool `tfsdk:"allow_websockets"`
36+
AllowSPDY types.Bool `tfsdk:"allow_spdy"`
37+
TLSSkipVerify types.Bool `tfsdk:"tls_skip_verify"`
38+
TLSUpstreamServerName types.String `tfsdk:"tls_upstream_server_name"`
39+
TLSDownstreamServerName types.String `tfsdk:"tls_downstream_server_name"`
40+
TLSUpstreamAllowRenegotiation types.Bool `tfsdk:"tls_upstream_allow_renegotiation"`
41+
SetRequestHeaders types.Map `tfsdk:"set_request_headers"`
42+
RemoveRequestHeaders types.List `tfsdk:"remove_request_headers"`
43+
SetResponseHeaders types.Map `tfsdk:"set_response_headers"`
44+
PreserveHostHeader types.Bool `tfsdk:"preserve_host_header"`
45+
PassIdentityHeaders types.Bool `tfsdk:"pass_identity_headers"`
46+
KubernetesServiceAccountToken types.String `tfsdk:"kubernetes_service_account_token"`
47+
IDPClientID types.String `tfsdk:"idp_client_id"`
48+
IDPClientSecret types.String `tfsdk:"idp_client_secret"`
49+
ShowErrorDetails types.Bool `tfsdk:"show_error_details"`
4950
}
5051

5152
func ConvertRouteToPB(
@@ -71,8 +72,8 @@ func ConvertRouteToPB(
7172
pbRoute.HostPathRegexRewritePattern = src.HostPathRegexRewritePattern.ValueStringPointer()
7273
pbRoute.HostPathRegexRewriteSubstitution = src.HostPathRegexRewriteSubstitution.ValueStringPointer()
7374
pbRoute.RegexPriorityOrder = src.RegexPriorityOrder.ValueInt64Pointer()
74-
ToDuration(&pbRoute.Timeout, src.Timeout, "timeout", &diagnostics)
75-
ToDuration(&pbRoute.IdleTimeout, src.IdleTimeout, "idle_timeout", &diagnostics)
75+
ToDuration(&pbRoute.Timeout, src.Timeout, &diagnostics)
76+
ToDuration(&pbRoute.IdleTimeout, src.IdleTimeout, &diagnostics)
7677
pbRoute.AllowWebsockets = src.AllowWebsockets.ValueBoolPointer()
7778
pbRoute.AllowSpdy = src.AllowSPDY.ValueBoolPointer()
7879
pbRoute.TlsSkipVerify = src.TLSSkipVerify.ValueBoolPointer()
@@ -134,8 +135,8 @@ func ConvertRouteFromPB(
134135
dst.HostPathRegexRewritePattern = types.StringPointerValue(src.HostPathRegexRewritePattern)
135136
dst.HostPathRegexRewriteSubstitution = types.StringPointerValue(src.HostPathRegexRewriteSubstitution)
136137
dst.RegexPriorityOrder = types.Int64PointerValue(src.RegexPriorityOrder)
137-
dst.Timeout = types.StringValue(src.Timeout.String())
138-
dst.IdleTimeout = types.StringValue(src.IdleTimeout.String())
138+
dst.Timeout = FromDuration(src.Timeout)
139+
dst.IdleTimeout = FromDuration(src.IdleTimeout)
139140
dst.AllowWebsockets = types.BoolPointerValue(src.AllowWebsockets)
140141
dst.AllowSPDY = types.BoolPointerValue(src.AllowSpdy)
141142
dst.TLSSkipVerify = types.BoolPointerValue(src.TlsSkipVerify)

0 commit comments

Comments
 (0)