cli: refactor to allow definition of subcommands next to their implementation

This commit is contained in:
Christian Schwarz
2018-10-13 15:07:50 +02:00
parent aeb87ffbcf
commit 5c3c83b2cb
9 changed files with 255 additions and 191 deletions
+32 -4
View File
@@ -1,8 +1,36 @@
package client
import "github.com/zrepl/zrepl/config"
import (
"encoding/json"
"github.com/kr/pretty"
"github.com/spf13/pflag"
"github.com/zrepl/yaml-config"
"github.com/zrepl/zrepl/cli"
"os"
)
func RunConfigcheck(conf *config.Config, args []string) error {
// TODO: do the 'build' steps, e.g. build the jobs and see if that fails
return nil
var configcheckArgs struct {
format string
}
var ConfigcheckCmd = &cli.Subcommand{
Use: "configcheck",
Short: "check if config can be parsed without errors",
SetupFlags: func(f *pflag.FlagSet) {
f.StringVar(&configcheckArgs.format, "format", "", "dump parsed config object [pretty|yaml|json]")
},
Run: func(subcommand *cli.Subcommand, args []string) error {
switch configcheckArgs.format {
case "pretty":
_, err := pretty.Println(subcommand.Config())
return err
case "json":
return json.NewEncoder(os.Stdout).Encode(subcommand.Config())
case "yaml":
return yaml.NewEncoder(os.Stdout).Encode(subcommand.Config())
default: // no output
}
return nil
},
}
+34 -3
View File
@@ -1,17 +1,48 @@
package client
import (
"errors"
"github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/daemon"
"log"
"os"
)
type PProfArgs struct {
var pprofArgs struct {
daemon.PprofServerControlMsg
}
func RunPProf(conf *config.Config, args PProfArgs) {
var PprofCmd = &cli.Subcommand{
Use: "pprof off | [on TCP_LISTEN_ADDRESS]",
Short: "start a http server exposing go-tool-compatible profiling endpoints at TCP_LISTEN_ADDRESS",
Run: func(subcommand *cli.Subcommand, args []string) error {
if len(args) < 1 {
goto enargs
}
switch args[0] {
case "on":
pprofArgs.Run = true
if len(args) != 2 {
return errors.New("must specify TCP_LISTEN_ADDRESS as second positional argument")
}
pprofArgs.HttpListenAddress = args[1]
case "off":
if len(args) != 1 {
goto enargs
}
pprofArgs.Run = false
}
RunPProf(subcommand.Config())
return nil
enargs:
return errors.New("invalid number of positional arguments")
},
}
func RunPProf(conf *config.Config) {
log := log.New(os.Stderr, "", 0)
die := func() {
@@ -26,7 +57,7 @@ func RunPProf(conf *config.Config, args PProfArgs) {
log.Printf("error creating http client: %s", err)
die()
}
err = jsonRequestResponse(httpc, daemon.ControlJobEndpointPProf, args.PprofServerControlMsg, struct{}{})
err = jsonRequestResponse(httpc, daemon.ControlJobEndpointPProf, pprofArgs.PprofServerControlMsg, struct{}{})
if err != nil {
log.Printf("error sending control message: %s", err)
die()
+10 -1
View File
@@ -2,11 +2,20 @@ package client
import (
"github.com/pkg/errors"
"github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/daemon"
)
func RunSignal(config *config.Config, args []string) error {
var SignalCmd = &cli.Subcommand{
Use: "signal [wakeup|reset] JOB",
Short: "wake up a job from wait state or abort its current invocation",
Run: func(subcommand *cli.Subcommand, args []string) error {
return runSignalCmd(subcommand.Config(), args)
},
}
func runSignalCmd(config *config.Config, args []string) error {
if len(args) != 2 {
return errors.Errorf("Expected 2 arguments: [wakeup|reset] JOB")
}
+18 -8
View File
@@ -4,21 +4,22 @@ import (
"fmt"
"github.com/nsf/termbox-go"
"github.com/pkg/errors"
"github.com/spf13/pflag"
"github.com/zrepl/yaml-config"
"github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/daemon"
"github.com/zrepl/zrepl/daemon/job"
"github.com/zrepl/zrepl/daemon/pruner"
"github.com/zrepl/zrepl/replication"
"github.com/zrepl/zrepl/replication/fsrep"
"io"
"math"
"net/http"
"os"
"sort"
"strings"
"sync"
"time"
"io"
"os"
"net/http"
)
type tui struct {
@@ -73,17 +74,26 @@ func (t *tui) addIndent(indent int) {
t.moveLine(0, 0)
}
type StatusFlags struct {
var statusFlags struct {
Raw bool
}
func RunStatus(flags StatusFlags, config *config.Config, args []string) error {
httpc, err := controlHttpClient(config.Global.Control.SockPath)
var StatusCmd = &cli.Subcommand{
Use: "status",
Short: "show job activity or dump as JSON for monitoring",
SetupFlags: func(f *pflag.FlagSet) {
f.BoolVar(&statusFlags.Raw, "raw", false, "dump raw status description from zrepl daemon")
},
Run: runStatus,
}
func runStatus(s *cli.Subcommand, args []string) error {
httpc, err := controlHttpClient(s.Config().Global.Control.SockPath)
if err != nil {
return err
}
if flags.Raw {
if statusFlags.Raw {
resp, err := httpc.Get("http://unix"+daemon.ControlJobEndpointStatus)
if err != nil {
return err
+11 -3
View File
@@ -1,18 +1,26 @@
package client
import (
"github.com/zrepl/zrepl/cli"
"os"
"context"
"errors"
"github.com/problame/go-netssh"
"github.com/zrepl/zrepl/config"
"log"
"path"
"github.com/zrepl/zrepl/config"
"errors"
)
var StdinserverCmd = &cli.Subcommand{
Use: "stdinserver CLIENT_IDENTITY",
Short: "stdinserver transport mode (started from authorized_keys file as forced command)",
Run: func(subcommand *cli.Subcommand, args []string) error {
return runStdinserver(subcommand.Config(), args)
},
}
func RunStdinserver(config *config.Config, args []string) error {
func runStdinserver(config *config.Config, args []string) error {
// NOTE: the netssh proxying protocol requires exiting with non-zero status if anything goes wrong
defer os.Exit(1)
+27 -12
View File
@@ -2,27 +2,39 @@ package client
import (
"fmt"
"github.com/spf13/pflag"
"github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/daemon"
"github.com/zrepl/zrepl/version"
"os"
)
type VersionArgs struct {
var versionArgs struct {
Show string
Config *config.Config
ConfigErr error
}
func RunVersion(args VersionArgs) {
var VersionCmd = &cli.Subcommand{
Use: "version",
Short: "print version of zrepl binary and running daemon",
NoRequireConfig: true,
SetupFlags: func(f *pflag.FlagSet) {
f.StringVar(&versionArgs.Show, "show", "", "version info to show (client|daemon)")
},
Run: func(subcommand *cli.Subcommand, args []string) error {
versionArgs.Config = subcommand.Config()
versionArgs.ConfigErr = subcommand.ConfigParsingError()
return runVersionCmd()
},
}
die := func() {
fmt.Fprintf(os.Stderr, "exiting after error\n")
os.Exit(1)
}
func runVersionCmd() error {
args := versionArgs
if args.Show != "daemon" && args.Show != "client" && args.Show != "" {
fmt.Fprintf(os.Stderr, "show flag must be 'client' or 'server' or be left empty")
die()
return fmt.Errorf("show flag must be 'client' or 'server' or be left empty")
}
var clientVersion, daemonVersion *version.ZreplVersionInformation
@@ -32,17 +44,19 @@ func RunVersion(args VersionArgs) {
}
if args.Show == "daemon" || args.Show == "" {
if args.ConfigErr != nil {
return fmt.Errorf("config parsing error: %s", args.ConfigErr)
}
httpc, err := controlHttpClient(args.Config.Global.Control.SockPath)
if err != nil {
fmt.Fprintf(os.Stderr, "server: error: %s\n", err)
die()
return fmt.Errorf("server: error: %s\n", err)
}
var info version.ZreplVersionInformation
err = jsonRequestResponse(httpc, daemon.ControlJobEndpointVersion, "", &info)
if err != nil {
fmt.Fprintf(os.Stderr, "server: error: %s\n", err)
die()
return fmt.Errorf("server: error: %s\n", err)
}
daemonVersion = &info
fmt.Printf("server: %s\n", daemonVersion.String())
@@ -54,4 +68,5 @@ func RunVersion(args VersionArgs) {
}
}
return nil
}