diff --git a/docs/appendices/0.38.0-migration-guide.md b/docs/appendices/0.38.0-migration-guide.md index 5debbd56f..7a7eb618e 100644 --- a/docs/appendices/0.38.0-migration-guide.md +++ b/docs/appendices/0.38.0-migration-guide.md @@ -20,6 +20,7 @@ - Fresh apt installs now ship a catch-all default site at `/etc/nginx/conf.d/00-default-vhost.conf` that rejects requests with unknown Host headers using `ssl_reject_handshake on` (HTTPS) and `return 444` (HTTP). This replaces the manual workaround previously documented in the nginx docs. The behavior can be opted out at install time via the `dokku/install_default_site` debconf prompt. See the [Default site documentation](/docs/networking/proxies/nginx.md#default-site). - The `docker-local` scheduler now sends `SIGTERM` to old containers immediately after a successful deploy, rather than waiting `wait-to-retire` seconds before signaling. This matches Heroku's graceful-shutdown contract and lets applications begin draining in-flight work as soon as proxy traffic switches. The `wait-to-retire` grace period and `stop-timeout-seconds` hard-stop continue to apply as before. See the [zero downtime deploys documentation](/docs/deployment/zero-downtime-deploys.md#wait-to-retire) for more details. - The `docker-local` scheduler no longer queues an image for retirement when another running container of the same app still uses it. This fixes the case where a `ps:rebuild` against an image-based deploy (`git:from-image`) produced an identical-SHA image and the `dokku-retire` cron timer would log `Image ... has running containers, skipping rm` on every run. Stuck entries from prior versions are pruned automatically on the next `ps:retire` run. +- All `:report` subcommands now accept the `--global` flag, which scopes the report to globally-configured properties. The flag composes with `--format json`, so a JSON report of global properties can be obtained via, for example, `dokku scheduler:report --global --format json`. Previously, combining `--global` with `--format json` was rejected with an "info flag" error, and `--global` on its own was treated as an unknown flag. ### TLS handshake behavior change diff --git a/plugins/app-json/report.go b/plugins/app-json/report.go index 511f12302..5d472a4d2 100644 --- a/plugins/app-json/report.go +++ b/plugins/app-json/report.go @@ -6,14 +6,23 @@ import ( // ReportSingleApp is an internal function that displays the builder report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--app-json-computed-selected": reportComputedAppjsonpath, - "--app-json-global-selected": reportGlobalAppjsonpath, - "--app-json-selected": reportAppjsonpath, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--app-json-global-selected": reportGlobalAppjsonpath, + } + } else { + flags = map[string]common.ReportFunc{ + "--app-json-computed-selected": reportComputedAppjsonpath, + "--app-json-global-selected": reportGlobalAppjsonpath, + "--app-json-selected": reportAppjsonpath, + } } flagKeys := []string{} diff --git a/plugins/app-json/src/subcommands/subcommands.go b/plugins/app-json/src/subcommands/subcommands.go index e4879e02e..61a58edab 100644 --- a/plugins/app-json/src/subcommands/subcommands.go +++ b/plugins/app-json/src/subcommands/subcommands.go @@ -21,11 +21,14 @@ func main() { case "report": args := flag.NewFlagSet("app-json:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("appjson", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("appjson", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = appjson.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = appjson.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("app-json:set", flag.ExitOnError) diff --git a/plugins/apps/report.go b/plugins/apps/report.go index bce46ff17..1de1069c8 100644 --- a/plugins/apps/report.go +++ b/plugins/apps/report.go @@ -9,16 +9,23 @@ import ( // ReportSingleApp is an internal function that displays the app report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--app-created-at": reportCreatedAt, - "--app-deploy-source": reportDeploySource, - "--app-deploy-source-metadata": reportDeploySourceMetadata, - "--app-dir": reportDir, - "--app-locked": reportLocked, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{} + } else { + flags = map[string]common.ReportFunc{ + "--app-created-at": reportCreatedAt, + "--app-deploy-source": reportDeploySource, + "--app-deploy-source-metadata": reportDeploySourceMetadata, + "--app-dir": reportDir, + "--app-locked": reportLocked, + } } flagKeys := []string{} diff --git a/plugins/apps/src/subcommands/subcommands.go b/plugins/apps/src/subcommands/subcommands.go index 802d0e1ed..29c0fe4c9 100644 --- a/plugins/apps/src/subcommands/subcommands.go +++ b/plugins/apps/src/subcommands/subcommands.go @@ -66,11 +66,14 @@ func main() { case "report": args := flag.NewFlagSet("apps:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("apps", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("apps", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = apps.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = apps.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("apps:set", flag.ExitOnError) diff --git a/plugins/builder-dockerfile/internal-functions b/plugins/builder-dockerfile/internal-functions index 28438710f..cce54dae7 100755 --- a/plugins/builder-dockerfile/internal-functions +++ b/plugins/builder-dockerfile/internal-functions @@ -8,9 +8,13 @@ cmd-builder-dockerfile-report() { declare desc="displays a builder-dockerfile report for one or more apps" declare cmd="builder-dockerfile:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -19,29 +23,49 @@ cmd-builder-dockerfile-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-builder-dockerfile-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-builder-dockerfile-report-single "$app" "$INFO_FLAG" | tee || true + cmd-builder-dockerfile-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-builder-dockerfile-report-single "$APP" "$INFO_FLAG" + cmd-builder-dockerfile-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-builder-dockerfile-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--builder-dockerfile-computed-dockerfile-path: $(fn-builder-dockerfile-computed-dockerfile-path "$APP")" - "--builder-dockerfile-global-dockerfile-path: $(fn-builder-dockerfile-global-dockerfile-path "$APP")" - "--builder-dockerfile-dockerfile-path: $(fn-builder-dockerfile-dockerfile-path "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--builder-dockerfile-global-dockerfile-path: $(fn-builder-dockerfile-global-dockerfile-path "$APP")" + ) + else + verify_app_name "$APP" + flag_map=( + "--builder-dockerfile-computed-dockerfile-path: $(fn-builder-dockerfile-computed-dockerfile-path "$APP")" + "--builder-dockerfile-global-dockerfile-path: $(fn-builder-dockerfile-global-dockerfile-path "$APP")" + "--builder-dockerfile-dockerfile-path: $(fn-builder-dockerfile-dockerfile-path "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "builder-dockerfile" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} builder-dockerfile information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global builder-dockerfile information" + else + dokku_log_info2_quiet "${APP} builder-dockerfile information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/builder-herokuish/internal-functions b/plugins/builder-herokuish/internal-functions index 912b13f2e..a5b16af24 100755 --- a/plugins/builder-herokuish/internal-functions +++ b/plugins/builder-herokuish/internal-functions @@ -8,9 +8,13 @@ cmd-builder-herokuish-report() { declare desc="displays a builder-herokuish report for one or more apps" declare cmd="builder-herokuish:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -19,29 +23,49 @@ cmd-builder-herokuish-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-builder-herokuish-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-builder-herokuish-report-single "$app" "$INFO_FLAG" | tee || true + cmd-builder-herokuish-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-builder-herokuish-report-single "$APP" "$INFO_FLAG" + cmd-builder-herokuish-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-builder-herokuish-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--builder-herokuish-computed-allowed: $(fn-builder-herokuish-computed-allowed "$APP")" - "--builder-herokuish-global-allowed: $(fn-builder-herokuish-global-allowed)" - "--builder-herokuish-allowed: $(fn-builder-herokuish-allowed "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--builder-herokuish-global-allowed: $(fn-builder-herokuish-global-allowed)" + ) + else + verify_app_name "$APP" + flag_map=( + "--builder-herokuish-computed-allowed: $(fn-builder-herokuish-computed-allowed "$APP")" + "--builder-herokuish-global-allowed: $(fn-builder-herokuish-global-allowed)" + "--builder-herokuish-allowed: $(fn-builder-herokuish-allowed "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "builder-herokuish" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} builder-herokuish information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global builder-herokuish information" + else + dokku_log_info2_quiet "${APP} builder-herokuish information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/builder-lambda/internal-functions b/plugins/builder-lambda/internal-functions index 7a4738bfc..832b156a5 100755 --- a/plugins/builder-lambda/internal-functions +++ b/plugins/builder-lambda/internal-functions @@ -8,9 +8,13 @@ cmd-builder-lambda-report() { declare desc="displays a builder-lambda report for one or more apps" declare cmd="builder-lambda:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -19,29 +23,49 @@ cmd-builder-lambda-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-builder-lambda-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-builder-lambda-report-single "$app" "$INFO_FLAG" | tee || true + cmd-builder-lambda-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-builder-lambda-report-single "$APP" "$INFO_FLAG" + cmd-builder-lambda-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-builder-lambda-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--builder-lambda-computed-lambdayml-path: $(fn-builder-lambda-computed-lambdayml-path "$APP")" - "--builder-lambda-global-lambdayml-path: $(fn-builder-lambda-global-lambdayml-path "$APP")" - "--builder-lambda-lambdayml-path: $(fn-builder-lambda-lambdayml-path "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--builder-lambda-global-lambdayml-path: $(fn-builder-lambda-global-lambdayml-path "$APP")" + ) + else + verify_app_name "$APP" + flag_map=( + "--builder-lambda-computed-lambdayml-path: $(fn-builder-lambda-computed-lambdayml-path "$APP")" + "--builder-lambda-global-lambdayml-path: $(fn-builder-lambda-global-lambdayml-path "$APP")" + "--builder-lambda-lambdayml-path: $(fn-builder-lambda-lambdayml-path "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "builder-lambda" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} builder-lambda information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global builder-lambda information" + else + dokku_log_info2_quiet "${APP} builder-lambda information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/builder-nixpacks/internal-functions b/plugins/builder-nixpacks/internal-functions index d2c60a133..58ee7eea8 100755 --- a/plugins/builder-nixpacks/internal-functions +++ b/plugins/builder-nixpacks/internal-functions @@ -8,9 +8,13 @@ cmd-builder-nixpacks-report() { declare desc="displays a builder-nixpacks report for one or more apps" declare cmd="builder-nixpacks:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -19,29 +23,49 @@ cmd-builder-nixpacks-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-builder-nixpacks-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-builder-nixpacks-report-single "$app" "$INFO_FLAG" | tee || true + cmd-builder-nixpacks-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-builder-nixpacks-report-single "$APP" "$INFO_FLAG" + cmd-builder-nixpacks-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-builder-nixpacks-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--builder-nixpacks-computed-nixpackstoml-path: $(fn-builder-nixpacks-computed-nixpackstoml-path "$APP")" - "--builder-nixpacks-global-nixpackstoml-path: $(fn-builder-nixpacks-global-nixpackstoml-path "$APP")" - "--builder-nixpacks-nixpackstoml-path: $(fn-builder-nixpacks-nixpackstoml-path "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--builder-nixpacks-global-nixpackstoml-path: $(fn-builder-nixpacks-global-nixpackstoml-path "$APP")" + ) + else + verify_app_name "$APP" + flag_map=( + "--builder-nixpacks-computed-nixpackstoml-path: $(fn-builder-nixpacks-computed-nixpackstoml-path "$APP")" + "--builder-nixpacks-global-nixpackstoml-path: $(fn-builder-nixpacks-global-nixpackstoml-path "$APP")" + "--builder-nixpacks-nixpackstoml-path: $(fn-builder-nixpacks-nixpackstoml-path "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "builder-nixpacks" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} builder-nixpacks information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global builder-nixpacks information" + else + dokku_log_info2_quiet "${APP} builder-nixpacks information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/builder-pack/internal-functions b/plugins/builder-pack/internal-functions index e1d6ecbb3..74c806e48 100755 --- a/plugins/builder-pack/internal-functions +++ b/plugins/builder-pack/internal-functions @@ -8,9 +8,13 @@ cmd-builder-pack-report() { declare desc="displays a builder-pack report for one or more apps" declare cmd="builder-pack:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -19,29 +23,49 @@ cmd-builder-pack-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-builder-pack-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-builder-pack-report-single "$app" "$INFO_FLAG" | tee || true + cmd-builder-pack-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-builder-pack-report-single "$APP" "$INFO_FLAG" + cmd-builder-pack-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-builder-pack-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--builder-pack-computed-projecttoml-path: $(fn-builder-pack-computed-projecttoml-path "$APP")" - "--builder-pack-global-projecttoml-path: $(fn-builder-pack-global-projecttoml-path "$APP")" - "--builder-pack-projecttoml-path: $(fn-builder-pack-projecttoml-path "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--builder-pack-global-projecttoml-path: $(fn-builder-pack-global-projecttoml-path "$APP")" + ) + else + verify_app_name "$APP" + flag_map=( + "--builder-pack-computed-projecttoml-path: $(fn-builder-pack-computed-projecttoml-path "$APP")" + "--builder-pack-global-projecttoml-path: $(fn-builder-pack-global-projecttoml-path "$APP")" + "--builder-pack-projecttoml-path: $(fn-builder-pack-projecttoml-path "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "builder-pack" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} builder-pack information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global builder-pack information" + else + dokku_log_info2_quiet "${APP} builder-pack information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/builder-railpack/internal-functions b/plugins/builder-railpack/internal-functions index 96dab71bc..b9c3fbf33 100755 --- a/plugins/builder-railpack/internal-functions +++ b/plugins/builder-railpack/internal-functions @@ -8,9 +8,13 @@ cmd-builder-railpack-report() { declare desc="displays a builder-railpack report for one or more apps" declare cmd="builder-railpack:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -19,29 +23,49 @@ cmd-builder-railpack-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-builder-railpack-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-builder-railpack-report-single "$app" "$INFO_FLAG" | tee || true + cmd-builder-railpack-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-builder-railpack-report-single "$APP" "$INFO_FLAG" + cmd-builder-railpack-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-builder-railpack-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--builder-railpack-computed-railpackjson-path: $(fn-builder-railpack-computed-railpackjson-path "$APP")" - "--builder-railpack-global-railpackjson-path: $(fn-builder-railpack-global-railpackjson-path "$APP")" - "--builder-railpack-railpackjson-path: $(fn-builder-railpack-railpackjson-path "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--builder-railpack-global-railpackjson-path: $(fn-builder-railpack-global-railpackjson-path "$APP")" + ) + else + verify_app_name "$APP" + flag_map=( + "--builder-railpack-computed-railpackjson-path: $(fn-builder-railpack-computed-railpackjson-path "$APP")" + "--builder-railpack-global-railpackjson-path: $(fn-builder-railpack-global-railpackjson-path "$APP")" + "--builder-railpack-railpackjson-path: $(fn-builder-railpack-railpackjson-path "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "builder-railpack" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} builder-railpack information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global builder-railpack information" + else + dokku_log_info2_quiet "${APP} builder-railpack information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/builder/report.go b/plugins/builder/report.go index 3a755d01e..bedf9c39d 100644 --- a/plugins/builder/report.go +++ b/plugins/builder/report.go @@ -6,18 +6,28 @@ import ( // ReportSingleApp is an internal function that displays the builder report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--builder-computed-selected": reportComputedSelected, - "--builder-global-selected": reportGlobalSelected, - "--builder-selected": reportSelected, - "--builder-detected": reportDetected, - "--builder-computed-build-dir": reportComputedBuildDir, - "--builder-global-build-dir": reportGlobalBuildDir, - "--builder-build-dir": reportBuildDir, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--builder-global-selected": reportGlobalSelected, + "--builder-global-build-dir": reportGlobalBuildDir, + } + } else { + flags = map[string]common.ReportFunc{ + "--builder-computed-selected": reportComputedSelected, + "--builder-global-selected": reportGlobalSelected, + "--builder-selected": reportSelected, + "--builder-detected": reportDetected, + "--builder-computed-build-dir": reportComputedBuildDir, + "--builder-global-build-dir": reportGlobalBuildDir, + "--builder-build-dir": reportBuildDir, + } } flagKeys := []string{} diff --git a/plugins/builder/src/subcommands/subcommands.go b/plugins/builder/src/subcommands/subcommands.go index e6d692691..6ebc420f9 100644 --- a/plugins/builder/src/subcommands/subcommands.go +++ b/plugins/builder/src/subcommands/subcommands.go @@ -21,11 +21,14 @@ func main() { case "report": args := flag.NewFlagSet("builder:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("builder", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("builder", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = builder.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = builder.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("builder:set", flag.ExitOnError) diff --git a/plugins/buildpacks/report.go b/plugins/buildpacks/report.go index cec28af2a..dc6b0f1c1 100644 --- a/plugins/buildpacks/report.go +++ b/plugins/buildpacks/report.go @@ -9,15 +9,24 @@ import ( // ReportSingleApp is an internal function that displays the buildpacks report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--buildpacks-computed-stack": reportComputedStack, - "--buildpacks-global-stack": reportGlobalStack, - "--buildpacks-list": reportList, - "--buildpacks-stack": reportStack, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--buildpacks-global-stack": reportGlobalStack, + } + } else { + flags = map[string]common.ReportFunc{ + "--buildpacks-computed-stack": reportComputedStack, + "--buildpacks-global-stack": reportGlobalStack, + "--buildpacks-list": reportList, + "--buildpacks-stack": reportStack, + } } flagKeys := []string{} diff --git a/plugins/buildpacks/src/subcommands/subcommands.go b/plugins/buildpacks/src/subcommands/subcommands.go index 9062e80fa..428c0859b 100644 --- a/plugins/buildpacks/src/subcommands/subcommands.go +++ b/plugins/buildpacks/src/subcommands/subcommands.go @@ -54,11 +54,14 @@ func main() { case "report": args := flag.NewFlagSet("buildpacks:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("buildpacks", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("buildpacks", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = buildpacks.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = buildpacks.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("buildpacks:set", flag.ExitOnError) diff --git a/plugins/caddy-vhosts/command-functions b/plugins/caddy-vhosts/command-functions index 56817212e..231c5a4ad 100755 --- a/plugins/caddy-vhosts/command-functions +++ b/plugins/caddy-vhosts/command-functions @@ -33,9 +33,13 @@ cmd-caddy-report() { declare desc="displays a caddy report for one or more apps" declare cmd="caddy:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -44,32 +48,56 @@ cmd-caddy-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-caddy-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-caddy-report-single "$app" "$INFO_FLAG" | tee || true + cmd-caddy-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-caddy-report-single "$APP" "$INFO_FLAG" + cmd-caddy-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-caddy-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--caddy-image: $(fn-caddy-image)" - "--caddy-letsencrypt-email: $(fn-caddy-letsencrypt-email)" - "--caddy-letsencrypt-server: $(fn-caddy-letsencrypt-server)" - "--caddy-log-level: $(fn-caddy-log-level)" - "--caddy-polling-interval: $(fn-caddy-polling-interval)" - "--caddy-tls-internal: $(fn-caddy-tls-internal "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--caddy-image: $(fn-caddy-image)" + "--caddy-letsencrypt-email: $(fn-caddy-letsencrypt-email)" + "--caddy-letsencrypt-server: $(fn-caddy-letsencrypt-server)" + "--caddy-log-level: $(fn-caddy-log-level)" + "--caddy-polling-interval: $(fn-caddy-polling-interval)" + ) + else + verify_app_name "$APP" + flag_map=( + "--caddy-image: $(fn-caddy-image)" + "--caddy-letsencrypt-email: $(fn-caddy-letsencrypt-email)" + "--caddy-letsencrypt-server: $(fn-caddy-letsencrypt-server)" + "--caddy-log-level: $(fn-caddy-log-level)" + "--caddy-polling-interval: $(fn-caddy-polling-interval)" + "--caddy-tls-internal: $(fn-caddy-tls-internal "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "caddy" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} caddy information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global caddy information" + else + dokku_log_info2_quiet "${APP} caddy information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/certs/internal-functions b/plugins/certs/internal-functions index 923f3faa3..cfda209bc 100755 --- a/plugins/certs/internal-functions +++ b/plugins/certs/internal-functions @@ -8,9 +8,13 @@ cmd-certs-report() { declare desc="displays an ssl report for one or more apps" declare cmd="certs:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -19,34 +23,50 @@ cmd-certs-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-certs-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-certs-report-single "$app" "$INFO_FLAG" | tee || true + cmd-certs-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-certs-report-single "$APP" "$INFO_FLAG" + cmd-certs-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-certs-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--ssl-dir: $DOKKU_ROOT/$APP/tls" - "--ssl-enabled: $(fn-ssl-enabled "$APP")" - "--ssl-hostnames: $(fn-ssl-hostnames "$APP")" - "--ssl-expires-at: $(fn-ssl-expires-at "$APP")" - "--ssl-issuer: $(fn-ssl-issuer "$APP")" - "--ssl-starts-at: $(fn-ssl-starts-at "$APP")" - "--ssl-subject: $(fn-ssl-subject "$APP")" - "--ssl-verified: $(fn-ssl-verified "$APP")" - ) + local flag_map=() + if [[ "$APP" != "--global" ]]; then + verify_app_name "$APP" + flag_map=( + "--ssl-dir: $DOKKU_ROOT/$APP/tls" + "--ssl-enabled: $(fn-ssl-enabled "$APP")" + "--ssl-hostnames: $(fn-ssl-hostnames "$APP")" + "--ssl-expires-at: $(fn-ssl-expires-at "$APP")" + "--ssl-issuer: $(fn-ssl-issuer "$APP")" + "--ssl-starts-at: $(fn-ssl-starts-at "$APP")" + "--ssl-subject: $(fn-ssl-subject "$APP")" + "--ssl-verified: $(fn-ssl-verified "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "ssl" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "$APP ssl information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global ssl information" + else + dokku_log_info2_quiet "$APP ssl information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/checks/internal-functions b/plugins/checks/internal-functions index 6d55ba45b..30dfe4c69 100755 --- a/plugins/checks/internal-functions +++ b/plugins/checks/internal-functions @@ -9,9 +9,13 @@ cmd-checks-report() { declare desc="shows reports for an app" declare cmd="checks:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -20,31 +24,51 @@ cmd-checks-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-checks-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-checks-report-single "$app" "$INFO_FLAG" | tee || true + cmd-checks-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-checks-report-single "$APP" "$INFO_FLAG" + cmd-checks-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-checks-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--checks-disabled-list: $(fn-checks-disabled-list "$APP")" - "--checks-skipped-list: $(fn-checks-skipped-list "$APP")" - "--checks-computed-wait-to-retire: $(fn-checks-computed-wait-to-retire "$APP")" - "--checks-global-wait-to-retire: $(fn-checks-global-wait-to-retire "$APP")" - "--checks-wait-to-retire: $(fn-checks-wait-to-retire "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--checks-global-wait-to-retire: $(fn-checks-global-wait-to-retire "$APP")" + ) + else + verify_app_name "$APP" + flag_map=( + "--checks-disabled-list: $(fn-checks-disabled-list "$APP")" + "--checks-skipped-list: $(fn-checks-skipped-list "$APP")" + "--checks-computed-wait-to-retire: $(fn-checks-computed-wait-to-retire "$APP")" + "--checks-global-wait-to-retire: $(fn-checks-global-wait-to-retire "$APP")" + "--checks-wait-to-retire: $(fn-checks-wait-to-retire "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "checks" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "$APP checks information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global checks information" + else + dokku_log_info2_quiet "$APP checks information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/common/common.go b/plugins/common/common.go index 21847aa7e..a3ec11acd 100644 --- a/plugins/common/common.go +++ b/plugins/common/common.go @@ -713,10 +713,18 @@ func GetenvWithDefault(key string, defaultValue string) (val string) { return } +// ReportArgs holds the parsed inputs to a :report subcommand +type ReportArgs struct { + OSArgs []string + InfoFlag string + IsGlobal bool +} + // ParseReportArgs splits out flags from non-flags for input into report commands -func ParseReportArgs(pluginName string, arguments []string) ([]string, string, error) { +func ParseReportArgs(pluginName string, arguments []string) (ReportArgs, error) { osArgs := []string{} infoFlags := []string{} + isGlobal := false skipNext := false for i, argument := range arguments { if skipNext { @@ -728,6 +736,10 @@ func ParseReportArgs(pluginName string, arguments []string) ([]string, string, e skipNext = true continue } + if argument == "--global" { + isGlobal = true + continue + } if strings.HasPrefix(argument, "--") { infoFlags = append(infoFlags, argument) } else { @@ -736,12 +748,12 @@ func ParseReportArgs(pluginName string, arguments []string) ([]string, string, e } if len(infoFlags) == 0 { - return osArgs, "", nil + return ReportArgs{OSArgs: osArgs, IsGlobal: isGlobal}, nil } if len(infoFlags) == 1 { - return osArgs, infoFlags[0], nil + return ReportArgs{OSArgs: osArgs, InfoFlag: infoFlags[0], IsGlobal: isGlobal}, nil } - return osArgs, "", fmt.Errorf("%s:report command allows only a single flag", pluginName) + return ReportArgs{OSArgs: osArgs, IsGlobal: isGlobal}, fmt.Errorf("%s:report command allows only a single flag", pluginName) } // ParseScaleOutput allows golang plugins to properly parse the output of ps-current-scale diff --git a/plugins/common/common_test.go b/plugins/common/common_test.go index e6f0faee5..f6fa98123 100644 --- a/plugins/common/common_test.go +++ b/plugins/common/common_test.go @@ -115,3 +115,81 @@ func TestCommonStripInlineComments(t *testing.T) { text := StripInlineComments(strings.Join([]string{testEnvLine, "# testing comment"}, " ")) Expect(text).To(Equal(testEnvLine)) } + +func TestParseReportArgsEmpty(t *testing.T) { + RegisterTestingT(t) + args, err := ParseReportArgs("scheduler", []string{}) + Expect(err).NotTo(HaveOccurred()) + Expect(args.IsGlobal).To(BeFalse()) + Expect(args.InfoFlag).To(Equal("")) + Expect(args.OSArgs).To(BeEmpty()) +} + +func TestParseReportArgsAppOnly(t *testing.T) { + RegisterTestingT(t) + args, err := ParseReportArgs("scheduler", []string{"myapp"}) + Expect(err).NotTo(HaveOccurred()) + Expect(args.IsGlobal).To(BeFalse()) + Expect(args.InfoFlag).To(Equal("")) + Expect(args.OSArgs).To(Equal([]string{"myapp"})) +} + +func TestParseReportArgsFormatJSON(t *testing.T) { + RegisterTestingT(t) + args, err := ParseReportArgs("scheduler", []string{"myapp", "--format", "json"}) + Expect(err).NotTo(HaveOccurred()) + Expect(args.IsGlobal).To(BeFalse()) + Expect(args.InfoFlag).To(Equal("")) + Expect(args.OSArgs).To(Equal([]string{"myapp", "--format", "json"})) +} + +func TestParseReportArgsGlobalAlone(t *testing.T) { + RegisterTestingT(t) + args, err := ParseReportArgs("scheduler", []string{"--global"}) + Expect(err).NotTo(HaveOccurred()) + Expect(args.IsGlobal).To(BeTrue()) + Expect(args.InfoFlag).To(Equal("")) + Expect(args.OSArgs).To(BeEmpty()) +} + +func TestParseReportArgsGlobalWithFormat(t *testing.T) { + RegisterTestingT(t) + args, err := ParseReportArgs("scheduler", []string{"--global", "--format", "json"}) + Expect(err).NotTo(HaveOccurred()) + Expect(args.IsGlobal).To(BeTrue()) + Expect(args.InfoFlag).To(Equal("")) + Expect(args.OSArgs).To(Equal([]string{"--format", "json"})) +} + +func TestParseReportArgsInfoFlag(t *testing.T) { + RegisterTestingT(t) + args, err := ParseReportArgs("scheduler", []string{"myapp", "--scheduler-selected"}) + Expect(err).NotTo(HaveOccurred()) + Expect(args.IsGlobal).To(BeFalse()) + Expect(args.InfoFlag).To(Equal("--scheduler-selected")) + Expect(args.OSArgs).To(Equal([]string{"myapp"})) +} + +func TestParseReportArgsAppThenGlobal(t *testing.T) { + RegisterTestingT(t) + args, err := ParseReportArgs("scheduler", []string{"myapp", "--global"}) + Expect(err).NotTo(HaveOccurred()) + Expect(args.IsGlobal).To(BeTrue()) + Expect(args.InfoFlag).To(Equal("")) + Expect(args.OSArgs).To(Equal([]string{"myapp"})) +} + +func TestParseReportArgsGlobalWithInfoFlag(t *testing.T) { + RegisterTestingT(t) + args, err := ParseReportArgs("scheduler", []string{"--global", "--scheduler-global-selected"}) + Expect(err).NotTo(HaveOccurred()) + Expect(args.IsGlobal).To(BeTrue()) + Expect(args.InfoFlag).To(Equal("--scheduler-global-selected")) + Expect(args.OSArgs).To(BeEmpty()) +} + +func TestParseReportArgsMultipleInfoFlags(t *testing.T) { + RegisterTestingT(t) + _, err := ParseReportArgs("scheduler", []string{"--scheduler-selected", "--scheduler-global-selected"}) + Expect(err).To(HaveOccurred()) +} diff --git a/plugins/common/functions b/plugins/common/functions index 59ea62fc6..5bcec750a 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -958,3 +958,62 @@ fn-registry-docker-config-dir() { echo "$config_dir" fi } + +fn-report-parse-args() { + declare desc="strips --format and --global flags from a report invocation, populating REPORT_FORMAT, REPORT_IS_GLOBAL, REPORT_ARGS" + REPORT_FORMAT="stdout" + REPORT_IS_GLOBAL="false" + REPORT_ARGS=() + while [[ $# -gt 0 ]]; do + case "$1" in + --format) + REPORT_FORMAT="$2" + shift 2 + ;; + --global) + REPORT_IS_GLOBAL="true" + shift + ;; + *) + REPORT_ARGS+=("$1") + shift + ;; + esac + done +} + +fn-report-emit-json() { + declare desc="serializes a flag_map array (passed by name) as a JSON object, stripping the --- prefix from each key" + declare flag_map_name="$1" prefix="$2" + local -n flag_map_ref="$flag_map_name" + local json_output="{}" + for flag in "${flag_map_ref[@]}"; do + local key value + key="$(echo "$flag" | cut -d':' -f1 | sed "s/^--${prefix}-//")" + value="$(echo "$flag" | cut -d':' -f2- | sed 's/^ //')" + json_output="$(echo "$json_output" | jq -c --arg key "$key" --arg value "$value" '. + {($key): $value}')" + done + echo "$json_output" +} + +fn-report-filter-global() { + declare desc="filters a flag_map array (passed by name) in place, keeping only entries with -global- in their flag name" + declare flag_map_name="$1" + local -n flag_map_ref="$flag_map_name" + local filtered=() + for flag in "${flag_map_ref[@]}"; do + local key="$(echo "$flag" | cut -d':' -f1)" + if [[ "$key" == *"-global-"* ]]; then + filtered+=("$flag") + fi + done + flag_map_ref=("${filtered[@]}") +} + +fn-report-validate-format() { + declare desc="rejects --format json when an info flag is also specified" + declare FORMAT="$1" INFO_FLAG="$2" + if [[ "$FORMAT" != "stdout" ]] && [[ -n "$INFO_FLAG" ]]; then + dokku_log_fail "--format flag cannot be specified when specifying an info flag" + fi +} diff --git a/plugins/cron/report.go b/plugins/cron/report.go index 6577b0a9a..0c4ae3a91 100644 --- a/plugins/cron/report.go +++ b/plugins/cron/report.go @@ -10,22 +10,33 @@ import ( // ReportSingleApp is an internal function that displays the cron report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--cron-mailfrom": reportMailfrom, - "--cron-mailto": reportMailto, - "--cron-task-count": reportTasks, - "--cron-global-maintenance": reportGlobalMaintenance, - "--cron-computed-maintenance": reportComputedMaintenance, - "--cron-maintenance": reportMaintenance, - } + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--cron-mailfrom": reportMailfrom, + "--cron-mailto": reportMailto, + "--cron-global-maintenance": reportGlobalMaintenance, + } + } else { + flags = map[string]common.ReportFunc{ + "--cron-mailfrom": reportMailfrom, + "--cron-mailto": reportMailto, + "--cron-task-count": reportTasks, + "--cron-global-maintenance": reportGlobalMaintenance, + "--cron-computed-maintenance": reportComputedMaintenance, + "--cron-maintenance": reportMaintenance, + } - extraFlags := addCronMaintenanceFlags(appName, infoFlag) - for flag, fn := range extraFlags { - flags[flag] = fn + extraFlags := addCronMaintenanceFlags(appName, infoFlag) + for flag, fn := range extraFlags { + flags[flag] = fn + } } flagKeys := []string{} diff --git a/plugins/cron/src/subcommands/subcommands.go b/plugins/cron/src/subcommands/subcommands.go index c9452ee05..ff5f16be4 100644 --- a/plugins/cron/src/subcommands/subcommands.go +++ b/plugins/cron/src/subcommands/subcommands.go @@ -31,11 +31,14 @@ func main() { case "report": args := flag.NewFlagSet("cron:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("cron", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("cron", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = cron.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = cron.CommandReport(appName, *format, reportArgs.InfoFlag) } case "resume": args := flag.NewFlagSet("cron:resume", flag.ExitOnError) diff --git a/plugins/docker-options/report.go b/plugins/docker-options/report.go index 8ea166cf3..656ff92a3 100644 --- a/plugins/docker-options/report.go +++ b/plugins/docker-options/report.go @@ -12,14 +12,21 @@ import ( // Process-scoped options surface as dynamic per-process keys, one per // configured process+phase combination. func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--docker-options-build": reportBuildOptions, - "--docker-options-deploy": reportDeployOptions, - "--docker-options-run": reportRunOptions, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{} + } else { + flags = map[string]common.ReportFunc{ + "--docker-options-build": reportBuildOptions, + "--docker-options-deploy": reportDeployOptions, + "--docker-options-run": reportRunOptions, + } } processTypes, err := ListProcessTypesWithOptions(appName) diff --git a/plugins/docker-options/src/subcommands/subcommands.go b/plugins/docker-options/src/subcommands/subcommands.go index 43f33bd69..7eedc7241 100644 --- a/plugins/docker-options/src/subcommands/subcommands.go +++ b/plugins/docker-options/src/subcommands/subcommands.go @@ -84,11 +84,14 @@ func main() { case "report": args := flag.NewFlagSet("docker-options:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("docker-options", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("docker-options", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = dockeroptions.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = dockeroptions.CommandReport(appName, *format, reportArgs.InfoFlag) } else { err = flagErr } diff --git a/plugins/domains/internal-functions b/plugins/domains/internal-functions index efc644d10..f53335fba 100755 --- a/plugins/domains/internal-functions +++ b/plugins/domains/internal-functions @@ -8,14 +8,15 @@ cmd-domains-report() { declare desc="displays a domains report for one or more apps" declare cmd="domains:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ "$APP" == "--global" ]]; then - cmd-domains-report-single "$APP" "$INFO_FLAG" - return - fi - - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ "$APP" == "--global" ]]; then + : + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -24,17 +25,19 @@ cmd-domains-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-domains-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-domains-report-single "$app" "$INFO_FLAG" | tee || true + cmd-domains-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-domains-report-single "$APP" "$INFO_FLAG" + cmd-domains-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-domains-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi @@ -55,6 +58,13 @@ cmd-domains-report-single() { flag_map=("${app_flags[@]}" "${global_flags[@]}") + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "domains" + return + fi + if [[ -z "$INFO_FLAG" ]]; then if [[ "$APP" == "--global" ]]; then dokku_log_info2_quiet "Global domains information" diff --git a/plugins/git/internal-functions b/plugins/git/internal-functions index 42b4e71f5..4ef9e1272 100755 --- a/plugins/git/internal-functions +++ b/plugins/git/internal-functions @@ -316,25 +316,14 @@ cmd-git-report() { declare desc="displays a git report for one or more apps" declare cmd="git:report" [[ "$1" == "$cmd" ]] && shift 1 - local FORMAT="stdout" - local args=() + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" - while [[ $# -gt 0 ]]; do - case "$1" in - --format) - FORMAT="$2" - shift 2 - ;; - *) - args+=("$1") - shift - ;; - esac - done + declare APP="${1:-}" INFO_FLAG="${2:-}" - declare APP="${args[0]:-}" INFO_FLAG="${args[1]:-}" - - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -343,12 +332,14 @@ cmd-git-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-git-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-git-report-single "$app" "$INFO_FLAG" "$FORMAT" | tee || true + cmd-git-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-git-report-single "$APP" "$INFO_FLAG" "$FORMAT" + cmd-git-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } @@ -358,35 +349,37 @@ cmd-git-report-single() { if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--git-deploy-branch: $(fn-plugin-property-get "git" "$APP" "deploy-branch" "master")" - "--git-global-deploy-branch: $(fn-plugin-property-get "git" "--global" "deploy-branch" "master")" - "--git-keep-git-dir: $(fn-plugin-property-get "git" "$APP" "keep-git-dir" "false")" - "--git-rev-env-var: $(fn-plugin-property-get "git" "$APP" "rev-env-var" "GIT_REV")" - "--git-sha: $(fn-git-cmd "$APP_ROOT" rev-parse HEAD 2>/dev/null || false)" - "--git-source-image: $(fn-git-source-image "$APP")" - "--git-last-updated-at: $(fn-git-last-updated-at "$APP")" - ) - - if [[ "$FORMAT" != "stdout" ]] && [[ -n "$INFO_FLAG" ]]; then - dokku_log_fail "--format flag cannot be specified when specifying an info flag" + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--git-global-deploy-branch: $(fn-plugin-property-get "git" "--global" "deploy-branch" "master")" + ) + else + verify_app_name "$APP" + flag_map=( + "--git-deploy-branch: $(fn-plugin-property-get "git" "$APP" "deploy-branch" "master")" + "--git-global-deploy-branch: $(fn-plugin-property-get "git" "--global" "deploy-branch" "master")" + "--git-keep-git-dir: $(fn-plugin-property-get "git" "$APP" "keep-git-dir" "false")" + "--git-rev-env-var: $(fn-plugin-property-get "git" "$APP" "rev-env-var" "GIT_REV")" + "--git-sha: $(fn-git-cmd "$APP_ROOT" rev-parse HEAD 2>/dev/null || false)" + "--git-source-image: $(fn-git-source-image "$APP")" + "--git-last-updated-at: $(fn-git-last-updated-at "$APP")" + ) fi + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + if [[ "$FORMAT" == "json" ]]; then - local json_output="{}" - for flag in "${flag_map[@]}"; do - local key value - key="$(echo "$flag" | cut -d':' -f1 | sed 's/^--git-//')" - value="$(echo "$flag" | cut -d':' -f2- | sed 's/^ //')" - json_output="$(echo "$json_output" | jq -c --arg key "$key" --arg value "$value" '. + {($key): $value}')" - done - echo "$json_output" + fn-report-emit-json flag_map "git" return fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} git information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global git information" + else + dokku_log_info2_quiet "${APP} git information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/haproxy-vhosts/command-functions b/plugins/haproxy-vhosts/command-functions index 0f907bb08..9644f5356 100755 --- a/plugins/haproxy-vhosts/command-functions +++ b/plugins/haproxy-vhosts/command-functions @@ -33,9 +33,13 @@ cmd-haproxy-report() { declare desc="displays a haproxy report for one or more apps" declare cmd="haproxy:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -44,21 +48,25 @@ cmd-haproxy-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-haproxy-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-haproxy-report-single "$app" "$INFO_FLAG" | tee || true + cmd-haproxy-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-haproxy-report-single "$APP" "$INFO_FLAG" + cmd-haproxy-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-haproxy-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" + if [[ "$APP" != "--global" ]]; then + verify_app_name "$APP" + fi local flag_map=( "--haproxy-image: $(fn-haproxy-image)" "--haproxy-letsencrypt-email: $(fn-haproxy-letsencrypt-email)" @@ -66,8 +74,19 @@ cmd-haproxy-report-single() { "--haproxy-log-level: $(fn-haproxy-log-level)" ) + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "haproxy" + return + fi + if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} haproxy information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global haproxy information" + else + dokku_log_info2_quiet "${APP} haproxy information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/logs/report.go b/plugins/logs/report.go index a18402473..714f09470 100644 --- a/plugins/logs/report.go +++ b/plugins/logs/report.go @@ -9,22 +9,34 @@ import ( // ReportSingleApp is an internal function that displays the logs report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } os.Setenv("DOKKU_REPORT_FORMAT", format) os.Setenv("DOKKU_REPORT_FLAG", infoFlag) - flags := map[string]common.ReportFunc{ - "--logs-computed-app-label-alias": reportComputedAppLabelAlias, - "--logs-computed-max-size": reportComputedMaxSize, - "--logs-global-app-label-alias": reportGlobalAppLabelAlias, - "--logs-global-max-size": reportGlobalMaxSize, - "--logs-global-vector-sink": reportGlobalVectorSink, - "--logs-app-label-alias": reportAppLabelAlias, - "--logs-max-size": reportMaxSize, - "--logs-vector-global-image": reportVectorGlobalImage, - "--logs-vector-sink": reportVectorSink, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--logs-global-app-label-alias": reportGlobalAppLabelAlias, + "--logs-global-max-size": reportGlobalMaxSize, + "--logs-global-vector-sink": reportGlobalVectorSink, + "--logs-vector-global-image": reportVectorGlobalImage, + } + } else { + flags = map[string]common.ReportFunc{ + "--logs-computed-app-label-alias": reportComputedAppLabelAlias, + "--logs-computed-max-size": reportComputedMaxSize, + "--logs-global-app-label-alias": reportGlobalAppLabelAlias, + "--logs-global-max-size": reportGlobalMaxSize, + "--logs-global-vector-sink": reportGlobalVectorSink, + "--logs-app-label-alias": reportAppLabelAlias, + "--logs-max-size": reportMaxSize, + "--logs-vector-global-image": reportVectorGlobalImage, + "--logs-vector-sink": reportVectorSink, + } } flagKeys := []string{} diff --git a/plugins/logs/src/subcommands/subcommands.go b/plugins/logs/src/subcommands/subcommands.go index a9f56604f..5dde88b50 100644 --- a/plugins/logs/src/subcommands/subcommands.go +++ b/plugins/logs/src/subcommands/subcommands.go @@ -27,11 +27,14 @@ func main() { case "report": args := flag.NewFlagSet("logs:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("logs", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("logs", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = logs.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = logs.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("logs:set", flag.ExitOnError) diff --git a/plugins/network/report.go b/plugins/network/report.go index fb2847a4f..9ddfcd67b 100644 --- a/plugins/network/report.go +++ b/plugins/network/report.go @@ -8,28 +8,41 @@ import ( // ReportSingleApp is an internal function that displays the network report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--network-bind-all-interfaces": reportBindAllInterfaces, - "--network-attach-post-create": reportAttachPostCreate, - "--network-attach-post-deploy": reportAttachPostDeploy, - "--network-computed-attach-post-create": reportComputedAttachPostCreate, - "--network-computed-attach-post-deploy": reportComputedAttachPostDeploy, - "--network-computed-bind-all-interfaces": reportComputedBindAllInterfaces, - "--network-computed-initial-network": reportComputedInitialNetwork, - "--network-computed-tld": reportComputedTld, - "--network-global-attach-post-create": reportGlobalAttachPostCreate, - "--network-global-attach-post-deploy": reportGlobalAttachPostDeploy, - "--network-global-bind-all-interfaces": reportGlobalBindAllInterfaces, - "--network-global-initial-network": reportGlobalInitialNetwork, - "--network-global-tld": reportGlobalTld, - "--network-initial-network": reportInitialNetwork, - "--network-static-web-listener": reportStaticWebListener, - "--network-tld": reportTld, - "--network-web-listeners": reportWebListeners, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--network-global-attach-post-create": reportGlobalAttachPostCreate, + "--network-global-attach-post-deploy": reportGlobalAttachPostDeploy, + "--network-global-bind-all-interfaces": reportGlobalBindAllInterfaces, + "--network-global-initial-network": reportGlobalInitialNetwork, + "--network-global-tld": reportGlobalTld, + } + } else { + flags = map[string]common.ReportFunc{ + "--network-bind-all-interfaces": reportBindAllInterfaces, + "--network-attach-post-create": reportAttachPostCreate, + "--network-attach-post-deploy": reportAttachPostDeploy, + "--network-computed-attach-post-create": reportComputedAttachPostCreate, + "--network-computed-attach-post-deploy": reportComputedAttachPostDeploy, + "--network-computed-bind-all-interfaces": reportComputedBindAllInterfaces, + "--network-computed-initial-network": reportComputedInitialNetwork, + "--network-computed-tld": reportComputedTld, + "--network-global-attach-post-create": reportGlobalAttachPostCreate, + "--network-global-attach-post-deploy": reportGlobalAttachPostDeploy, + "--network-global-bind-all-interfaces": reportGlobalBindAllInterfaces, + "--network-global-initial-network": reportGlobalInitialNetwork, + "--network-global-tld": reportGlobalTld, + "--network-initial-network": reportInitialNetwork, + "--network-static-web-listener": reportStaticWebListener, + "--network-tld": reportTld, + "--network-web-listeners": reportWebListeners, + } } flagKeys := []string{} diff --git a/plugins/network/src/subcommands/subcommands.go b/plugins/network/src/subcommands/subcommands.go index 359a3d37a..02e4cc7d2 100644 --- a/plugins/network/src/subcommands/subcommands.go +++ b/plugins/network/src/subcommands/subcommands.go @@ -57,11 +57,14 @@ func main() { case "report": args := flag.NewFlagSet("network:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("network", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("network", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = network.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = network.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("network:set", flag.ExitOnError) diff --git a/plugins/nginx-vhosts/command-functions b/plugins/nginx-vhosts/command-functions index 5efbd339c..b75eb711d 100755 --- a/plugins/nginx-vhosts/command-functions +++ b/plugins/nginx-vhosts/command-functions @@ -10,25 +10,14 @@ cmd-nginx-report() { declare desc="displays a nginx report for one or more apps" declare cmd="nginx:report" [[ "$1" == "$cmd" ]] && shift 1 - local FORMAT="stdout" - local args=() + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" - while [[ $# -gt 0 ]]; do - case "$1" in - --format) - FORMAT="$2" - shift 2 - ;; - *) - args+=("$1") - shift - ;; - esac - done + declare APP="${1:-}" INFO_FLAG="${2:-}" - declare APP="${args[0]:-}" INFO_FLAG="${args[1]:-}" - - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -37,12 +26,14 @@ cmd-nginx-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-nginx-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-nginx-report-single "$app" "$INFO_FLAG" "$FORMAT" | tee || true + cmd-nginx-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-nginx-report-single "$APP" "$INFO_FLAG" "$FORMAT" + cmd-nginx-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } @@ -51,7 +42,9 @@ cmd-nginx-report-single() { if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" + if [[ "$APP" != "--global" ]]; then + verify_app_name "$APP" + fi local flag_map=( "--nginx-access-log-format: $(fn-nginx-access-log-format "$APP")" "--nginx-computed-access-log-format: $(fn-nginx-computed-access-log-format "$APP")" @@ -146,24 +139,23 @@ cmd-nginx-report-single() { "--nginx-global-x-forwarded-ssl: $(fn-nginx-global-x-forwarded-ssl "$APP")" ) - if [[ "$FORMAT" != "stdout" ]] && [[ -n "$INFO_FLAG" ]]; then - dokku_log_fail "--format flag cannot be specified when specifying an info flag" + if [[ "$APP" == "--global" ]]; then + fn-report-filter-global flag_map fi + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + if [[ "$FORMAT" == "json" ]]; then - local json_output="{}" - for flag in "${flag_map[@]}"; do - local key value - key="$(echo "$flag" | cut -d':' -f1 | sed 's/^--nginx-//')" - value="$(echo "$flag" | cut -d':' -f2- | sed 's/^ //')" - json_output="$(echo "$json_output" | jq -c --arg key "$key" --arg value "$value" '. + {($key): $value}')" - done - echo "$json_output" + fn-report-emit-json flag_map "nginx" return fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} nginx information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global nginx information" + else + dokku_log_info2_quiet "${APP} nginx information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/openresty-vhosts/command-functions b/plugins/openresty-vhosts/command-functions index 081362b91..1ddbe475c 100755 --- a/plugins/openresty-vhosts/command-functions +++ b/plugins/openresty-vhosts/command-functions @@ -33,9 +33,13 @@ cmd-openresty-report() { declare desc="displays a openresty report for one or more apps" declare cmd="openresty:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -44,59 +48,83 @@ cmd-openresty-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-openresty-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-openresty-report-single "$app" "$INFO_FLAG" | tee || true + cmd-openresty-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-openresty-report-single "$APP" "$INFO_FLAG" + cmd-openresty-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-openresty-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" - local flag_map=( - "--openresty-access-log-format: $(fn-openresty-access-log-format "$APP")" - "--openresty-access-log-path: $(fn-openresty-access-log-path "$APP")" - "--openresty-allowed-letsencrypt-domains-func-base64: $(fn-openresty-allowed-letsencrypt-domains-func-base64)" - "--openresty-bind-address-ipv4: $(fn-openresty-bind-address-ipv4 "$APP")" - "--openresty-bind-address-ipv6: $(fn-openresty-bind-address-ipv6 "$APP")" - "--openresty-client-body-timeout: $(fn-openresty-client-body-timeout "$APP")" - "--openresty-client-header-timeout: $(fn-openresty-client-header-timeout "$APP")" - "--openresty-client-max-body-size: $(fn-openresty-client-max-body-size "$APP")" - "--openresty-error-log-path: $(fn-openresty-error-log-path "$APP")" - "--openresty-global-hsts: $(fn-plugin-property-get-default "openresty" "--global" "hsts" "true")" - "--openresty-computed-hsts: $(fn-openresty-hsts-is-enabled "$APP")" - "--openresty-hsts: $(fn-plugin-property-get-default "openresty" "$APP" "hsts" "")" - "--openresty-hsts-include-subdomains: $(fn-openresty-hsts-include-subdomains "$APP")" - "--openresty-hsts-max-age: $(fn-openresty-hsts-max-age "$APP")" - "--openresty-hsts-preload: $(fn-openresty-hsts-preload "$APP")" - "--openresty-image: $(fn-openresty-image)" - "--openresty-keepalive-timeout: $(fn-openresty-keepalive-timeout "$APP")" - "--openresty-letsencrypt-email: $(fn-openresty-letsencrypt-email)" - "--openresty-letsencrypt-server: $(fn-openresty-letsencrypt-server)" - "--openresty-lingering-timeout: $(fn-openresty-lingering-timeout "$APP")" - "--openresty-proxy-buffer-size: $(fn-openresty-proxy-buffer-size "$APP")" - "--openresty-proxy-buffering: $(fn-openresty-proxy-buffering "$APP")" - "--openresty-proxy-buffers: $(fn-openresty-proxy-buffers "$APP")" - "--openresty-proxy-busy-buffers-size: $(fn-openresty-proxy-busy-buffers-size "$APP")" - "--openresty-proxy-connect-timeout: $(fn-openresty-proxy-connect-timeout "$APP")" - "--openresty-proxy-read-timeout: $(fn-openresty-proxy-read-timeout "$APP")" - "--openresty-proxy-send-timeout: $(fn-openresty-proxy-send-timeout "$APP")" - "--openresty-send-timeout: $(fn-openresty-send-timeout "$APP")" - "--openresty-underscore-in-headers: $(fn-openresty-underscore-in-headers "$APP")" - "--openresty-x-forwarded-for-value: $(fn-openresty-x-forwarded-for-value "$APP")" - "--openresty-x-forwarded-port-value: $(fn-openresty-x-forwarded-port-value "$APP")" - "--openresty-x-forwarded-proto-value: $(fn-openresty-x-forwarded-proto-value "$APP")" - "--openresty-x-forwarded-ssl: $(fn-openresty-x-forwarded-ssl "$APP")" - ) + local flag_map=() + if [[ "$APP" == "--global" ]]; then + flag_map=( + "--openresty-allowed-letsencrypt-domains-func-base64: $(fn-openresty-allowed-letsencrypt-domains-func-base64)" + "--openresty-global-hsts: $(fn-plugin-property-get-default "openresty" "--global" "hsts" "true")" + "--openresty-image: $(fn-openresty-image)" + "--openresty-letsencrypt-email: $(fn-openresty-letsencrypt-email)" + "--openresty-letsencrypt-server: $(fn-openresty-letsencrypt-server)" + ) + else + verify_app_name "$APP" + flag_map=( + "--openresty-access-log-format: $(fn-openresty-access-log-format "$APP")" + "--openresty-access-log-path: $(fn-openresty-access-log-path "$APP")" + "--openresty-allowed-letsencrypt-domains-func-base64: $(fn-openresty-allowed-letsencrypt-domains-func-base64)" + "--openresty-bind-address-ipv4: $(fn-openresty-bind-address-ipv4 "$APP")" + "--openresty-bind-address-ipv6: $(fn-openresty-bind-address-ipv6 "$APP")" + "--openresty-client-body-timeout: $(fn-openresty-client-body-timeout "$APP")" + "--openresty-client-header-timeout: $(fn-openresty-client-header-timeout "$APP")" + "--openresty-client-max-body-size: $(fn-openresty-client-max-body-size "$APP")" + "--openresty-error-log-path: $(fn-openresty-error-log-path "$APP")" + "--openresty-global-hsts: $(fn-plugin-property-get-default "openresty" "--global" "hsts" "true")" + "--openresty-computed-hsts: $(fn-openresty-hsts-is-enabled "$APP")" + "--openresty-hsts: $(fn-plugin-property-get-default "openresty" "$APP" "hsts" "")" + "--openresty-hsts-include-subdomains: $(fn-openresty-hsts-include-subdomains "$APP")" + "--openresty-hsts-max-age: $(fn-openresty-hsts-max-age "$APP")" + "--openresty-hsts-preload: $(fn-openresty-hsts-preload "$APP")" + "--openresty-image: $(fn-openresty-image)" + "--openresty-keepalive-timeout: $(fn-openresty-keepalive-timeout "$APP")" + "--openresty-letsencrypt-email: $(fn-openresty-letsencrypt-email)" + "--openresty-letsencrypt-server: $(fn-openresty-letsencrypt-server)" + "--openresty-lingering-timeout: $(fn-openresty-lingering-timeout "$APP")" + "--openresty-proxy-buffer-size: $(fn-openresty-proxy-buffer-size "$APP")" + "--openresty-proxy-buffering: $(fn-openresty-proxy-buffering "$APP")" + "--openresty-proxy-buffers: $(fn-openresty-proxy-buffers "$APP")" + "--openresty-proxy-busy-buffers-size: $(fn-openresty-proxy-busy-buffers-size "$APP")" + "--openresty-proxy-connect-timeout: $(fn-openresty-proxy-connect-timeout "$APP")" + "--openresty-proxy-read-timeout: $(fn-openresty-proxy-read-timeout "$APP")" + "--openresty-proxy-send-timeout: $(fn-openresty-proxy-send-timeout "$APP")" + "--openresty-send-timeout: $(fn-openresty-send-timeout "$APP")" + "--openresty-underscore-in-headers: $(fn-openresty-underscore-in-headers "$APP")" + "--openresty-x-forwarded-for-value: $(fn-openresty-x-forwarded-for-value "$APP")" + "--openresty-x-forwarded-port-value: $(fn-openresty-x-forwarded-port-value "$APP")" + "--openresty-x-forwarded-proto-value: $(fn-openresty-x-forwarded-proto-value "$APP")" + "--openresty-x-forwarded-ssl: $(fn-openresty-x-forwarded-ssl "$APP")" + ) + fi + + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "openresty" + return + fi if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} openresty information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global openresty information" + else + dokku_log_info2_quiet "${APP} openresty information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/ports/report.go b/plugins/ports/report.go index 8031478b7..357cda900 100644 --- a/plugins/ports/report.go +++ b/plugins/ports/report.go @@ -8,13 +8,20 @@ import ( // ReportSingleApp is an internal function that displays the ports report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--ports-map": reportPortMap, - "--ports-map-detected": reportPortMapDetected, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{} + } else { + flags = map[string]common.ReportFunc{ + "--ports-map": reportPortMap, + "--ports-map-detected": reportPortMapDetected, + } } flagKeys := []string{} diff --git a/plugins/ports/src/subcommands/subcommands.go b/plugins/ports/src/subcommands/subcommands.go index 14f97ed94..35d0b5e46 100644 --- a/plugins/ports/src/subcommands/subcommands.go +++ b/plugins/ports/src/subcommands/subcommands.go @@ -49,11 +49,14 @@ func main() { case "report": args := flag.NewFlagSet("ports:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("ports", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("ports", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = ports.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = ports.CommandReport(appName, *format, reportArgs.InfoFlag) } default: err = fmt.Errorf("Invalid plugin subcommand call: %s", subcommand) diff --git a/plugins/proxy/report.go b/plugins/proxy/report.go index 00f126cd1..305e808e0 100644 --- a/plugins/proxy/report.go +++ b/plugins/proxy/report.go @@ -6,15 +6,24 @@ import ( // ReportSingleApp is an internal function that displays the proxy report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--proxy-enabled": reportEnabled, - "--proxy-computed-type": reportComputedType, - "--proxy-global-type": reportGlobalType, - "--proxy-type": reportType, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--proxy-global-type": reportGlobalType, + } + } else { + flags = map[string]common.ReportFunc{ + "--proxy-enabled": reportEnabled, + "--proxy-computed-type": reportComputedType, + "--proxy-global-type": reportGlobalType, + "--proxy-type": reportType, + } } flagKeys := []string{} diff --git a/plugins/proxy/src/subcommands/subcommands.go b/plugins/proxy/src/subcommands/subcommands.go index 11498b8b0..07b1a5655 100644 --- a/plugins/proxy/src/subcommands/subcommands.go +++ b/plugins/proxy/src/subcommands/subcommands.go @@ -48,11 +48,14 @@ func main() { case "report": args := flag.NewFlagSet("proxy:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("proxy", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("proxy", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = proxy.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = proxy.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("proxy:set", flag.ExitOnError) diff --git a/plugins/ps/report.go b/plugins/ps/report.go index a95dca567..1ccfd3e3f 100644 --- a/plugins/ps/report.go +++ b/plugins/ps/report.go @@ -10,28 +10,38 @@ import ( // ReportSingleApp is an internal function that displays the ps report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--deployed": reportDeployed, - "--processes": reportProcesses, - "--ps-can-scale": reportCanScale, - "--ps-restart-policy": reportRestartPolicy, - "--ps-computed-procfile-path": reportComputedProcfilePath, - "--ps-global-procfile-path": reportGlobalProcfilePath, - "--ps-procfile-path": reportProcfilePath, - "--restore": reportRestore, - "--running": reportRunningState, - "--global-stop-timeout-seconds": reportGlobalStopTimeoutSeconds, - "--computed-stop-timeout-seconds": reportComputedStopTimeoutSeconds, - "--stop-timeout-seconds": reportStopTimeoutSeconds, - } + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--ps-global-procfile-path": reportGlobalProcfilePath, + "--global-stop-timeout-seconds": reportGlobalStopTimeoutSeconds, + } + } else { + flags = map[string]common.ReportFunc{ + "--deployed": reportDeployed, + "--processes": reportProcesses, + "--ps-can-scale": reportCanScale, + "--ps-restart-policy": reportRestartPolicy, + "--ps-computed-procfile-path": reportComputedProcfilePath, + "--ps-global-procfile-path": reportGlobalProcfilePath, + "--ps-procfile-path": reportProcfilePath, + "--restore": reportRestore, + "--running": reportRunningState, + "--global-stop-timeout-seconds": reportGlobalStopTimeoutSeconds, + "--computed-stop-timeout-seconds": reportComputedStopTimeoutSeconds, + "--stop-timeout-seconds": reportStopTimeoutSeconds, + } - extraFlags := addStatusFlags(appName, infoFlag) - for flag, fn := range extraFlags { - flags[flag] = fn + extraFlags := addStatusFlags(appName, infoFlag) + for flag, fn := range extraFlags { + flags[flag] = fn + } } flagKeys := []string{} diff --git a/plugins/ps/src/subcommands/subcommands.go b/plugins/ps/src/subcommands/subcommands.go index 24172b490..440640214 100644 --- a/plugins/ps/src/subcommands/subcommands.go +++ b/plugins/ps/src/subcommands/subcommands.go @@ -33,11 +33,14 @@ func main() { case "report": args := flag.NewFlagSet("ps:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("ps", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("ps", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = ps.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = ps.CommandReport(appName, *format, reportArgs.InfoFlag) } case "restart": args := flag.NewFlagSet("ps:restart", flag.ExitOnError) diff --git a/plugins/registry/report.go b/plugins/registry/report.go index 9d1fe3251..a4ca924e7 100644 --- a/plugins/registry/report.go +++ b/plugins/registry/report.go @@ -8,22 +8,33 @@ import ( // ReportSingleApp is an internal function that displays the registry report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--registry-computed-image-repo": reportComputedImageRepo, - "--registry-image-repo": reportImageRepo, - "--registry-computed-push-on-release": reportComputedPushOnRelease, - "--registry-global-push-on-release": reportGlobalPushOnRelease, - "--registry-push-on-release": reportPushOnRelease, - "--registry-computed-server": reportComputedServer, - "--registry-global-server": reportGlobalServer, - "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, - "--registry-server": reportServer, - "--registry-tag-version": reportTagVersion, - "--registry-push-extra-tags": reportPushExtraTags, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--registry-global-push-on-release": reportGlobalPushOnRelease, + "--registry-global-server": reportGlobalServer, + "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, + } + } else { + flags = map[string]common.ReportFunc{ + "--registry-computed-image-repo": reportComputedImageRepo, + "--registry-image-repo": reportImageRepo, + "--registry-computed-push-on-release": reportComputedPushOnRelease, + "--registry-global-push-on-release": reportGlobalPushOnRelease, + "--registry-push-on-release": reportPushOnRelease, + "--registry-computed-server": reportComputedServer, + "--registry-global-server": reportGlobalServer, + "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, + "--registry-server": reportServer, + "--registry-tag-version": reportTagVersion, + "--registry-push-extra-tags": reportPushExtraTags, + } } flagKeys := []string{} diff --git a/plugins/registry/src/subcommands/subcommands.go b/plugins/registry/src/subcommands/subcommands.go index 35377be84..c8fa06479 100644 --- a/plugins/registry/src/subcommands/subcommands.go +++ b/plugins/registry/src/subcommands/subcommands.go @@ -84,11 +84,14 @@ func main() { case "report": args := flag.NewFlagSet("registry:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("registry", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("registry", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = registry.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = registry.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("registry:set", flag.ExitOnError) diff --git a/plugins/resource/resource.go b/plugins/resource/resource.go index 9c14a7e54..93c8285d4 100644 --- a/plugins/resource/resource.go +++ b/plugins/resource/resource.go @@ -19,8 +19,10 @@ type Resource struct { // ReportSingleApp is an internal function that displays the resource report for one or more apps func ReportSingleApp(appName, format, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } resources, err := common.PropertyGetAll("resource", appName) diff --git a/plugins/resource/src/subcommands/subcommands.go b/plugins/resource/src/subcommands/subcommands.go index c54697ba6..09f9e97df 100644 --- a/plugins/resource/src/subcommands/subcommands.go +++ b/plugins/resource/src/subcommands/subcommands.go @@ -51,11 +51,14 @@ func main() { case "report": args := flag.NewFlagSet("resource:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("resource", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("resource", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = resource.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = resource.CommandReport(appName, *format, reportArgs.InfoFlag) } case "reserve": args := flag.NewFlagSet("resource:reserve", flag.ExitOnError) diff --git a/plugins/scheduler-docker-local/internal-functions b/plugins/scheduler-docker-local/internal-functions index dd34eecbe..08426ac9a 100755 --- a/plugins/scheduler-docker-local/internal-functions +++ b/plugins/scheduler-docker-local/internal-functions @@ -9,9 +9,13 @@ cmd-scheduler-docker-local-report() { declare desc="displays a scheduler-docker-local report for one or more apps" declare cmd="scheduler-docker-local:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" + elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" fi @@ -20,28 +24,43 @@ cmd-scheduler-docker-local-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-scheduler-docker-local-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-scheduler-docker-local-report-single "$app" "$INFO_FLAG" | tee || true + cmd-scheduler-docker-local-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-scheduler-docker-local-report-single "$APP" "$INFO_FLAG" + cmd-scheduler-docker-local-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } cmd-scheduler-docker-local-report-single() { - declare APP="$1" INFO_FLAG="$2" + declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}" if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" + if [[ "$APP" != "--global" ]]; then + verify_app_name "$APP" + fi local flag_map=( "--scheduler-docker-local-init-process: $(fn-plugin-property-get "scheduler-docker-local" "$APP" "init-process" "true")" "--scheduler-docker-local-parallel-schedule-count: $(fn-plugin-property-get "scheduler-docker-local" "$APP" "parallel-schedule-count" "")" ) + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + + if [[ "$FORMAT" == "json" ]]; then + fn-report-emit-json flag_map "scheduler-docker-local" + return + fi + if [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} scheduler-docker-local information" + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global scheduler-docker-local information" + else + dokku_log_info2_quiet "${APP} scheduler-docker-local information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/plugins/scheduler-k3s/report.go b/plugins/scheduler-k3s/report.go index d1bb6d2de..4ba9a5c8d 100644 --- a/plugins/scheduler-k3s/report.go +++ b/plugins/scheduler-k3s/report.go @@ -9,38 +9,59 @@ import ( // ReportSingleApp is an internal function that displays the scheduler-k3s report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--scheduler-k3s-computed-deploy-timeout": reportComputedDeployTimeout, - "--scheduler-k3s-deploy-timeout": reportDeployTimeout, - "--scheduler-k3s-global-deploy-timeout": reportGlobalDeployTimeout, - "--scheduler-k3s-computed-image-pull-secrets": reportComputedImagePullSecrets, - "--scheduler-k3s-image-pull-secrets": reportImagePullSecrets, - "--scheduler-k3s-global-image-pull-secrets": reportGlobalImagePullSecrets, - "--scheduler-k3s-global-kubeconfig-path": reportGlobalKubeconfigPath, - "--scheduler-k3s-global-kube-context": reportGlobalKubeContext, - "--scheduler-k3s-computed-letsencrypt-server": reportComputedLetsencryptServer, - "--scheduler-k3s-letsencrypt-server": reportLetsencryptServer, - "--scheduler-k3s-global-letsencrypt-server": reportGlobalLetsencryptServer, - "--scheduler-k3s-global-ingress-class": reportGlobalIngressClass, - "--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd, - "--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag, - "--scheduler-k3s-computed-kustomize-root-path": reportComputedKustomizeRootPath, - "--scheduler-k3s-kustomize-root-path": reportKustomizeRootPath, - "--scheduler-k3s-global-kustomize-root-path": reportGlobalKustomizeRootPath, - "--scheduler-k3s-computed-namespace": reportComputedNamespace, - "--scheduler-k3s-namespace": reportNamespace, - "--scheduler-k3s-global-namespace": reportGlobalNamespace, - "--scheduler-k3s-global-network-interface": reportGlobalNetworkInterface, - "--scheduler-k3s-computed-rollback-on-failure": reportComputedRollbackOnFailure, - "--scheduler-k3s-rollback-on-failure": reportRollbackOnFailure, - "--scheduler-k3s-global-rollback-on-failure": reportGlobalRollbackOnFailure, - "--scheduler-k3s-computed-shm-size": reportComputedShmSize, - "--scheduler-k3s-global-shm-size": reportGlobalShmSize, - "--scheduler-k3s-shm-size": reportShmSize, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--scheduler-k3s-global-deploy-timeout": reportGlobalDeployTimeout, + "--scheduler-k3s-global-image-pull-secrets": reportGlobalImagePullSecrets, + "--scheduler-k3s-global-kubeconfig-path": reportGlobalKubeconfigPath, + "--scheduler-k3s-global-kube-context": reportGlobalKubeContext, + "--scheduler-k3s-global-letsencrypt-server": reportGlobalLetsencryptServer, + "--scheduler-k3s-global-ingress-class": reportGlobalIngressClass, + "--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd, + "--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag, + "--scheduler-k3s-global-kustomize-root-path": reportGlobalKustomizeRootPath, + "--scheduler-k3s-global-namespace": reportGlobalNamespace, + "--scheduler-k3s-global-network-interface": reportGlobalNetworkInterface, + "--scheduler-k3s-global-rollback-on-failure": reportGlobalRollbackOnFailure, + "--scheduler-k3s-global-shm-size": reportGlobalShmSize, + } + } else { + flags = map[string]common.ReportFunc{ + "--scheduler-k3s-computed-deploy-timeout": reportComputedDeployTimeout, + "--scheduler-k3s-deploy-timeout": reportDeployTimeout, + "--scheduler-k3s-global-deploy-timeout": reportGlobalDeployTimeout, + "--scheduler-k3s-computed-image-pull-secrets": reportComputedImagePullSecrets, + "--scheduler-k3s-image-pull-secrets": reportImagePullSecrets, + "--scheduler-k3s-global-image-pull-secrets": reportGlobalImagePullSecrets, + "--scheduler-k3s-global-kubeconfig-path": reportGlobalKubeconfigPath, + "--scheduler-k3s-global-kube-context": reportGlobalKubeContext, + "--scheduler-k3s-computed-letsencrypt-server": reportComputedLetsencryptServer, + "--scheduler-k3s-letsencrypt-server": reportLetsencryptServer, + "--scheduler-k3s-global-letsencrypt-server": reportGlobalLetsencryptServer, + "--scheduler-k3s-global-ingress-class": reportGlobalIngressClass, + "--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd, + "--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag, + "--scheduler-k3s-computed-kustomize-root-path": reportComputedKustomizeRootPath, + "--scheduler-k3s-kustomize-root-path": reportKustomizeRootPath, + "--scheduler-k3s-global-kustomize-root-path": reportGlobalKustomizeRootPath, + "--scheduler-k3s-computed-namespace": reportComputedNamespace, + "--scheduler-k3s-namespace": reportNamespace, + "--scheduler-k3s-global-namespace": reportGlobalNamespace, + "--scheduler-k3s-global-network-interface": reportGlobalNetworkInterface, + "--scheduler-k3s-computed-rollback-on-failure": reportComputedRollbackOnFailure, + "--scheduler-k3s-rollback-on-failure": reportRollbackOnFailure, + "--scheduler-k3s-global-rollback-on-failure": reportGlobalRollbackOnFailure, + "--scheduler-k3s-computed-shm-size": reportComputedShmSize, + "--scheduler-k3s-global-shm-size": reportGlobalShmSize, + "--scheduler-k3s-shm-size": reportShmSize, + } } chartProperties, err := common.PropertyGetAllByPrefix("scheduler-k3s", "--global", "chart.") diff --git a/plugins/scheduler-k3s/src/subcommands/subcommands.go b/plugins/scheduler-k3s/src/subcommands/subcommands.go index 7a950f1ec..c5680e66d 100644 --- a/plugins/scheduler-k3s/src/subcommands/subcommands.go +++ b/plugins/scheduler-k3s/src/subcommands/subcommands.go @@ -126,11 +126,14 @@ func main() { case "report": args := flag.NewFlagSet("scheduler-k3s:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("scheduler-k3s", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("scheduler-k3s", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = scheduler_k3s.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = scheduler_k3s.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("scheduler-k3s:set", flag.ExitOnError) diff --git a/plugins/scheduler/report.go b/plugins/scheduler/report.go index 6b9548f29..095fe851b 100644 --- a/plugins/scheduler/report.go +++ b/plugins/scheduler/report.go @@ -6,14 +6,23 @@ import ( // ReportSingleApp is an internal function that displays the scheduler report for one or more apps func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--scheduler-computed-selected": reportComputedSelected, - "--scheduler-global-selected": reportGlobalSelected, - "--scheduler-selected": reportSelected, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{ + "--scheduler-global-selected": reportGlobalSelected, + } + } else { + flags = map[string]common.ReportFunc{ + "--scheduler-computed-selected": reportComputedSelected, + "--scheduler-global-selected": reportGlobalSelected, + "--scheduler-selected": reportSelected, + } } flagKeys := []string{} diff --git a/plugins/scheduler/src/subcommands/subcommands.go b/plugins/scheduler/src/subcommands/subcommands.go index 148c3d753..93d8c6865 100644 --- a/plugins/scheduler/src/subcommands/subcommands.go +++ b/plugins/scheduler/src/subcommands/subcommands.go @@ -21,11 +21,14 @@ func main() { case "report": args := flag.NewFlagSet("scheduler:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("scheduler", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("scheduler", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = scheduler.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = scheduler.CommandReport(appName, *format, reportArgs.InfoFlag) } case "set": args := flag.NewFlagSet("scheduler:set", flag.ExitOnError) diff --git a/plugins/storage/report.go b/plugins/storage/report.go index cdb46a3d5..d29c42e4e 100644 --- a/plugins/storage/report.go +++ b/plugins/storage/report.go @@ -3,14 +3,21 @@ package storage import "github.com/dokku/dokku/plugins/common" func ReportSingleApp(appName string, format string, infoFlag string) error { - if err := common.VerifyAppName(appName); err != nil { - return err + if appName != "--global" { + if err := common.VerifyAppName(appName); err != nil { + return err + } } - flags := map[string]common.ReportFunc{ - "--storage-build-mounts": reportBuildMounts, - "--storage-deploy-mounts": reportDeployMounts, - "--storage-run-mounts": reportRunMounts, + var flags map[string]common.ReportFunc + if appName == "--global" { + flags = map[string]common.ReportFunc{} + } else { + flags = map[string]common.ReportFunc{ + "--storage-build-mounts": reportBuildMounts, + "--storage-deploy-mounts": reportDeployMounts, + "--storage-run-mounts": reportRunMounts, + } } flagKeys := []string{} diff --git a/plugins/storage/src/subcommands/subcommands.go b/plugins/storage/src/subcommands/subcommands.go index 87f00c831..3e051c341 100644 --- a/plugins/storage/src/subcommands/subcommands.go +++ b/plugins/storage/src/subcommands/subcommands.go @@ -40,11 +40,14 @@ func main() { case "report": args := flag.NewFlagSet("storage:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") - osArgs, infoFlag, flagErr := common.ParseReportArgs("storage", os.Args[2:]) + reportArgs, flagErr := common.ParseReportArgs("storage", os.Args[2:]) if flagErr == nil { - args.Parse(osArgs) + args.Parse(reportArgs.OSArgs) appName := args.Arg(0) - err = storage.CommandReport(appName, *format, infoFlag) + if reportArgs.IsGlobal { + appName = "--global" + } + err = storage.CommandReport(appName, *format, reportArgs.InfoFlag) } case "unmount": args := flag.NewFlagSet("storage:unmount", flag.ExitOnError) diff --git a/plugins/traefik-vhosts/command-functions b/plugins/traefik-vhosts/command-functions index f37149b72..aab85bf01 100755 --- a/plugins/traefik-vhosts/command-functions +++ b/plugins/traefik-vhosts/command-functions @@ -33,16 +33,12 @@ cmd-traefik-report() { declare desc="displays a traefik report for one or more apps" declare cmd="traefik:report" [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" INFO_FLAG="$2" - local FORMAT="stdout" + fn-report-parse-args "$@" + set -- "${REPORT_ARGS[@]}" + declare APP="${1:-}" INFO_FLAG="${2:-}" - if [[ -n "$APP" ]] && [[ "$APP" == "--format" ]]; then - FORMAT="$INFO_FLAG" - APP="" - INFO_FLAG="" - elif [[ -n "$INFO_FLAG" ]] && [[ "$INFO_FLAG" == "--format" ]]; then - FORMAT="$3" - INFO_FLAG="" + if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then + APP="--global" elif [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" APP="" @@ -52,12 +48,14 @@ cmd-traefik-report() { INFO_FLAG="true" fi - if [[ -z "$APP" ]]; then + if [[ "$APP" == "--global" ]]; then + cmd-traefik-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" + elif [[ -z "$APP" ]]; then for app in $(dokku_apps); do - cmd-traefik-report-single "$app" "$INFO_FLAG" "$FORMAT" | tee || true + cmd-traefik-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true done else - cmd-traefik-report-single "$APP" "$INFO_FLAG" "$FORMAT" + cmd-traefik-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT" fi } @@ -66,7 +64,9 @@ cmd-traefik-report-single() { if [[ "$INFO_FLAG" == "true" ]]; then INFO_FLAG="" fi - verify_app_name "$APP" + if [[ "$APP" != "--global" ]]; then + verify_app_name "$APP" + fi local flag_map=( "--traefik-api-enabled: $(fn-traefik-api-enabled)" "--traefik-api-entry-point: $(fn-traefik-api-entry-point)" @@ -85,7 +85,6 @@ cmd-traefik-report-single() { "--traefik-https-entry-point: $(fn-traefik-https-entry-point)" ) - # Get dns-provider-* env vars and add them (masked for stdout, unmasked for json) local dns_provider_env_vars dns_provider_env_vars="$(fn-traefik-dns-provider-env-vars)" if [[ -n "$dns_provider_env_vars" ]]; then @@ -103,17 +102,19 @@ cmd-traefik-report-single() { done <<<"$dns_provider_env_vars" fi + fn-report-validate-format "$FORMAT" "$INFO_FLAG" + if [[ "$FORMAT" == "json" ]]; then - local json_output="{}" - for flag in "${flag_map[@]}"; do - local key value - key="$(echo "$flag" | cut -d':' -f1 | sed 's/^--traefik-//')" - value="$(echo "$flag" | cut -d':' -f2- | sed 's/^ //')" - json_output="$(echo "$json_output" | jq -c --arg key "$key" --arg value "$value" '. + {($key): $value}')" - done - echo "$json_output" - elif [[ -z "$INFO_FLAG" ]]; then - dokku_log_info2_quiet "${APP} traefik information" + fn-report-emit-json flag_map "traefik" + return + fi + + if [[ -z "$INFO_FLAG" ]]; then + if [[ "$APP" == "--global" ]]; then + dokku_log_info2_quiet "global traefik information" + else + dokku_log_info2_quiet "${APP} traefik information" + fi for flag in "${flag_map[@]}"; do key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" diff --git a/tests/unit/builder-dockerfile.bats b/tests/unit/builder-dockerfile.bats index ca62231f0..cf4d88ac0 100644 --- a/tests/unit/builder-dockerfile.bats +++ b/tests/unit/builder-dockerfile.bats @@ -12,6 +12,31 @@ teardown() { destroy_app } +@test "(builder-dockerfile:report) --global --format json" { + run /bin/bash -c "dokku builder-dockerfile:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku builder-dockerfile:report --global --format json | jq -r '.\"global-dockerfile-path\"'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "Dockerfile" + + run /bin/bash -c "dokku builder-dockerfile:report --global --format json | jq -r 'has(\"dockerfile-path\")'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "false" + + run /bin/bash -c "dokku builder-dockerfile:report --global" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "global builder-dockerfile information" +} + @test "(builder-dockerfile:set)" { run deploy_app dockerfile echo "output: $output" diff --git a/tests/unit/builder.bats b/tests/unit/builder.bats index 6cbaa790e..770b9f0a7 100644 --- a/tests/unit/builder.bats +++ b/tests/unit/builder.bats @@ -175,6 +175,40 @@ teardown() { assert_line 0 "herokuish" } +@test "(builder:report) --global --format json" { + run /bin/bash -c "dokku builder:set --global selected dockerfile" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku builder:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku builder:report --global --format json | jq -r '.\"builder-global-selected\"'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "dockerfile" + + run /bin/bash -c "dokku builder:report --global --format json | jq -r 'has(\"builder-selected\")'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "false" + + run /bin/bash -c "dokku builder:report --global" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku builder:set --global selected" + echo "output: $output" + echo "status: $status" + assert_success +} + @test "(builder:set)" { run deploy_app python echo "output: $output" diff --git a/tests/unit/certs.bats b/tests/unit/certs.bats index ba8f7fe5f..6a5b16d1d 100644 --- a/tests/unit/certs.bats +++ b/tests/unit/certs.bats @@ -41,6 +41,20 @@ teardown() { assert_output "$help_output" } +@test "(certs:report) --global --format json" { + run /bin/bash -c "dokku certs:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + assert_output "{}" + + run /bin/bash -c "dokku certs:report --global" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "global ssl information" +} + @test "(certs) certs:add" { run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key" echo "output: $output" diff --git a/tests/unit/checks.bats b/tests/unit/checks.bats index 138b389c1..b73094c7a 100644 --- a/tests/unit/checks.bats +++ b/tests/unit/checks.bats @@ -16,6 +16,41 @@ teardown() { global_teardown } +@test "(checks:report) --global --format json" { + run /bin/bash -c "dokku checks:set --global wait-to-retire 90" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku checks:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku checks:report --global --format json | jq -r '.\"global-wait-to-retire\"'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "90" + + run /bin/bash -c "dokku checks:report --global --format json | jq -r 'has(\"wait-to-retire\")'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "false" + + run /bin/bash -c "dokku checks:report --global" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "global checks information" + + run /bin/bash -c "dokku checks:set --global wait-to-retire" + echo "output: $output" + echo "status: $status" + assert_success +} + @test "(checks) checks:help" { run /bin/bash -c "dokku checks" echo "output: $output" diff --git a/tests/unit/cron.bats b/tests/unit/cron.bats index 5eb2bc34a..c9f36e471 100644 --- a/tests/unit/cron.bats +++ b/tests/unit/cron.bats @@ -102,6 +102,28 @@ teardown() { assert_output_contains "python3 task.py daily" } +@test "(cron:report) --global --format json" { + run /bin/bash -c "dokku cron:set --global mailto admin@example.com" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku cron:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku cron:report --global" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku cron:set --global mailto" + echo "output: $output" + echo "status: $status" + assert_success +} + @test "(cron) create [multiple]" { run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_multiple echo "output: $output" diff --git a/tests/unit/domains.bats b/tests/unit/domains.bats index 577239b01..bbbe71aac 100644 --- a/tests/unit/domains.bats +++ b/tests/unit/domains.bats @@ -28,6 +28,25 @@ teardown() { assert_output "$help_output" } +@test "(domains:report) --global --format json" { + run /bin/bash -c "dokku domains:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku domains:report --global --format json | jq -r 'keys[]' | grep -v 'global-' | wc -l" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "0" + + run /bin/bash -c "dokku domains:report --global" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Global domains information" +} + @test "(domains) domains" { run /bin/bash -c "dokku domains:report $TEST_APP 2>/dev/null | grep ${TEST_APP}.${DOKKU_DOMAIN}" echo "output: $output" diff --git a/tests/unit/git_3.bats b/tests/unit/git_3.bats index 21a7e06bb..a924b99ea 100644 --- a/tests/unit/git_3.bats +++ b/tests/unit/git_3.bats @@ -831,3 +831,31 @@ teardown() { assert_failure assert_output_contains "--format flag cannot be specified when specifying an info flag" } + +@test "(git:report) --global" { + run /bin/bash -c "dokku git:report --global" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "global git information" + assert_output_contains "Global deploy branch" +} + +@test "(git:report) --global --format json" { + run /bin/bash -c "dokku git:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"global-deploy-branch\"'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "master" + + run /bin/bash -c "dokku git:report --global --format json | jq -r 'has(\"deploy-branch\")'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "false" +} diff --git a/tests/unit/network.bats b/tests/unit/network.bats index 166ddd084..311fa3154 100644 --- a/tests/unit/network.bats +++ b/tests/unit/network.bats @@ -31,6 +31,41 @@ teardown() { assert_output "$help_output" } +@test "(network:report) --global --format json" { + run /bin/bash -c "dokku network:set --global tld dokku.test" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku network:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-global-tld\"'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "dokku.test" + + run /bin/bash -c "dokku network:report --global --format json | jq -r 'has(\"network-tld\")'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "false" + + run /bin/bash -c "dokku network:report --global" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "--global" + + run /bin/bash -c "dokku network:set --global tld" + echo "output: $output" + echo "status: $status" + assert_success +} + @test "(network) network:set bind-all-interfaces" { run deploy_app echo "output: $output" diff --git a/tests/unit/nginx-vhosts_1.bats b/tests/unit/nginx-vhosts_1.bats index cd038bef8..6d11422dd 100644 --- a/tests/unit/nginx-vhosts_1.bats +++ b/tests/unit/nginx-vhosts_1.bats @@ -62,6 +62,25 @@ teardown() { assert_output_contains "--format flag cannot be specified when specifying an info flag" } +@test "(nginx:report) --global --format json" { + run /bin/bash -c "dokku nginx:report --global --format json | jq -e ." + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku nginx:report --global --format json | jq -r 'keys[]' | grep -v 'global-' | wc -l" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "0" + + run /bin/bash -c "dokku nginx:report --global" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "global nginx information" +} + @test "(nginx-vhosts) proxy:build-config (domains:disable/enable)" { run deploy_app echo "output: $output"