From 2db3977408b906a0c7dc1bffc6b47d67397f0d6f Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Fri, 16 Nov 2018 11:25:48 +0100 Subject: [PATCH] cli: add 'test placeholder' subcommand for placeholder debugging --- cli/cli.go | 4 ++- client/testcmd.go | 87 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 8904bdc..6bfc313 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -42,6 +42,7 @@ func init() { type Subcommand struct { Use string Short string + Example string NoRequireConfig bool Run func(subcommand *Subcommand, args []string) error SetupFlags func(f *pflag.FlagSet) @@ -94,6 +95,7 @@ func addSubcommandToCobraCmd(c *cobra.Command, s *Subcommand) { cmd := cobra.Command{ Use: s.Use, Short: s.Short, + Example: s.Example, } if s.SetupSubcommands == nil { cmd.Run = s.run @@ -113,4 +115,4 @@ func Run() { if err := rootCmd.Execute(); err != nil { os.Exit(1) } -} \ No newline at end of file +} diff --git a/client/testcmd.go b/client/testcmd.go index 6635db5..e57a808 100644 --- a/client/testcmd.go +++ b/client/testcmd.go @@ -2,6 +2,7 @@ package client import ( "fmt" + "github.com/pkg/errors" "github.com/spf13/pflag" "github.com/zrepl/zrepl/cli" "github.com/zrepl/zrepl/config" @@ -12,7 +13,7 @@ import ( var TestCmd = &cli.Subcommand { Use: "test", 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 nil -} \ No newline at end of file +} + +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) +}