Merge pull request #7978 from dokku/7732-cron-list-global
This commit is contained in:
@@ -112,6 +112,17 @@ dokku cron:list node-js-app --format json
|
|||||||
[{"id":"cGhwPT09cGhwIHRlc3QucGhwPT09QGRhaWx5","app":"node-js-app","command":"node index.js","schedule":"@daily"}]
|
[{"id":"cGhwPT09cGhwIHRlc3QucGhwPT09QGRhaWx5","app":"node-js-app","command":"node index.js","schedule":"@daily"}]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To fetch global tasks, use the `--global` flag:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
dokku cron:list --global
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
ID Schedule Command
|
||||||
|
5cruaotm4yzzpnjlsdunblj8qyjp @daily /bin/true
|
||||||
|
```
|
||||||
|
|
||||||
#### Executing a cron task on the fly
|
#### Executing a cron task on the fly
|
||||||
|
|
||||||
Cron tasks can be invoked via the `cron:run` command. This command takes an `app` argument and a `cron id` (retrievable from `cron:list` output).
|
Cron tasks can be invoked via the `cron:run` command. This command takes an `app` argument and a `cron id` (retrievable from `cron:list` output).
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cron
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
appjson "github.com/dokku/dokku/plugins/app-json"
|
appjson "github.com/dokku/dokku/plugins/app-json"
|
||||||
"github.com/dokku/dokku/plugins/common"
|
"github.com/dokku/dokku/plugins/common"
|
||||||
@@ -32,11 +33,14 @@ type TemplateCommand struct {
|
|||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
|
||||||
// App is the app the cron command belongs to
|
// App is the app the cron command belongs to
|
||||||
App string `json:"app"`
|
App string `json:"app,omitempty"`
|
||||||
|
|
||||||
// Command is the command to run
|
// Command is the command to run
|
||||||
Command string `json:"command"`
|
Command string `json:"command"`
|
||||||
|
|
||||||
|
// Global is whether the cron command is global
|
||||||
|
Global bool `json:"global,omitempty"`
|
||||||
|
|
||||||
// Schedule is the cron schedule
|
// Schedule is the cron schedule
|
||||||
Schedule string `json:"schedule"`
|
Schedule string `json:"schedule"`
|
||||||
|
|
||||||
@@ -125,6 +129,43 @@ func FetchCronEntries(input FetchCronEntriesInput) ([]TemplateCommand, error) {
|
|||||||
return commands, nil
|
return commands, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchGlobalCronEntries returns a list of global cron commands
|
||||||
|
// This function should only be used for the cron:list --global command
|
||||||
|
// and not internally by the cron plugin
|
||||||
|
func FetchGlobalCronEntries() ([]TemplateCommand, error) {
|
||||||
|
commands := []TemplateCommand{}
|
||||||
|
response, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||||
|
Trigger: "cron-entries",
|
||||||
|
Args: []string{"docker-local"},
|
||||||
|
})
|
||||||
|
for _, line := range strings.Split(response.StdoutContents(), "\n") {
|
||||||
|
if strings.TrimSpace(line) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(line, ";")
|
||||||
|
if len(parts) != 2 && len(parts) != 3 {
|
||||||
|
common.LogWarn(fmt.Sprintf("Invalid injected cron task: %v", line))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
id := base36.EncodeToStringLc([]byte(strings.Join(parts, ";;;")))
|
||||||
|
command := TemplateCommand{
|
||||||
|
ID: id,
|
||||||
|
Schedule: parts[0],
|
||||||
|
Command: parts[1],
|
||||||
|
AltCommand: parts[1],
|
||||||
|
Maintenance: false,
|
||||||
|
Global: true,
|
||||||
|
}
|
||||||
|
if len(parts) == 3 {
|
||||||
|
command.LogFile = parts[2]
|
||||||
|
}
|
||||||
|
commands = append(commands, command)
|
||||||
|
}
|
||||||
|
return commands, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GenerateCommandID creates a unique ID for a given app/command/schedule combination
|
// GenerateCommandID creates a unique ID for a given app/command/schedule combination
|
||||||
func GenerateCommandID(appName string, c appjson.CronCommand) string {
|
func GenerateCommandID(appName string, c appjson.CronCommand) string {
|
||||||
return base36.EncodeToStringLc([]byte(appName + "===" + c.Command + "===" + c.Schedule))
|
return base36.EncodeToStringLc([]byte(appName + "===" + c.Command + "===" + c.Schedule))
|
||||||
|
|||||||
@@ -20,9 +20,13 @@ func main() {
|
|||||||
switch subcommand {
|
switch subcommand {
|
||||||
case "list":
|
case "list":
|
||||||
args := flag.NewFlagSet("cron:list", flag.ExitOnError)
|
args := flag.NewFlagSet("cron:list", flag.ExitOnError)
|
||||||
|
global := args.Bool("global", false, "--global: set a global property")
|
||||||
format := args.String("format", "stdout", "format: [ stdout | json ]")
|
format := args.String("format", "stdout", "format: [ stdout | json ]")
|
||||||
args.Parse(os.Args[2:])
|
args.Parse(os.Args[2:])
|
||||||
appName := args.Arg(0)
|
appName := args.Arg(0)
|
||||||
|
if *global {
|
||||||
|
appName = "--global"
|
||||||
|
}
|
||||||
err = cron.CommandList(appName, *format)
|
err = cron.CommandList(appName, *format)
|
||||||
case "report":
|
case "report":
|
||||||
args := flag.NewFlagSet("cron:report", flag.ExitOnError)
|
args := flag.NewFlagSet("cron:report", flag.ExitOnError)
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ import (
|
|||||||
|
|
||||||
// CommandList lists all scheduled cron tasks for a given app
|
// CommandList lists all scheduled cron tasks for a given app
|
||||||
func CommandList(appName string, format string) error {
|
func CommandList(appName string, format string) error {
|
||||||
if err := common.VerifyAppName(appName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if format == "" {
|
if format == "" {
|
||||||
format = "stdout"
|
format = "stdout"
|
||||||
}
|
}
|
||||||
@@ -26,9 +22,22 @@ func CommandList(appName string, format string) error {
|
|||||||
return fmt.Errorf("Invalid format specified, supported formats: json, stdout")
|
return fmt.Errorf("Invalid format specified, supported formats: json, stdout")
|
||||||
}
|
}
|
||||||
|
|
||||||
entries, err := FetchCronEntries(FetchCronEntriesInput{AppName: appName})
|
var entries []TemplateCommand
|
||||||
if err != nil {
|
if appName == "--global" {
|
||||||
return err
|
var err error
|
||||||
|
entries, err = FetchGlobalCronEntries()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
if err := common.VerifyAppName(appName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
entries, err = FetchCronEntries(FetchCronEntriesInput{AppName: appName})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if format == "stdout" {
|
if format == "stdout" {
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ version = "0.0.1"
|
|||||||
[plugin.config]
|
[plugin.config]
|
||||||
EOF
|
EOF
|
||||||
cp /var/lib/dokku/plugins/available/cron-entries/plugin.toml /var/lib/dokku/plugins/enabled/cron-entries/plugin.toml
|
cp /var/lib/dokku/plugins/available/cron-entries/plugin.toml /var/lib/dokku/plugins/enabled/cron-entries/plugin.toml
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown() {
|
teardown() {
|
||||||
@@ -126,6 +125,12 @@ teardown() {
|
|||||||
echo "status: $status"
|
echo "status: $status"
|
||||||
assert_success
|
assert_success
|
||||||
|
|
||||||
|
run /bin/bash -c "dokku cron:list --global --format json"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
assert_output '[{"id":"5cruaotm4yzzpnjlsdunblj8qyjp","command":"/bin/true","global":true,"schedule":"@daily","maintenance":false}]'
|
||||||
|
|
||||||
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
|
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
|
||||||
echo "output: $output"
|
echo "output: $output"
|
||||||
echo "status: $status"
|
echo "status: $status"
|
||||||
|
|||||||
Reference in New Issue
Block a user