Merge pull request #7579 from dokku/6872-stop-all
Stop all app containers when calling ps:stop
This commit is contained in:
@@ -98,7 +98,7 @@ At this time, the following dokku commands are used to implement a complete sche
|
|||||||
- `apps:clone`: handles app cloning
|
- `apps:clone`: handles app cloning
|
||||||
- triggers: post-app-clone-setup
|
- triggers: post-app-clone-setup
|
||||||
- `cron`: generates cron tasks for the app
|
- `cron`: generates cron tasks for the app
|
||||||
- triggers: cron-write
|
- triggers: scheduler-cron-write
|
||||||
- `deploy`: deploys app proceses and checks the status of a deploy
|
- `deploy`: deploys app proceses and checks the status of a deploy
|
||||||
- triggers: scheduler-app-status, scheduler-deploy, scheduler-is-deployed, scheduler-logs-failed
|
- triggers: scheduler-app-status, scheduler-deploy, scheduler-is-deployed, scheduler-logs-failed
|
||||||
- `enter`: enters a running container
|
- `enter`: enters a running container
|
||||||
@@ -112,7 +112,9 @@ At this time, the following dokku commands are used to implement a complete sche
|
|||||||
- `run:logs`: fetches running container logs
|
- `run:logs`: fetches running container logs
|
||||||
- triggers: scheduler-run-logs
|
- triggers: scheduler-run-logs
|
||||||
- `ps:stop`: stops app processes
|
- `ps:stop`: stops app processes
|
||||||
- triggers: scheduler-stop
|
- triggers: scheduler-stop, scheduler-cron-write
|
||||||
|
- `ps:start`: starts app processes
|
||||||
|
- triggers: scheduler-deploy, scheduler-cron-write
|
||||||
- `ps:inspect`: outputs inspect output for processes in an app
|
- `ps:inspect`: outputs inspect output for processes in an app
|
||||||
- triggers: scheduler-inspect
|
- triggers: scheduler-inspect
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,21 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
|||||||
# TODO
|
# TODO
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `app-json-is-valid`
|
||||||
|
|
||||||
|
- Description: Checks to see if the provided app.json file is valid
|
||||||
|
- Invoked by: Appjson extraction during deployment
|
||||||
|
- Arguments: `$APP $APP_JSON_PATH`
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
```
|
||||||
|
|
||||||
### `app-maybe-create`
|
### `app-maybe-create`
|
||||||
|
|
||||||
- Description: Creates an app (gated by whether this is globally enabled or not)
|
- Description: Creates an app (gated by whether this is globally enabled or not)
|
||||||
@@ -583,22 +598,6 @@ 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.
|
||||||
@@ -2445,6 +2444,26 @@ DOKKU_SCHEDULER="$1"; APP="$2";
|
|||||||
# TODO
|
# TODO
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `scheduler-cron-write`
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> The scheduler plugin trigger apis are under development and may change
|
||||||
|
> between minor releases until the 1.0 release.
|
||||||
|
|
||||||
|
- Description: Force triggers writing out cron entries. Arguments are optional.
|
||||||
|
- Invoked by: `ps:start`, `ps:stop`, `cron:set`
|
||||||
|
- Arguments: `$DOKKU_SCHEDULER $APP`
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||||
|
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
```
|
||||||
|
|
||||||
### `scheduler-deploy`
|
### `scheduler-deploy`
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
|
|||||||
@@ -200,21 +200,9 @@ func GetAppJSON(appName string) (AppJSON, error) {
|
|||||||
return AppJSON{}, nil
|
return AppJSON{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := os.ReadFile(getProcessSpecificAppJSONPath(appName))
|
appJSONPath := getProcessSpecificAppJSONPath(appName)
|
||||||
if err != nil {
|
|
||||||
return AppJSON{}, fmt.Errorf("Cannot read app.json file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.TrimSpace(string(b)) == "" {
|
return ReadAppJSON(appJSONPath)
|
||||||
return AppJSON{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var appJSON AppJSON
|
|
||||||
if err = json.Unmarshal(b, &appJSON); err != nil {
|
|
||||||
return AppJSON{}, fmt.Errorf("Cannot parse app.json: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return appJSON, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAutoscalingConfig(appName string, processType string, replicas int) (FormationAutoscaling, bool, error) {
|
func GetAutoscalingConfig(appName string, processType string, replicas int) (FormationAutoscaling, bool, error) {
|
||||||
@@ -256,3 +244,22 @@ func GetAutoscalingConfig(appName string, processType string, replicas int) (For
|
|||||||
|
|
||||||
return autoscaling, true, nil
|
return autoscaling, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadAppJSON reads an app.json file from a given path
|
||||||
|
func ReadAppJSON(path string) (AppJSON, error) {
|
||||||
|
b, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return AppJSON{}, fmt.Errorf("Cannot read app.json file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.TrimSpace(string(b)) == "" {
|
||||||
|
return AppJSON{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var appJSON AppJSON
|
||||||
|
if err = json.Unmarshal(b, &appJSON); err != nil {
|
||||||
|
return AppJSON{}, fmt.Errorf("Cannot parse app.json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return appJSON, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package appjson
|
package appjson
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -140,6 +141,22 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if common.FileExists(processSpecificAppJSON) {
|
||||||
|
result, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||||
|
Trigger: "app-json-is-valid",
|
||||||
|
Args: []string{appName, processSpecificAppJSON},
|
||||||
|
StreamStdout: true,
|
||||||
|
StreamStderr: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if result.StderrContents() != "" {
|
||||||
|
return errors.New(result.StderrContents())
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: add validation to app.json file by ensuring it can be deserialized
|
// TODO: add validation to app.json file by ensuring it can be deserialized
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
SUBCOMMANDS = subcommands/list subcommands/report subcommands/run subcommands/set
|
SUBCOMMANDS = subcommands/list subcommands/report subcommands/run subcommands/set
|
||||||
TRIGGERS = triggers/cron-get-property triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/scheduler-stop
|
TRIGGERS = triggers/app-json-is-valid triggers/cron-get-property triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/scheduler-stop
|
||||||
BUILD = commands subcommands triggers
|
BUILD = commands subcommands triggers
|
||||||
PLUGIN_NAME = cron
|
PLUGIN_NAME = cron
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
appjson "github.com/dokku/dokku/plugins/app-json"
|
appjson "github.com/dokku/dokku/plugins/app-json"
|
||||||
|
"github.com/dokku/dokku/plugins/common"
|
||||||
|
|
||||||
"github.com/multiformats/go-base36"
|
"github.com/multiformats/go-base36"
|
||||||
cronparser "github.com/robfig/cron/v3"
|
cronparser "github.com/robfig/cron/v3"
|
||||||
@@ -61,25 +62,55 @@ func (t TemplateCommand) CronCommand() string {
|
|||||||
return fmt.Sprintf("dokku run --cron-id %s %s %s", t.ID, t.App, t.Command)
|
return fmt.Sprintf("dokku run --cron-id %s %s %s", t.ID, t.App, t.Command)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchCronEntriesInput is the input for the FetchCronEntries function
|
||||||
|
type FetchCronEntriesInput struct {
|
||||||
|
AppName string
|
||||||
|
AppJSON *appjson.AppJSON
|
||||||
|
WarnToFailure bool
|
||||||
|
}
|
||||||
|
|
||||||
// FetchCronEntries returns a list of cron commands for a given app
|
// FetchCronEntries returns a list of cron commands for a given app
|
||||||
func FetchCronEntries(appName string) ([]TemplateCommand, error) {
|
func FetchCronEntries(input FetchCronEntriesInput) ([]TemplateCommand, error) {
|
||||||
|
appName := input.AppName
|
||||||
commands := []TemplateCommand{}
|
commands := []TemplateCommand{}
|
||||||
isMaintenance := reportComputedMaintenance(appName) == "true"
|
isMaintenance := reportComputedMaintenance(appName) == "true"
|
||||||
|
|
||||||
appJSON, err := appjson.GetAppJSON(appName)
|
if input.AppJSON == nil {
|
||||||
if err != nil {
|
appJSON, err := appjson.GetAppJSON(appName)
|
||||||
return commands, fmt.Errorf("Unable to fetch app.json for app %s: %s", appName, err.Error())
|
if err != nil {
|
||||||
|
return commands, fmt.Errorf("Unable to fetch app.json for app %s: %s", appName, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
input.AppJSON = &appJSON
|
||||||
}
|
}
|
||||||
|
|
||||||
if appJSON.Cron == nil {
|
if input.AppJSON.Cron == nil {
|
||||||
return commands, nil
|
return commands, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range appJSON.Cron {
|
for i, c := range input.AppJSON.Cron {
|
||||||
|
if c.Command == "" {
|
||||||
|
if input.WarnToFailure {
|
||||||
|
return commands, fmt.Errorf("Missing cron command for app %s (index %d)", appName, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
common.LogWarn(fmt.Sprintf("Missing cron command for app %s (index %d)", appName, i))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Schedule == "" {
|
||||||
|
if input.WarnToFailure {
|
||||||
|
return commands, fmt.Errorf("Missing cron schedule for app %s (index %d)", appName, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
common.LogWarn(fmt.Sprintf("Missing cron schedule for app %s (index %d)", appName, i))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
parser := cronparser.NewParser(cronparser.Minute | cronparser.Hour | cronparser.Dom | cronparser.Month | cronparser.Dow | cronparser.Descriptor)
|
parser := cronparser.NewParser(cronparser.Minute | cronparser.Hour | cronparser.Dom | cronparser.Month | cronparser.Dow | cronparser.Descriptor)
|
||||||
_, err := parser.Parse(c.Schedule)
|
_, err := parser.Parse(c.Schedule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return commands, fmt.Errorf("Invalid cron schedule %s: %s", c.Schedule, err.Error())
|
return commands, fmt.Errorf("Invalid cron schedule for app %s (schedule %s): %s", appName, c.Schedule, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
commands = append(commands, TemplateCommand{
|
commands = append(commands, TemplateCommand{
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func reportMailto(_ string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func reportTasks(appName string) string {
|
func reportTasks(appName string) string {
|
||||||
c, _ := FetchCronEntries(appName)
|
c, _ := FetchCronEntries(FetchCronEntriesInput{AppName: appName})
|
||||||
return strconv.Itoa(len(c))
|
return strconv.Itoa(len(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ func main() {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch trigger {
|
switch trigger {
|
||||||
|
case "app-json-is-valid":
|
||||||
|
appName := flag.Arg(0)
|
||||||
|
appJSONPath := flag.Arg(1)
|
||||||
|
err = cron.TriggerAppJSONIsValid(appName, appJSONPath)
|
||||||
case "cron-get-property":
|
case "cron-get-property":
|
||||||
appName := flag.Arg(0)
|
appName := flag.Arg(0)
|
||||||
property := flag.Arg(1)
|
property := flag.Arg(1)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ 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(appName)
|
entries, err := FetchCronEntries(FetchCronEntriesInput{AppName: appName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ func CommandRun(appName string, cronID string, detached bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
entries, err := FetchCronEntries(appName)
|
entries, err := FetchCronEntries(FetchCronEntriesInput{AppName: appName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -130,8 +130,10 @@ func CommandSet(appName string, property string, value string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
common.CommandPropertySet("cron", appName, property, value, DefaultProperties, GlobalProperties)
|
common.CommandPropertySet("cron", appName, property, value, DefaultProperties, GlobalProperties)
|
||||||
|
scheduler := common.GetAppScheduler(appName)
|
||||||
_, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
_, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||||
Trigger: "cron-write",
|
Trigger: "scheduler-cron-write",
|
||||||
|
Args: []string{scheduler, appName},
|
||||||
StreamStdio: true,
|
StreamStdio: true,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
appjson "github.com/dokku/dokku/plugins/app-json"
|
||||||
"github.com/dokku/dokku/plugins/common"
|
"github.com/dokku/dokku/plugins/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,6 +24,29 @@ func TriggerCronGetProperty(appName string, key string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TriggerAppJSONIsValid validates the cron entries for a given app
|
||||||
|
func TriggerAppJSONIsValid(appName string, appJSONPath string) error {
|
||||||
|
if !common.FileExists(appJSONPath) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
appJSON, err := appjson.ReadAppJSON(appJSONPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = FetchCronEntries(FetchCronEntriesInput{
|
||||||
|
AppName: appName,
|
||||||
|
AppJSON: &appJSON,
|
||||||
|
WarnToFailure: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TriggerInstall runs the install step for the cron plugin
|
// TriggerInstall runs the install step for the cron plugin
|
||||||
func TriggerInstall() error {
|
func TriggerInstall() error {
|
||||||
if err := common.PropertySetup("cron"); err != nil {
|
if err := common.PropertySetup("cron"); err != nil {
|
||||||
@@ -57,7 +81,21 @@ func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error {
|
|||||||
|
|
||||||
// TriggerPostDelete destroys the cron property for a given app container
|
// TriggerPostDelete destroys the cron property for a given app container
|
||||||
func TriggerPostDelete(appName string) error {
|
func TriggerPostDelete(appName string) error {
|
||||||
return common.PropertyDestroy("cron", appName)
|
scheduler := common.GetAppScheduler(appName)
|
||||||
|
_, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||||
|
Trigger: "scheduler-cron-write",
|
||||||
|
Args: []string{scheduler, appName},
|
||||||
|
StreamStdio: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := common.PropertyDestroy("cron", appName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TriggerSchedulerStop stops the scheduler for a given app container
|
// TriggerSchedulerStop stops the scheduler for a given app container
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
TRIGGERS = triggers/cron-write
|
TRIGGERS = triggers/scheduler-cron-write
|
||||||
BUILD = triggers
|
BUILD = triggers
|
||||||
PLUGIN_NAME = scheduler-docker-local
|
PLUGIN_NAME = scheduler-docker-local
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,11 @@ func generateCronEntries() ([]cron.TemplateCommand, error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := cron.FetchCronEntries(appName)
|
c, err := cron.FetchCronEntries(cron.FetchCronEntriesInput{AppName: appName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
results <- []cron.TemplateCommand{}
|
results <- []cron.TemplateCommand{}
|
||||||
return err
|
common.LogWarn(err.Error())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
results <- c
|
results <- c
|
||||||
@@ -115,7 +116,12 @@ func generateCronEntries() ([]cron.TemplateCommand, error) {
|
|||||||
return commands, nil
|
return commands, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeCronEntries() error {
|
func writeCronEntries(scheduler string) error {
|
||||||
|
// allow empty scheduler, which means all apps (used by letsencrypt)
|
||||||
|
if scheduler != "docker-local" && scheduler != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
commands, err := generateCronEntries()
|
commands, err := generateCronEntries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ trigger-scheduler-docker-local-post-delete() {
|
|||||||
|
|
||||||
# remove all application containers
|
# remove all application containers
|
||||||
"$DOCKER_BIN" container ls --filter "label=com.dokku.app-name=${APP}" -q | xargs -n1 -I {} "$DOCKER_BIN" container rm --force {} &>/dev/null || true
|
"$DOCKER_BIN" container ls --filter "label=com.dokku.app-name=${APP}" -q | xargs -n1 -I {} "$DOCKER_BIN" container rm --force {} &>/dev/null || true
|
||||||
|
|
||||||
plugn trigger cron-write
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger-scheduler-docker-local-post-delete "$@"
|
trigger-scheduler-docker-local-post-delete "$@"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||||
[[ $DOKKU_TRACE ]] && set -x
|
[[ $DOKKU_TRACE ]] && set -x
|
||||||
|
|
||||||
trigger-scheduler-docker-local-post-deploy() {
|
trigger-scheduler-docker-local-post-deploy() {
|
||||||
@@ -7,7 +8,8 @@ trigger-scheduler-docker-local-post-deploy() {
|
|||||||
declare trigger="post-deploy"
|
declare trigger="post-deploy"
|
||||||
declare APP="$1"
|
declare APP="$1"
|
||||||
|
|
||||||
plugn trigger cron-write
|
local DOKKU_SCHEDULER="$(get_app_scheduler "$APP")"
|
||||||
|
plugn trigger scheduler-cron-write "$DOKKU_SCHEDULER" "$APP"
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger-scheduler-docker-local-post-deploy "$@"
|
trigger-scheduler-docker-local-post-deploy "$@"
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ set -eo pipefail
|
|||||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||||
|
|
||||||
|
fn-stop-container() {
|
||||||
|
declare APP="$1" CID="$2"
|
||||||
|
"$DOCKER_BIN" container update --restart=no "$CID" &>/dev/null || true
|
||||||
|
"$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$CID" &>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
trigger-scheduler-docker-local-scheduler-stop() {
|
trigger-scheduler-docker-local-scheduler-stop() {
|
||||||
declare desc="scheduler-docker-local scheduler-stop plugin trigger"
|
declare desc="scheduler-docker-local scheduler-stop plugin trigger"
|
||||||
declare trigger="scheduler-stop"
|
declare trigger="scheduler-stop"
|
||||||
@@ -19,14 +25,22 @@ trigger-scheduler-docker-local-scheduler-stop() {
|
|||||||
[[ -n "$DOKKU_DOCKER_STOP_TIMEOUT" ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}"
|
[[ -n "$DOKKU_DOCKER_STOP_TIMEOUT" ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}"
|
||||||
|
|
||||||
if [[ -n "$DOKKU_APP_RUNNING_CONTAINER_IDS" ]]; then
|
if [[ -n "$DOKKU_APP_RUNNING_CONTAINER_IDS" ]]; then
|
||||||
# Disable the container restart policy
|
for CID in $DOKKU_APP_RUNNING_CONTAINER_IDS; do
|
||||||
"$DOCKER_BIN" container update --restart=no $DOKKU_APP_RUNNING_CONTAINER_IDS &>/dev/null || true
|
fn-stop-container "$APP" "$CID"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
"$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG $DOKKU_APP_RUNNING_CONTAINER_IDS >/dev/null || true
|
# Stop all other containers related to the app
|
||||||
|
# fetch all containers with the com.dokku.app-name label
|
||||||
|
local DOKKU_APP_CIDS="$(docker container ls -q -f label=com.dokku.app-name="$APP")"
|
||||||
|
if [[ -n "$DOKKU_APP_CIDS" ]]; then
|
||||||
|
for CID in $DOKKU_APP_CIDS; do
|
||||||
|
fn-stop-container "$APP" "$CID"
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$REMOVE_CONTAINERS" == "true" ]]; then
|
if [[ "$REMOVE_CONTAINERS" == "true" ]]; then
|
||||||
local DOKKU_APP_CIDS=$(get_app_container_ids "$APP")
|
local DOKKU_APP_CIDS="$(docker ps -q -f label=com.dokku.app-name="$APP")"
|
||||||
|
|
||||||
if [[ -n "$DOKKU_APP_CIDS" ]]; then
|
if [[ -n "$DOKKU_APP_CIDS" ]]; then
|
||||||
for CID in $DOKKU_APP_CIDS; do
|
for CID in $DOKKU_APP_CIDS; do
|
||||||
@@ -36,6 +50,8 @@ trigger-scheduler-docker-local-scheduler-stop() {
|
|||||||
"$DOCKER_BIN" container rm --force $DOKKU_APP_CIDS &>/dev/null || true
|
"$DOCKER_BIN" container rm --force $DOKKU_APP_CIDS &>/dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
plugn trigger scheduler-cron-write "$DOKKU_SCHEDULER" "$APP"
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger-scheduler-docker-local-scheduler-stop "$@"
|
trigger-scheduler-docker-local-scheduler-stop "$@"
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ func main() {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch trigger {
|
switch trigger {
|
||||||
case "cron-write":
|
case "scheduler-cron-write":
|
||||||
err = schedulerdockerlocal.TriggerCronWrite()
|
scheduler := flag.Arg(0)
|
||||||
|
err = schedulerdockerlocal.TriggerSchedulerCronWrite(scheduler)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("Invalid plugin trigger call: %s", trigger)
|
err = fmt.Errorf("Invalid plugin trigger call: %s", trigger)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package schedulerdockerlocal
|
package schedulerdockerlocal
|
||||||
|
|
||||||
// TriggerCronWrite force updates the cron file for all apps
|
// TriggerSchedulerCronWrite force updates the cron file for all apps
|
||||||
func TriggerCronWrite() error {
|
func TriggerSchedulerCronWrite(scheduler string) error {
|
||||||
return writeCronEntries()
|
return writeCronEntries(scheduler)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -940,3 +940,32 @@ func streamLogsFromRequest(ctx context.Context, request rest.ResponseWrapper, ou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SuspendCronJobsInput contains all the information needed to suspend a Kubernetes cron job
|
||||||
|
type SuspendCronJobsInput struct {
|
||||||
|
// LabelSelector is the Kubernetes label selector
|
||||||
|
LabelSelector string
|
||||||
|
|
||||||
|
// Namespace is the Kubernetes namespace
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuspendCronJobs suspends a Kubernetes cron job
|
||||||
|
func (k KubernetesClient) SuspendCronJobs(ctx context.Context, input SuspendCronJobsInput) error {
|
||||||
|
cronJobs, err := k.Client.BatchV1().CronJobs(input.Namespace).List(ctx, metav1.ListOptions{
|
||||||
|
LabelSelector: input.LabelSelector,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cronJob := range cronJobs.Items {
|
||||||
|
cronJob.Spec.Suspend = ptr.To(true)
|
||||||
|
_, err := k.Client.BatchV1().CronJobs(input.Namespace).Update(ctx, &cronJob, metav1.UpdateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e
|
|||||||
|
|
||||||
workingDir := common.GetWorkingDir(appName, image)
|
workingDir := common.GetWorkingDir(appName, image)
|
||||||
|
|
||||||
allCronEntries, err := cron.FetchCronEntries(appName)
|
allCronEntries, err := cron.FetchCronEntries(cron.FetchCronEntriesInput{AppName: appName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error fetching cron entries: %w", err)
|
return fmt.Errorf("Error fetching cron entries: %w", err)
|
||||||
}
|
}
|
||||||
@@ -1499,5 +1499,14 @@ func TriggerSchedulerStop(scheduler string, appName string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get all cronjobs for the app
|
||||||
|
err = clientset.SuspendCronJobs(ctx, SuspendCronJobsInput{
|
||||||
|
Namespace: namespace,
|
||||||
|
LabelSelector: fmt.Sprintf("app.kubernetes.io/part-of=%s", appName),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error suspending cron jobs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ teardown() {
|
|||||||
echo "echo '@daily;/bin/true'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-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
|
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||||
|
|
||||||
run /bin/bash -c "dokku plugin:trigger cron-write"
|
run /bin/bash -c "dokku plugin:trigger scheduler-cron-write"
|
||||||
echo "output: $output"
|
echo "output: $output"
|
||||||
echo "status: $status"
|
echo "status: $status"
|
||||||
assert_success
|
assert_success
|
||||||
@@ -136,7 +136,7 @@ teardown() {
|
|||||||
echo "echo '@daily;/bin/true;/var/log/dokku/log.log'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
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
|
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||||
|
|
||||||
run /bin/bash -c "dokku plugin:trigger cron-write"
|
run /bin/bash -c "dokku plugin:trigger scheduler-cron-write"
|
||||||
echo "output: $output"
|
echo "output: $output"
|
||||||
echo "status: $status"
|
echo "status: $status"
|
||||||
assert_success
|
assert_success
|
||||||
@@ -151,7 +151,7 @@ teardown() {
|
|||||||
echo "[[ \$1 == 'docker-local' ]] && echo '@daily;/bin/true'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
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
|
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||||
|
|
||||||
run /bin/bash -c "dokku plugin:trigger cron-write"
|
run /bin/bash -c "dokku plugin:trigger scheduler-cron-write"
|
||||||
echo "output: $output"
|
echo "output: $output"
|
||||||
echo "status: $status"
|
echo "status: $status"
|
||||||
assert_success
|
assert_success
|
||||||
@@ -166,7 +166,7 @@ teardown() {
|
|||||||
echo "[[ \$1 == 'kubernetes' ]] && echo '@daily;/bin/true'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
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
|
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
|
||||||
|
|
||||||
run /bin/bash -c "dokku plugin:trigger cron-write"
|
run /bin/bash -c "dokku plugin:trigger scheduler-cron-write"
|
||||||
echo "output: $output"
|
echo "output: $output"
|
||||||
echo "status: $status"
|
echo "status: $status"
|
||||||
assert_success
|
assert_success
|
||||||
|
|||||||
Reference in New Issue
Block a user