forked from TrueCloudLab/frostfs-node
[#755] neofs-adm: allow to restore containers
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
a013dcbab5
commit
5072b703bc
2 changed files with 92 additions and 0 deletions
|
@ -6,11 +6,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
@ -96,6 +98,81 @@ func dumpContainers(cmd *cobra.Command, _ []string) error {
|
||||||
return ioutil.WriteFile(filename, out, 0o660)
|
return ioutil.WriteFile(filename, out, 0o660)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func restoreContainers(cmd *cobra.Command, _ []string) error {
|
||||||
|
filename, err := cmd.Flags().GetString(containerDumpFlag)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid filename: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wCtx, err := newInitializeContext(cmd, viper.GetViper())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nnsCs, err := wCtx.Client.GetContractStateByID(1)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't get NNS contract state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ch, err := nnsResolveHash(wCtx.Client, nnsCs.Hash, containerContract+".neofs")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't fetch container contract hash: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't read dump file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var containers []Container
|
||||||
|
err = json.Unmarshal(data, &containers)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't parse dump file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bw := io.NewBufBinWriter()
|
||||||
|
for _, cnt := range containers {
|
||||||
|
hv := hash.Sha256(cnt.Value)
|
||||||
|
bw.Reset()
|
||||||
|
emit.AppCall(bw.BinWriter, ch, "get", callflag.All, hv.BytesBE())
|
||||||
|
res, err := wCtx.Client.InvokeScript(bw.Bytes(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't check if container is already restored: %w", err)
|
||||||
|
}
|
||||||
|
if len(res.Stack) == 0 {
|
||||||
|
return errors.New("empty stack")
|
||||||
|
}
|
||||||
|
|
||||||
|
old := new(Container)
|
||||||
|
if err := old.FromStackItem(res.Stack[0]); err != nil {
|
||||||
|
return fmt.Errorf("%w: %v", errInvalidContainerResponse, err)
|
||||||
|
}
|
||||||
|
if len(old.Value) != 0 {
|
||||||
|
id := cid.New()
|
||||||
|
id.SetSHA256(hv)
|
||||||
|
cmd.Printf("Container %s is already deployed.\n", id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
bw.Reset()
|
||||||
|
emit.AppCall(bw.BinWriter, ch, "put", callflag.All,
|
||||||
|
cnt.Value, cnt.Signature, cnt.PublicKey, cnt.Token)
|
||||||
|
if ea := cnt.EACL; ea != nil {
|
||||||
|
emit.AppCall(bw.BinWriter, ch, "setEACL", callflag.All,
|
||||||
|
ea.Value, ea.Signature, ea.PublicKey, ea.Token)
|
||||||
|
}
|
||||||
|
if bw.Err != nil {
|
||||||
|
panic(bw.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := wCtx.sendCommitteeTx(bw.Bytes(), -1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wCtx.awaitTx()
|
||||||
|
}
|
||||||
|
|
||||||
// Container represents container struct in contract storage.
|
// Container represents container struct in contract storage.
|
||||||
type Container struct {
|
type Container struct {
|
||||||
Value []byte `json:"value"`
|
Value []byte `json:"value"`
|
||||||
|
|
|
@ -121,6 +121,16 @@ var (
|
||||||
},
|
},
|
||||||
RunE: dumpContainers,
|
RunE: dumpContainers,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restoreContainersCmd = &cobra.Command{
|
||||||
|
Use: "restore-containers",
|
||||||
|
Short: "Restore NeoFS containers from file.",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag))
|
||||||
|
_ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag))
|
||||||
|
},
|
||||||
|
RunE: restoreContainers,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -159,4 +169,9 @@ func init() {
|
||||||
RootCmd.AddCommand(dumpContainersCmd)
|
RootCmd.AddCommand(dumpContainersCmd)
|
||||||
dumpContainersCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint")
|
dumpContainersCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint")
|
||||||
dumpContainersCmd.Flags().String(containerDumpFlag, "", "file where to save dumped containers")
|
dumpContainersCmd.Flags().String(containerDumpFlag, "", "file where to save dumped containers")
|
||||||
|
|
||||||
|
RootCmd.AddCommand(restoreContainersCmd)
|
||||||
|
restoreContainersCmd.Flags().String(alphabetWalletsFlag, "", "path to alphabet wallets dir")
|
||||||
|
restoreContainersCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint")
|
||||||
|
restoreContainersCmd.Flags().String(containerDumpFlag, "", "file to restore containers from")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue