Skip to content

feat: add expiration_policy parameter to prebuild resource #404

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

Merged
merged 12 commits into from
May 23, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
chores: update terraform schema to expiration_policy.ttl & update max…
… validation ttl value to 1 year
  • Loading branch information
ssncferreira committed May 23, 2025
commit 2a34f0d27a4687fa0b8094d03f35a7adab5d1c6a
8 changes: 4 additions & 4 deletions docs/data-sources/workspace_preset.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ Required:

Optional:

- `cache_invalidation` (Block Set, Max: 1) Configuration block that defines TTL (time-to-live) behavior for prebuilds. Use this to automatically invalidate and delete prebuilds after a certain period, ensuring they stay up-to-date. (see [below for nested schema](#nestedblock--prebuilds--cache_invalidation))
- `expiration_policy` (Block Set, Max: 1) Configuration block that defines TTL (time-to-live) behavior for prebuilds. Use this to automatically invalidate and delete prebuilds after a certain period, ensuring they stay up-to-date. (see [below for nested schema](#nestedblock--prebuilds--expiration_policy))

<a id="nestedblock--prebuilds--cache_invalidation"></a>
### Nested Schema for `prebuilds.cache_invalidation`
<a id="nestedblock--prebuilds--expiration_policy"></a>
### Nested Schema for `prebuilds.expiration_policy`

Required:

- `invalidate_after_secs` (Number) Time in seconds after which an unclaimed prebuild is considered expired and eligible for cleanup.
- `ttl` (Number) Time in seconds after which an unclaimed prebuild is considered expired and eligible for cleanup.
12 changes: 6 additions & 6 deletions integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ func TestIntegration(t *testing.T) {
// TODO (sasswart): the cli doesn't support presets yet.
// once it does, the value for workspace_parameter.value
// will be the preset value.
"workspace_parameter.value": `param value`,
"workspace_parameter.icon": `param icon`,
"workspace_preset.name": `preset`,
"workspace_preset.parameters.param": `preset param value`,
"workspace_preset.prebuilds.instances": `1`,
"workspace_preset.prebuilds.cache_invalidation.invalidate_after_secs": `86400`,
"workspace_parameter.value": `param value`,
"workspace_parameter.icon": `param icon`,
"workspace_preset.name": `preset`,
"workspace_preset.parameters.param": `preset param value`,
"workspace_preset.prebuilds.instances": `1`,
"workspace_preset.prebuilds.expiration_policy.ttl": `86400`,
},
},
{
Expand Down
6 changes: 3 additions & 3 deletions integration/test-data-source/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ data "coder_workspace_preset" "preset" {

prebuilds {
instances = 1
cache_invalidation {
invalidate_after_secs = 86400
expiration_policy {
ttl = 86400
}
}
}
Expand All @@ -55,7 +55,7 @@ locals {
"workspace_preset.name" : data.coder_workspace_preset.preset.name,
"workspace_preset.parameters.param" : data.coder_workspace_preset.preset.parameters.param,
"workspace_preset.prebuilds.instances" : tostring(one(data.coder_workspace_preset.preset.prebuilds).instances),
"workspace_preset.prebuilds.cache_invalidation.invalidate_after_secs" : tostring(one(one(data.coder_workspace_preset.preset.prebuilds).cache_invalidation).invalidate_after_secs),
"workspace_preset.prebuilds.expiration_policy.ttl" : tostring(one(one(data.coder_workspace_preset.preset.prebuilds).expiration_policy).ttl),
}
}

Expand Down
16 changes: 8 additions & 8 deletions provider/workspace_preset.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ type WorkspacePreset struct {

type WorkspacePrebuild struct {
Instances int `mapstructure:"instances"`
// There should always be only one cache_invalidation block, but Terraform's type system
// There should always be only one expiration_policy block, but Terraform's type system
// still parses them as a slice, so we need to handle it as such. We could use
// an anonymous type and rd.Get to avoid a slice here, but that would not be possible
// for utilities that parse our terraform output using this type. To remain compatible
// with those cases, we use a slice here.
CacheInvalidation []CacheInvalidation `mapstructure:"cache_invalidation"`
ExpirationPolicy []ExpirationPolicy `mapstructure:"expiration_policy"`
}

type CacheInvalidation struct {
InvalidateAfterSecs int `mapstructure:"invalidate_after_secs"`
type ExpirationPolicy struct {
TTL int `mapstructure:"ttl"`
}

func workspacePresetDataSource() *schema.Resource {
Expand Down Expand Up @@ -91,20 +91,20 @@ func workspacePresetDataSource() *schema.Resource {
ForceNew: true,
ValidateFunc: validation.IntAtLeast(0),
},
"cache_invalidation": {
"expiration_policy": {
Type: schema.TypeSet,
Description: "Configuration block that defines TTL (time-to-live) behavior for prebuilds. Use this to automatically invalidate and delete prebuilds after a certain period, ensuring they stay up-to-date.",
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"invalidate_after_secs": {
"ttl": {
Type: schema.TypeInt,
Description: "Time in seconds after which an unclaimed prebuild is considered expired and eligible for cleanup.",
Required: true,
ForceNew: true,
// Ensure invalidation is between 0 and 604800 seconds (7 days) to prevent stale prebuilds
ValidateFunc: validation.IntBetween(0, 604800),
// Ensure invalidation is between 0 and 31536000 seconds (1 year) to prevent stale prebuilds
ValidateFunc: validation.IntBetween(0, 31536000),
},
},
},
Expand Down
31 changes: 14 additions & 17 deletions provider/workspace_preset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func TestWorkspacePreset(t *testing.T) {
},
},
{
Name: "Prebuilds is set with a cache_invalidation field without its required fields",
Name: "Prebuilds is set with a expiration_policy field without its required fields",
Config: `
data "coder_workspace_preset" "preset_1" {
name = "preset_1"
Expand All @@ -154,16 +154,13 @@ func TestWorkspacePreset(t *testing.T) {
}
prebuilds {
instances = 1
cache_invalidation {}
expiration_policy {}
}
}`,
// Note: Match only the beginning of the error message to make the test more reliable.
// The full error message includes formatting differences like newlines, which could
// cause the test to fail unnecessarily.
ExpectError: regexp.MustCompile("The argument \"invalidate_after_secs\" is required,"),
ExpectError: regexp.MustCompile("The argument \"ttl\" is required, but no definition was found."),
},
{
Name: "Prebuilds is set with a cache_invalidation field with its required fields",
Name: "Prebuilds is set with a expiration_policy field with its required fields",
Config: `
data "coder_workspace_preset" "preset_1" {
name = "preset_1"
Expand All @@ -172,8 +169,8 @@ func TestWorkspacePreset(t *testing.T) {
}
prebuilds {
instances = 1
cache_invalidation {
invalidate_after_secs = 86400
expiration_policy {
ttl = 86400
}
}
}`,
Expand All @@ -185,12 +182,12 @@ func TestWorkspacePreset(t *testing.T) {
require.NotNil(t, resource)
attrs := resource.Primary.Attributes
require.Equal(t, attrs["name"], "preset_1")
require.Equal(t, attrs["prebuilds.0.cache_invalidation.0.invalidate_after_secs"], "86400")
require.Equal(t, attrs["prebuilds.0.expiration_policy.0.ttl"], "86400")
return nil
},
},
{
Name: "Prebuilds block with cache_invalidation.invalidate_after_secs set to 15 days (exceeds 7 days limit)",
Name: "Prebuilds block with expiration_policy.ttl set to 2 years (exceeds 1 year limit)",
Config: `
data "coder_workspace_preset" "preset_1" {
name = "preset_1"
Expand All @@ -199,15 +196,15 @@ func TestWorkspacePreset(t *testing.T) {
}
prebuilds {
instances = 1
cache_invalidation {
invalidate_after_secs = 1296000
expiration_policy {
ttl = 63072000
}
}
}`,
ExpectError: regexp.MustCompile(`expected prebuilds.0.cache_invalidation.0.invalidate_after_secs to be in the range \(0 - 604800\), got 1296000`),
ExpectError: regexp.MustCompile(`expected prebuilds.0.expiration_policy.0.ttl to be in the range \(0 - 31536000\), got 63072000`),
},
{
Name: "Prebuilds is set with a cache_invalidation field with its required fields and an unexpected argument",
Name: "Prebuilds is set with a expiration_policy field with its required fields and an unexpected argument",
Config: `
data "coder_workspace_preset" "preset_1" {
name = "preset_1"
Expand All @@ -216,8 +213,8 @@ func TestWorkspacePreset(t *testing.T) {
}
prebuilds {
instances = 1
cache_invalidation {
invalidate_after_secs = 86400
expiration_policy {
ttl = 86400
invalid_argument = "test"
}
}
Expand Down
Loading