Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd: extend decode cmd to print any field #519

Merged
merged 4 commits into from Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions cmd/cmd.go
Expand Up @@ -4,6 +4,7 @@ package cmd

import (
"context"
"fmt"
"os"
"path/filepath"
"sync"
Expand Down Expand Up @@ -70,7 +71,7 @@ func AddFlags(cmd *cobra.Command) {
_ = cmd.PersistentFlags().MarkHidden(FlagSlowLogFile)
}

// Init ...
// Init initializes BR cli.
func Init(cmd *cobra.Command) (err error) {
initOnce.Do(func() {
// Initialize the logger.
Expand All @@ -95,7 +96,8 @@ func Init(cmd *cobra.Command) (err error) {
if len(conf.File.Filename) != 0 {
atomic.StoreUint64(&hasLogFile, 1)
summary.InitCollector(true)
cmd.Printf("Detail BR log in %s\n", conf.File.Filename)
// cmd.PrintErr prints to stderr, but PrintErrf prints to stdout.
cmd.PrintErr(fmt.Sprintf("Detail BR log in %s \n", conf.File.Filename))
Comment on lines +99 to +100
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol a bug fix spf13/cobra#894 has been submitted but stay unmerged for over a year because some dependencies now relied on the bug (classic xkcd-1172 scenario)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bug becomes a feature 🤯

}
lg, p, e := log.InitLogger(conf)
if e != nil {
Expand Down
58 changes: 37 additions & 21 deletions cmd/validate.go → cmd/debug.go
Expand Up @@ -8,7 +8,8 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"path"
"reflect"
"strings"

"github.com/gogo/protobuf/proto"
Expand All @@ -29,10 +30,10 @@ import (
"github.com/pingcap/br/pkg/utils"
)

// NewValidateCommand return a debug subcommand.
func NewValidateCommand() *cobra.Command {
// NewDebugCommand return a debug subcommand.
func NewDebugCommand() *cobra.Command {
meta := &cobra.Command{
Use: "validate <subcommand>",
Use: "debug <subcommand>",
Short: "commands to check/debug backup data",
SilenceUsage: false,
PersistentPreRunE: func(c *cobra.Command, args []string) error {
Expand All @@ -43,6 +44,8 @@ func NewValidateCommand() *cobra.Command {
task.LogArguments(c)
return nil
},
// To be compatible with older BR.
Aliases: []string{"validate"},
}
meta.AddCommand(newCheckSumCommand())
meta.AddCommand(newBackupMetaCommand())
Expand Down Expand Up @@ -244,33 +247,46 @@ func decodeBackupMetaCommand() *cobra.Command {

var cfg task.Config
if err := cfg.ParseFromFlags(cmd.Flags()); err != nil {
return err
return errors.Trace(err)
}
_, s, backupMeta, err := task.ReadBackupMeta(ctx, utils.MetaFile, &cfg)
if err != nil {
return err
}

backupMetaJSON, err := json.Marshal(backupMeta)
if err != nil {
return errors.Trace(err)
}

err = s.Write(ctx, utils.MetaJSONFile, backupMetaJSON)
if err != nil {
return errors.Trace(err)
fieldName, _ := cmd.Flags().GetString("field")
if fieldName == "" {
// No field flag, write backupmeta to external storage in JSON format.
backupMetaJSON, err := json.Marshal(backupMeta)
if err != nil {
return errors.Trace(err)
}
err = s.Write(ctx, utils.MetaJSONFile, backupMetaJSON)
if err != nil {
return errors.Trace(err)
}
cmd.Printf("backupmeta decoded at %s\n", path.Join(cfg.Storage, utils.MetaJSONFile))
return nil
}

field, err := cmd.Flags().GetString("field")
if err != nil {
log.Error("get field flag failed", zap.Error(err))
return err
}
switch field {
switch fieldName {
// To be compatible with older BR.
case "start-version":
fmt.Println(backupMeta.StartVersion)
fieldName = "StartVersion"
case "end-version":
fmt.Println(backupMeta.EndVersion)
fieldName = "EndVersion"
}

_, found := reflect.TypeOf(*backupMeta).FieldByName(fieldName)
if !found {
cmd.Printf("field '%s' not found\n", fieldName)
return nil
}
field := reflect.ValueOf(*backupMeta).FieldByName(fieldName)
if !field.CanInterface() {
cmd.Printf("field '%s' can not print\n", fieldName)
} else {
cmd.Printf("%v\n", field.Interface())
}
return nil
},
Expand Down
5 changes: 4 additions & 1 deletion main.go
Expand Up @@ -49,10 +49,13 @@ func main() {
cmd.AddFlags(rootCmd)
cmd.SetDefaultContext(ctx)
rootCmd.AddCommand(
cmd.NewValidateCommand(),
cmd.NewDebugCommand(),
cmd.NewBackupCommand(),
cmd.NewRestoreCommand(),
)
// Ouputs cmd.Print to stdout.
rootCmd.SetOut(os.Stdout)

rootCmd.SetArgs(os.Args[1:])
if err := rootCmd.Execute(); err != nil {
log.Error("br failed", zap.Error(err))
Expand Down
9 changes: 7 additions & 2 deletions tests/br_other/run.sh
Expand Up @@ -33,6 +33,12 @@ done
echo "backup start..."
run_br --pd $PD_ADDR backup full -s "local://$TEST_DIR/$DB" --ratelimit 5 --concurrency 4

# Test debug decode
run_br -s "local://$TEST_DIR/$DB" debug decode --field "Schemas"
run_br -s "local://$TEST_DIR/$DB" debug decode --field "EndVersion"
# Ensure compatibility
run_br -s "local://$TEST_DIR/$DB" validate decode --field "end-version"

# Test validate backupmeta
run_br validate backupmeta -s "local://$TEST_DIR/$DB"
run_br validate backupmeta -s "local://$TEST_DIR/$DB" --offset 100
Expand Down Expand Up @@ -62,7 +68,6 @@ run_br --pd $PD_ADDR backup full -s "local://$TEST_DIR/$DB/lock" --remove-schedu
# record last backup pid
_pid=$!


# give the former backup some time to write down lock file (and initialize signal listener).
sleep 1
pkill -10 -P $_pid
Expand Down Expand Up @@ -93,7 +98,7 @@ else
exit 1
fi

# make sure we won't stuck in non-scheduler state, even we send a SIGTERM to it.
# make sure we won't stuck in non-scheduler state, even we send a SIGTERM to it.
# give enough time to BR so it can gracefully stop.
sleep 5
if curl http://$PD_ADDR/pd/api/v1/config/schedule | jq '[."schedulers-v2"][0][0]' | grep -q '"disable": false'
Expand Down