Merge pull request #4369 from dokku/report-json-output

Allow formatting :report command output as json
This commit is contained in:
Jose Diaz-Gonzalez
2021-02-01 22:42:00 -05:00
committed by GitHub
34 changed files with 104 additions and 58 deletions

View File

@@ -9,6 +9,10 @@ cmd-report() {
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1"
if [[ "$APP" == "--format" ]]; then
dokku_log_fail "--format flag not supported on global report"
fi
dokku_log_info1 "uname: $(uname -a)"
dokku_log_info1 "memory: "
free -m | sed "s/^/ /"

View File

@@ -7,7 +7,7 @@ import (
)
// ReportSingleApp is an internal function that displays the app report for one or more apps
func ReportSingleApp(appName, infoFlag string) error {
func ReportSingleApp(appName string, format string, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
@@ -26,7 +26,7 @@ func ReportSingleApp(appName, infoFlag string) error {
trimPrefix := false
uppercaseFirstCharacter := true
infoFlags := common.CollectReport(appName, infoFlag, flags)
return common.ReportSingleApp("app", appName, infoFlag, infoFlags, flagKeys, trimPrefix, uppercaseFirstCharacter)
return common.ReportSingleApp("app", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func reportDir(appName string) string {

View File

@@ -65,11 +65,12 @@ func main() {
err = apps.CommandRename(oldAppName, newAppName, *skipDeploy)
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:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = apps.CommandReport(appName, infoFlag)
err = apps.CommandReport(appName, *format, infoFlag)
}
case "unlock":
args := flag.NewFlagSet("apps:unlock", flag.ExitOnError)

View File

@@ -35,7 +35,7 @@ func main() {
err = apps.TriggerPostDelete(appName)
case "report":
appName := flag.Arg(0)
err = apps.ReportSingleApp(appName, "")
err = apps.ReportSingleApp(appName, "", "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}

View File

@@ -175,21 +175,21 @@ func CommandRename(oldAppName string, newAppName string, skipDeploy bool) error
}
// CommandReport displays an app report for one or more apps
func CommandReport(appName string, infoFlag string) error {
func CommandReport(appName string, format string, infoFlag string) error {
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return err
}
for _, appName := range apps {
if err := ReportSingleApp(appName, infoFlag); err != nil {
if err := ReportSingleApp(appName, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, infoFlag)
return ReportSingleApp(appName, format, infoFlag)
}
// CommandUnlock unlocks an app for deployment

View File

@@ -8,7 +8,7 @@ import (
)
// ReportSingleApp is an internal function that displays the buildpacks report for one or more apps
func ReportSingleApp(appName, infoFlag string) error {
func ReportSingleApp(appName string, format string, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
@@ -28,7 +28,7 @@ func ReportSingleApp(appName, infoFlag string) error {
trimPrefix := false
uppercaseFirstCharacter := true
infoFlags := common.CollectReport(appName, infoFlag, flags)
return common.ReportSingleApp("buildpacks", appName, infoFlag, infoFlags, flagKeys, trimPrefix, uppercaseFirstCharacter)
return common.ReportSingleApp("buildpacks", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func reportComputedStack(appName string) string {

View File

@@ -44,11 +44,12 @@ func main() {
err = buildpacks.CommandRemove(appName, buildpack, *index)
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:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = buildpacks.CommandReport(appName, infoFlag)
err = buildpacks.CommandReport(appName, *format, infoFlag)
}
case "set":
args := flag.NewFlagSet("buildpacks:set", flag.ExitOnError)

View File

@@ -40,7 +40,7 @@ func main() {
err = buildpacks.TriggerPostExtract(appName, sourceWorkDir)
case "report":
appName := flag.Arg(0)
err = buildpacks.ReportSingleApp(appName, "")
err = buildpacks.ReportSingleApp(appName, "", "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}

View File

@@ -104,21 +104,21 @@ func CommandRemove(appName string, buildpack string, index int) (err error) {
}
// CommandReport displays a buildpacks report for one or more apps
func CommandReport(appName string, infoFlag string) error {
func CommandReport(appName string, format string, infoFlag string) error {
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return err
}
for _, appName := range apps {
if err := ReportSingleApp(appName, infoFlag); err != nil {
if err := ReportSingleApp(appName, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, infoFlag)
return ReportSingleApp(appName, format, infoFlag)
}
// CommandSet implements buildpacks:set

View File

@@ -2,6 +2,7 @@ package common
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
@@ -305,7 +306,17 @@ func GetenvWithDefault(key string, defaultValue string) (val string) {
func ParseReportArgs(pluginName string, arguments []string) ([]string, string, error) {
osArgs := []string{}
infoFlags := []string{}
for _, argument := range arguments {
skipNext := false
for i, argument := range arguments {
if skipNext {
skipNext = false
continue
}
if argument == "--format" {
osArgs = append(osArgs, argument, arguments[i+1])
skipNext = true
continue
}
if strings.HasPrefix(argument, "--") {
infoFlags = append(infoFlags, argument)
} else {
@@ -323,7 +334,30 @@ func ParseReportArgs(pluginName string, arguments []string) ([]string, string, e
}
// ReportSingleApp is an internal function that displays a report for an app
func ReportSingleApp(reportType string, appName string, infoFlag string, infoFlags map[string]string, infoFlagKeys []string, trimPrefix bool, uppercaseFirstCharacter bool) error {
func ReportSingleApp(reportType string, appName string, infoFlag string, infoFlags map[string]string, infoFlagKeys []string, format string, trimPrefix bool, uppercaseFirstCharacter bool) error {
if format != "stdout" && infoFlag != "" {
return errors.New("--format flag cannot be specified when specifying an info flag")
}
if format == "json" {
data := map[string]string{}
for key, value := range infoFlags {
prefix := "--"
if trimPrefix {
prefix = fmt.Sprintf("--%v-", reportType)
}
// key = strings.Replace(strings.Replace(strings.TrimPrefix(key, prefix), "-", " ", -1), ".", " ", -1)
data[strings.TrimPrefix(key, prefix)] = value
}
out, err := json.Marshal(data)
if err != nil {
return err
}
Log(string(out))
return nil
}
flags := []string{}
for key := range infoFlags {
flags = append(flags, key)

View File

@@ -7,7 +7,7 @@ import (
)
// ReportSingleApp is an internal function that displays the cron report for one or more apps
func ReportSingleApp(appName, infoFlag string) error {
func ReportSingleApp(appName string, format string, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
@@ -24,7 +24,7 @@ func ReportSingleApp(appName, infoFlag string) error {
trimPrefix := false
uppercaseFirstCharacter := true
infoFlags := common.CollectReport(appName, infoFlag, flags)
return common.ReportSingleApp("cron", appName, infoFlag, infoFlags, flagKeys, trimPrefix, uppercaseFirstCharacter)
return common.ReportSingleApp("cron", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func reportTasks(appName string) string {

View File

@@ -25,11 +25,12 @@ func main() {
err = cron.CommandList(appName)
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:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = cron.CommandReport(appName, infoFlag)
err = cron.CommandReport(appName, *format, infoFlag)
}
default:
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))

View File

@@ -24,7 +24,7 @@ func main() {
err = cron.TriggerPostDeploy()
case "report":
appName := flag.Arg(0)
err = cron.ReportSingleApp(appName, "")
err = cron.ReportSingleApp(appName, "", "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}

View File

@@ -29,19 +29,19 @@ func CommandList(appName string) error {
}
// CommandReport displays a cron report for one or more apps
func CommandReport(appName string, infoFlag string) error {
func CommandReport(appName string, format string, infoFlag string) error {
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return err
}
for _, appName := range apps {
if err := ReportSingleApp(appName, infoFlag); err != nil {
if err := ReportSingleApp(appName, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, infoFlag)
return ReportSingleApp(appName, format, infoFlag)
}

View File

@@ -5,7 +5,7 @@ import (
)
// ReportSingleApp is an internal function that displays the logs report for one or more apps
func ReportSingleApp(appName, infoFlag string) error {
func ReportSingleApp(appName string, format string, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
@@ -26,7 +26,7 @@ func ReportSingleApp(appName, infoFlag string) error {
trimPrefix := false
uppercaseFirstCharacter := true
infoFlags := common.CollectReport(appName, infoFlag, flags)
return common.ReportSingleApp("logs", appName, infoFlag, infoFlags, flagKeys, trimPrefix, uppercaseFirstCharacter)
return common.ReportSingleApp("logs", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func reportComputedMaxSize(appName string) string {

View File

@@ -26,11 +26,12 @@ func main() {
err = logs.CommandFailed(appName, *allApps)
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:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = logs.CommandReport(appName, infoFlag)
err = logs.CommandReport(appName, *format, infoFlag)
}
case "set":
args := flag.NewFlagSet("logs:set", flag.ExitOnError)

View File

@@ -32,7 +32,7 @@ func main() {
err = logs.TriggerPostDelete(appName)
case "report":
appName := flag.Arg(0)
err = logs.ReportSingleApp(appName, "")
err = logs.ReportSingleApp(appName, "", "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}

View File

@@ -50,21 +50,21 @@ func CommandFailed(appName string, allApps bool) error {
}
// CommandReport displays a logs report for one or more apps
func CommandReport(appName string, infoFlag string) error {
func CommandReport(appName string, format string, infoFlag string) error {
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return err
}
for _, appName := range apps {
if err := ReportSingleApp(appName, infoFlag); err != nil {
if err := ReportSingleApp(appName, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, infoFlag)
return ReportSingleApp(appName, format, infoFlag)
}
// CommandSet sets or clears a logs property for an app

View File

@@ -7,7 +7,7 @@ import (
)
// ReportSingleApp is an internal function that displays the network report for one or more apps
func ReportSingleApp(appName, infoFlag string) error {
func ReportSingleApp(appName string, format string, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
@@ -27,7 +27,7 @@ func ReportSingleApp(appName, infoFlag string) error {
trimPrefix := false
uppercaseFirstCharacter := true
infoFlags := common.CollectReport(appName, infoFlag, flags)
return common.ReportSingleApp("network", appName, infoFlag, infoFlags, flagKeys, trimPrefix, uppercaseFirstCharacter)
return common.ReportSingleApp("network", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func reportBindAllInterfaces(appName string) string {

View File

@@ -53,11 +53,12 @@ func main() {
err = network.CommandRebuildall()
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:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = network.CommandReport(appName, infoFlag)
err = network.CommandReport(appName, *format, infoFlag)
}
case "set":
args := flag.NewFlagSet("network:set", flag.ExitOnError)

View File

@@ -88,7 +88,7 @@ func main() {
network.TriggerCorePostDeploy(appName)
case "report":
appName := flag.Arg(0)
err = network.ReportSingleApp(appName, "")
err = network.ReportSingleApp(appName, "", "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}

View File

@@ -123,21 +123,21 @@ func CommandRebuildall() error {
}
// CommandReport displays a network report for one or more apps
func CommandReport(appName string, infoFlag string) error {
func CommandReport(appName string, format string, infoFlag string) error {
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return err
}
for _, appName := range apps {
if err := ReportSingleApp(appName, infoFlag); err != nil {
if err := ReportSingleApp(appName, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, infoFlag)
return ReportSingleApp(appName, format, infoFlag)
}
// CommandSet set or clear a network property for an app

View File

@@ -7,7 +7,7 @@ import (
)
// ReportSingleApp is an internal function that displays the proxy report for one or more apps
func ReportSingleApp(appName string, infoFlag string) error {
func ReportSingleApp(appName string, format string, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
@@ -26,7 +26,7 @@ func ReportSingleApp(appName string, infoFlag string) error {
trimPrefix := false
uppercaseFirstCharacter := true
infoFlags := common.CollectReport(appName, infoFlag, flags)
return common.ReportSingleApp("proxy", appName, infoFlag, infoFlags, flagKeys, trimPrefix, uppercaseFirstCharacter)
return common.ReportSingleApp("proxy", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func reportEnabled(appName string) string {

View File

@@ -64,11 +64,12 @@ func main() {
err = proxy.CommandPortsSet(appName, portMaps)
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:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = proxy.CommandReport(appName, infoFlag)
err = proxy.CommandReport(appName, *format, infoFlag)
}
case "set":
args := flag.NewFlagSet("proxy:set", flag.ExitOnError)

View File

@@ -32,7 +32,7 @@ func main() {
proxy.TriggerPostCertsUpdate(appName)
case "report":
appName := flag.Arg(0)
err = proxy.ReportSingleApp(appName, "")
err = proxy.ReportSingleApp(appName, "", "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}

View File

@@ -150,21 +150,21 @@ func CommandPortsSet(appName string, portMaps []string) error {
}
// CommandReport displays a proxy report for one or more apps
func CommandReport(appName string, infoFlag string) error {
func CommandReport(appName string, format string, infoFlag string) error {
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return err
}
for _, appName := range apps {
if err := ReportSingleApp(appName, infoFlag); err != nil {
if err := ReportSingleApp(appName, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, infoFlag)
return ReportSingleApp(appName, format, infoFlag)
}
// CommandSet sets a proxy for an app

View File

@@ -9,7 +9,7 @@ import (
)
// ReportSingleApp is an internal function that displays the ps report for one or more apps
func ReportSingleApp(appName, infoFlag string) error {
func ReportSingleApp(appName string, format string, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
@@ -36,7 +36,7 @@ func ReportSingleApp(appName, infoFlag string) error {
trimPrefix := false
uppercaseFirstCharacter := true
infoFlags := common.CollectReport(appName, infoFlag, flags)
return common.ReportSingleApp("ps", appName, infoFlag, infoFlags, flagKeys, trimPrefix, uppercaseFirstCharacter)
return common.ReportSingleApp("ps", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func addStatusFlags(appName string, infoFlag string) map[string]common.ReportFunc {

View File

@@ -32,11 +32,12 @@ func main() {
err = ps.CommandRebuild(appName, *allApps, *parallelCount)
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:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = ps.CommandReport(appName, infoFlag)
err = ps.CommandReport(appName, *format, infoFlag)
}
case "restart":
args := flag.NewFlagSet("ps:restart", flag.ExitOnError)

View File

@@ -73,7 +73,7 @@ func main() {
err = ps.TriggerProcfileRemove(appName)
case "report":
appName := flag.Arg(0)
err = ps.ReportSingleApp(appName, "")
err = ps.ReportSingleApp(appName, "", "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}

View File

@@ -35,21 +35,21 @@ func CommandRebuild(appName string, allApps bool, parallelCount int) error {
}
// CommandReport displays a ps report for one or more apps
func CommandReport(appName string, infoFlag string) error {
func CommandReport(appName string, format string, infoFlag string) error {
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return err
}
for _, appName := range apps {
if err := ReportSingleApp(appName, infoFlag); err != nil {
if err := ReportSingleApp(appName, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, infoFlag)
return ReportSingleApp(appName, format, infoFlag)
}
// CommandRestart restarts an app

View File

@@ -18,7 +18,7 @@ type Resource struct {
}
// ReportSingleApp is an internal function that displays the resource report for one or more apps
func ReportSingleApp(appName, infoFlag string) error {
func ReportSingleApp(appName, format, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
@@ -41,7 +41,7 @@ func ReportSingleApp(appName, infoFlag string) error {
trimPrefix := true
uppercaseFirstCharacter := false
return common.ReportSingleApp("resource", appName, infoFlag, flags, flagKeys, trimPrefix, uppercaseFirstCharacter)
return common.ReportSingleApp("resource", appName, infoFlag, flags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
// GetResourceValue fetches a single value for a given app/process/request/key combination

View File

@@ -50,11 +50,12 @@ func main() {
err = resource.CommandLimitClear(appName, *processType)
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:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = resource.CommandReport(appName, infoFlag)
err = resource.CommandReport(appName, *format, infoFlag)
}
case "reserve":
args := flag.NewFlagSet("resource:reserve", flag.ExitOnError)

View File

@@ -37,7 +37,7 @@ func main() {
err = resource.TriggerPostDelete(appName)
case "report":
appName := flag.Arg(0)
err = resource.ReportSingleApp(appName, "")
err = resource.ReportSingleApp(appName, "", "")
case "resource-get-property":
appName := flag.Arg(0)
processType := flag.Arg(1)

View File

@@ -24,21 +24,21 @@ func CommandLimitClear(appName string, processType string) error {
}
// CommandReport displays a resource report for one or more apps
func CommandReport(appName string, infoFlag string) error {
func CommandReport(appName string, format string, infoFlag string) error {
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return err
}
for _, appName := range apps {
if err := ReportSingleApp(appName, infoFlag); err != nil {
if err := ReportSingleApp(appName, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, infoFlag)
return ReportSingleApp(appName, format, infoFlag)
}
// CommandReserve implements resource:reserve