feat: add the ability to specify a custom mailto for all cron output
This commit is contained in:
@@ -549,18 +549,18 @@ echo "clock: some-command" >> Procfile
|
|||||||
popd &>/dev/null
|
popd &>/dev/null
|
||||||
```
|
```
|
||||||
|
|
||||||
### `cron-write`
|
### `cron-get-property`
|
||||||
|
|
||||||
- Description: Force triggers writing out cron entries
|
- Description: Return the value for an app's cron property
|
||||||
- Invoked by:
|
- Invoked by:
|
||||||
- Arguments:
|
- Arguments: `$APP $KEY`
|
||||||
- Example:
|
- Example:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
APP="$1"; PROPERTY="$2"
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
```
|
```
|
||||||
@@ -583,6 +583,22 @@ DOKKU_SCHEDULER="$1"
|
|||||||
# TODO
|
# TODO
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `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
|
||||||
|
```
|
||||||
|
|
||||||
### `dependencies`
|
### `dependencies`
|
||||||
|
|
||||||
- Description: Used to install system-level dependencies.
|
- Description: Used to install system-level dependencies.
|
||||||
|
|||||||
@@ -46,10 +46,27 @@ When running scheduled cron tasks, there are a few items to be aware of:
|
|||||||
- Scheduled cron tasks are performed within the app environment available at runtime. If the app image does not exist, the command may fail to execute.
|
- Scheduled cron tasks are performed within the app environment available at runtime. If the app image does not exist, the command may fail to execute.
|
||||||
- Schedules are performed on the hosting server's timezone, which is typically UTC.
|
- Schedules are performed on the hosting server's timezone, which is typically UTC.
|
||||||
- At this time, only the `PATH` and `SHELL` environment variables are specified in the cron template.
|
- At this time, only the `PATH` and `SHELL` environment variables are specified in the cron template.
|
||||||
|
- A `MAILTO` value can be set via the `cron:set` command.
|
||||||
- Each scheduled task is executed within a one-off `run` container, and thus inherit any docker-options specified for `run` containers. Resources are never shared between scheduled tasks.
|
- Each scheduled task is executed within a one-off `run` container, and thus inherit any docker-options specified for `run` containers. Resources are never shared between scheduled tasks.
|
||||||
- Scheduled cron tasks are supported on a per-scheduler basis, and are currently only implemented by the `docker-local` scheduler.
|
- Scheduled cron tasks are supported on a per-scheduler basis, and are currently only implemented by the `docker-local` scheduler.
|
||||||
- Tasks for _all_ apps managed by the `docker-local` scheduler are written to a single crontab file owned by the `dokku` user. The `dokku` user's crontab should be considered reserved for this purpose.
|
- Tasks for _all_ apps managed by the `docker-local` scheduler are written to a single crontab file owned by the `dokku` user. The `dokku` user's crontab should be considered reserved for this purpose.
|
||||||
|
|
||||||
|
#### Specifying a MAILTO value
|
||||||
|
|
||||||
|
By default, cron tasks complete and do not perform any reporting. Users can specify a value for `MAILTO` via the global `mailto` cron property by using the `cron:set` command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
dokku cron:set --global mailto example@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
All output for individual cron runs will be sent to the specified email.
|
||||||
|
|
||||||
|
Cron emails can be disabled by running the `cron:set` command for the global `mailto` property with no value.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
dokku cron:set --global mailto
|
||||||
|
```
|
||||||
|
|
||||||
#### Listing Cron tasks
|
#### Listing Cron tasks
|
||||||
|
|
||||||
Cron tasks for an app can be listed via the `cron:list` command. This command takes an `app` argument.
|
Cron tasks for an app can be listed via the `cron:list` command. This command takes an `app` argument.
|
||||||
|
|||||||
1
plugins/20_events/cron-get-property
Symbolic link
1
plugins/20_events/cron-get-property
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
hook
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
SUBCOMMANDS = subcommands/list subcommands/report subcommands/run
|
SUBCOMMANDS = subcommands/list subcommands/report subcommands/run
|
||||||
BUILD = commands subcommands
|
TRIGGERS = triggers/cron-get-property
|
||||||
|
BUILD = commands subcommands triggers
|
||||||
PLUGIN_NAME = cron
|
PLUGIN_NAME = cron
|
||||||
|
|
||||||
include ../../common.mk
|
include ../../common.mk
|
||||||
|
|||||||
@@ -13,6 +13,18 @@ import (
|
|||||||
cronparser "github.com/robfig/cron/v3"
|
cronparser "github.com/robfig/cron/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultProperties is a map of all valid network properties with corresponding default property values
|
||||||
|
DefaultProperties = map[string]string{
|
||||||
|
"mailto": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalProperties is a map of all valid global network properties
|
||||||
|
GlobalProperties = map[string]bool{
|
||||||
|
"mailto": true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
type TemplateCommand struct {
|
type TemplateCommand struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
App string `json:"app"`
|
App string `json:"app"`
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ func ReportSingleApp(appName string, format string, infoFlag string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
flags := map[string]common.ReportFunc{
|
flags := map[string]common.ReportFunc{
|
||||||
|
"--cron-mailto": reportMailto,
|
||||||
"--cron-task-count": reportTasks,
|
"--cron-task-count": reportTasks,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +28,10 @@ func ReportSingleApp(appName string, format string, infoFlag string) error {
|
|||||||
return common.ReportSingleApp("cron", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
|
return common.ReportSingleApp("cron", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func reportMailto(_ string) string {
|
||||||
|
return common.PropertyGet("cron", "--global", "mailto")
|
||||||
|
}
|
||||||
|
|
||||||
func reportTasks(appName string) string {
|
func reportTasks(appName string) string {
|
||||||
c, _ := FetchCronEntries(appName)
|
c, _ := FetchCronEntries(appName)
|
||||||
return strconv.Itoa(len(c))
|
return strconv.Itoa(len(c))
|
||||||
|
|||||||
11
plugins/cron/set.go
Normal file
11
plugins/cron/set.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package cron
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
func validateSetValue(appName string, key string, value string) error {
|
||||||
|
if key == "mailto" && appName != "--global" {
|
||||||
|
return errors.New("Property cannot be specified on a per-app basis")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
48
plugins/cron/src/triggers/triggers.go
Normal file
48
plugins/cron/src/triggers/triggers.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/dokku/dokku/plugins/common"
|
||||||
|
"github.com/dokku/dokku/plugins/cron"
|
||||||
|
)
|
||||||
|
|
||||||
|
// main entrypoint to all triggers
|
||||||
|
func main() {
|
||||||
|
parts := strings.Split(os.Args[0], "/")
|
||||||
|
trigger := parts[len(parts)-1]
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
switch trigger {
|
||||||
|
case "cron-get-property":
|
||||||
|
appName := flag.Arg(0)
|
||||||
|
property := flag.Arg(1)
|
||||||
|
err = cron.TriggerCronGetProperty(appName, property)
|
||||||
|
case "install":
|
||||||
|
err = cron.TriggerInstall()
|
||||||
|
case "post-app-clone-setup":
|
||||||
|
oldAppName := flag.Arg(0)
|
||||||
|
newAppName := flag.Arg(1)
|
||||||
|
err = cron.TriggerPostAppCloneSetup(oldAppName, newAppName)
|
||||||
|
case "post-app-rename-setup":
|
||||||
|
oldAppName := flag.Arg(0)
|
||||||
|
newAppName := flag.Arg(1)
|
||||||
|
err = cron.TriggerPostAppRenameSetup(oldAppName, newAppName)
|
||||||
|
case "post-delete":
|
||||||
|
appName := flag.Arg(0)
|
||||||
|
err = cron.TriggerPostDelete(appName)
|
||||||
|
case "report":
|
||||||
|
appName := flag.Arg(0)
|
||||||
|
err = cron.ReportSingleApp(appName, "", "")
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("Invalid plugin trigger call: %s", trigger)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
common.LogFailWithError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -112,3 +112,13 @@ func CommandRun(appName string, cronID string, detached bool) error {
|
|||||||
args := append([]string{scheduler, appName, "0"}, fields...)
|
args := append([]string{scheduler, appName, "0"}, fields...)
|
||||||
return common.PlugnTrigger("scheduler-run", args...)
|
return common.PlugnTrigger("scheduler-run", args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommandSet set or clear a cron property for an app
|
||||||
|
func CommandSet(appName string, property string, value string) error {
|
||||||
|
if err := validateSetValue(appName, property, value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
common.CommandPropertySet("cron", appName, property, value, DefaultProperties, GlobalProperties)
|
||||||
|
return common.PlugnTrigger("cron-write")
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
{{ if .Mailto -}}
|
||||||
|
MAILTO={{ .Mailto }}
|
||||||
|
{{ end -}}
|
||||||
PATH=/usr/local/bin:/usr/bin:/bin
|
PATH=/usr/local/bin:/usr/bin:/bin
|
||||||
SHELL=/bin/bash
|
SHELL=/bin/bash
|
||||||
|
|
||||||
|
|||||||
55
plugins/cron/triggers.go
Normal file
55
plugins/cron/triggers.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package cron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/dokku/dokku/plugins/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TriggerCronGetProperty writes the cron key to stdout for a given app container
|
||||||
|
func TriggerCronGetProperty(appName string, key string) error {
|
||||||
|
if key != "mailto" {
|
||||||
|
return errors.New("Invalid cron property specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(common.PropertyGet("cron", appName, key))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TriggerInstall runs the install step for the cron plugin
|
||||||
|
func TriggerInstall() error {
|
||||||
|
if err := common.PropertySetup("cron"); err != nil {
|
||||||
|
return fmt.Errorf("Unable to install the cron plugin: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TriggerPostAppCloneSetup creates new cron files
|
||||||
|
func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error {
|
||||||
|
err := common.PropertyClone("cron", oldAppName, newAppName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TriggerPostAppRenameSetup renames cron files
|
||||||
|
func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error {
|
||||||
|
if err := common.PropertyClone("cron", oldAppName, newAppName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := common.PropertyDestroy("cron", oldAppName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TriggerPostDelete destroys the cron property for a given app container
|
||||||
|
func TriggerPostDelete(appName string) error {
|
||||||
|
return common.PropertyDestroy("cron", appName)
|
||||||
|
}
|
||||||
@@ -116,8 +116,11 @@ func writeCronEntries() error {
|
|||||||
return deleteCrontab()
|
return deleteCrontab()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mailto, _ := common.PlugnTriggerOutputAsString("cron-get-property", []string{"--global", "mailto"}...)
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"Commands": commands,
|
"Commands": commands,
|
||||||
|
"Mailto": mailto,
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := getCronTemplate()
|
t, err := getCronTemplate()
|
||||||
|
|||||||
Reference in New Issue
Block a user