2020-07-06 09:18:16 +00:00
package main
import (
2020-10-13 09:31:23 +00:00
"context"
2020-07-06 09:18:16 +00:00
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"io"
2020-10-13 09:31:23 +00:00
"io/ioutil"
2020-07-06 09:18:16 +00:00
"os"
2020-10-19 08:47:13 +00:00
"sort"
2020-07-06 09:18:16 +00:00
"strconv"
"strings"
"time"
2020-10-13 09:31:23 +00:00
"github.com/nspcc-dev/neofs-authmate/accessbox/hcs"
2020-07-06 09:18:16 +00:00
crypto "github.com/nspcc-dev/neofs-crypto"
2020-08-06 12:02:13 +00:00
"github.com/nspcc-dev/neofs-s3-gate/api/pool"
"github.com/nspcc-dev/neofs-s3-gate/auth"
"github.com/nspcc-dev/neofs-s3-gate/misc"
"github.com/pkg/errors"
2020-07-06 09:18:16 +00:00
"github.com/spf13/pflag"
"github.com/spf13/viper"
"go.uber.org/zap"
)
const (
devNull = empty ( 0 )
generated = "generated"
minimumTTLInMinutes = 5
defaultTTL = minimumTTLInMinutes * time . Minute
2020-07-12 23:00:47 +00:00
defaultRebalanceTimer = 15 * time . Second
defaultRequestTimeout = 15 * time . Second
defaultConnectTimeout = 30 * time . Second
defaultShutdownTimeout = 15 * time . Second
2020-07-06 09:18:16 +00:00
defaultKeepaliveTime = 10 * time . Second
defaultKeepaliveTimeout = 10 * time . Second
2020-07-22 13:02:32 +00:00
defaultMaxClientsCount = 100
defaultMaxClientsDeadline = time . Second * 30
2020-07-06 09:18:16 +00:00
)
2020-07-07 11:25:13 +00:00
const ( // settings
// Logger:
cfgLoggerLevel = "logger.level"
cfgLoggerFormat = "logger.format"
cfgLoggerTraceLevel = "logger.trace_level"
cfgLoggerNoDisclaimer = "logger.no_disclaimer"
cfgLoggerSamplingInitial = "logger.sampling.initial"
cfgLoggerSamplingThereafter = "logger.sampling.thereafter"
// KeepAlive
cfgKeepaliveTime = "keepalive.time"
cfgKeepaliveTimeout = "keepalive.timeout"
cfgKeepalivePermitWithoutStream = "keepalive.permit_without_stream"
2020-07-15 20:16:27 +00:00
// Keys
2020-08-06 15:07:10 +00:00
cfgNeoFSPrivateKey = "neofs-key"
cfgGateAuthPrivateKey = "auth-key"
2020-07-15 20:16:27 +00:00
// HTTPS/TLS
2020-07-13 15:50:11 +00:00
cfgTLSKeyFile = "tls.key_file"
cfgTLSCertFile = "tls.cert_file"
2020-07-07 11:25:13 +00:00
// Timeouts
cfgConnectionTTL = "con_ttl"
cfgConnectTimeout = "connect_timeout"
cfgRequestTimeout = "request_timeout"
cfgRebalanceTimer = "rebalance_timer"
2020-07-22 13:02:32 +00:00
// MaxClients
cfgMaxClientsCount = "max_clients_count"
cfgMaxClientsDeadline = "max_clients_deadline"
2020-07-07 11:25:13 +00:00
// gRPC
2020-07-15 20:16:27 +00:00
cfgGRPCVerbose = "verbose"
2020-07-07 11:25:13 +00:00
// Metrics / Profiler / Web
cfgEnableMetrics = "metrics"
cfgEnableProfiler = "pprof"
cfgListenAddress = "listen_address"
2020-10-19 08:47:13 +00:00
// Peers
cfgPeers = "peers"
2020-07-07 11:25:13 +00:00
// Application
cfgApplicationName = "app.name"
cfgApplicationVersion = "app.version"
cfgApplicationBuildTime = "app.build_time"
2020-10-19 08:47:13 +00:00
// command line args
cmdHelp = "help"
cmdVersion = "version"
2020-07-07 11:25:13 +00:00
)
2020-07-15 20:16:27 +00:00
type empty int
2020-10-19 08:47:13 +00:00
var ignore = map [ string ] struct { } {
cfgApplicationName : { } ,
cfgApplicationVersion : { } ,
cfgApplicationBuildTime : { } ,
cfgPeers : { } ,
cmdHelp : { } ,
cmdVersion : { } ,
}
2020-07-06 09:18:16 +00:00
func ( empty ) Read ( [ ] byte ) ( int , error ) { return 0 , io . EOF }
2020-10-13 09:31:23 +00:00
func fetchGateAuthKeys ( v * viper . Viper ) ( * hcs . X25519Keys , error ) {
path := v . GetString ( cfgGateAuthPrivateKey )
data , err := ioutil . ReadFile ( path )
if err != nil {
return nil , err
}
return hcs . NewKeys ( data )
}
func fetchNeoFSKey ( v * viper . Viper ) ( * ecdsa . PrivateKey , error ) {
2020-07-15 20:16:27 +00:00
var (
2020-10-13 09:31:23 +00:00
err error
key * ecdsa . PrivateKey
2020-07-15 20:16:27 +00:00
)
2020-10-13 09:31:23 +00:00
switch val := v . GetString ( cfgNeoFSPrivateKey ) ; val {
2020-07-06 09:18:16 +00:00
case generated :
2020-10-13 09:31:23 +00:00
key , err = ecdsa . GenerateKey ( elliptic . P256 ( ) , rand . Reader )
2020-07-06 09:18:16 +00:00
if err != nil {
2020-07-15 20:16:27 +00:00
return nil , errors . Wrap ( err , "could not generate NeoFS private key" )
2020-07-06 09:18:16 +00:00
}
default :
2020-10-13 09:31:23 +00:00
key , err = crypto . LoadPrivateKey ( val )
2020-07-06 09:18:16 +00:00
if err != nil {
2020-07-15 20:16:27 +00:00
return nil , errors . Wrap ( err , "could not load NeoFS private key" )
2020-07-06 09:18:16 +00:00
}
}
2020-10-13 09:31:23 +00:00
return key , nil
}
func fetchAuthCenter ( ctx context . Context , p * authCenterParams ) ( * auth . Center , error ) {
return auth . New ( ctx , & auth . Params {
Con : p . Pool ,
Log : p . Logger ,
Timeout : p . Timeout ,
GAKey : p . GateAuthKeys ,
NFKey : p . NeoFSPrivateKey ,
} )
2020-07-06 09:18:16 +00:00
}
2020-07-07 11:25:13 +00:00
func fetchPeers ( l * zap . Logger , v * viper . Viper ) [ ] pool . Peer {
peers := make ( [ ] pool . Peer , 0 )
for i := 0 ; ; i ++ {
2020-10-19 08:47:13 +00:00
key := cfgPeers + "." + strconv . Itoa ( i ) + "."
2020-07-07 11:25:13 +00:00
address := v . GetString ( key + "address" )
weight := v . GetFloat64 ( key + "weight" )
if address == "" {
l . Warn ( "skip, empty address" )
break
}
peers = append ( peers , pool . Peer {
Address : address ,
Weight : weight ,
} )
}
return peers
}
2020-07-06 09:18:16 +00:00
func newSettings ( ) * viper . Viper {
v := viper . New ( )
v . AutomaticEnv ( )
2020-10-19 08:47:13 +00:00
v . SetEnvPrefix ( misc . Prefix )
2020-07-06 09:18:16 +00:00
v . SetConfigType ( "yaml" )
v . SetEnvKeyReplacer ( strings . NewReplacer ( "." , "_" ) )
// flags setup:
flags := pflag . NewFlagSet ( "commandline" , pflag . ExitOnError )
flags . SortFlags = false
2020-07-07 11:25:13 +00:00
flags . Bool ( cfgEnableProfiler , false , "enable pprof" )
2020-07-15 20:16:27 +00:00
flags . Bool ( cfgEnableMetrics , false , "enable prometheus metrics" )
2020-07-06 09:18:16 +00:00
2020-10-19 08:47:13 +00:00
help := flags . BoolP ( cmdHelp , "h" , false , "show help" )
version := flags . BoolP ( cmdVersion , "v" , false , "show version" )
2020-07-06 09:18:16 +00:00
2020-07-15 20:16:27 +00:00
flags . String ( cfgNeoFSPrivateKey , generated , fmt . Sprintf ( ` set value to hex string, WIF string, or path to NeoFS private key file (use "%s" to generate key) ` , generated ) )
2020-08-06 11:56:40 +00:00
flags . String ( cfgGateAuthPrivateKey , "" , "set path to file with auth (curve25519) private key to use in auth scheme" )
2020-07-06 09:18:16 +00:00
2020-07-15 20:16:27 +00:00
flags . Bool ( cfgGRPCVerbose , false , "set debug mode of gRPC connections" )
flags . Duration ( cfgRequestTimeout , defaultRequestTimeout , "set gRPC request timeout" )
flags . Duration ( cfgConnectTimeout , defaultConnectTimeout , "set gRPC connect timeout" )
flags . Duration ( cfgRebalanceTimer , defaultRebalanceTimer , "set gRPC connection rebalance timer" )
2020-07-06 09:18:16 +00:00
2020-07-22 13:02:32 +00:00
flags . Int ( cfgMaxClientsCount , defaultMaxClientsCount , "set max-clients count" )
flags . Duration ( cfgMaxClientsDeadline , defaultMaxClientsDeadline , "set max-clients deadline" )
2020-07-15 20:16:27 +00:00
ttl := flags . DurationP ( cfgConnectionTTL , "t" , defaultTTL , "set gRPC connection time to live" )
2020-07-06 09:18:16 +00:00
2020-07-15 20:16:27 +00:00
flags . String ( cfgListenAddress , "0.0.0.0:8080" , "set address to listen" )
2020-10-19 08:47:13 +00:00
peers := flags . StringArrayP ( cfgPeers , "p" , nil , "set NeoFS nodes" )
2020-07-06 09:18:16 +00:00
// set prefers:
2020-07-07 11:28:49 +00:00
v . Set ( cfgApplicationName , misc . ApplicationName )
2020-07-07 11:25:13 +00:00
v . Set ( cfgApplicationVersion , misc . Version )
v . Set ( cfgApplicationBuildTime , misc . Build )
2020-07-06 09:18:16 +00:00
// set defaults:
// logger:
2020-07-07 11:25:13 +00:00
v . SetDefault ( cfgLoggerLevel , "debug" )
v . SetDefault ( cfgLoggerFormat , "console" )
2020-07-24 16:10:41 +00:00
v . SetDefault ( cfgLoggerTraceLevel , "panic" )
2020-07-07 11:25:13 +00:00
v . SetDefault ( cfgLoggerNoDisclaimer , true )
v . SetDefault ( cfgLoggerSamplingInitial , 1000 )
v . SetDefault ( cfgLoggerSamplingThereafter , 1000 )
2020-07-06 09:18:16 +00:00
// keepalive:
// If set below 10s, a minimum value of 10s will be used instead.
2020-07-07 11:25:13 +00:00
v . SetDefault ( cfgKeepaliveTime , defaultKeepaliveTime )
v . SetDefault ( cfgKeepaliveTimeout , defaultKeepaliveTimeout )
v . SetDefault ( cfgKeepalivePermitWithoutStream , true )
2020-07-06 09:18:16 +00:00
if err := v . BindPFlags ( flags ) ; err != nil {
panic ( err )
}
if err := v . ReadConfig ( devNull ) ; err != nil {
panic ( err )
}
if err := flags . Parse ( os . Args ) ; err != nil {
panic ( err )
}
2020-10-19 08:47:13 +00:00
if peers != nil && len ( * peers ) > 0 {
for i := range * peers {
v . SetDefault ( cfgPeers + "." + strconv . Itoa ( i ) + ".address" , ( * peers ) [ i ] )
v . SetDefault ( cfgPeers + "." + strconv . Itoa ( i ) + ".weight" , 1 )
}
}
2020-07-06 09:18:16 +00:00
switch {
case help != nil && * help :
fmt . Printf ( "NeoFS S3 Gateway %s (%s)\n" , misc . Version , misc . Build )
flags . PrintDefaults ( )
2020-10-19 08:47:13 +00:00
fmt . Println ( )
fmt . Println ( "Default environments:" )
fmt . Println ( )
keys := v . AllKeys ( )
sort . Strings ( keys )
for i := range keys {
if _ , ok := ignore [ keys [ i ] ] ; ok {
continue
}
k := strings . Replace ( keys [ i ] , "." , "_" , - 1 )
fmt . Printf ( "%s_%s = %v\n" , misc . Prefix , strings . ToUpper ( k ) , v . Get ( keys [ i ] ) )
}
fmt . Println ( )
fmt . Println ( "Peers preset:" )
fmt . Println ( )
fmt . Printf ( "%s_%s_[N]_ADDRESS = string\n" , misc . Prefix , strings . ToUpper ( cfgPeers ) )
fmt . Printf ( "%s_%s_[N]_WEIGHT = 0..1 (float)\n" , misc . Prefix , strings . ToUpper ( cfgPeers ) )
2020-07-06 09:18:16 +00:00
os . Exit ( 0 )
case version != nil && * version :
fmt . Printf ( "NeoFS S3 Gateway %s (%s)\n" , misc . Version , misc . Build )
os . Exit ( 0 )
case ttl != nil && ttl . Minutes ( ) < minimumTTLInMinutes :
fmt . Printf ( "connection ttl should not be less than %s" , defaultTTL )
}
return v
}