2020-08-04 14:46:12 +00:00
package cmd
import (
2020-10-20 12:21:17 +00:00
"bytes"
"encoding/json"
2021-05-18 08:12:51 +00:00
"errors"
2020-08-04 14:46:12 +00:00
"fmt"
2020-10-14 12:51:22 +00:00
"os"
"strconv"
"strings"
"time"
2020-08-04 14:46:12 +00:00
2020-10-14 12:51:22 +00:00
"github.com/google/uuid"
2022-05-16 13:15:31 +00:00
"github.com/nspcc-dev/neofs-api-go/v2/refs"
2021-10-28 14:48:46 +00:00
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
2022-05-18 11:03:40 +00:00
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
2022-05-18 09:22:02 +00:00
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
2022-05-24 08:22:23 +00:00
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
2022-06-01 12:42:28 +00:00
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
2021-11-10 07:08:33 +00:00
"github.com/nspcc-dev/neofs-sdk-go/acl"
"github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/nspcc-dev/neofs-sdk-go/policy"
2022-05-18 15:20:08 +00:00
"github.com/nspcc-dev/neofs-sdk-go/session"
2021-11-26 17:46:07 +00:00
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
2022-05-17 13:59:46 +00:00
"github.com/nspcc-dev/neofs-sdk-go/user"
2021-11-10 07:08:33 +00:00
versionSDK "github.com/nspcc-dev/neofs-sdk-go/version"
2020-08-04 14:46:12 +00:00
"github.com/spf13/cobra"
)
2020-10-14 12:51:22 +00:00
const (
2020-10-16 09:29:57 +00:00
attributeDelimiter = "="
2020-10-14 12:51:22 +00:00
awaitTimeout = 120 // in seconds
)
2021-05-19 13:12:01 +00:00
// keywords of predefined basic ACL values
const (
basicACLPrivate = "private"
2021-05-19 13:16:05 +00:00
basicACLReadOnly = "public-read"
basicACLPublic = "public-read-write"
2021-12-30 09:07:52 +00:00
basicACLAppend = "public-append"
basicACLNoFinalPrivate = "eacl-private"
basicACLNoFinalReadOnly = "eacl-public-read"
basicACLNoFinalPublic = "eacl-public-read-write"
basicACLNoFinalAppend = "eacl-public-append"
2021-05-19 13:12:01 +00:00
)
2022-01-13 15:01:50 +00:00
var wellKnownBasicACL = map [ string ] acl . BasicACL {
2021-12-30 09:07:52 +00:00
basicACLPublic : acl . PublicBasicRule ,
basicACLPrivate : acl . PrivateBasicRule ,
basicACLReadOnly : acl . ReadOnlyBasicRule ,
basicACLAppend : acl . PublicAppendRule ,
basicACLNoFinalPublic : acl . EACLPublicBasicRule ,
basicACLNoFinalPrivate : acl . EACLPrivateBasicRule ,
basicACLNoFinalReadOnly : acl . EACLReadOnlyBasicRule ,
basicACLNoFinalAppend : acl . EACLPublicAppendRule ,
}
2020-10-14 12:51:22 +00:00
var (
containerOwner string
2020-11-03 13:44:50 +00:00
containerACL string
containerNonce string
containerPolicy string
containerAttributes [ ] string
containerAwait bool
containerName string
containerNoTimestamp bool
2021-11-26 17:46:07 +00:00
containerSubnet string
2020-10-14 12:51:22 +00:00
containerID string
2020-10-15 15:00:53 +00:00
containerPathFrom string
containerPathTo string
2020-10-20 12:21:17 +00:00
containerJSON bool
eaclPathFrom string
2020-10-14 12:51:22 +00:00
)
2021-07-06 12:27:54 +00:00
var (
2022-05-25 16:15:27 +00:00
errDeleteTimeout = errors . New ( "timeout: container has not been removed from sidechain" )
errCreateTimeout = errors . New ( "timeout: container has not been persisted on sidechain" )
errSetEACLTimeout = errors . New ( "timeout: EACL has not been persisted on sidechain" )
2021-07-06 12:27:54 +00:00
)
2020-08-04 14:46:12 +00:00
// containerCmd represents the container command
var containerCmd = & cobra . Command {
Use : "container" ,
2020-10-14 12:51:22 +00:00
Short : "Operations with containers" ,
Long : "Operations with containers" ,
2021-09-27 15:36:14 +00:00
PersistentPreRun : func ( cmd * cobra . Command , args [ ] string ) {
// bind exactly that cmd's flags to
// the viper before execution
2022-05-18 09:22:02 +00:00
commonflags . Bind ( cmd )
2022-05-30 13:04:40 +00:00
commonflags . BindAPI ( cmd )
2021-09-27 15:36:14 +00:00
} ,
2020-10-14 12:51:22 +00:00
}
var listContainersCmd = & cobra . Command {
Use : "list" ,
Short : "List all created containers" ,
Long : "List all created containers" ,
2021-06-20 23:02:56 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2022-05-17 13:59:46 +00:00
var idUser user . ID
2020-10-14 12:51:22 +00:00
2022-05-24 08:22:23 +00:00
key := key . GetOrGenerate ( cmd )
2020-10-14 12:51:22 +00:00
2021-04-21 12:27:32 +00:00
if containerOwner == "" {
2022-05-17 13:59:46 +00:00
user . IDFromKey ( & idUser , key . PublicKey )
2021-03-15 11:23:04 +00:00
} else {
2022-05-30 13:46:54 +00:00
err := idUser . DecodeString ( containerOwner )
common . ExitOnErr ( cmd , "invalid user ID: %w" , err )
2020-10-14 12:51:22 +00:00
}
2022-05-30 13:46:54 +00:00
cli := internalclient . GetSDKClientByFlag ( cmd , key , commonflags . RPC )
2021-10-28 14:48:46 +00:00
2022-05-30 13:46:54 +00:00
var prm internalclient . ListContainersPrm
prm . SetClient ( cli )
2022-05-17 13:59:46 +00:00
prm . SetAccount ( idUser )
2021-10-28 14:48:46 +00:00
res , err := internalclient . ListContainers ( prm )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "rpc error: %w" , err )
2020-10-14 12:51:22 +00:00
// print to stdout
2021-10-28 14:48:46 +00:00
prettyPrintContainerList ( cmd , res . IDList ( ) )
2020-10-14 12:51:22 +00:00
} ,
}
var createContainerCmd = & cobra . Command {
Use : "create" ,
Short : "Create new container" ,
Long : ` Create new container and register it in the NeoFS .
It will be stored in sidechain when inner ring will accepts it . ` ,
2021-06-20 23:02:56 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2020-10-14 12:51:22 +00:00
placementPolicy , err := parseContainerPolicy ( containerPolicy )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2020-10-14 12:51:22 +00:00
2022-06-15 08:08:10 +00:00
var subnetID subnetid . ID
err = subnetID . DecodeString ( containerSubnet )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "could not parse subnetID: %w" , err )
2021-11-26 17:46:07 +00:00
2022-06-15 08:08:10 +00:00
placementPolicy . SetSubnetID ( & subnetID )
2021-11-26 17:46:07 +00:00
2020-10-14 12:51:22 +00:00
attributes , err := parseAttributes ( containerAttributes )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2020-10-14 12:51:22 +00:00
basicACL , err := parseBasicACL ( containerACL )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2020-10-14 12:51:22 +00:00
nonce , err := parseNonce ( containerNonce )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2020-10-14 12:51:22 +00:00
2022-05-24 08:22:23 +00:00
key := key . GetOrGenerate ( cmd )
2022-01-21 16:53:06 +00:00
2022-05-18 15:20:08 +00:00
cnr := container . New ( )
var tok * session . Container
2022-05-30 13:43:02 +00:00
sessionTokenPath , _ := cmd . Flags ( ) . GetString ( commonflags . SessionToken )
2022-05-18 15:20:08 +00:00
if sessionTokenPath != "" {
tok = new ( session . Container )
common . ReadSessionToken ( cmd , tok , sessionTokenPath )
2022-01-21 16:53:06 +00:00
2022-05-18 15:20:08 +00:00
issuer := tok . Issuer ( )
cnr . SetOwnerID ( & issuer )
cnr . SetSessionToken ( tok )
} else {
var idOwner user . ID
user . IDFromKey ( & idOwner , key . PublicKey )
cnr . SetOwnerID ( & idOwner )
2022-01-21 16:53:06 +00:00
}
2022-05-11 14:58:52 +00:00
ver := versionSDK . Current ( )
cnr . SetVersion ( & ver )
2020-11-16 09:43:52 +00:00
cnr . SetPlacementPolicy ( placementPolicy )
2020-10-14 12:51:22 +00:00
cnr . SetBasicACL ( basicACL )
cnr . SetAttributes ( attributes )
2020-12-24 10:20:20 +00:00
cnr . SetNonceUUID ( nonce )
2021-05-28 13:28:50 +00:00
cnr . SetSessionToken ( tok )
2020-10-14 12:51:22 +00:00
2022-05-30 13:46:54 +00:00
cli := internalclient . GetSDKClientByFlag ( cmd , key , commonflags . RPC )
2021-10-28 14:48:46 +00:00
2022-05-30 13:46:54 +00:00
var putPrm internalclient . PutContainerPrm
putPrm . SetClient ( cli )
2022-01-21 16:53:06 +00:00
putPrm . SetContainer ( * cnr )
2021-10-28 14:48:46 +00:00
res , err := internalclient . PutContainer ( putPrm )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "rpc error: %w" , err )
2020-10-14 12:51:22 +00:00
2021-10-28 14:48:46 +00:00
id := res . ID ( )
2021-06-20 23:02:56 +00:00
cmd . Println ( "container ID:" , id )
2020-10-14 12:51:22 +00:00
if containerAwait {
2021-06-20 23:02:56 +00:00
cmd . Println ( "awaiting..." )
2020-10-14 12:51:22 +00:00
2022-05-30 13:46:54 +00:00
var getPrm internalclient . GetContainerPrm
getPrm . SetClient ( cli )
2022-05-31 17:00:41 +00:00
getPrm . SetContainer ( id )
2021-10-28 14:48:46 +00:00
2020-10-14 12:51:22 +00:00
for i := 0 ; i < awaitTimeout ; i ++ {
time . Sleep ( 1 * time . Second )
2021-10-28 14:48:46 +00:00
_ , err := internalclient . GetContainer ( getPrm )
2020-10-14 12:51:22 +00:00
if err == nil {
2021-06-20 23:02:56 +00:00
cmd . Println ( "container has been persisted on sidechain" )
return
2020-10-14 12:51:22 +00:00
}
}
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , errCreateTimeout )
2020-10-14 12:51:22 +00:00
}
} ,
}
var deleteContainerCmd = & cobra . Command {
Use : "delete" ,
Short : "Delete existing container" ,
Long : ` Delete existing container .
Only owner of the container has a permission to remove container . ` ,
2021-06-20 23:02:56 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2020-10-14 12:51:22 +00:00
id , err := parseContainerID ( containerID )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2020-10-14 12:51:22 +00:00
2022-05-18 15:20:08 +00:00
var tok * session . Container
2022-05-30 13:43:02 +00:00
sessionTokenPath , _ := cmd . Flags ( ) . GetString ( commonflags . SessionToken )
2022-05-18 15:20:08 +00:00
if sessionTokenPath != "" {
tok = new ( session . Container )
common . ReadSessionToken ( cmd , tok , sessionTokenPath )
}
2021-05-28 13:28:50 +00:00
2021-10-28 14:48:46 +00:00
var (
delPrm internalclient . DeleteContainerPrm
getPrm internalclient . GetContainerPrm
)
2021-05-28 13:28:50 +00:00
2021-10-28 14:48:46 +00:00
prepareAPIClient ( cmd , & delPrm , & getPrm )
2022-01-21 16:53:06 +00:00
delPrm . SetContainer ( * id )
if tok != nil {
2022-05-18 15:20:08 +00:00
delPrm . WithinSession ( * tok )
2022-01-21 16:53:06 +00:00
}
2021-05-28 13:28:50 +00:00
2021-10-28 14:48:46 +00:00
_ , err = internalclient . DeleteContainer ( delPrm )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "rpc error: %w" , err )
2020-10-14 12:51:22 +00:00
2021-06-20 23:02:56 +00:00
cmd . Println ( "container delete method invoked" )
2020-10-14 12:51:22 +00:00
if containerAwait {
2021-06-20 23:02:56 +00:00
cmd . Println ( "awaiting..." )
2020-10-14 12:51:22 +00:00
2022-01-21 16:53:06 +00:00
getPrm . SetContainer ( * id )
2021-10-28 14:48:46 +00:00
2020-10-14 12:51:22 +00:00
for i := 0 ; i < awaitTimeout ; i ++ {
time . Sleep ( 1 * time . Second )
2021-10-28 14:48:46 +00:00
_ , err := internalclient . GetContainer ( getPrm )
2020-10-14 12:51:22 +00:00
if err != nil {
2021-06-20 23:02:56 +00:00
cmd . Println ( "container has been removed:" , containerID )
return
2020-10-14 12:51:22 +00:00
}
}
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , errDeleteTimeout )
2020-10-14 12:51:22 +00:00
}
2020-08-04 14:46:12 +00:00
} ,
}
2020-10-15 14:54:33 +00:00
var listContainerObjectsCmd = & cobra . Command {
Use : "list-objects" ,
Short : "List existing objects in container" ,
Long : ` List existing objects in container ` ,
2021-06-20 23:02:56 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2020-10-15 14:54:33 +00:00
id , err := parseContainerID ( containerID )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2020-10-15 14:54:33 +00:00
filters := new ( object . SearchFilters )
filters . AddRootFilter ( ) // search only user created objects
2022-06-01 12:42:28 +00:00
pk := key . GetOrGenerate ( cmd )
2020-10-15 14:54:33 +00:00
2022-06-01 12:42:28 +00:00
var prm internalclient . SearchObjectsPrm
sessionCli . Prepare ( cmd , * id , nil , pk , & prm )
objectCli . Prepare ( cmd , & prm )
2022-05-31 17:00:41 +00:00
prm . SetContainerID ( * id )
2021-10-28 14:48:46 +00:00
prm . SetFilters ( * filters )
res , err := internalclient . SearchObjects ( prm )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "rpc error: %w" , err )
2020-10-15 14:54:33 +00:00
2021-10-28 14:48:46 +00:00
objectIDs := res . IDList ( )
2020-10-15 14:54:33 +00:00
for i := range objectIDs {
2022-05-31 17:00:41 +00:00
cmd . Println ( objectIDs [ i ] )
2020-10-15 14:54:33 +00:00
}
} ,
}
2020-10-15 15:00:53 +00:00
var getContainerInfoCmd = & cobra . Command {
Use : "get" ,
Short : "Get container field info" ,
Long : ` Get container field info ` ,
2021-06-20 23:02:56 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2021-10-28 14:48:46 +00:00
var cnr * container . Container
2020-10-15 15:00:53 +00:00
if containerPathFrom != "" {
2021-06-28 14:01:31 +00:00
data , err := os . ReadFile ( containerPathFrom )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "can't read file: %w" , err )
2020-10-15 15:00:53 +00:00
2020-11-16 10:26:35 +00:00
cnr = container . New ( )
2021-07-06 12:27:54 +00:00
err = cnr . Unmarshal ( data )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "can't unmarshal container: %w" , err )
2020-10-15 15:00:53 +00:00
} else {
2021-10-28 14:48:46 +00:00
id , err := parseContainerID ( containerID )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2021-04-21 12:27:32 +00:00
2021-10-28 14:48:46 +00:00
var prm internalclient . GetContainerPrm
2020-10-15 15:00:53 +00:00
2021-10-28 14:48:46 +00:00
prepareAPIClient ( cmd , & prm )
2022-01-21 16:53:06 +00:00
prm . SetContainer ( * id )
2020-10-15 15:00:53 +00:00
2021-10-28 14:48:46 +00:00
res , err := internalclient . GetContainer ( prm )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "rpc error: %w" , err )
2021-10-28 14:48:46 +00:00
cnr = res . Container ( )
2020-10-15 15:00:53 +00:00
}
2021-06-20 23:02:56 +00:00
prettyPrintContainer ( cmd , cnr , containerJSON )
2020-10-15 15:00:53 +00:00
if containerPathTo != "" {
2020-10-20 12:34:13 +00:00
var (
data [ ] byte
err error
)
if containerJSON {
2020-11-16 09:43:52 +00:00
data , err = cnr . MarshalJSON ( )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "can't JSON encode container: %w" , err )
2020-10-20 12:34:13 +00:00
} else {
2020-11-16 10:26:35 +00:00
data , err = cnr . Marshal ( )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "can't binary encode container: %w" , err )
2020-10-15 15:00:53 +00:00
}
2021-06-28 14:01:31 +00:00
err = os . WriteFile ( containerPathTo , data , 0644 )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "can't write container to file: %w" , err )
2020-10-15 15:00:53 +00:00
}
} ,
}
2020-10-20 12:21:17 +00:00
var getExtendedACLCmd = & cobra . Command {
Use : "get-eacl" ,
Short : "Get extended ACL table of container" ,
Long : ` Get extended ACL talbe of container ` ,
2021-06-20 23:02:56 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2021-10-28 14:48:46 +00:00
id , err := parseContainerID ( containerID )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2021-04-21 12:27:32 +00:00
2021-10-28 14:48:46 +00:00
var eaclPrm internalclient . EACLPrm
2020-10-20 12:21:17 +00:00
2021-10-28 14:48:46 +00:00
prepareAPIClient ( cmd , & eaclPrm )
2022-01-21 16:53:06 +00:00
eaclPrm . SetContainer ( * id )
2020-10-20 12:21:17 +00:00
2021-10-28 14:48:46 +00:00
res , err := internalclient . EACL ( eaclPrm )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "rpc error: %w" , err )
2020-10-20 12:21:17 +00:00
2020-11-24 13:06:02 +00:00
eaclTable := res . EACL ( )
2021-10-28 14:48:46 +00:00
2021-05-31 11:03:17 +00:00
sig := eaclTable . Signature ( )
2020-11-24 13:06:02 +00:00
2022-05-16 13:15:31 +00:00
// TODO(@cthulhu-rider): #1387 avoid type conversion
var sigV2 refs . Signature
sig . WriteToV2 ( & sigV2 )
2020-10-20 12:21:17 +00:00
if containerPathTo == "" {
2021-06-20 23:02:56 +00:00
cmd . Println ( "eACL: " )
prettyPrintEACL ( cmd , eaclTable )
2020-11-24 13:06:02 +00:00
2022-05-16 13:15:31 +00:00
var sigV2 refs . Signature
sig . WriteToV2 ( & sigV2 )
2021-06-20 23:02:56 +00:00
cmd . Println ( "Signature:" )
2022-05-23 15:48:01 +00:00
common . PrettyPrintJSON ( cmd , & sigV2 , "signature" )
2020-11-24 13:06:02 +00:00
2021-06-20 23:02:56 +00:00
return
2020-10-20 12:21:17 +00:00
}
var data [ ] byte
if containerJSON {
2020-11-16 09:43:52 +00:00
data , err = eaclTable . MarshalJSON ( )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "can't encode to JSON: %w" , err )
2020-10-20 12:21:17 +00:00
} else {
2020-11-16 10:26:35 +00:00
data , err = eaclTable . Marshal ( )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "can't encode to binary: %w" , err )
2020-10-20 12:21:17 +00:00
}
2021-06-20 23:02:56 +00:00
cmd . Println ( "dumping data to file:" , containerPathTo )
2020-10-20 12:21:17 +00:00
2021-06-20 23:02:56 +00:00
cmd . Println ( "Signature:" )
2022-05-23 15:48:01 +00:00
common . PrettyPrintJSON ( cmd , & sigV2 , "signature" )
2020-11-24 13:06:02 +00:00
2021-07-06 12:27:54 +00:00
err = os . WriteFile ( containerPathTo , data , 0644 )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "could not write eACL to file: %w" , err )
2020-10-20 12:21:17 +00:00
} ,
}
var setExtendedACLCmd = & cobra . Command {
Use : "set-eacl" ,
Short : "Set new extended ACL table for container" ,
Long : ` Set new extended ACL table for container .
Container ID in EACL table will be substituted with ID from the CLI . ` ,
2021-06-20 23:02:56 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2020-10-20 12:21:17 +00:00
id , err := parseContainerID ( containerID )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , err )
2020-10-20 12:21:17 +00:00
2022-05-25 16:15:27 +00:00
eaclTable := common . ReadEACL ( cmd , eaclPathFrom )
2020-10-20 12:21:17 +00:00
2022-05-18 15:20:08 +00:00
var tok * session . Container
2022-05-30 13:43:02 +00:00
sessionTokenPath , _ := cmd . Flags ( ) . GetString ( commonflags . SessionToken )
2022-05-18 15:20:08 +00:00
if sessionTokenPath != "" {
tok = new ( session . Container )
common . ReadSessionToken ( cmd , tok , sessionTokenPath )
}
2021-05-28 13:28:50 +00:00
2022-05-12 16:37:46 +00:00
eaclTable . SetCID ( * id )
2021-05-28 13:28:50 +00:00
eaclTable . SetSessionToken ( tok )
2020-10-20 12:21:17 +00:00
2021-10-28 14:48:46 +00:00
var (
setEACLPrm internalclient . SetEACLPrm
getEACLPrm internalclient . EACLPrm
)
prepareAPIClient ( cmd , & setEACLPrm , & getEACLPrm )
2022-01-21 16:53:06 +00:00
setEACLPrm . SetTable ( * eaclTable )
2021-10-28 14:48:46 +00:00
_ , err = internalclient . SetEACL ( setEACLPrm )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "rpc error: %w" , err )
2020-10-20 12:21:17 +00:00
if containerAwait {
2020-11-16 10:26:35 +00:00
exp , err := eaclTable . Marshal ( )
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "broken EACL table: %w" , err )
2020-10-20 12:21:17 +00:00
2021-06-20 23:02:56 +00:00
cmd . Println ( "awaiting..." )
2020-10-20 12:21:17 +00:00
2022-01-21 16:53:06 +00:00
getEACLPrm . SetContainer ( * id )
2021-10-28 14:48:46 +00:00
2020-10-20 12:21:17 +00:00
for i := 0 ; i < awaitTimeout ; i ++ {
time . Sleep ( 1 * time . Second )
2021-10-28 14:48:46 +00:00
res , err := internalclient . EACL ( getEACLPrm )
2020-10-20 12:21:17 +00:00
if err == nil {
// compare binary values because EACL could have been set already
2021-10-28 14:48:46 +00:00
got , err := res . EACL ( ) . Marshal ( )
2020-10-20 12:21:17 +00:00
if err != nil {
continue
}
if bytes . Equal ( exp , got ) {
2021-06-20 23:02:56 +00:00
cmd . Println ( "EACL has been persisted on sidechain" )
return
2020-10-20 12:21:17 +00:00
}
}
}
2022-05-18 11:03:40 +00:00
common . ExitOnErr ( cmd , "" , errSetEACLTimeout )
2020-10-20 12:21:17 +00:00
}
} ,
}
2021-09-27 15:36:14 +00:00
func initContainerListContainersCmd ( ) {
2022-05-18 09:22:02 +00:00
commonflags . Init ( listContainersCmd )
2021-09-27 15:36:14 +00:00
flags := listContainersCmd . Flags ( )
flags . StringVar ( & containerOwner , "owner" , "" , "owner of containers (omit to use owner from private key)" )
}
func initContainerCreateCmd ( ) {
2022-05-18 09:22:02 +00:00
commonflags . Init ( createContainerCmd )
2021-09-27 15:36:14 +00:00
flags := createContainerCmd . Flags ( )
2021-12-30 09:07:52 +00:00
flags . StringVar ( & containerACL , "basic-acl" , basicACLPrivate , fmt . Sprintf ( "hex encoded basic ACL value or keywords like '%s', '%s', '%s'" , basicACLPublic , basicACLPrivate , basicACLNoFinalReadOnly ) )
2021-09-27 15:36:14 +00:00
flags . StringVarP ( & containerPolicy , "policy" , "p" , "" , "QL-encoded or JSON-encoded placement policy or path to file with it" )
flags . StringSliceVarP ( & containerAttributes , "attributes" , "a" , nil , "comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2" )
flags . StringVarP ( & containerNonce , "nonce" , "n" , "" , "UUIDv4 nonce value for container" )
flags . BoolVar ( & containerAwait , "await" , false , "block execution until container is persisted" )
flags . StringVar ( & containerName , "name" , "" , "container name attribute" )
flags . BoolVar ( & containerNoTimestamp , "disable-timestamp" , false , "disable timestamp container attribute" )
2021-11-26 17:46:07 +00:00
flags . StringVar ( & containerSubnet , "subnet" , "" , "string representation of container subnetwork" )
2021-09-27 15:36:14 +00:00
}
func initContainerDeleteCmd ( ) {
2022-05-18 09:22:02 +00:00
commonflags . Init ( deleteContainerCmd )
2021-09-27 15:36:14 +00:00
flags := deleteContainerCmd . Flags ( )
flags . StringVar ( & containerID , "cid" , "" , "container ID" )
flags . BoolVar ( & containerAwait , "await" , false , "block execution until container is removed" )
}
func initContainerListObjectsCmd ( ) {
2022-05-18 09:22:02 +00:00
commonflags . Init ( listContainerObjectsCmd )
2021-09-27 15:36:14 +00:00
flags := listContainerObjectsCmd . Flags ( )
flags . StringVar ( & containerID , "cid" , "" , "container ID" )
}
func initContainerInfoCmd ( ) {
2022-05-18 09:22:02 +00:00
commonflags . Init ( getContainerInfoCmd )
2021-09-27 15:36:14 +00:00
flags := getContainerInfoCmd . Flags ( )
flags . StringVar ( & containerID , "cid" , "" , "container ID" )
flags . StringVar ( & containerPathTo , "to" , "" , "path to dump encoded container" )
flags . StringVar ( & containerPathFrom , "from" , "" , "path to file with encoded container" )
flags . BoolVar ( & containerJSON , "json" , false , "print or dump container in JSON format" )
}
func initContainerGetEACLCmd ( ) {
2022-05-18 09:22:02 +00:00
commonflags . Init ( getExtendedACLCmd )
2021-09-27 15:36:14 +00:00
flags := getExtendedACLCmd . Flags ( )
flags . StringVar ( & containerID , "cid" , "" , "container ID" )
flags . StringVar ( & containerPathTo , "to" , "" , "path to dump encoded container (default: binary encoded)" )
flags . BoolVar ( & containerJSON , "json" , false , "encode EACL table in json format" )
}
func initContainerSetEACLCmd ( ) {
2022-05-18 09:22:02 +00:00
commonflags . Init ( setExtendedACLCmd )
2021-09-27 15:36:14 +00:00
flags := setExtendedACLCmd . Flags ( )
flags . StringVar ( & containerID , "cid" , "" , "container ID" )
flags . StringVar ( & eaclPathFrom , "table" , "" , "path to file with JSON or binary encoded EACL table" )
flags . BoolVar ( & containerAwait , "await" , false , "block execution until EACL is persisted" )
}
2020-08-04 14:46:12 +00:00
func init ( ) {
2021-09-27 15:36:14 +00:00
containerChildCommand := [ ] * cobra . Command {
listContainersCmd ,
createContainerCmd ,
deleteContainerCmd ,
listContainerObjectsCmd ,
getContainerInfoCmd ,
getExtendedACLCmd ,
setExtendedACLCmd ,
}
2020-08-04 14:46:12 +00:00
rootCmd . AddCommand ( containerCmd )
2021-09-27 15:36:14 +00:00
containerCmd . AddCommand ( containerChildCommand ... )
2020-08-04 14:46:12 +00:00
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// containerCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// containerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
2020-10-14 12:51:22 +00:00
2021-09-27 15:36:14 +00:00
initContainerListContainersCmd ( )
initContainerCreateCmd ( )
initContainerDeleteCmd ( )
initContainerListObjectsCmd ( )
initContainerInfoCmd ( )
initContainerGetEACLCmd ( )
initContainerSetEACLCmd ( )
for _ , containerCommand := range containerChildCommand {
2022-05-30 13:04:40 +00:00
commonflags . InitAPI ( containerCommand )
2021-09-27 15:36:14 +00:00
}
2021-05-28 13:28:50 +00:00
for _ , cmd := range [ ] * cobra . Command {
createContainerCmd ,
deleteContainerCmd ,
setExtendedACLCmd ,
} {
2022-05-30 13:43:02 +00:00
commonflags . InitSession ( cmd )
2021-05-28 13:28:50 +00:00
}
}
2022-03-15 11:16:46 +00:00
func prettyPrintContainerList ( cmd * cobra . Command , list [ ] cid . ID ) {
2020-10-14 12:51:22 +00:00
for i := range list {
2022-05-31 17:00:41 +00:00
cmd . Println ( list [ i ] )
2020-10-14 12:51:22 +00:00
}
}
func parseContainerPolicy ( policyString string ) ( * netmap . PlacementPolicy , error ) {
_ , err := os . Stat ( policyString ) // check if `policyString` is a path to file with placement policy
if err == nil {
2022-05-23 15:48:01 +00:00
common . PrintVerbose ( "Reading placement policy from file: %s" , policyString )
2020-10-14 12:51:22 +00:00
2021-06-28 14:01:31 +00:00
data , err := os . ReadFile ( policyString )
2020-10-14 12:51:22 +00:00
if err != nil {
return nil , fmt . Errorf ( "can't read file with placement policy: %w" , err )
}
policyString = string ( data )
}
result , err := policy . Parse ( policyString )
if err == nil {
2022-05-23 15:48:01 +00:00
common . PrintVerbose ( "Parsed QL encoded policy" )
2020-10-14 12:51:22 +00:00
return result , nil
}
2020-11-16 09:43:52 +00:00
result = netmap . NewPlacementPolicy ( )
if err = result . UnmarshalJSON ( [ ] byte ( policyString ) ) ; err == nil {
2022-05-23 15:48:01 +00:00
common . PrintVerbose ( "Parsed JSON encoded policy" )
2020-10-14 12:51:22 +00:00
return result , nil
}
return nil , errors . New ( "can't parse placement policy" )
}
2022-03-15 11:16:46 +00:00
func parseAttributes ( attributes [ ] string ) ( [ ] container . Attribute , error ) {
result := make ( [ ] container . Attribute , len ( attributes ) , len ( attributes ) + 2 ) // name + timestamp attributes
2020-10-14 12:51:22 +00:00
for i := range attributes {
kvPair := strings . Split ( attributes [ i ] , attributeDelimiter )
if len ( kvPair ) != 2 {
return nil , errors . New ( "invalid container attribute" )
}
2022-03-15 11:16:46 +00:00
result [ i ] . SetKey ( kvPair [ 0 ] )
result [ i ] . SetValue ( kvPair [ 1 ] )
2020-10-14 12:51:22 +00:00
}
2020-11-03 13:44:50 +00:00
if ! containerNoTimestamp {
2022-03-15 11:16:46 +00:00
index := len ( result )
result = append ( result , container . Attribute { } )
result [ index ] . SetKey ( container . AttributeTimestamp )
result [ index ] . SetValue ( strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) )
2020-11-03 13:44:50 +00:00
}
if containerName != "" {
2022-03-15 11:16:46 +00:00
index := len ( result )
result = append ( result , container . Attribute { } )
result [ index ] . SetKey ( container . AttributeName )
result [ index ] . SetValue ( containerName )
2020-11-03 13:44:50 +00:00
}
2020-10-14 12:51:22 +00:00
return result , nil
}
2022-01-13 15:01:50 +00:00
func parseBasicACL ( basicACL string ) ( acl . BasicACL , error ) {
2021-12-30 09:07:52 +00:00
if value , ok := wellKnownBasicACL [ basicACL ] ; ok {
return value , nil
}
basicACL = strings . Trim ( strings . ToLower ( basicACL ) , "0x" )
2020-10-14 12:51:22 +00:00
2021-12-30 09:07:52 +00:00
value , err := strconv . ParseUint ( basicACL , 16 , 32 )
if err != nil {
return 0 , fmt . Errorf ( "can't parse basic ACL: %s" , basicACL )
2020-10-14 12:51:22 +00:00
}
2021-12-30 09:07:52 +00:00
2022-01-13 15:01:50 +00:00
return acl . BasicACL ( value ) , nil
2020-10-14 12:51:22 +00:00
}
func parseNonce ( nonce string ) ( uuid . UUID , error ) {
if nonce == "" {
result := uuid . New ( )
2022-05-23 15:48:01 +00:00
common . PrintVerbose ( "Generating container nonce: %s" , result )
2020-10-14 12:51:22 +00:00
return result , nil
}
2021-09-01 16:33:48 +00:00
uid , err := uuid . Parse ( nonce )
if err != nil {
return uuid . UUID { } , fmt . Errorf ( "could not parse nonce: %w" , err )
}
return uid , nil
2020-10-14 12:51:22 +00:00
}
2021-05-31 11:03:17 +00:00
func parseContainerID ( idStr string ) ( * cid . ID , error ) {
if idStr == "" {
2020-10-15 14:54:33 +00:00
return nil , errors . New ( "container ID is not set" )
}
2022-05-12 16:37:46 +00:00
var id cid . ID
2020-10-15 08:45:00 +00:00
2022-05-12 16:37:46 +00:00
err := id . DecodeString ( idStr )
2020-10-15 08:45:00 +00:00
if err != nil {
2020-10-14 12:51:22 +00:00
return nil , errors . New ( "can't decode container ID value" )
}
2022-05-12 16:37:46 +00:00
return & id , nil
2020-08-04 14:46:12 +00:00
}
2020-10-15 15:00:53 +00:00
2021-06-20 23:02:56 +00:00
func prettyPrintContainer ( cmd * cobra . Command , cnr * container . Container , jsonEncoding bool ) {
2020-10-15 15:00:53 +00:00
if cnr == nil {
return
}
2020-10-20 12:34:13 +00:00
if jsonEncoding {
2020-11-16 09:43:52 +00:00
data , err := cnr . MarshalJSON ( )
2020-10-29 16:36:59 +00:00
if err != nil {
2022-05-23 15:48:01 +00:00
common . PrintVerbose ( "Can't convert container to json: %w" , err )
2020-10-29 16:36:59 +00:00
return
}
2020-10-20 12:34:13 +00:00
buf := new ( bytes . Buffer )
if err := json . Indent ( buf , data , "" , " " ) ; err != nil {
2022-05-23 15:48:01 +00:00
common . PrintVerbose ( "Can't pretty print json: %w" , err )
2020-10-20 12:34:13 +00:00
}
2021-06-20 23:02:56 +00:00
cmd . Println ( buf )
2020-10-20 12:34:13 +00:00
return
}
2020-10-15 15:00:53 +00:00
id := container . CalculateID ( cnr )
2021-06-20 23:02:56 +00:00
cmd . Println ( "container ID:" , id )
2020-10-15 15:00:53 +00:00
2022-02-25 09:20:49 +00:00
v := cnr . Version ( )
cmd . Printf ( "version: %d.%d\n" , v . Major ( ) , v . Minor ( ) )
2020-10-15 15:00:53 +00:00
2021-06-20 23:02:56 +00:00
cmd . Println ( "owner ID:" , cnr . OwnerID ( ) )
2020-10-15 15:00:53 +00:00
2020-11-16 09:43:52 +00:00
basicACL := cnr . BasicACL ( )
2022-01-13 15:01:50 +00:00
prettyPrintBasicACL ( cmd , acl . BasicACL ( basicACL ) )
2020-10-15 15:00:53 +00:00
2020-11-16 09:43:52 +00:00
for _ , attribute := range cnr . Attributes ( ) {
if attribute . Key ( ) == container . AttributeTimestamp {
2021-06-20 23:02:56 +00:00
cmd . Printf ( "attribute: %s=%s (%s)\n" ,
2020-11-16 09:43:52 +00:00
attribute . Key ( ) ,
attribute . Value ( ) ,
2022-05-26 06:41:17 +00:00
common . PrettyPrintUnixTime ( attribute . Value ( ) ) )
2020-11-03 13:44:50 +00:00
continue
}
2021-06-20 23:02:56 +00:00
cmd . Printf ( "attribute: %s=%s\n" , attribute . Key ( ) , attribute . Value ( ) )
2020-10-15 15:00:53 +00:00
}
2020-12-24 10:20:20 +00:00
nonce , err := cnr . NonceUUID ( )
2020-10-15 15:00:53 +00:00
if err == nil {
2021-06-20 23:02:56 +00:00
cmd . Println ( "nonce:" , nonce )
2020-12-24 10:20:20 +00:00
} else {
2021-06-20 23:02:56 +00:00
cmd . Println ( "invalid nonce:" , err )
2020-10-15 15:00:53 +00:00
}
2021-06-20 23:02:56 +00:00
cmd . Println ( "placement policy:" )
cmd . Println ( strings . Join ( policy . Encode ( cnr . PlacementPolicy ( ) ) , "\n" ) )
2020-10-15 15:00:53 +00:00
}
2020-10-20 12:21:17 +00:00
2021-06-20 23:02:56 +00:00
func prettyPrintEACL ( cmd * cobra . Command , table * eacl . Table ) {
2022-05-23 15:48:01 +00:00
common . PrettyPrintJSON ( cmd , table , "eACL" )
2020-10-20 12:21:17 +00:00
}
2021-12-30 09:07:52 +00:00
2022-01-13 15:01:50 +00:00
func prettyPrintBasicACL ( cmd * cobra . Command , basicACL acl . BasicACL ) {
2022-02-21 09:36:12 +00:00
cmd . Printf ( "basic ACL: %s" , basicACL )
2021-12-30 09:07:52 +00:00
for k , v := range wellKnownBasicACL {
if v == basicACL {
cmd . Printf ( " (%s)\n" , k )
return
}
}
cmd . Println ( )
}