forked from TrueCloudLab/frostfs-node
Move to frostfs-node
Signed-off-by: Pavel Karpy <p.karpy@yadro.com>
This commit is contained in:
parent
42554a9298
commit
923f84722a
934 changed files with 3470 additions and 3451 deletions
166
cmd/frostfs-adm/internal/modules/config/config.go
Normal file
166
cmd/frostfs-adm/internal/modules/config/config.go
Normal file
|
@ -0,0 +1,166 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
"github.com/TrueCloudLab/frostfs-node/pkg/innerring"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type configTemplate struct {
|
||||
Endpoint string
|
||||
AlphabetDir string
|
||||
MaxObjectSize int
|
||||
EpochDuration int
|
||||
BasicIncomeRate int
|
||||
AuditFee int
|
||||
CandidateFee int
|
||||
ContainerFee int
|
||||
ContainerAliasFee int
|
||||
WithdrawFee int
|
||||
Glagolitics []string
|
||||
HomomorphicHashDisabled bool
|
||||
}
|
||||
|
||||
const configTxtTemplate = `rpc-endpoint: {{ .Endpoint}}
|
||||
alphabet-wallets: {{ .AlphabetDir}}
|
||||
network:
|
||||
max_object_size: {{ .MaxObjectSize}}
|
||||
epoch_duration: {{ .EpochDuration}}
|
||||
basic_income_rate: {{ .BasicIncomeRate}}
|
||||
homomorphic_hash_disabled: {{ .HomomorphicHashDisabled}}
|
||||
fee:
|
||||
audit: {{ .AuditFee}}
|
||||
candidate: {{ .CandidateFee}}
|
||||
container: {{ .ContainerFee}}
|
||||
container_alias: {{ .ContainerAliasFee }}
|
||||
withdraw: {{ .WithdrawFee}}
|
||||
# if credentials section is omitted, then frostfs-adm will require manual password input
|
||||
credentials:
|
||||
contract: password # wallet for contract group signature{{ range.Glagolitics}}
|
||||
{{.}}: password{{end}}
|
||||
`
|
||||
|
||||
func initConfig(cmd *cobra.Command, args []string) error {
|
||||
configPath, err := readConfigPathFromArgs(cmd)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pathDir := filepath.Dir(configPath)
|
||||
err = os.MkdirAll(pathDir, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create dir %s: %w", pathDir, err)
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open %s: %w", configPath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
configText, err := generateConfigExample(pathDir, 7)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = f.WriteString(configText)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing to %s: %w", configPath, err)
|
||||
}
|
||||
|
||||
cmd.Printf("Initial config file saved to %s\n", configPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readConfigPathFromArgs(cmd *cobra.Command) (string, error) {
|
||||
configPath, err := cmd.Flags().GetString(configPathFlag)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if configPath != "" {
|
||||
return configPath, nil
|
||||
}
|
||||
|
||||
return defaultConfigPath()
|
||||
}
|
||||
|
||||
func defaultConfigPath() (string, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting home dir path: %w", err)
|
||||
}
|
||||
|
||||
return filepath.Join(home, ".frostfs", "adm", "config.yml"), nil
|
||||
}
|
||||
|
||||
// generateConfigExample builds .yml representation of the config file. It is
|
||||
// easier to build it manually with template instead of using viper, because we
|
||||
// want to order records in specific order in file and, probably, provide
|
||||
// some comments as well.
|
||||
func generateConfigExample(appDir string, credSize int) (string, error) {
|
||||
tmpl := configTemplate{
|
||||
Endpoint: "https://neo.rpc.node:30333",
|
||||
MaxObjectSize: 67108864, // 64 MiB
|
||||
EpochDuration: 240, // 1 hour with 15s per block
|
||||
BasicIncomeRate: 1_0000_0000, // 0.0001 GAS per GiB (Fixed12)
|
||||
HomomorphicHashDisabled: false, // object homomorphic hash is enabled
|
||||
AuditFee: 1_0000, // 0.00000001 GAS per audit (Fixed12)
|
||||
CandidateFee: 100_0000_0000, // 100.0 GAS (Fixed8)
|
||||
ContainerFee: 1000, // 0.000000001 * 7 GAS per container (Fixed12)
|
||||
ContainerAliasFee: 500, // ContainerFee / 2
|
||||
WithdrawFee: 1_0000_0000, // 1.0 GAS (Fixed8)
|
||||
Glagolitics: make([]string, 0, credSize),
|
||||
}
|
||||
|
||||
appDir, err := filepath.Abs(appDir)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("making absolute path for %s: %w", appDir, err)
|
||||
}
|
||||
tmpl.AlphabetDir = filepath.Join(appDir, "alphabet-wallets")
|
||||
|
||||
var i innerring.GlagoliticLetter
|
||||
for i = 0; i < innerring.GlagoliticLetter(credSize); i++ {
|
||||
tmpl.Glagolitics = append(tmpl.Glagolitics, i.String())
|
||||
}
|
||||
|
||||
t, err := template.New("config.yml").Parse(configTxtTemplate)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parsing config template: %w", err)
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
err = t.Execute(buf, tmpl)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("generating config from template: %w", err)
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func GetPassword(v *viper.Viper, name string) (string, error) {
|
||||
key := "credentials." + name
|
||||
if v.IsSet(key) {
|
||||
return v.GetString(key), nil
|
||||
}
|
||||
|
||||
prompt := "Password for " + name + " wallet > "
|
||||
return input.ReadPassword(prompt)
|
||||
}
|
||||
|
||||
func GetStoragePassword(v *viper.Viper, name string) (string, error) {
|
||||
key := "storage." + name
|
||||
if name != "" && v.IsSet(key) {
|
||||
return v.GetString(key), nil
|
||||
}
|
||||
return input.ReadPassword("New password > ")
|
||||
}
|
46
cmd/frostfs-adm/internal/modules/config/config_test.go
Normal file
46
cmd/frostfs-adm/internal/modules/config/config_test.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/TrueCloudLab/frostfs-node/pkg/innerring"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGenerateConfigExample(t *testing.T) {
|
||||
const (
|
||||
n = 10
|
||||
appDir = "/home/example/.frostfs"
|
||||
)
|
||||
|
||||
configText, err := generateConfigExample(appDir, n)
|
||||
require.NoError(t, err)
|
||||
|
||||
v := viper.New()
|
||||
v.SetConfigType("yml")
|
||||
|
||||
require.NoError(t, v.ReadConfig(bytes.NewBufferString(configText)))
|
||||
|
||||
require.Equal(t, "https://neo.rpc.node:30333", v.GetString("rpc-endpoint"))
|
||||
require.Equal(t, filepath.Join(appDir, "alphabet-wallets"), v.GetString("alphabet-wallets"))
|
||||
require.Equal(t, 67108864, v.GetInt("network.max_object_size"))
|
||||
require.Equal(t, 240, v.GetInt("network.epoch_duration"))
|
||||
require.Equal(t, 100000000, v.GetInt("network.basic_income_rate"))
|
||||
require.Equal(t, 10000, v.GetInt("network.fee.audit"))
|
||||
require.Equal(t, 10000000000, v.GetInt("network.fee.candidate"))
|
||||
require.Equal(t, 1000, v.GetInt("network.fee.container"))
|
||||
require.Equal(t, 100000000, v.GetInt("network.fee.withdraw"))
|
||||
|
||||
var i innerring.GlagoliticLetter
|
||||
for i = 0; i < innerring.GlagoliticLetter(n); i++ {
|
||||
key := "credentials." + i.String()
|
||||
require.Equal(t, "password", v.GetString(key))
|
||||
}
|
||||
require.Equal(t, "password", v.GetString("credentials.contract"))
|
||||
|
||||
key := "credentials." + i.String()
|
||||
require.Equal(t, "", v.GetString(key))
|
||||
}
|
29
cmd/frostfs-adm/internal/modules/config/root.go
Normal file
29
cmd/frostfs-adm/internal/modules/config/root.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const configPathFlag = "path"
|
||||
|
||||
var (
|
||||
// RootCmd is a root command of config section.
|
||||
RootCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Section for frostfs-adm config related commands",
|
||||
}
|
||||
|
||||
initCmd = &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize basic frostfs-adm configuration file",
|
||||
Example: `frostfs-adm config init
|
||||
frostfs-adm config init --path .config/frostfs-adm.yml`,
|
||||
RunE: initConfig,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(initCmd)
|
||||
|
||||
initCmd.Flags().String(configPathFlag, "", "Path to config (default ~/.frostfs/adm/config.yml)")
|
||||
}
|
24
cmd/frostfs-adm/internal/modules/config/util.go
Normal file
24
cmd/frostfs-adm/internal/modules/config/util.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ResolveHomePath replaces leading `~`
|
||||
// with home directory.
|
||||
//
|
||||
// Does nothing if path does not start
|
||||
// with contain `~`.
|
||||
func ResolveHomePath(path string) string {
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
|
||||
if path == "~" {
|
||||
path = homeDir
|
||||
} else if strings.HasPrefix(path, "~/") {
|
||||
path = filepath.Join(homeDir, path[2:])
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue