go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/dbadmin/main.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  	"regexp"
     6  
     7  	"go.etcd.io/bbolt"
     8  
     9  	"github.com/urfave/cli"
    10  	"go.dedis.ch/onet/v3/log"
    11  	"golang.org/x/xerrors"
    12  )
    13  
    14  func main() {
    15  	cliApp := cli.NewApp()
    16  	cliApp.Name = "dbadmin"
    17  	cliApp.Usage = "work with onet service dbs"
    18  	cliApp.Version = "0.1"
    19  	cliApp.Commands = cli.Commands{
    20  		{
    21  			Name:      "inspect",
    22  			Usage:     "print information about an existing db",
    23  			Action:    inspect,
    24  			ArgsUsage: "source.db",
    25  			Flags: cli.FlagsByName{
    26  				cli.StringFlag{
    27  					Name:      "source,src",
    28  					Usage:     "Indicate source database",
    29  					Required:  false,
    30  					TakesFile: true,
    31  				},
    32  				cli.BoolFlag{
    33  					Name:  "verbose,v",
    34  					Usage: "print additional information",
    35  				},
    36  			},
    37  		},
    38  		{
    39  			Name:      "extract",
    40  			Usage:     "extract information from one db",
    41  			Action:    extract,
    42  			ArgsUsage: "service1 [service2 [service3...]]",
    43  			Flags: cli.FlagsByName{
    44  				cli.StringFlag{
    45  					Name:      "source,src",
    46  					Usage:     "Indicate source database",
    47  					Required:  true,
    48  					TakesFile: true,
    49  				},
    50  				cli.StringFlag{
    51  					Name: "destination,dst",
    52  					Usage: "Indicate destination database - must not" +
    53  						" exist yet",
    54  					Required:  true,
    55  					TakesFile: true,
    56  				},
    57  				cli.BoolFlag{
    58  					Name: "overwrite",
    59  					Usage: "allow overwriting of existing dbs and" +
    60  						" buckets",
    61  					Required: false,
    62  				},
    63  			},
    64  		},
    65  	}
    66  	cliApp.Flags = []cli.Flag{
    67  		cli.IntFlag{
    68  			Name:  "debug, d",
    69  			Value: 0,
    70  			Usage: "debug-level: 1 for terse, 5 for maximal",
    71  		},
    72  	}
    73  	cliApp.Before = func(c *cli.Context) error {
    74  		log.SetDebugVisible(c.Int("debug"))
    75  		return nil
    76  	}
    77  
    78  	err := cliApp.Run(os.Args)
    79  	if err != nil {
    80  		log.Fatalf("Error while running app: %+v", err)
    81  	}
    82  }
    83  
    84  func inspect(c *cli.Context) error {
    85  	var dbName string
    86  	if c.NArg() != 1 {
    87  		if c.String("source") == "" {
    88  			return xerrors.New("Please give the following arguments: source.db")
    89  		}
    90  		dbName = c.String("source")
    91  	} else {
    92  		dbName = c.Args().First()
    93  	}
    94  	verbose := c.Bool("verbose")
    95  	if _, err := os.Stat(dbName); os.IsNotExist(err) {
    96  		return xerrors.New("this db doesn't exist")
    97  	}
    98  	db, err := bbolt.Open(dbName, 0600, nil)
    99  	if err != nil {
   100  		return xerrors.Errorf("opening db: %v", err)
   101  	}
   102  
   103  	log.Info("Opened", dbName)
   104  
   105  	err = db.View(func(tx *bbolt.Tx) error {
   106  		return tx.ForEach(func(name []byte, b *bbolt.Bucket) error {
   107  			log.Info("Bucket:", string(name))
   108  			if verbose {
   109  				stats := b.Stats()
   110  				log.Infof("Has %d entries using %d bytes", stats.KeyN,
   111  					stats.LeafAlloc)
   112  			}
   113  			return nil
   114  		})
   115  	})
   116  	if err != nil {
   117  		return xerrors.Errorf("couldn't list buckets: %+v", err)
   118  	}
   119  
   120  	return nil
   121  }
   122  
   123  func extract(c *cli.Context) error {
   124  	var buckets []*regexp.Regexp
   125  	if c.NArg() == 0 {
   126  		log.Info("No service given - copying all services")
   127  		buckets = append(buckets, regexp.MustCompile(".*"))
   128  	} else {
   129  		for _, b := range c.Args() {
   130  			buckets = append(buckets, regexp.MustCompile(b))
   131  		}
   132  	}
   133  
   134  	overwrite := c.Bool("overwrite")
   135  	srcName := c.String("source")
   136  	dstName := c.String("destination")
   137  	if _, err := os.Stat(srcName); err != nil {
   138  		return xerrors.Errorf("cannot read '%s': %v", srcName, err)
   139  	}
   140  	if _, err := os.Stat(dstName); err == nil && !overwrite {
   141  		return xerrors.Errorf("destination '%s' will be created, "+
   142  			"please remove it first", dstName)
   143  	}
   144  
   145  	dbSrc, err := bbolt.Open(srcName, 0600, nil)
   146  	if err != nil {
   147  		return xerrors.Errorf("couldn't open source-DB: %v", err)
   148  	}
   149  	dbDst, err := bbolt.Open(dstName, 0600, nil)
   150  	if err != nil {
   151  		return xerrors.Errorf("couldn't open destination-DB: %v", err)
   152  	}
   153  
   154  	err = dbSrc.View(func(txSrc *bbolt.Tx) error {
   155  		return dbDst.Update(func(txDest *bbolt.Tx) error {
   156  			return txSrc.ForEach(func(name []byte, bSrc *bbolt.Bucket) error {
   157  				extr := false
   158  				for _, b := range buckets {
   159  					if b.Match(name) {
   160  						extr = true
   161  						break
   162  					}
   163  				}
   164  				if extr {
   165  					log.Info("Extracting bucket:", string(name))
   166  					bDst, err := txDest.CreateBucket(name)
   167  					if err != nil {
   168  						return xerrors.Errorf("couldn't create bucket: %v", err)
   169  					}
   170  					return bSrc.ForEach(func(k, v []byte) error {
   171  						return bDst.Put(k, v)
   172  					})
   173  				}
   174  				return nil
   175  			})
   176  		})
   177  	})
   178  	if err != nil {
   179  		return xerrors.Errorf("error while copying: %v", err)
   180  	}
   181  	if err := dbSrc.Close(); err != nil {
   182  		return xerrors.Errorf("couldn't close source DB: %v", err)
   183  	}
   184  	if err := dbDst.Close(); err != nil {
   185  		return xerrors.Errorf("couldn't close destination DB: %v", err)
   186  	}
   187  	return nil
   188  }