cli: add 'test placeholder' subcommand for placeholder debugging

This commit is contained in:
Christian Schwarz 2018-11-16 11:25:48 +01:00
parent ca6d5d3bb5
commit 2db3977408
2 changed files with 88 additions and 3 deletions

View File

@ -42,6 +42,7 @@ func init() {
type Subcommand struct { type Subcommand struct {
Use string Use string
Short string Short string
Example string
NoRequireConfig bool NoRequireConfig bool
Run func(subcommand *Subcommand, args []string) error Run func(subcommand *Subcommand, args []string) error
SetupFlags func(f *pflag.FlagSet) SetupFlags func(f *pflag.FlagSet)
@ -94,6 +95,7 @@ func addSubcommandToCobraCmd(c *cobra.Command, s *Subcommand) {
cmd := cobra.Command{ cmd := cobra.Command{
Use: s.Use, Use: s.Use,
Short: s.Short, Short: s.Short,
Example: s.Example,
} }
if s.SetupSubcommands == nil { if s.SetupSubcommands == nil {
cmd.Run = s.run cmd.Run = s.run
@ -113,4 +115,4 @@ func Run() {
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
os.Exit(1) os.Exit(1)
} }
} }

View File

@ -2,6 +2,7 @@ package client
import ( import (
"fmt" "fmt"
"github.com/pkg/errors"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/config" "github.com/zrepl/zrepl/config"
@ -12,7 +13,7 @@ import (
var TestCmd = &cli.Subcommand { var TestCmd = &cli.Subcommand {
Use: "test", Use: "test",
SetupSubcommands: func() []*cli.Subcommand { SetupSubcommands: func() []*cli.Subcommand {
return []*cli.Subcommand{testFilter} return []*cli.Subcommand{testFilter, testPlaceholder}
}, },
} }
@ -105,4 +106,86 @@ func runTestFilterCmd(subcommand *cli.Subcommand, args []string) error {
return fmt.Errorf("filter errors occurred") return fmt.Errorf("filter errors occurred")
} }
return nil return nil
} }
var testPlaceholderArgs struct {
action string
ds string
plv string
all bool
}
var testPlaceholder = &cli.Subcommand{
Use: "placeholder [--all | --dataset DATASET --action [compute | check [--placeholder PROP_VALUE]]]",
Short: fmt.Sprintf("list received placeholder filesystems & compute the ZFS property %q", zfs.ZREPL_PLACEHOLDER_PROPERTY_NAME),
Example: `
placeholder --all
placeholder --dataset path/to/sink/clientident/fs --action compute
placeholder --dataset path/to/sink/clientident/fs --action check --placeholder 1671a61be44d32d1f3f047c5f124b06f98f54143d82900545ee529165060b859`,
NoRequireConfig: true,
SetupFlags: func(f *pflag.FlagSet) {
f.StringVar(&testPlaceholderArgs.action, "action", "", "check | compute")
f.StringVar(&testPlaceholderArgs.ds, "dataset", "", "dataset path (not required to exist)")
f.StringVar(&testPlaceholderArgs.plv, "placeholder", "", "existing placeholder value to check against DATASET path")
f.BoolVar(&testPlaceholderArgs.all, "all", false, "list tab-separated placeholder status of all filesystems")
},
Run: runTestPlaceholder,
}
func runTestPlaceholder(subcommand *cli.Subcommand, args []string) error {
// all actions first
if testPlaceholderArgs.all {
out, err := zfs.ZFSList([]string{"name", zfs.ZREPL_PLACEHOLDER_PROPERTY_NAME})
if err != nil {
return errors.Wrap(err, "could not list ZFS filesystems")
}
fmt.Printf("IS_PLACEHOLDER\tDATASET\tPROPVALUE\tCOMPUTED\n")
for _, row := range out {
dp, err := zfs.NewDatasetPath(row[0])
if err != nil {
panic(err)
}
computedProp := zfs.PlaceholderPropertyValue(dp)
is := "yes"
if computedProp != row[1] {
is = "no"
}
fmt.Printf("%s\t%s\t%q\t%q\n", is, dp.ToString(), row[1], computedProp)
}
return nil
}
// other actions
dp, err := zfs.NewDatasetPath(testPlaceholderArgs.ds)
if err != nil {
return err
}
computedProp := zfs.PlaceholderPropertyValue(dp)
switch testPlaceholderArgs.action {
case "check":
var isPlaceholder bool
if testPlaceholderArgs.plv != "" {
isPlaceholder = computedProp == testPlaceholderArgs.plv
} else {
isPlaceholder, err = zfs.ZFSIsPlaceholderFilesystem(dp)
if err != nil {
return err
}
}
if isPlaceholder {
fmt.Printf("%s is placeholder\n", dp.ToString())
return nil
} else {
return fmt.Errorf("%s is not a placeholder", dp.ToString())
}
case "compute":
fmt.Printf("%s\n", computedProp)
return nil
}
return fmt.Errorf("unknown --action %q", testPlaceholderArgs.action)
}