227 lines
5.5 KiB
Go
227 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
"github.com/urfave/cli/v2"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
|
|
"github.com/filecoin-project/lotus/node/config"
|
|
)
|
|
|
|
var configCmd = &cli.Command{
|
|
Name: "config",
|
|
Usage: "Manage node config by layers. The layer 'base' will always be applied. ",
|
|
Subcommands: []*cli.Command{
|
|
configDefaultCmd,
|
|
configSetCmd,
|
|
configGetCmd,
|
|
configListCmd,
|
|
configViewCmd,
|
|
configRmCmd,
|
|
configMigrateCmd,
|
|
},
|
|
}
|
|
|
|
var configDefaultCmd = &cli.Command{
|
|
Name: "default",
|
|
Aliases: []string{"defaults"},
|
|
Usage: "Print default node config",
|
|
Flags: []cli.Flag{
|
|
&cli.BoolFlag{
|
|
Name: "no-comment",
|
|
Usage: "don't comment default values",
|
|
},
|
|
},
|
|
Action: func(cctx *cli.Context) error {
|
|
comment := !cctx.Bool("no-comment")
|
|
cfg, err := getDefaultConfig(comment)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Print(cfg)
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func getDefaultConfig(comment bool) (string, error) {
|
|
c := config.DefaultLotusProvider()
|
|
cb, err := config.ConfigUpdate(c, nil, config.Commented(comment), config.DefaultKeepUncommented(), config.NoEnv())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(cb), nil
|
|
}
|
|
|
|
var configSetCmd = &cli.Command{
|
|
Name: "set",
|
|
Aliases: []string{"add", "update", "create"},
|
|
Usage: "Set a config layer or the base by providing a filename or stdin.",
|
|
ArgsUsage: "a layer's file name",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "title",
|
|
Usage: "title of the config layer (req'd for stdin)",
|
|
},
|
|
},
|
|
Action: func(cctx *cli.Context) error {
|
|
args := cctx.Args()
|
|
|
|
db, err := deps.MakeDB(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
name := cctx.String("title")
|
|
var stream io.Reader = os.Stdin
|
|
if args.Len() != 1 {
|
|
if cctx.String("title") == "" {
|
|
return errors.New("must have a title for stdin, or a file name")
|
|
}
|
|
} else {
|
|
stream, err = os.Open(args.First())
|
|
if err != nil {
|
|
return fmt.Errorf("cannot open file %s: %w", args.First(), err)
|
|
}
|
|
if name == "" {
|
|
name = strings.Split(path.Base(args.First()), ".")[0]
|
|
}
|
|
}
|
|
bytes, err := io.ReadAll(stream)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot read stream/file %w", err)
|
|
}
|
|
|
|
lp := config.DefaultLotusProvider() // ensure it's toml
|
|
_, err = toml.Decode(string(bytes), lp)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot decode file: %w", err)
|
|
}
|
|
_ = lp
|
|
|
|
_, err = db.Exec(context.Background(),
|
|
`INSERT INTO harmony_config (title, config) VALUES ($1, $2)
|
|
ON CONFLICT (title) DO UPDATE SET config = excluded.config`, name, string(bytes))
|
|
if err != nil {
|
|
return fmt.Errorf("unable to save config layer: %w", err)
|
|
}
|
|
|
|
fmt.Println("Layer " + name + " created/updated")
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var configGetCmd = &cli.Command{
|
|
Name: "get",
|
|
Aliases: []string{"cat", "show"},
|
|
Usage: "Get a config layer by name. You may want to pipe the output to a file, or use 'less'",
|
|
ArgsUsage: "layer name",
|
|
Action: func(cctx *cli.Context) error {
|
|
args := cctx.Args()
|
|
if args.Len() != 1 {
|
|
return fmt.Errorf("want 1 layer arg, got %d", args.Len())
|
|
}
|
|
db, err := deps.MakeDB(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var cfg string
|
|
err = db.QueryRow(context.Background(), `SELECT config FROM harmony_config WHERE title=$1`, args.First()).Scan(&cfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println(cfg)
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var configListCmd = &cli.Command{
|
|
Name: "list",
|
|
Aliases: []string{"ls"},
|
|
Usage: "List config layers you can get.",
|
|
Flags: []cli.Flag{},
|
|
Action: func(cctx *cli.Context) error {
|
|
db, err := deps.MakeDB(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var res []string
|
|
err = db.Select(context.Background(), &res, `SELECT title FROM harmony_config ORDER BY title`)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read from db: %w", err)
|
|
}
|
|
for _, r := range res {
|
|
fmt.Println(r)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var configRmCmd = &cli.Command{
|
|
Name: "remove",
|
|
Aliases: []string{"rm", "del", "delete"},
|
|
Usage: "Remove a named config layer.",
|
|
Flags: []cli.Flag{},
|
|
Action: func(cctx *cli.Context) error {
|
|
args := cctx.Args()
|
|
if args.Len() != 1 {
|
|
return errors.New("must have exactly 1 arg for the layer name")
|
|
}
|
|
db, err := deps.MakeDB(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ct, err := db.Exec(context.Background(), `DELETE FROM harmony_config WHERE title=$1`, args.First())
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read from db: %w", err)
|
|
}
|
|
if ct == 0 {
|
|
return fmt.Errorf("no layer named %s", args.First())
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
var configViewCmd = &cli.Command{
|
|
Name: "interpret",
|
|
Aliases: []string{"view", "stacked", "stack"},
|
|
Usage: "Interpret stacked config layers by this version of lotus-provider, with system-generated comments.",
|
|
ArgsUsage: "a list of layers to be interpreted as the final config",
|
|
Flags: []cli.Flag{
|
|
&cli.StringSliceFlag{
|
|
Name: "layers",
|
|
Usage: "comma or space separated list of layers to be interpreted",
|
|
Value: cli.NewStringSlice("base"),
|
|
Required: true,
|
|
},
|
|
},
|
|
Action: func(cctx *cli.Context) error {
|
|
db, err := deps.MakeDB(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lp, err := deps.GetConfig(cctx, db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cb, err := config.ConfigUpdate(lp, config.DefaultLotusProvider(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv())
|
|
if err != nil {
|
|
return xerrors.Errorf("cannot interpret config: %w", err)
|
|
}
|
|
fmt.Println(string(cb))
|
|
return nil
|
|
},
|
|
}
|