From ee4d174af2474f0d8e4c1165ee0ea3ae30cb78e3 Mon Sep 17 00:00:00 2001 From: Anton Nikiforov Date: Wed, 14 Feb 2024 08:58:43 +0300 Subject: [PATCH] [#932] adm: Add commands to manipulate with `NNS` contract Signed-off-by: Anton Nikiforov --- .../internal/modules/morph/ape/ape_util.go | 10 +- .../modules/morph/helper/initialize.go | 12 ++ .../internal/modules/morph/nns/helper.go | 28 ++++ .../internal/modules/morph/nns/record.go | 148 ++++++++++++++++++ .../internal/modules/morph/nns/register.go | 44 ++++++ .../internal/modules/morph/nns/renew.go | 26 +++ .../internal/modules/morph/nns/root.go | 101 ++++++++++++ .../internal/modules/morph/nns/tokens.go | 24 +++ .../internal/modules/morph/nns/update.go | 50 ++++++ .../internal/modules/morph/root.go | 2 + 10 files changed, 436 insertions(+), 9 deletions(-) create mode 100644 cmd/frostfs-adm/internal/modules/morph/nns/helper.go create mode 100644 cmd/frostfs-adm/internal/modules/morph/nns/record.go create mode 100644 cmd/frostfs-adm/internal/modules/morph/nns/register.go create mode 100644 cmd/frostfs-adm/internal/modules/morph/nns/renew.go create mode 100644 cmd/frostfs-adm/internal/modules/morph/nns/root.go create mode 100644 cmd/frostfs-adm/internal/modules/morph/nns/tokens.go create mode 100644 cmd/frostfs-adm/internal/modules/morph/nns/update.go diff --git a/cmd/frostfs-adm/internal/modules/morph/ape/ape_util.go b/cmd/frostfs-adm/internal/modules/morph/ape/ape_util.go index fe09776ed..dccd8909f 100644 --- a/cmd/frostfs-adm/internal/modules/morph/ape/ape_util.go +++ b/cmd/frostfs-adm/internal/modules/morph/ape/ape_util.go @@ -4,8 +4,6 @@ import ( "fmt" "strings" - "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" - "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/config" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper" parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util" @@ -91,13 +89,7 @@ func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *ac c, err := helper.GetN3Client(v) commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err) - walletDir := config.ResolveHomePath(viper.GetString(commonflags.AlphabetWalletsFlag)) - wallets, err := helper.GetAlphabetWallets(v, walletDir) - commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err) - - committeeAcc, err := helper.GetWalletAccount(wallets[0], constants.CommitteeAccountName) - commonCmd.ExitOnErr(cmd, "can't find committee account: %w", err) - + committeeAcc := helper.GetComitteAcc(cmd, v) ac, err := helper.NewActor(c, committeeAcc) commonCmd.ExitOnErr(cmd, "can't create actor: %w", err) diff --git a/cmd/frostfs-adm/internal/modules/morph/helper/initialize.go b/cmd/frostfs-adm/internal/modules/morph/helper/initialize.go index 00c2fae6d..961ceba53 100644 --- a/cmd/frostfs-adm/internal/modules/morph/helper/initialize.go +++ b/cmd/frostfs-adm/internal/modules/morph/helper/initialize.go @@ -7,7 +7,9 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-contract/nns" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/config" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants" + commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/encoding/address" @@ -101,6 +103,16 @@ func GetWalletAccount(w *wallet.Wallet, typ string) (*wallet.Account, error) { return nil, fmt.Errorf("account for '%s' not found", typ) } +func GetComitteAcc(cmd *cobra.Command, v *viper.Viper) *wallet.Account { + walletDir := config.ResolveHomePath(viper.GetString(commonflags.AlphabetWalletsFlag)) + wallets, err := GetAlphabetWallets(v, walletDir) + commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err) + + committeeAcc, err := GetWalletAccount(wallets[0], constants.CommitteeAccountName) + commonCmd.ExitOnErr(cmd, "can't find committee account: %w", err) + return committeeAcc +} + func NNSResolve(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (stackitem.Item, error) { return unwrap.Item(inv.Call(nnsHash, "resolve", domain, int64(nns.TXT))) } diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/helper.go b/cmd/frostfs-adm/internal/modules/morph/nns/helper.go new file mode 100644 index 000000000..4c9c9e576 --- /dev/null +++ b/cmd/frostfs-adm/internal/modules/morph/nns/helper.go @@ -0,0 +1,28 @@ +package nns + +import ( + client "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/nns" + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper" + commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/management" + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func getRPCClient(cmd *cobra.Command) (*client.Contract, *actor.Actor, util.Uint160) { + v := viper.GetViper() + c, err := helper.GetN3Client(v) + commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err) + + committeeAcc := helper.GetComitteAcc(cmd, v) + ac, err := helper.NewActor(c, committeeAcc) + commonCmd.ExitOnErr(cmd, "can't create actor: %w", err) + + inv := &ac.Invoker + r := management.NewReader(inv) + nnsCs, err := r.GetContractByID(1) + commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err) + return client.New(ac, nnsCs.Hash), ac, nnsCs.Hash +} diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/record.go b/cmd/frostfs-adm/internal/modules/morph/nns/record.go new file mode 100644 index 000000000..0e217eb61 --- /dev/null +++ b/cmd/frostfs-adm/internal/modules/morph/nns/record.go @@ -0,0 +1,148 @@ +package nns + +import ( + "errors" + "math/big" + "strings" + + "git.frostfs.info/TrueCloudLab/frostfs-contract/nns" + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" + commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "github.com/spf13/cobra" +) + +func initAddRecordCmd() { + Cmd.AddCommand(addRecordCmd) + addRecordCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc) + addRecordCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc) + addRecordCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc) + addRecordCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc) + addRecordCmd.Flags().String(nnsRecordDataFlag, "", nnsRecordDataFlagDesc) + + _ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsNameFlag) + _ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsRecordTypeFlag) + _ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsRecordDataFlag) +} + +func initGetRecordsCmd() { + Cmd.AddCommand(getRecordsCmd) + getRecordsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc) + getRecordsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc) + getRecordsCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc) + getRecordsCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc) + + _ = cobra.MarkFlagRequired(getRecordsCmd.Flags(), nnsNameFlag) +} + +func initDelRecordsCmd() { + Cmd.AddCommand(delRecordsCmd) + delRecordsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc) + delRecordsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc) + delRecordsCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc) + delRecordsCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc) + + _ = cobra.MarkFlagRequired(delRecordsCmd.Flags(), nnsNameFlag) + _ = cobra.MarkFlagRequired(delRecordsCmd.Flags(), nnsRecordTypeFlag) +} + +func addRecord(cmd *cobra.Command, _ []string) { + c, actor, _ := getRPCClient(cmd) + name, _ := cmd.Flags().GetString(nnsNameFlag) + data, _ := cmd.Flags().GetString(nnsRecordDataFlag) + recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag) + typ, err := getRecordType(recordType) + commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err) + h, vub, err := c.AddRecord(name, typ, data) + commonCmd.ExitOnErr(cmd, "unable to add record: %w", err) + + cmd.Println("Waiting for transaction to persist...") + _, err = actor.Wait(h, vub, err) + commonCmd.ExitOnErr(cmd, "renew domain error: %w", err) + cmd.Println("Record added successfully") +} + +func getRecords(cmd *cobra.Command, _ []string) { + c, act, hash := getRPCClient(cmd) + name, _ := cmd.Flags().GetString(nnsNameFlag) + recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag) + if recordType == "" { + sid, r, err := unwrap.SessionIterator(act.Invoker.Call(hash, "getAllRecords", name)) + commonCmd.ExitOnErr(cmd, "unable to get records: %w", err) + defer func() { + _ = act.Invoker.TerminateSession(sid) + }() + items, err := act.Invoker.TraverseIterator(sid, &r, 0) + commonCmd.ExitOnErr(cmd, "unable to get records: %w", err) + for len(items) != 0 { + for j := range items { + rs := items[j].Value().([]stackitem.Item) + bs, err := rs[2].TryBytes() + commonCmd.ExitOnErr(cmd, "unable to parse record state: %w", err) + cmd.Printf("%s %s\n", + recordTypeToString(nns.RecordType(rs[1].Value().(*big.Int).Int64())), + string(bs)) + } + items, err = act.Invoker.TraverseIterator(sid, &r, 0) + commonCmd.ExitOnErr(cmd, "unable to get records: %w", err) + } + } else { + typ, err := getRecordType(recordType) + commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err) + items, err := c.GetRecords(name, typ) + commonCmd.ExitOnErr(cmd, "unable to get records: %w", err) + for _, item := range items { + record, err := item.TryBytes() + commonCmd.ExitOnErr(cmd, "unable to parse response: %w", err) + cmd.Println(string(record)) + } + } +} + +func delRecords(cmd *cobra.Command, _ []string) { + c, actor, _ := getRPCClient(cmd) + name, _ := cmd.Flags().GetString(nnsNameFlag) + recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag) + typ, err := getRecordType(recordType) + commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err) + h, vub, err := c.DeleteRecords(name, typ) + commonCmd.ExitOnErr(cmd, "unable to delete records: %w", err) + + cmd.Println("Waiting for transaction to persist...") + _, err = actor.Wait(h, vub, err) + commonCmd.ExitOnErr(cmd, "delete records error: %w", err) + cmd.Println("Records removed successfully") +} + +func getRecordType(recordType string) (*big.Int, error) { + switch strings.ToUpper(recordType) { + case "A": + return big.NewInt(int64(nns.A)), nil + case "CNAME": + return big.NewInt(int64(nns.CNAME)), nil + case "SOA": + return big.NewInt(int64(nns.SOA)), nil + case "TXT": + return big.NewInt(int64(nns.TXT)), nil + case "AAAA": + return big.NewInt(int64(nns.AAAA)), nil + } + return nil, errors.New("unsupported record type") +} + +func recordTypeToString(rt nns.RecordType) string { + switch rt { + case nns.A: + return "A" + case nns.CNAME: + return "CNAME" + case nns.SOA: + return "SOA" + case nns.TXT: + return "TXT" + case nns.AAAA: + return "AAAA" + } + return "" +} diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/register.go b/cmd/frostfs-adm/internal/modules/morph/nns/register.go new file mode 100644 index 000000000..d05d9f171 --- /dev/null +++ b/cmd/frostfs-adm/internal/modules/morph/nns/register.go @@ -0,0 +1,44 @@ +package nns + +import ( + "math/big" + + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants" + commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" + "github.com/spf13/cobra" +) + +func initRegisterCmd() { + Cmd.AddCommand(registerCmd) + registerCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc) + registerCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc) + registerCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc) + registerCmd.Flags().String(nnsEmailFlag, constants.FrostfsOpsEmail, "Domain owner email") + registerCmd.Flags().Int64(nnsRefreshFlag, constants.NNSRefreshDefVal, "SOA record REFRESH parameter") + registerCmd.Flags().Int64(nnsRetryFlag, constants.NNSRetryDefVal, "SOA record RETRY parameter") + registerCmd.Flags().Int64(nnsExpireFlag, int64(constants.DefaultExpirationTime), "SOA record EXPIRE parameter") + registerCmd.Flags().Int64(nnsTTLFlag, constants.NNSTtlDefVal, "SOA record TTL parameter") + + _ = cobra.MarkFlagRequired(registerCmd.Flags(), nnsNameFlag) +} + +func registerDomain(cmd *cobra.Command, _ []string) { + c, actor, _ := getRPCClient(cmd) + + name, _ := cmd.Flags().GetString(nnsNameFlag) + email, _ := cmd.Flags().GetString(nnsEmailFlag) + refresh, _ := cmd.Flags().GetInt64(nnsRefreshFlag) + retry, _ := cmd.Flags().GetInt64(nnsRetryFlag) + expire, _ := cmd.Flags().GetInt64(nnsExpireFlag) + ttl, _ := cmd.Flags().GetInt64(nnsTTLFlag) + + h, vub, err := c.Register(name, actor.Sender(), email, big.NewInt(refresh), + big.NewInt(retry), big.NewInt(expire), big.NewInt(ttl)) + commonCmd.ExitOnErr(cmd, "unable to register domain: %w", err) + + cmd.Println("Waiting for transaction to persist...") + _, err = actor.Wait(h, vub, err) + commonCmd.ExitOnErr(cmd, "register domain error: %w", err) + cmd.Println("Domain registered successfully") +} diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/renew.go b/cmd/frostfs-adm/internal/modules/morph/nns/renew.go new file mode 100644 index 000000000..b13092240 --- /dev/null +++ b/cmd/frostfs-adm/internal/modules/morph/nns/renew.go @@ -0,0 +1,26 @@ +package nns + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" + commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" + "github.com/spf13/cobra" +) + +func initRenewCmd() { + Cmd.AddCommand(renewCmd) + renewCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc) + renewCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc) + renewCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc) +} + +func renewDomain(cmd *cobra.Command, _ []string) { + c, actor, _ := getRPCClient(cmd) + name, _ := cmd.Flags().GetString(nnsNameFlag) + h, vub, err := c.Renew(name) + commonCmd.ExitOnErr(cmd, "unable to renew domain: %w", err) + + cmd.Println("Waiting for transaction to persist...") + _, err = actor.Wait(h, vub, err) + commonCmd.ExitOnErr(cmd, "renew domain error: %w", err) + cmd.Println("Domain renewed successfully") +} diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/root.go b/cmd/frostfs-adm/internal/modules/morph/nns/root.go new file mode 100644 index 000000000..09133f932 --- /dev/null +++ b/cmd/frostfs-adm/internal/modules/morph/nns/root.go @@ -0,0 +1,101 @@ +package nns + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +const ( + nnsNameFlag = "name" + nnsNameFlagDesc = "Domain name" + nnsEmailFlag = "email" + nnsRefreshFlag = "refresh" + nnsRetryFlag = "retry" + nnsExpireFlag = "expire" + nnsTTLFlag = "ttl" + nnsRecordTypeFlag = "type" + nnsRecordTypeFlagDesc = "Domain name service record type(A|CNAME|SOA|TXT)" + nnsRecordDataFlag = "data" + nnsRecordDataFlagDesc = "Domain name service record data" +) + +var ( + Cmd = &cobra.Command{ + Use: "nns", + Short: "Section for Neo Name Service (NNS)", + } + tokensCmd = &cobra.Command{ + Use: "tokens", + Short: "List all registered domain names", + PreRun: func(cmd *cobra.Command, _ []string) { + _ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag)) + _ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag)) + }, + Run: listTokens, + } + registerCmd = &cobra.Command{ + Use: "register", + Short: "Registers a new domain", + PreRun: func(cmd *cobra.Command, _ []string) { + _ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag)) + _ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag)) + }, + Run: registerDomain, + } + renewCmd = &cobra.Command{ + Use: "renew", + Short: "Increases domain expiration date", + PreRun: func(cmd *cobra.Command, _ []string) { + _ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag)) + _ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag)) + }, + Run: renewDomain, + } + updateCmd = &cobra.Command{ + Use: "update", + Short: "Updates soa record", + PreRun: func(cmd *cobra.Command, _ []string) { + _ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag)) + _ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag)) + }, + Run: updateSOA, + } + addRecordCmd = &cobra.Command{ + Use: "add-record", + Short: "Adds a new record of the specified type to the provided domain", + PreRun: func(cmd *cobra.Command, _ []string) { + _ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag)) + _ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag)) + }, + Run: addRecord, + } + getRecordsCmd = &cobra.Command{ + Use: "get-records", + Short: "Returns domain record of the specified type", + PreRun: func(cmd *cobra.Command, _ []string) { + _ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag)) + _ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag)) + }, + Run: getRecords, + } + delRecordsCmd = &cobra.Command{ + Use: "delete-records", + Short: "Removes domain records with the specified type", + PreRun: func(cmd *cobra.Command, _ []string) { + _ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag)) + _ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag)) + }, + Run: delRecords, + } +) + +func init() { + initTokensCmd() + initRegisterCmd() + initRenewCmd() + initUpdateCmd() + initAddRecordCmd() + initGetRecordsCmd() + initDelRecordsCmd() +} diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/tokens.go b/cmd/frostfs-adm/internal/modules/morph/nns/tokens.go new file mode 100644 index 000000000..6e8ffb40a --- /dev/null +++ b/cmd/frostfs-adm/internal/modules/morph/nns/tokens.go @@ -0,0 +1,24 @@ +package nns + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" + commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" + "github.com/spf13/cobra" +) + +func initTokensCmd() { + Cmd.AddCommand(tokensCmd) + tokensCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc) + tokensCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc) +} + +func listTokens(cmd *cobra.Command, _ []string) { + c, _, _ := getRPCClient(cmd) + it, err := c.Tokens() + commonCmd.ExitOnErr(cmd, "unable to get tokens: %w", err) + for toks, err := it.Next(10); err == nil && len(toks) > 0; toks, err = it.Next(10) { + for _, token := range toks { + cmd.Println(string(token)) + } + } +} diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/update.go b/cmd/frostfs-adm/internal/modules/morph/nns/update.go new file mode 100644 index 000000000..3437316e3 --- /dev/null +++ b/cmd/frostfs-adm/internal/modules/morph/nns/update.go @@ -0,0 +1,50 @@ +package nns + +import ( + "math/big" + + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants" + commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" + "github.com/spf13/cobra" +) + +func initUpdateCmd() { + Cmd.AddCommand(updateCmd) + updateCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc) + updateCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc) + updateCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc) + updateCmd.Flags().String(nnsEmailFlag, constants.FrostfsOpsEmail, "Domain owner email") + updateCmd.Flags().Int64(nnsRefreshFlag, constants.NNSRefreshDefVal, + "The number of seconds between update requests from secondary and slave name servers") + updateCmd.Flags().Int64(nnsRetryFlag, constants.NNSRetryDefVal, + "The number of seconds the secondary or slave will wait before retrying when the last attempt has failed") + updateCmd.Flags().Int64(nnsExpireFlag, int64(constants.DefaultExpirationTime), + "The number of seconds a master or slave will wait before considering the data stale "+ + "if it cannot reach the primary name server") + updateCmd.Flags().Int64(nnsTTLFlag, constants.NNSTtlDefVal, + "The number of seconds a domain name is cached locally before expiration and return to authoritative "+ + "nameservers for updated information") + + _ = cobra.MarkFlagRequired(updateCmd.Flags(), nnsNameFlag) +} + +func updateSOA(cmd *cobra.Command, _ []string) { + c, actor, _ := getRPCClient(cmd) + + name, _ := cmd.Flags().GetString(nnsNameFlag) + email, _ := cmd.Flags().GetString(nnsEmailFlag) + refresh, _ := cmd.Flags().GetInt64(nnsRefreshFlag) + retry, _ := cmd.Flags().GetInt64(nnsRetryFlag) + expire, _ := cmd.Flags().GetInt64(nnsExpireFlag) + ttl, _ := cmd.Flags().GetInt64(nnsTTLFlag) + + h, vub, err := c.UpdateSOA(name, email, big.NewInt(refresh), + big.NewInt(retry), big.NewInt(expire), big.NewInt(ttl)) + commonCmd.ExitOnErr(cmd, "unable to send transaction: %w", err) + + cmd.Println("Waiting for transaction to persist...") + _, err = actor.Wait(h, vub, err) + commonCmd.ExitOnErr(cmd, "register domain error: %w", err) + cmd.Println("SOA records updated successfully") +} diff --git a/cmd/frostfs-adm/internal/modules/morph/root.go b/cmd/frostfs-adm/internal/modules/morph/root.go index 9d2b25ceb..e8426d56e 100644 --- a/cmd/frostfs-adm/internal/modules/morph/root.go +++ b/cmd/frostfs-adm/internal/modules/morph/root.go @@ -10,6 +10,7 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/generate" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/initialize" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/netmap" + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/nns" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/node" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/notary" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/policy" @@ -49,4 +50,5 @@ func init() { RootCmd.AddCommand(proxy.RemoveAccountCmd) RootCmd.AddCommand(frostfsid.Cmd) + RootCmd.AddCommand(nns.Cmd) }