Merge pull request #4384 from dokku/cron-trigger
Add support for injected cron entries from external plugins
This commit is contained in:
@@ -309,6 +309,40 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
curl "http://httpstat.us/200"
|
||||
```
|
||||
|
||||
### `cron-write`
|
||||
|
||||
- Description: Force triggers writing out cron entries
|
||||
- Invoked by:
|
||||
- Arguments:
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `cron-entries`
|
||||
|
||||
- Description: Allows injecting cron entries into the written out scheduled cron task list. Each entry is newline delimited, and individual entries come in the form `$SCHEDULE;$FULL_COMMAND;$ARBITRARY_DATA`. Individual implementations of cron writing can decide whether and how to include these cron entries. The `ARBITRARY_DATA` includes the log file path for the basic `docker-local` cron implementation.
|
||||
- Invoked by:
|
||||
- Arguments: `$DOKKU_SCHEDULER`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
|
||||
DOKKU_SCHEDULER="$1"
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `dependencies`
|
||||
|
||||
- Description: Used to install system-level dependencies.
|
||||
|
||||
1
plugins/20_events/cron-entries
Symbolic link
1
plugins/20_events/cron-entries
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/cron-write
Symbolic link
1
plugins/20_events/cron-write
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/cron/.gitignore
vendored
1
plugins/cron/.gitignore
vendored
@@ -2,5 +2,6 @@
|
||||
/subcommands/*
|
||||
/triggers/*
|
||||
/triggers
|
||||
/cron-*
|
||||
/post-*
|
||||
/report
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SUBCOMMANDS = subcommands/list subcommands/report
|
||||
TRIGGERS = triggers/post-delete triggers/post-deploy triggers/report
|
||||
TRIGGERS = triggers/cron-write triggers/post-delete triggers/post-deploy triggers/report
|
||||
BUILD = commands subcommands triggers
|
||||
PLUGIN_NAME = cron
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
appjson "github.com/dokku/dokku/plugins/app-json"
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
@@ -17,10 +17,23 @@ import (
|
||||
)
|
||||
|
||||
type templateCommand struct {
|
||||
ID string
|
||||
App string
|
||||
Command string
|
||||
Schedule string
|
||||
ID string
|
||||
App string
|
||||
Command string
|
||||
Schedule string
|
||||
AltCommand string
|
||||
LogFile string
|
||||
}
|
||||
|
||||
func (t templateCommand) CronCommand() string {
|
||||
if t.AltCommand != "" {
|
||||
if t.LogFile != "" {
|
||||
return fmt.Sprintf("%s &>> %s", t.AltCommand, t.LogFile)
|
||||
}
|
||||
return t.AltCommand
|
||||
}
|
||||
|
||||
return fmt.Sprintf("dokku --rm run --cron-id %s %s", t.ID, t.App, t.Command)
|
||||
}
|
||||
|
||||
func fetchCronEntries(appName string) ([]templateCommand, error) {
|
||||
@@ -86,11 +99,7 @@ func deleteCrontab() error {
|
||||
}
|
||||
|
||||
func writeCronEntries() error {
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
return deleteCrontab()
|
||||
}
|
||||
|
||||
apps, _ := common.DokkuApps()
|
||||
commands := []templateCommand{}
|
||||
for _, appName := range apps {
|
||||
scheduler := common.GetAppScheduler(appName)
|
||||
@@ -106,6 +115,30 @@ func writeCronEntries() error {
|
||||
commands = append(commands, c...)
|
||||
}
|
||||
|
||||
b, _ := common.PlugnTriggerOutput("cron-entries", "docker-local")
|
||||
common.Log(fmt.Sprintf("output: %s", string(b)))
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(b[:])), "\n") {
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Split(line, ";")
|
||||
if len(parts) != 2 && len(parts) != 3 {
|
||||
return fmt.Errorf("Invalid injected cron task: %v", line)
|
||||
}
|
||||
|
||||
id := base64.StdEncoding.EncodeToString([]byte(strings.Join(parts, ";;;")))
|
||||
command := templateCommand{
|
||||
ID: id,
|
||||
Schedule: parts[0],
|
||||
AltCommand: parts[1],
|
||||
}
|
||||
if len(parts) == 3 {
|
||||
command.LogFile = parts[2]
|
||||
}
|
||||
commands = append(commands, command)
|
||||
}
|
||||
|
||||
if len(commands) == 0 {
|
||||
return deleteCrontab()
|
||||
}
|
||||
@@ -119,7 +152,7 @@ func writeCronEntries() error {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), fmt.Sprintf("dokku-%s-%s", common.MustGetEnv("DOKKU_PID"), "CopyFromImage"))
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), fmt.Sprintf("dokku-%s-%s", common.MustGetEnv("DOKKU_PID"), "WriteCronEntries"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot create temporary schedule file: %v", err)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ func main() {
|
||||
|
||||
var err error
|
||||
switch trigger {
|
||||
case "cron-write":
|
||||
err = cron.TriggerCronWrite()
|
||||
case "post-delete":
|
||||
err = cron.TriggerPostDelete()
|
||||
case "post-deploy":
|
||||
|
||||
@@ -2,5 +2,5 @@ PATH=/usr/local/bin:/usr/bin:/bin
|
||||
SHELL=/bin/bash
|
||||
|
||||
{{ range $entry := .Commands -}}
|
||||
{{ $entry.Schedule }} dokku --rm run --cron-id {{ $entry.ID }} {{ $entry.App }} {{ $entry.Command }}
|
||||
{{ $entry.Schedule }} {{ $entry.CronCommand }}
|
||||
{{ end -}}
|
||||
|
||||
@@ -9,3 +9,8 @@ func TriggerPostDelete() error {
|
||||
func TriggerPostDeploy() error {
|
||||
return writeCronEntries()
|
||||
}
|
||||
|
||||
// TriggerCronWrite force updates the cron file for all apps
|
||||
func TriggerCronWrite() error {
|
||||
return writeCronEntries()
|
||||
}
|
||||
|
||||
@@ -5,9 +5,20 @@ load test_helper
|
||||
setup() {
|
||||
global_setup
|
||||
create_app
|
||||
mkdir -p /var/lib/dokku/plugins/available/cron-entries
|
||||
mkdir -p /var/lib/dokku/plugins/enabled/cron-entries
|
||||
cat >"/var/lib/dokku/plugins/available/cron-entries/plugin.toml" <<EOF
|
||||
[plugin]
|
||||
description = "dokku test cron-entries plugin"
|
||||
version = "0.0.1"
|
||||
[plugin.config]
|
||||
EOF
|
||||
cp /var/lib/dokku/plugins/available/cron-entries/plugin.toml /var/lib/dokku/plugins/enabled/cron-entries/plugin.toml
|
||||
|
||||
}
|
||||
|
||||
teardown() {
|
||||
rm -rf /var/lib/dokku/plugins/available/cron-entries /var/lib/dokku/plugins/enabled/cron-entries
|
||||
destroy_app
|
||||
global_teardown
|
||||
}
|
||||
@@ -99,6 +110,69 @@ teardown() {
|
||||
assert_output_contains "python task.py second"
|
||||
}
|
||||
|
||||
@test "(cron) injected entries" {
|
||||
echo "echo '@daily;/bin/true'" > /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||
|
||||
run /bin/bash -c "dokku plugin:trigger cron-write"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
|
||||
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "@daily /bin/true"
|
||||
|
||||
# log file
|
||||
echo "echo '@daily;/bin/true;/var/log/dokku/log.log'" > /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||
|
||||
run /bin/bash -c "dokku plugin:trigger cron-write"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
|
||||
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "@daily /bin/true &>> /var/log/dokku/log.log"
|
||||
|
||||
# specify matching scheduler
|
||||
echo "[[ \$1 == 'docker-local' ]] && echo '@daily;/bin/true'" > /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||
|
||||
run /bin/bash -c "dokku plugin:trigger cron-write"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
|
||||
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "@daily /bin/true"
|
||||
|
||||
# specify non-matching scheduler
|
||||
echo "[[ \$1 == 'kubernetes' ]] && echo '@daily;/bin/true'" > /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||
|
||||
run /bin/bash -c "dokku plugin:trigger cron-write"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
|
||||
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
template_cron_file_invalid() {
|
||||
local APP="$1"
|
||||
|
||||
Reference in New Issue
Block a user