frostfs-node/cmd/frostfs-cli/modules/session/create.go
Evgenii Stratonikov e81f8689f5
All checks were successful
DCO action / DCO (pull_request) Successful in 3m49s
Vulncheck / Vulncheck (pull_request) Successful in 5m17s
Build / Build Components (1.21) (pull_request) Successful in 8m46s
Build / Build Components (1.20) (pull_request) Successful in 10m14s
Tests and linters / Staticcheck (pull_request) Successful in 11m0s
Tests and linters / Tests (1.21) (pull_request) Successful in 13m1s
Tests and linters / Lint (pull_request) Successful in 13m20s
Tests and linters / Tests (1.20) (pull_request) Successful in 2m43s
Tests and linters / Tests with -race (pull_request) Successful in 5m21s
[#808] cli: Use EnableTraverseRunHooks in cobra
Adopt EnableTraverseRunHooks to get rid of tracing boilerplate in
multiple commands. Now adding `--trace` flag is sufficient for a command
to support tracing. Finally, it looks how it _should_.

Refs #406

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-11-15 14:37:02 +03:00

135 lines
4.2 KiB
Go

package session
import (
"context"
"fmt"
"os"
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
"github.com/google/uuid"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
outFlag = "out"
jsonFlag = commonflags.JSON
)
const defaultLifetime = 10
var createCmd = &cobra.Command{
Use: "create",
Short: "Create session token",
Run: createSession,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
_ = viper.BindPFlag(commonflags.WalletPath, cmd.Flags().Lookup(commonflags.WalletPath))
_ = viper.BindPFlag(commonflags.Account, cmd.Flags().Lookup(commonflags.Account))
},
}
func init() {
createCmd.Flags().Uint64P(commonflags.Lifetime, "l", defaultLifetime, "Number of epochs for token to stay valid")
createCmd.Flags().StringP(commonflags.WalletPath, commonflags.WalletPathShorthand, commonflags.WalletPathDefault, commonflags.WalletPathUsage)
createCmd.Flags().StringP(commonflags.Account, commonflags.AccountShorthand, commonflags.AccountDefault, commonflags.AccountUsage)
createCmd.Flags().String(outFlag, "", "File to write session token to")
createCmd.Flags().Bool(jsonFlag, false, "Output token in JSON")
createCmd.Flags().StringP(commonflags.RPC, commonflags.RPCShorthand, commonflags.RPCDefault, commonflags.RPCUsage)
_ = cobra.MarkFlagRequired(createCmd.Flags(), commonflags.WalletPath)
_ = cobra.MarkFlagRequired(createCmd.Flags(), outFlag)
_ = cobra.MarkFlagRequired(createCmd.Flags(), commonflags.RPC)
}
func createSession(cmd *cobra.Command, _ []string) {
privKey := key.Get(cmd)
var netAddr network.Address
addrStr, _ := cmd.Flags().GetString(commonflags.RPC)
commonCmd.ExitOnErr(cmd, "can't parse endpoint: %w", netAddr.FromString(addrStr))
c, err := internalclient.GetSDKClient(cmd.Context(), cmd, privKey, netAddr)
commonCmd.ExitOnErr(cmd, "can't create client: %w", err)
lifetime := uint64(defaultLifetime)
if lfArg, _ := cmd.Flags().GetUint64(commonflags.Lifetime); lfArg != 0 {
lifetime = lfArg
}
var tok session.Object
err = CreateSession(cmd.Context(), &tok, c, lifetime)
commonCmd.ExitOnErr(cmd, "can't create session: %w", err)
var data []byte
if toJSON, _ := cmd.Flags().GetBool(jsonFlag); toJSON {
data, err = tok.MarshalJSON()
commonCmd.ExitOnErr(cmd, "can't decode session token JSON: %w", err)
} else {
data = tok.Marshal()
}
filename, _ := cmd.Flags().GetString(outFlag)
err = os.WriteFile(filename, data, 0o644)
commonCmd.ExitOnErr(cmd, "can't write token to file: %w", err)
}
// CreateSession opens a new communication with FrostFS storage node using client connection.
// The session is expected to be maintained by the storage node during the given
// number of epochs.
//
// Fills ID, lifetime and session key.
func CreateSession(ctx context.Context, dst *session.Object, c *client.Client, lifetime uint64) error {
netInfoPrm := internalclient.NetworkInfoPrm{
Client: c,
}
ni, err := internalclient.NetworkInfo(ctx, netInfoPrm)
if err != nil {
return fmt.Errorf("can't fetch network info: %w", err)
}
cur := ni.NetworkInfo().CurrentEpoch()
exp := cur + lifetime
var sessionPrm internalclient.CreateSessionPrm
sessionPrm.SetClient(c)
sessionPrm.Expiration = exp
sessionRes, err := internalclient.CreateSession(ctx, sessionPrm)
if err != nil {
return fmt.Errorf("can't open session: %w", err)
}
binIDSession := sessionRes.ID()
var keySession frostfsecdsa.PublicKey
err = keySession.Decode(sessionRes.SessionKey())
if err != nil {
return fmt.Errorf("decode public session key: %w", err)
}
var idSession uuid.UUID
err = idSession.UnmarshalBinary(binIDSession)
if err != nil {
return fmt.Errorf("decode session ID: %w", err)
}
dst.SetID(idSession)
dst.SetNbf(cur)
dst.SetIat(cur)
dst.SetExp(exp)
dst.SetAuthKey(&keySession)
return nil
}