Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0ce611a

Browse files
docs: clarify cron attribute format for coder_script resource (#409)
Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
1 parente6bbd8c commit0ce611a

File tree

4 files changed

+130
-13
lines changed

4 files changed

+130
-13
lines changed

‎docs/resources/script.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,26 @@ resource "coder_script" "code-server" {
4343
})
4444
}
4545
46-
resource "coder_script" "nightly_sleep_reminder" {
46+
resource "coder_script" "nightly_update" {
4747
agent_id = coder_agent.dev.agent_id
4848
display_name = "Nightly update"
4949
icon = "/icon/database.svg"
50-
cron = "0 22 * * *"
50+
cron = "0022 * * *" # Run at 22:00 (10 PM) every day
5151
script = <<EOF
5252
#!/bin/sh
5353
echo "Running nightly update"
54-
sudo apt-get install
54+
sudo apt-get update
55+
EOF
56+
}
57+
58+
resource "coder_script" "every_5_minutes" {
59+
agent_id = coder_agent.dev.agent_id
60+
display_name = "Health check"
61+
icon = "/icon/heart.svg"
62+
cron = "0 */5 * * * *" # Run every 5 minutes
63+
script = <<EOF
64+
#!/bin/sh
65+
echo "Health check at $(date)"
5566
EOF
5667
}
5768
@@ -78,7 +89,7 @@ resource "coder_script" "shutdown" {
7889

7990
###Optional
8091

81-
-`cron` (String) The cron schedule to run the script on. Thisis a cron expression.
92+
-`cron` (String) The cron schedule to run the script on. Thisuses a6-fieldcron expression format:`seconds minutes hours day-of-month month day-of-week`. Note that this differs from the standard Unix 5-field format by including seconds as the first field. Examples:`"0 0 22 * * *"` (daily at 10 PM),`"0 */5 * * * *"` (every 5 minutes),`"30 0 9 * * 1-5"` (weekdays at 9:30 AM).
8293
-`icon` (String) A URL to an icon that will display in the dashboard. View built-in icons[here](https://github.com/coder/coder/tree/main/site/static/icon). Use a built-in icon with`"${data.coder_workspace.me.access_url}/icon/<path>"`.
8394
-`log_path` (String) The path of a file to write the logs to. If relative, it will be appended to tmp.
8495
-`run_on_start` (Boolean) This option defines whether or not the script should run when the agent starts. The script should exit when it is done to signal that the agent is ready.

‎examples/resources/coder_script/resource.tf

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,26 @@ resource "coder_script" "code-server" {
2828
})
2929
}
3030

31-
resource"coder_script""nightly_sleep_reminder" {
31+
resource"coder_script""nightly_update" {
3232
agent_id=coder_agent.dev.agent_id
3333
display_name="Nightly update"
3434
icon="/icon/database.svg"
35-
cron="0 22 * * *"
35+
cron="0022 * * *"# Run at 22:00 (10 PM) every day
3636
script=<<EOF
3737
#!/bin/sh
3838
echo "Running nightly update"
39-
sudo apt-get install
39+
sudo apt-get update
40+
EOF
41+
}
42+
43+
resource"coder_script""every_5_minutes" {
44+
agent_id=coder_agent.dev.agent_id
45+
display_name="Health check"
46+
icon="/icon/heart.svg"
47+
cron="0 */5 * * * *"# Run every 5 minutes
48+
script=<<EOF
49+
#!/bin/sh
50+
echo "Health check at $(date)"
4051
EOF
4152
}
4253

‎provider/script.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package provider
33
import (
44
"context"
55
"fmt"
6+
"strings"
67

78
"github.com/google/uuid"
89
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -13,6 +14,32 @@ import (
1314

1415
varScriptCRONParser=cron.NewParser(cron.Second|cron.Minute|cron.Hour|cron.Dom|cron.Month|cron.DowOptional|cron.Descriptor)
1516

17+
// ValidateCronExpression validates a cron expression and provides helpful warnings for common mistakes
18+
funcValidateCronExpression(cronExprstring) (warnings []string,errors []error) {
19+
// Check if it looks like a 5-field Unix cron expression
20+
fields:=strings.Fields(cronExpr)
21+
iflen(fields)==5 {
22+
// Try to parse as standard Unix cron (without seconds)
23+
unixParser:=cron.NewParser(cron.Minute|cron.Hour|cron.Dom|cron.Month|cron.DowOptional|cron.Descriptor)
24+
if_,err:=unixParser.Parse(cronExpr);err==nil {
25+
// It's a valid 5-field expression, provide a helpful warning
26+
warnings=append(warnings,fmt.Sprintf(
27+
"The cron expression '%s' appears to be in Unix 5-field format. "+
28+
"Coder uses 6-field format (seconds minutes hours day month day-of-week). "+
29+
"Consider prefixing with '0 ' to run at the start of each minute: '0 %s'",
30+
cronExpr,cronExpr))
31+
}
32+
}
33+
34+
// Validate with the actual 6-field parser
35+
_,err:=ScriptCRONParser.Parse(cronExpr)
36+
iferr!=nil {
37+
errors=append(errors,fmt.Errorf("%s is not a valid cron expression: %w",cronExpr,err))
38+
}
39+
40+
returnwarnings,errors
41+
}
42+
1643
funcscriptResource()*schema.Resource {
1744
return&schema.Resource{
1845
SchemaVersion:1,
@@ -72,17 +99,13 @@ func scriptResource() *schema.Resource {
7299
ForceNew:true,
73100
Type:schema.TypeString,
74101
Optional:true,
75-
Description:"The cron schedule to run the script on. Thisis a cron expression.",
102+
Description:"The cron schedule to run the script on. Thisuses a6-fieldcron expression format: `seconds minutes hours day-of-month month day-of-week`. Note that this differs from the standard Unix 5-field format by including seconds as the first field. Examples: `\"0 0 22 * * *\"` (daily at 10 PM), `\"0 */5 * * * *\"` (every 5 minutes), `\"30 0 9 * * 1-5\"` (weekdays at 9:30 AM).",
76103
ValidateFunc:func(iinterface{},_string) ([]string, []error) {
77104
v,ok:=i.(string)
78105
if!ok {
79106
return []string{}, []error{fmt.Errorf("got type %T instead of string",i)}
80107
}
81-
_,err:=ScriptCRONParser.Parse(v)
82-
iferr!=nil {
83-
return []string{}, []error{fmt.Errorf("%s is not a valid cron expression: %w",v,err)}
84-
}
85-
returnnil,nil
108+
returnValidateCronExpression(v)
86109
},
87110
},
88111
"start_blocks_login": {

‎provider/script_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88

99
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
1010
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
11+
12+
"github.com/coder/terraform-provider-coder/v2/provider"
1113
)
1214

1315
funcTestScript(t*testing.T) {
@@ -124,3 +126,73 @@ func TestScriptStartBlocksLoginRequiresRunOnStart(t *testing.T) {
124126
}},
125127
})
126128
}
129+
130+
funcTestValidateCronExpression(t*testing.T) {
131+
t.Parallel()
132+
133+
tests:= []struct {
134+
namestring
135+
cronExprstring
136+
expectWarningsbool
137+
expectErrorsbool
138+
warningContainsstring
139+
}{
140+
{
141+
name:"valid 6-field expression",
142+
cronExpr:"0 0 22 * * *",
143+
expectWarnings:false,
144+
expectErrors:false,
145+
},
146+
{
147+
name:"valid 6-field expression with seconds",
148+
cronExpr:"30 0 9 * * 1-5",
149+
expectWarnings:false,
150+
expectErrors:false,
151+
},
152+
{
153+
name:"5-field Unix format - should warn",
154+
cronExpr:"0 22 * * *",
155+
expectWarnings:true,
156+
expectErrors:false,
157+
warningContains:"appears to be in Unix 5-field format",
158+
},
159+
{
160+
name:"5-field every 5 minutes - should warn",
161+
cronExpr:"*/5 * * * *",
162+
expectWarnings:true,
163+
expectErrors:false,
164+
warningContains:"Consider prefixing with '0 '",
165+
},
166+
{
167+
name:"invalid expression",
168+
cronExpr:"invalid",
169+
expectErrors:true,
170+
},
171+
{
172+
name:"too many fields",
173+
cronExpr:"0 0 0 0 0 0 0",
174+
expectErrors:true,
175+
},
176+
}
177+
178+
for_,tt:=rangetests {
179+
t.Run(tt.name,func(t*testing.T) {
180+
warnings,errors:=provider.ValidateCronExpression(tt.cronExpr)
181+
182+
iftt.expectWarnings {
183+
require.NotEmpty(t,warnings,"Expected warnings but got none")
184+
iftt.warningContains!="" {
185+
require.Contains(t,warnings[0],tt.warningContains)
186+
}
187+
}else {
188+
require.Empty(t,warnings,"Expected no warnings but got: %v",warnings)
189+
}
190+
191+
iftt.expectErrors {
192+
require.NotEmpty(t,errors,"Expected errors but got none")
193+
}else {
194+
require.Empty(t,errors,"Expected no errors but got: %v",errors)
195+
}
196+
})
197+
}
198+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp