vspadmin: New binary to create empty databases.
vspadmin is a new binary which implements one-off admin tasks which are necessarily interactive and thus do not fit neatly into the long-lived vspd binary. The first behaviour added to vspadmin is the ability to create a new vspd database. This behaviour is removed from vspd with the associated config option deprecated. Documentation and scripts updated to reflect the change.
This commit is contained in:
parent
0633260a3c
commit
997205ed95
30
cmd/vspadmin/README.md
Normal file
30
cmd/vspadmin/README.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# vspadmin
|
||||||
|
|
||||||
|
vspadmin is a tool to perform various VSP administration tasks.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```no-highlight
|
||||||
|
vspadmin [OPTIONS] COMMAND
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
```no-highlight
|
||||||
|
--homedir= Path to application home directory. (default: /home/user/.vspd)
|
||||||
|
--network=[mainnet|testnet|simnet] Decred network to use. (default: mainnet)
|
||||||
|
-h, --help Show help message
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### `createdatabase`
|
||||||
|
|
||||||
|
Creates a new database for a new deployment of vspd. Accepts the xpub key to be
|
||||||
|
used for collecting fees as a parameter.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```no-highlight
|
||||||
|
go run ./cmd/vspadmin createdatabase <xpub>
|
||||||
|
```
|
||||||
130
cmd/vspadmin/main.go
Normal file
130
cmd/vspadmin/main.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// Copyright (c) 2024 The Decred developers
|
||||||
|
// Use of this source code is governed by an ISC
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/decred/dcrd/dcrutil/v4"
|
||||||
|
"github.com/decred/dcrd/hdkeychain/v3"
|
||||||
|
"github.com/decred/vspd/database"
|
||||||
|
"github.com/decred/vspd/internal/config"
|
||||||
|
"github.com/jessevdk/go-flags"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
dbFilename = "vspd.db"
|
||||||
|
)
|
||||||
|
|
||||||
|
type conf struct {
|
||||||
|
HomeDir string `long:"homedir" description:"Path to application home directory."`
|
||||||
|
Network string `long:"network" description:"Decred network to use." choice:"mainnet" choice:"testnet" choice:"simnet"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultConf = conf{
|
||||||
|
HomeDir: dcrutil.AppDataDir("vspd", false),
|
||||||
|
Network: "mainnet",
|
||||||
|
}
|
||||||
|
|
||||||
|
func log(format string, a ...any) {
|
||||||
|
fmt.Printf(format+"\n", a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileExists reports whether the named file or directory exists.
|
||||||
|
func fileExists(name string) bool {
|
||||||
|
if _, err := os.Stat(name); os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDatabase(homeDir string, feeXPub string, network *config.Network) error {
|
||||||
|
dataDir := filepath.Join(homeDir, "data", network.Name)
|
||||||
|
dbFile := filepath.Join(dataDir, dbFilename)
|
||||||
|
|
||||||
|
// Return error if database already exists.
|
||||||
|
if fileExists(dbFile) {
|
||||||
|
return fmt.Errorf("%s database already exists in %s", network.Name, dataDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure provided xpub is a valid key for the selected network.
|
||||||
|
_, err := hdkeychain.NewKeyFromString(feeXPub, network.Params)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse feexpub: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the data directory exists.
|
||||||
|
err = os.MkdirAll(dataDir, 0700)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create data directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new database.
|
||||||
|
err = database.CreateNew(dbFile, feeXPub)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating db file %s: %w", dbFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// run is the real main function for vspadmin. It is necessary to work around
|
||||||
|
// the fact that deferred functions do not run when os.Exit() is called.
|
||||||
|
func run() int {
|
||||||
|
cfg := defaultConf
|
||||||
|
|
||||||
|
// If command line options are requesting help, write it to stdout and exit.
|
||||||
|
if config.WriteHelp(&cfg) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse command line options.
|
||||||
|
remainingArgs, err := flags.Parse(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
// Don't need to log the error, flags lib has already done it.
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
network, err := config.NetworkFromName(cfg.Network)
|
||||||
|
if err != nil {
|
||||||
|
log("%v", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(remainingArgs) < 1 {
|
||||||
|
log("No command specified")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
switch remainingArgs[0] {
|
||||||
|
case "createdatabase":
|
||||||
|
if len(remainingArgs) != 2 {
|
||||||
|
log("createdatabase has one required argument, fee xpub")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
feeXPub := remainingArgs[1]
|
||||||
|
|
||||||
|
err = createDatabase(cfg.HomeDir, feeXPub, network)
|
||||||
|
if err != nil {
|
||||||
|
log("createdatabase failed: %v", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log("New %s vspd database created in %s", network.Name, cfg.HomeDir)
|
||||||
|
|
||||||
|
default:
|
||||||
|
log("%q is not a valid command", remainingArgs[0])
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
os.Exit(run())
|
||||||
|
}
|
||||||
@ -102,6 +102,12 @@ func run() int {
|
|||||||
log.Warnf("")
|
log.Warnf("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.FeeXPub != "" {
|
||||||
|
log.Warnf("")
|
||||||
|
log.Warnf("\tWARNING: Config --feexpub is set. This behavior has been moved into vspadmin and will be removed from vspd in a future release")
|
||||||
|
log.Warnf("")
|
||||||
|
}
|
||||||
|
|
||||||
// Open database.
|
// Open database.
|
||||||
db, err := database.Open(cfg.DatabaseFile(), makeLogger(" DB"), maxVoteChangeRecords)
|
db, err := database.Open(cfg.DatabaseFile(), makeLogger(" DB"), maxVoteChangeRecords)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -96,15 +96,14 @@ vspd. **Do not run a voting wallet on your webserver.**
|
|||||||
config file to set your dcrd and dcrwallet connection details, and any other
|
config file to set your dcrd and dcrwallet connection details, and any other
|
||||||
required customization.
|
required customization.
|
||||||
|
|
||||||
1. A vspd database must be initialized before vpsd can be started. To do this,
|
1. Use [vspadmin](./cmd/vspadmin) to initialize a vpsd database. The xpub key to
|
||||||
provide vspd with the xpub key it should use for collecting fees:
|
be used for collecting fees must be passed in as an argument.
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
$ vspd --feexpub=tpubVppjaMjp8GEW...
|
$ go run ./cmd/vspadmin createdatabase tpubVppjaMjp8GEW...
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Once the database is initialized, vspd can be started for normal operation by
|
1. Once the database is initialized, vspd can be started for normal operation.
|
||||||
running it without the `--feexpub` flag.
|
|
||||||
|
|
||||||
1. Configure nginx with SSL and set up reverse proxy to forward requests to the
|
1. Configure nginx with SSL and set up reverse proxy to forward requests to the
|
||||||
vspd process. nginx must also set the `X-Forwarded-For` header to make vspd
|
vspd process. nginx must also set the `X-Forwarded-For` header to make vspd
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# Copyright (c) 2020-2023 The Decred developers
|
# Copyright (c) 2020-2024 The Decred developers
|
||||||
# Use of this source code is governed by an ISC
|
# Use of this source code is governed by an ISC
|
||||||
# license that can be found in the LICENSE file.
|
# license that can be found in the LICENSE file.
|
||||||
#
|
#
|
||||||
@ -170,7 +170,7 @@ EOF
|
|||||||
tmux new-window -t $TMUX_SESSION -n "vspd"
|
tmux new-window -t $TMUX_SESSION -n "vspd"
|
||||||
|
|
||||||
echo "Creating vspd database"
|
echo "Creating vspd database"
|
||||||
tmux send-keys "vspd --homedir=${HARNESS_ROOT}/vspd --feexpub=${VSPD_FEE_XPUB}" C-m
|
tmux send-keys "go run ./cmd/vspadmin --homedir=${HARNESS_ROOT}/vspd --network=testnet createdatabase ${VSPD_FEE_XPUB}" C-m
|
||||||
sleep 3 # wait for database creation and ensure dcrwallet rpc listeners are started
|
sleep 3 # wait for database creation and ensure dcrwallet rpc listeners are started
|
||||||
echo "Starting vspd"
|
echo "Starting vspd"
|
||||||
tmux send-keys "vspd --homedir=${HARNESS_ROOT}/vspd" C-m
|
tmux send-keys "vspd --homedir=${HARNESS_ROOT}/vspd" C-m
|
||||||
|
|||||||
@ -17,8 +17,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/decred/dcrd/dcrutil/v4"
|
"github.com/decred/dcrd/dcrutil/v4"
|
||||||
"github.com/decred/dcrd/hdkeychain/v3"
|
|
||||||
"github.com/decred/vspd/database"
|
|
||||||
"github.com/decred/vspd/internal/config"
|
"github.com/decred/vspd/internal/config"
|
||||||
"github.com/decred/vspd/internal/version"
|
"github.com/decred/vspd/internal/version"
|
||||||
flags "github.com/jessevdk/go-flags"
|
flags "github.com/jessevdk/go-flags"
|
||||||
@ -55,12 +53,11 @@ type Config struct {
|
|||||||
|
|
||||||
// The following flags should be set on CLI only, not via config file.
|
// The following flags should be set on CLI only, not via config file.
|
||||||
ShowVersion bool `long:"version" no-ini:"true" description:"Display version information and exit."`
|
ShowVersion bool `long:"version" no-ini:"true" description:"Display version information and exit."`
|
||||||
FeeXPub string `long:"feexpub" no-ini:"true" description:"Cold wallet xpub used for collecting fees. Should be provided once to initialize a vspd database."`
|
FeeXPub string `long:"feexpub" no-ini:"true" description:"DEPRECATED: This behavior has been moved into vspadmin and will be removed from vspd in a future version of the software."`
|
||||||
HomeDir string `long:"homedir" no-ini:"true" description:"Path to application home directory. Used for storing VSP database and logs."`
|
HomeDir string `long:"homedir" no-ini:"true" description:"Path to application home directory. Used for storing VSP database and logs."`
|
||||||
ConfigFile string `long:"configfile" no-ini:"true" description:"DEPRECATED: This behavior is no longer available and this option will be removed in a future version of the software."`
|
ConfigFile string `long:"configfile" no-ini:"true" description:"DEPRECATED: This behavior is no longer available and this option will be removed in a future version of the software."`
|
||||||
|
|
||||||
// The following fields are derived from the above fields by LoadConfig().
|
// The following fields are derived from the above fields by LoadConfig().
|
||||||
dataDir string
|
|
||||||
network *config.Network
|
network *config.Network
|
||||||
dcrdDetails *DcrdDetails
|
dcrdDetails *DcrdDetails
|
||||||
walletDetails *WalletDetails
|
walletDetails *WalletDetails
|
||||||
@ -89,7 +86,7 @@ func (cfg *Config) LogDir() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) DatabaseFile() string {
|
func (cfg *Config) DatabaseFile() string {
|
||||||
return filepath.Join(cfg.dataDir, dbFilename)
|
return filepath.Join(cfg.HomeDir, "data", cfg.network.Name, dbFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) DcrdDetails() *DcrdDetails {
|
func (cfg *Config) DcrdDetails() *DcrdDetails {
|
||||||
@ -420,45 +417,10 @@ func LoadConfig() (*Config, error) {
|
|||||||
Certs: walletCerts,
|
Certs: walletCerts,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the data directory.
|
|
||||||
cfg.dataDir = filepath.Join(cfg.HomeDir, "data", cfg.network.Name)
|
|
||||||
err = os.MkdirAll(cfg.dataDir, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create data directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dbPath := cfg.DatabaseFile()
|
|
||||||
|
|
||||||
// If xpub has been provided, create a new database and exit.
|
|
||||||
if cfg.FeeXPub != "" {
|
|
||||||
// If database already exists, return error.
|
|
||||||
if fileExists(dbPath) {
|
|
||||||
return nil, fmt.Errorf("database already initialized at %s, "+
|
|
||||||
"--feexpub option is not needed", dbPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure provided value is a valid key for the selected network.
|
|
||||||
_, err = hdkeychain.NewKeyFromString(cfg.FeeXPub, cfg.network.Params)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse feexpub: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new database.
|
|
||||||
fmt.Printf("Initializing new database at %s\n", dbPath)
|
|
||||||
err = database.CreateNew(dbPath, cfg.FeeXPub)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error creating db file %s: %w", dbPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit with success
|
|
||||||
fmt.Printf("Database initialized\n")
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If database does not exist, return error.
|
// If database does not exist, return error.
|
||||||
if !fileExists(dbPath) {
|
if !fileExists(cfg.DatabaseFile()) {
|
||||||
return nil, fmt.Errorf("no database exists in %s. Run vspd with the"+
|
return nil, fmt.Errorf("no %s database exists in %s. A new database can"+
|
||||||
" --feexpub option to initialize one", cfg.dataDir)
|
" be created with vspadmin", cfg.network.Name, cfg.HomeDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user