Skip to content

Commit

Permalink
Merge pull request #115 from soh-kuranaga/add-cron-validator
Browse files Browse the repository at this point in the history
add cron validator
  • Loading branch information
Songmu authored Jan 26, 2025
2 parents f694008 + 8fb78ac commit 84bebc9
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 0 deletions.
31 changes: 31 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import (
"io"
"io/ioutil"
"path/filepath"
"strings"
"text/template"

"github.com/goccy/go-yaml"
"github.com/google/go-jsonnet"
gc "github.com/kayac/go-config"
"github.com/winebarrel/cronplan"
)

const defaultRole = "ecsEventsRole"
Expand Down Expand Up @@ -58,6 +60,32 @@ func (c *Config) setupPlugins(ctx context.Context) error {
return nil
}

func (c *Config) cronValidate() error {
var errMsgs []string
for _, r := range c.Rules {
exp := r.ScheduleExpression
if strings.HasPrefix(exp, "rate(") && strings.HasSuffix(exp, ")") {
continue
}
if !strings.HasPrefix(exp, "cron(") || !strings.HasSuffix(exp, ")") {
errMsgs = append(errMsgs, fmt.Sprintf("\trule %q: invalid expression", r.Name))
continue
}
_, err := cronplan.Parse(strings.TrimSuffix(strings.TrimPrefix(exp, "cron("), ")"))
if err != nil {
errMsg := err.Error()
if idx := strings.LastIndex(errMsg, ": "); idx != -1 {
errMsg = errMsg[idx+2:]
}
errMsgs = append(errMsgs, fmt.Sprintf("\trule %q: %s", r.Name, errMsg))
}
}
if len(errMsgs) > 0 {
return fmt.Errorf("schedule expression validation errors:\n%s", strings.Join(errMsgs, "\n"))
}
return nil
}

// LoadConfig loads config
func LoadConfig(ctx context.Context, r io.Reader, accountID string, confPath string) (*Config, error) {
c := Config{}
Expand All @@ -73,6 +101,9 @@ func LoadConfig(ctx context.Context, r io.Reader, accountID string, confPath str
if err := unmarshalConfig(bs, &c, ext); err != nil {
return nil, err
}
if err := c.cronValidate(); err != nil {
return nil, err
}
c.AccountID = accountID
if err := c.setupPlugins(ctx); err != nil {
return nil, err
Expand Down
23 changes: 23 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,26 @@ func TestLoadConfig_undefined(t *testing.T) {
t.Errorf("error should be nil, but: %v", c.Rules[0].PropagateTags)
}
}

func TestCronValidate(t *testing.T) {
c := &Config{
Rules: []*Rule{
{Name: "rule-1", ScheduleExpression: "cron(0 0 * * ? *)"}, // valid
{Name: "rule-2", ScheduleExpression: "rate(1 day)"}, // rate expressions are excluded from validation
{Name: "rule-3", ScheduleExpression: "invalid(0 0 * * *)"}, // invalid cron expression prefix
{Name: "rule-4", ScheduleExpression: "cron(0 0 * * * *)"}, // missing '?'
{Name: "rule-5", ScheduleExpression: "cron( 0 0 * * ? * )"}, // leading and trailing spaces are invalid but passes current cronplan.Parse()
},
}
err := c.cronValidate()
if err == nil {
t.Errorf("error should be occurred, but nil")
}

e := "schedule expression validation errors:\n" +
"\trule \"rule-3\": invalid expression\n" +
"\trule \"rule-4\": either day-of-month or day-of-week must be '?'"
if g := err.Error(); g != e {
t.Errorf("unexpected error message\nwant:\n%s\n\ngot:\n%s", e, g)
}
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 // indirect
github.com/Azure/go-autorest/autorest/mocks v0.4.2 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/alecthomas/participle/v2 v2.1.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.52.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
Expand All @@ -30,6 +31,7 @@ require (
github.com/google/s2a-go v0.1.7 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/winebarrel/cronplan v1.10.4 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8=
github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c=
github.com/aws/aws-sdk-go-v2 v1.30.1 h1:4y/5Dvfrhd1MxRDD77SrfsDaj8kUkkljU7XE83NPV+o=
github.com/aws/aws-sdk-go-v2 v1.30.1/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
Expand Down Expand Up @@ -241,6 +243,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/winebarrel/cronplan v1.10.4 h1:lpDvd+gihqGEi7aYcvmJ1nyFVCXDULMk8XPvUQtcPyQ=
github.com/winebarrel/cronplan v1.10.4/go.mod h1:ZGEHrRZU3YNI22nDLTr9obcRMX3uBYPektCQoCmFmaY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
Expand Down

0 comments on commit 84bebc9

Please sign in to comment.