2019-01-24 20:15:10 +00:00
// Copyright (C) 2019 Storj Labs, Inc.
2019-01-02 18:07:49 +00:00
// See LICENSE for copying information.
package main
import (
"context"
"errors"
"fmt"
2019-11-01 17:27:47 +00:00
"io/ioutil"
2019-01-02 18:07:49 +00:00
"net"
2019-12-05 20:42:12 +00:00
"net/url"
2019-01-02 18:07:49 +00:00
"os"
"os/exec"
"path/filepath"
2019-03-02 15:22:20 +00:00
"runtime"
2019-01-11 16:18:16 +00:00
"sort"
2019-01-02 18:07:49 +00:00
"strconv"
"strings"
2019-02-05 17:22:17 +00:00
"time"
2019-01-02 18:07:49 +00:00
2019-11-11 18:58:08 +00:00
"github.com/alessio/shellescape"
2019-01-29 14:23:30 +00:00
"github.com/spf13/viper"
2019-01-02 18:07:49 +00:00
"github.com/zeebo/errs"
"golang.org/x/sync/errgroup"
2019-12-27 11:48:47 +00:00
"storj.io/common/fpath"
"storj.io/common/identity"
"storj.io/common/storj"
2019-08-05 18:01:20 +01:00
"storj.io/storj/lib/uplink"
2019-12-05 20:42:12 +00:00
"storj.io/storj/private/dbutil"
2019-11-14 19:46:15 +00:00
"storj.io/storj/private/dbutil/pgutil"
"storj.io/storj/private/processgroup"
2019-01-02 18:07:49 +00:00
)
2019-04-19 16:49:46 +01:00
const (
maxInstanceCount = 100
maxStoragenodeCount = 200
folderPermissions = 0744
)
2019-08-05 18:01:20 +01:00
var (
defaultAPIKeyData = "13YqgH45XZLg7nm6KsQ72QgXfjbDu2uhTaeSdMVP2A85QuANthM9K58ww5Y4nhMowrZDoqdA4Kyqt1ioQghQcm9fT5uR2drPHpFEqeb"
defaultAPIKey , _ = uplink . ParseAPIKey ( defaultAPIKeyData )
)
2019-04-19 16:49:46 +01:00
const (
// The following values of peer class and endpoints are used
// to create a port with a consistent format for storj-sim services.
// Peer class
satellitePeer = 0
gatewayPeer = 1
versioncontrolPeer = 2
2019-10-04 21:48:41 +01:00
storagenodePeer = 3
2019-04-19 16:49:46 +01:00
// Endpoint
publicGRPC = 0
privateGRPC = 1
publicHTTP = 2
2019-06-11 16:00:59 +01:00
privateHTTP = 3
2019-04-19 16:49:46 +01:00
debugHTTP = 9
2019-10-30 19:23:09 +00:00
2019-10-29 15:25:25 +00:00
// satellite specific constants
2019-11-02 20:09:07 +00:00
redisPort = 4
debugMigrationHTTP = 6
debugPeerHTTP = 7
debugRepairerHTTP = 8
2019-04-19 16:49:46 +01:00
)
// port creates a port with a consistent format for storj-sim services.
// The port format is: "1PXXE", where P is the peer class, XX is the index of the instance, and E is the endpoint.
func port ( peerclass , index , endpoint int ) string {
port := 10000 + peerclass * 1000 + index * 10 + endpoint
return strconv . Itoa ( port )
}
2019-01-02 18:07:49 +00:00
func networkExec ( flags * Flags , args [ ] string , command string ) error {
2019-01-08 15:24:15 +00:00
processes , err := newNetwork ( flags )
2019-01-02 18:07:49 +00:00
if err != nil {
return err
}
ctx , cancel := NewCLIContext ( context . Background ( ) )
defer cancel ( )
2019-01-18 10:36:58 +00:00
if command == "setup" {
2019-10-16 21:34:25 +01:00
if flags . Postgres == "" {
return errors . New ( "postgres connection URL is required for running storj-sim. Example: `storj-sim network setup --postgres=<connection URL>`.\nSee docs for more details https://github.com/storj/docs/blob/master/Test-network.md#running-tests-with-postgres" )
}
2019-01-18 10:36:58 +00:00
identities , err := identitySetup ( processes )
if err != nil {
return err
}
err = identities . Exec ( ctx , command )
if err != nil {
return err
}
}
2019-01-02 18:07:49 +00:00
err = processes . Exec ( ctx , command )
closeErr := processes . Close ( )
return errs . Combine ( err , closeErr )
}
2019-11-11 18:58:08 +00:00
func escapeEnv ( env string ) string {
// TODO(jeff): escape env variables appropriately on windows. perhaps the
// env output should be of the form `set KEY=VALUE` as well.
if runtime . GOOS == "windows" {
return env
}
parts := strings . SplitN ( env , "=" , 2 )
if len ( parts ) != 2 {
return env
}
return parts [ 0 ] + "=" + shellescape . Quote ( parts [ 1 ] )
}
2019-03-23 21:53:03 +00:00
func networkEnv ( flags * Flags , args [ ] string ) error {
flags . OnlyEnv = true
2019-11-01 17:27:47 +00:00
2019-03-23 21:53:03 +00:00
processes , err := newNetwork ( flags )
if err != nil {
return err
}
// run exec before, since it will load env vars from configs
for _ , process := range processes . List {
if exec := process . ExecBefore [ "run" ] ; exec != nil {
if err := exec ( process ) ; err != nil {
return err
}
}
}
2019-04-10 02:16:12 +01:00
if len ( args ) == 1 {
envprefix := strings . ToUpper ( args [ 0 ] + "=" )
// find the environment value that the environment variable is set to
for _ , env := range processes . Env ( ) {
if strings . HasPrefix ( strings . ToUpper ( env ) , envprefix ) {
2019-11-11 18:58:08 +00:00
fmt . Println ( escapeEnv ( env [ len ( envprefix ) : ] ) )
2019-04-10 02:16:12 +01:00
return nil
}
}
return nil
}
2019-03-23 21:53:03 +00:00
for _ , env := range processes . Env ( ) {
2019-11-11 18:58:08 +00:00
fmt . Println ( escapeEnv ( env ) )
2019-03-23 21:53:03 +00:00
}
return nil
}
2019-01-02 18:07:49 +00:00
func networkTest ( flags * Flags , command string , args [ ] string ) error {
2019-01-08 15:24:15 +00:00
processes , err := newNetwork ( flags )
2019-01-02 18:07:49 +00:00
if err != nil {
return err
}
ctx , cancel := NewCLIContext ( context . Background ( ) )
var group errgroup . Group
processes . Start ( ctx , & group , "run" )
2019-01-08 15:24:15 +00:00
for _ , process := range processes . List {
2019-10-28 14:04:31 +00:00
process . Status . Started . Wait ( ctx )
}
if err := ctx . Err ( ) ; err != nil {
return err
2019-01-08 15:24:15 +00:00
}
2019-01-02 18:07:49 +00:00
cmd := exec . CommandContext ( ctx , command , args ... )
cmd . Env = append ( os . Environ ( ) , processes . Env ( ) ... )
stdout := processes . Output . Prefixed ( "test:out" )
stderr := processes . Output . Prefixed ( "test:err" )
cmd . Stdout , cmd . Stderr = stdout , stderr
processgroup . Setup ( cmd )
if printCommands {
fmt . Fprintf ( processes . Output , "exec: %v\n" , strings . Join ( cmd . Args , " " ) )
}
errRun := cmd . Run ( )
cancel ( )
return errs . Combine ( errRun , processes . Close ( ) , group . Wait ( ) )
}
func networkDestroy ( flags * Flags , args [ ] string ) error {
if fpath . IsRoot ( flags . Directory ) {
return errors . New ( "safety check: disallowed to remove root directory " + flags . Directory )
}
if printCommands {
2019-01-16 23:09:57 +00:00
fmt . Println ( "sim | exec: rm -rf" , flags . Directory )
2019-01-02 18:07:49 +00:00
}
return os . RemoveAll ( flags . Directory )
}
// newNetwork creates a default network
2019-01-08 15:24:15 +00:00
func newNetwork ( flags * Flags ) ( * Processes , error ) {
2019-06-20 12:52:32 +01:00
_ , filename , _ , ok := runtime . Caller ( 0 )
if ! ok {
return nil , errs . New ( "no caller information" )
}
storjRoot := strings . TrimSuffix ( filename , "/cmd/storj-sim/network.go" )
2019-01-08 15:24:15 +00:00
// with common adds all common arguments to the process
2019-03-19 09:10:23 +00:00
withCommon := func ( dir string , all Arguments ) Arguments {
common := [ ] string { "--metrics.app-suffix" , "sim" , "--log.level" , "debug" , "--config-dir" , dir }
2019-03-12 12:51:06 +00:00
if flags . IsDev {
2019-08-05 18:01:20 +01:00
common = append ( common , "--defaults" , "dev" )
2019-03-12 12:51:06 +00:00
}
2019-01-08 15:24:15 +00:00
for command , args := range all {
2019-03-12 12:51:06 +00:00
all [ command ] = append ( append ( common , command ) , args ... )
2019-01-08 15:24:15 +00:00
}
return all
}
2019-01-02 18:07:49 +00:00
2019-03-19 09:10:23 +00:00
processes := NewProcesses ( flags . Directory )
2019-04-19 16:49:46 +01:00
var host = flags . Host
2019-04-03 20:13:39 +01:00
versioncontrol := processes . New ( Info {
Name : "versioncontrol/0" ,
Executable : "versioncontrol" ,
Directory : filepath . Join ( processes . Directory , "versioncontrol" , "0" ) ,
2019-04-19 16:49:46 +01:00
Address : net . JoinHostPort ( host , port ( versioncontrolPeer , 0 , publicGRPC ) ) ,
2019-04-03 20:13:39 +01:00
} )
versioncontrol . Arguments = withCommon ( versioncontrol . Directory , Arguments {
"setup" : {
"--address" , versioncontrol . Address ,
2019-05-14 16:13:18 +01:00
"--debug.addr" , net . JoinHostPort ( host , port ( versioncontrolPeer , 0 , debugHTTP ) ) ,
2019-11-06 14:06:10 +00:00
"--binary.gateway.rollout.seed" , "0000000000000000000000000000000000000000000000000000000000000001" ,
"--binary.identity.rollout.seed" , "0000000000000000000000000000000000000000000000000000000000000001" ,
"--binary.satellite.rollout.seed" , "0000000000000000000000000000000000000000000000000000000000000001" ,
"--binary.storagenode-updater.rollout.seed" , "0000000000000000000000000000000000000000000000000000000000000001" ,
"--binary.storagenode.rollout.seed" , "0000000000000000000000000000000000000000000000000000000000000001" ,
"--binary.uplink.rollout.seed" , "0000000000000000000000000000000000000000000000000000000000000001" ,
2019-04-03 20:13:39 +01:00
} ,
"run" : { } ,
} )
versioncontrol . ExecBefore [ "run" ] = func ( process * Process ) error {
return readConfigString ( & versioncontrol . Address , versioncontrol . Directory , "address" )
}
// gateway must wait for the versioncontrol to start up
2019-10-04 21:48:41 +01:00
// Create satellites
2019-04-19 16:49:46 +01:00
if flags . SatelliteCount > maxInstanceCount {
return nil , fmt . Errorf ( "exceeded the max instance count of %d with Satellite count of %d" , maxInstanceCount , flags . SatelliteCount )
}
2019-11-01 17:27:47 +00:00
// set up redis servers
var redisServers [ ] * Process
2019-11-01 19:48:37 +00:00
if flags . Redis == "" {
for i := 0 ; i < flags . SatelliteCount ; i ++ {
rp := port ( satellitePeer , i , redisPort )
process := processes . New ( Info {
Name : fmt . Sprintf ( "redis/%d" , i ) ,
Executable : "redis-server" ,
Directory : filepath . Join ( processes . Directory , "satellite" , fmt . Sprint ( i ) , "redis" ) ,
Address : net . JoinHostPort ( host , rp ) ,
} )
redisServers = append ( redisServers , process )
process . ExecBefore [ "setup" ] = func ( process * Process ) error {
confpath := filepath . Join ( process . Directory , "redis.conf" )
arguments := [ ] string {
"daemonize no" ,
"bind " + host ,
"port " + rp ,
"timeout 0" ,
"databases 2" ,
"dbfilename sim.rdb" ,
"dir ./" ,
}
conf := strings . Join ( arguments , "\n" ) + "\n"
err := ioutil . WriteFile ( confpath , [ ] byte ( conf ) , 0755 )
return err
}
process . Arguments = Arguments {
"run" : [ ] string { filepath . Join ( process . Directory , "redis.conf" ) } ,
2019-11-01 17:27:47 +00:00
}
}
}
2019-01-09 15:59:51 +00:00
var satellites [ ] * Process
2019-01-08 15:24:15 +00:00
for i := 0 ; i < flags . SatelliteCount ; i ++ {
2019-11-04 19:01:02 +00:00
apiProcess := processes . New ( Info {
2019-01-08 15:24:15 +00:00
Name : fmt . Sprintf ( "satellite/%d" , i ) ,
Executable : "satellite" ,
2019-03-19 09:10:23 +00:00
Directory : filepath . Join ( processes . Directory , "satellite" , fmt . Sprint ( i ) ) ,
2019-04-19 16:49:46 +01:00
Address : net . JoinHostPort ( host , port ( satellitePeer , i , publicGRPC ) ) ,
2019-01-08 15:24:15 +00:00
} )
2019-11-04 19:01:02 +00:00
satellites = append ( satellites , apiProcess )
2019-01-08 15:24:15 +00:00
2019-03-19 17:55:43 +00:00
consoleAuthToken := "secure_token"
2019-11-01 19:48:37 +00:00
redisAddress := flags . Redis
2019-11-04 12:55:02 +00:00
redisPortBase := flags . RedisStartDB + i * 2
2019-11-01 19:48:37 +00:00
if redisAddress == "" {
redisAddress = redisServers [ i ] . Address
redisPortBase = 0
2019-11-04 19:01:02 +00:00
apiProcess . WaitForStart ( redisServers [ i ] )
2019-11-01 19:48:37 +00:00
}
2019-11-04 19:01:02 +00:00
apiProcess . Arguments = withCommon ( apiProcess . Directory , Arguments {
2019-01-22 12:35:48 +00:00
"setup" : {
2019-11-04 19:01:02 +00:00
"--identity-dir" , apiProcess . Directory ,
2019-04-19 16:49:46 +01:00
"--console.address" , net . JoinHostPort ( host , port ( satellitePeer , i , publicHTTP ) ) ,
2019-03-02 15:22:20 +00:00
"--console.static-dir" , filepath . Join ( storjRoot , "web/satellite/" ) ,
2019-03-19 17:55:43 +00:00
// TODO: remove console.auth-token after vanguard release
"--console.auth-token" , consoleAuthToken ,
2019-08-30 23:43:53 +01:00
"--marketing.base-url" , "" ,
2019-06-11 16:00:59 +01:00
"--marketing.address" , net . JoinHostPort ( host , port ( satellitePeer , i , privateHTTP ) ) ,
2019-06-12 14:42:39 +01:00
"--marketing.static-dir" , filepath . Join ( storjRoot , "web/marketing/" ) ,
2019-11-04 19:01:02 +00:00
"--server.address" , apiProcess . Address ,
2019-04-19 16:49:46 +01:00
"--server.private-address" , net . JoinHostPort ( host , port ( satellitePeer , i , privateGRPC ) ) ,
2019-01-08 23:41:01 +00:00
2019-11-01 19:48:37 +00:00
"--live-accounting.storage-backend" , "redis://" + redisAddress + "?db=" + strconv . Itoa ( redisPortBase ) ,
"--server.revocation-dburl" , "redis://" + redisAddress + "?db=" + strconv . Itoa ( redisPortBase + 1 ) ,
2019-11-01 17:27:47 +00:00
2019-02-11 11:17:32 +00:00
"--server.extensions.revocation=false" ,
"--server.use-peer-ca-whitelist=false" ,
2019-03-02 15:22:20 +00:00
"--mail.smtp-server-address" , "smtp.gmail.com:587" ,
"--mail.from" , "Storj <yaroslav-satellite-test@storj.io>" ,
"--mail.template-path" , filepath . Join ( storjRoot , "web/satellite/static/emails" ) ,
2019-04-03 20:13:39 +01:00
"--version.server-address" , fmt . Sprintf ( "http://%s/" , versioncontrol . Address ) ,
2019-05-14 16:13:18 +01:00
"--debug.addr" , net . JoinHostPort ( host , port ( satellitePeer , i , debugHTTP ) ) ,
2019-01-08 15:24:15 +00:00
} ,
2019-10-30 19:23:09 +00:00
"run" : { "api" } ,
2019-01-08 15:24:15 +00:00
} )
2019-02-06 12:47:00 +00:00
2019-05-14 16:13:18 +01:00
if flags . Postgres != "" {
2019-12-05 20:42:12 +00:00
masterDBURL , err := namespacedDatabaseURL ( flags . Postgres , fmt . Sprintf ( "satellite/%d" , i ) )
if err != nil {
return nil , err
}
metainfoDBURL , err := namespacedDatabaseURL ( flags . Postgres , fmt . Sprintf ( "satellite/%d/meta" , i ) )
if err != nil {
return nil , err
}
2019-11-04 19:01:02 +00:00
apiProcess . Arguments [ "setup" ] = append ( apiProcess . Arguments [ "setup" ] ,
2019-12-05 20:42:12 +00:00
"--database" , masterDBURL ,
"--metainfo.database-url" , metainfoDBURL ,
2019-05-14 16:13:18 +01:00
)
}
2019-11-04 19:01:02 +00:00
apiProcess . ExecBefore [ "run" ] = func ( process * Process ) error {
2019-02-06 12:47:00 +00:00
return readConfigString ( & process . Address , process . Directory , "server.address" )
}
2019-01-02 18:07:49 +00:00
2019-11-02 20:09:07 +00:00
migrationProcess := processes . New ( Info {
Name : fmt . Sprintf ( "satellite-migration/%d" , i ) ,
2019-10-16 21:34:25 +01:00
Executable : "satellite" ,
Directory : filepath . Join ( processes . Directory , "satellite" , fmt . Sprint ( i ) ) ,
2019-11-02 20:09:07 +00:00
} )
2019-11-04 19:01:02 +00:00
migrationProcess . Arguments = withCommon ( apiProcess . Directory , Arguments {
2019-11-02 20:09:07 +00:00
"run" : {
"migration" ,
"--debug.addr" , net . JoinHostPort ( host , port ( satellitePeer , i , debugMigrationHTTP ) ) ,
} ,
2019-10-16 21:34:25 +01:00
} )
2019-11-02 20:09:07 +00:00
coreProcess := processes . New ( Info {
Name : fmt . Sprintf ( "satellite-core/%d" , i ) ,
Executable : "satellite" ,
Directory : filepath . Join ( processes . Directory , "satellite" , fmt . Sprint ( i ) ) ,
Address : "" ,
} )
2019-11-04 19:01:02 +00:00
coreProcess . Arguments = withCommon ( apiProcess . Directory , Arguments {
2019-10-16 21:34:25 +01:00
"run" : {
2019-10-30 19:23:09 +00:00
"--debug.addr" , net . JoinHostPort ( host , port ( satellitePeer , i , debugPeerHTTP ) ) ,
2019-10-16 21:34:25 +01:00
} ,
} )
2019-11-02 20:09:07 +00:00
coreProcess . WaitForExited ( migrationProcess )
2019-10-16 21:34:25 +01:00
2019-11-02 20:09:07 +00:00
repairProcess := processes . New ( Info {
2019-10-29 14:55:57 +00:00
Name : fmt . Sprintf ( "satellite-repairer/%d" , i ) ,
Executable : "satellite" ,
Directory : filepath . Join ( processes . Directory , "satellite" , fmt . Sprint ( i ) ) ,
} )
2019-11-04 19:01:02 +00:00
repairProcess . Arguments = withCommon ( apiProcess . Directory , Arguments {
2019-10-29 14:55:57 +00:00
"run" : {
"repair" ,
2019-10-29 15:25:25 +00:00
"--debug.addr" , net . JoinHostPort ( host , port ( satellitePeer , i , debugRepairerHTTP ) ) ,
2019-10-29 14:55:57 +00:00
} ,
} )
2019-11-02 20:09:07 +00:00
repairProcess . WaitForExited ( migrationProcess )
2019-11-04 19:01:02 +00:00
apiProcess . WaitForExited ( migrationProcess )
2019-10-29 14:55:57 +00:00
}
2019-10-16 21:34:25 +01:00
// Create gateways for each satellite
2019-10-30 19:23:09 +00:00
for i , satellite := range satellites {
2019-02-06 12:47:00 +00:00
satellite := satellite
2019-01-08 15:24:15 +00:00
process := processes . New ( Info {
Name : fmt . Sprintf ( "gateway/%d" , i ) ,
Executable : "gateway" ,
2019-03-19 09:10:23 +00:00
Directory : filepath . Join ( processes . Directory , "gateway" , fmt . Sprint ( i ) ) ,
2019-04-19 16:49:46 +01:00
Address : net . JoinHostPort ( host , port ( gatewayPeer , i , publicGRPC ) ) ,
2019-01-08 15:24:15 +00:00
} )
2019-08-05 18:01:20 +01:00
scopeData , err := ( & uplink . Scope {
SatelliteAddr : satellite . Address ,
APIKey : defaultAPIKey ,
EncryptionAccess : uplink . NewEncryptionAccessWithDefaultKey ( storj . Key { } ) ,
} ) . Serialize ( )
if err != nil {
return nil , err
}
2019-01-08 15:24:15 +00:00
// gateway must wait for the corresponding satellite to start up
process . WaitForStart ( satellite )
2019-03-19 09:10:23 +00:00
process . Arguments = withCommon ( process . Directory , Arguments {
2019-01-08 15:24:15 +00:00
"setup" : {
2019-06-07 17:14:40 +01:00
"--non-interactive" ,
2019-08-05 18:01:20 +01:00
"--scope" , scopeData ,
2019-01-22 12:35:48 +00:00
"--identity-dir" , process . Directory ,
2019-01-08 15:24:15 +00:00
"--server.address" , process . Address ,
"--rs.min-threshold" , strconv . Itoa ( 1 * flags . StorageNodeCount / 5 ) ,
"--rs.repair-threshold" , strconv . Itoa ( 2 * flags . StorageNodeCount / 5 ) ,
"--rs.success-threshold" , strconv . Itoa ( 3 * flags . StorageNodeCount / 5 ) ,
"--rs.max-threshold" , strconv . Itoa ( 4 * flags . StorageNodeCount / 5 ) ,
2019-02-11 11:17:32 +00:00
"--tls.extensions.revocation=false" ,
"--tls.use-peer-ca-whitelist=false" ,
2019-04-19 16:49:46 +01:00
"--debug.addr" , net . JoinHostPort ( host , port ( gatewayPeer , i , debugHTTP ) ) ,
2019-01-08 15:24:15 +00:00
} ,
2019-08-05 18:01:20 +01:00
2019-06-07 17:14:40 +01:00
"run" : { } ,
2019-01-08 15:24:15 +00:00
} )
2019-01-29 14:23:30 +00:00
2019-12-11 00:51:10 +00:00
process . ExecBefore [ "run" ] = func ( process * Process ) ( err error ) {
err = readConfigString ( & process . Address , process . Directory , "server.address" )
2019-02-06 12:47:00 +00:00
if err != nil {
return err
}
2019-01-29 14:23:30 +00:00
vip := viper . New ( )
vip . AddConfigPath ( process . Directory )
if err := vip . ReadInConfig ( ) ; err != nil {
return err
}
// TODO: maybe all the config flags should be exposed for all processes?
2019-02-05 17:22:17 +00:00
// check if gateway config has an api key, if it's not
// create example project with key and add it to the config
// so that gateway can have access to the satellite
2019-08-05 18:01:20 +01:00
if runScopeData := vip . GetString ( "scope" ) ; ! flags . OnlyEnv && runScopeData == scopeData {
2019-02-06 12:47:00 +00:00
var consoleAddress string
2019-08-05 18:01:20 +01:00
err := readConfigString ( & consoleAddress , satellite . Directory , "console.address" )
if err != nil {
return err
2019-02-06 12:47:00 +00:00
}
2019-12-11 00:51:10 +00:00
// try with 100ms delays until we hit 3s
apiKey , start := "" , time . Now ( )
for apiKey == "" {
apiKey , err = newConsoleEndpoints ( consoleAddress ) . createOrGetAPIKey ( )
if err != nil && time . Since ( start ) > 3 * time . Second {
return err
}
time . Sleep ( 100 * time . Millisecond )
2019-02-05 17:22:17 +00:00
}
2019-08-05 18:01:20 +01:00
scope , err := uplink . ParseScope ( runScopeData )
if err != nil {
return err
}
scope . APIKey , err = uplink . ParseAPIKey ( apiKey )
if err != nil {
return err
}
scopeData , err := scope . Serialize ( )
if err != nil {
return err
}
vip . Set ( "scope" , scopeData )
2019-02-05 17:22:17 +00:00
if err := vip . WriteConfig ( ) ; err != nil {
return err
}
}
2019-08-05 18:01:20 +01:00
if runScopeData := vip . GetString ( "scope" ) ; runScopeData != scopeData {
2019-11-11 18:58:08 +00:00
process . AddExtra ( "SCOPE" , runScopeData )
2019-10-09 19:33:53 +01:00
if scope , err := uplink . ParseScope ( runScopeData ) ; err == nil {
2019-11-11 18:58:08 +00:00
process . AddExtra ( "API_KEY" , scope . APIKey . Serialize ( ) )
2019-10-09 19:33:53 +01:00
}
2019-03-23 21:53:03 +00:00
}
2019-11-11 18:58:08 +00:00
process . AddExtra ( "ACCESS_KEY" , vip . GetString ( "minio.access-key" ) )
process . AddExtra ( "SECRET_KEY" , vip . GetString ( "minio.secret-key" ) )
2019-01-29 14:23:30 +00:00
return nil
}
2019-01-02 18:07:49 +00:00
}
2019-01-08 15:24:15 +00:00
// Create storage nodes
2019-04-19 16:49:46 +01:00
if flags . StorageNodeCount > maxStoragenodeCount {
return nil , fmt . Errorf ( "exceeded the max instance count of %d with Storage Node count of %d" , maxStoragenodeCount , flags . StorageNodeCount )
}
2019-01-08 15:24:15 +00:00
for i := 0 ; i < flags . StorageNodeCount ; i ++ {
process := processes . New ( Info {
Name : fmt . Sprintf ( "storagenode/%d" , i ) ,
Executable : "storagenode" ,
2019-03-19 09:10:23 +00:00
Directory : filepath . Join ( processes . Directory , "storagenode" , fmt . Sprint ( i ) ) ,
2019-04-19 16:49:46 +01:00
Address : net . JoinHostPort ( host , port ( storagenodePeer , i , publicGRPC ) ) ,
2019-01-08 15:24:15 +00:00
} )
2019-10-30 19:23:09 +00:00
for _ , satellite := range satellites {
2019-02-22 14:35:51 +00:00
process . WaitForStart ( satellite )
}
2019-01-08 15:24:15 +00:00
2019-03-19 09:10:23 +00:00
process . Arguments = withCommon ( process . Directory , Arguments {
2019-01-22 12:35:48 +00:00
"setup" : {
"--identity-dir" , process . Directory ,
2019-06-20 12:52:32 +01:00
"--console.address" , net . JoinHostPort ( host , port ( storagenodePeer , i , publicHTTP ) ) ,
2019-09-12 13:20:52 +01:00
"--console.static-dir" , filepath . Join ( storjRoot , "web/storagenode/" ) ,
2019-01-28 14:48:49 +00:00
"--server.address" , process . Address ,
2019-04-19 16:49:46 +01:00
"--server.private-address" , net . JoinHostPort ( host , port ( storagenodePeer , i , privateGRPC ) ) ,
2019-01-28 14:48:49 +00:00
2019-10-04 21:48:41 +01:00
"--operator.email" , fmt . Sprintf ( "storage%d@mail.test" , i ) ,
"--operator.wallet" , "0x0123456789012345678901234567890123456789" ,
2019-02-11 11:17:32 +00:00
2019-08-05 18:01:20 +01:00
"--storage2.monitor.minimum-disk-space" , "0" ,
"--storage2.monitor.minimum-bandwidth" , "0" ,
2019-06-10 11:14:50 +01:00
2019-02-11 11:17:32 +00:00
"--server.extensions.revocation=false" ,
"--server.use-peer-ca-whitelist=false" ,
2019-04-03 20:13:39 +01:00
"--version.server-address" , fmt . Sprintf ( "http://%s/" , versioncontrol . Address ) ,
2019-05-14 16:13:18 +01:00
"--debug.addr" , net . JoinHostPort ( host , port ( storagenodePeer , i , debugHTTP ) ) ,
2019-01-08 15:24:15 +00:00
} ,
2019-01-28 14:48:49 +00:00
"run" : { } ,
2019-01-08 15:24:15 +00:00
} )
2019-02-06 12:47:00 +00:00
2019-07-17 19:14:44 +01:00
process . ExecBefore [ "setup" ] = func ( process * Process ) error {
whitelisted := [ ] string { }
2019-10-30 19:23:09 +00:00
for _ , satellite := range satellites {
2019-07-17 19:14:44 +01:00
peer , err := identity . PeerConfig {
2019-10-30 19:23:09 +00:00
CertPath : filepath . Join ( satellite . Directory , "identity.cert" ) ,
2019-07-17 19:14:44 +01:00
} . Load ( )
if err != nil {
return err
}
2019-10-30 19:23:09 +00:00
whitelisted = append ( whitelisted , peer . ID . String ( ) + "@" + satellite . Address )
2019-07-17 19:14:44 +01:00
}
process . Arguments [ "setup" ] = append ( process . Arguments [ "setup" ] ,
2019-11-16 00:59:32 +00:00
"--storage2.trust.sources" , strings . Join ( whitelisted , "," ) ,
2019-07-17 19:14:44 +01:00
)
return nil
}
2019-02-06 12:47:00 +00:00
process . ExecBefore [ "run" ] = func ( process * Process ) error {
return readConfigString ( & process . Address , process . Directory , "server.address" )
}
2019-01-08 15:24:15 +00:00
}
2019-01-02 18:07:49 +00:00
2019-01-11 16:18:16 +00:00
{ // verify that we have all binaries
missing := map [ string ] bool { }
for _ , process := range processes . List {
_ , err := exec . LookPath ( process . Executable )
if err != nil {
missing [ process . Executable ] = true
}
}
if len ( missing ) > 0 {
var list [ ] string
for executable := range missing {
list = append ( list , executable )
}
sort . Strings ( list )
return nil , fmt . Errorf ( "some executables cannot be found: %v" , list )
}
}
2019-01-08 15:24:15 +00:00
// Create directories for all processes
for _ , process := range processes . List {
if err := os . MkdirAll ( process . Directory , folderPermissions ) ; err != nil {
2019-01-02 18:07:49 +00:00
return nil , err
}
}
return processes , nil
}
2019-01-08 15:24:15 +00:00
2019-01-18 10:36:58 +00:00
func identitySetup ( network * Processes ) ( * Processes , error ) {
2019-03-19 09:10:23 +00:00
processes := NewProcesses ( network . Directory )
2019-01-18 10:36:58 +00:00
for _ , process := range network . List {
2019-11-01 17:27:47 +00:00
if process . Info . Executable == "gateway" || process . Info . Executable == "redis-server" {
// gateways and redis-servers don't need an identity
2019-05-10 12:17:58 +01:00
continue
}
2019-11-02 20:09:07 +00:00
if strings . Contains ( process . Name , "satellite-" ) {
// we only need to create the identity once for the satellite system, we create the
// identity for the satellite process and share it with these other satellite processes
2019-10-29 14:55:57 +00:00
continue
}
2019-10-16 21:34:25 +01:00
2019-01-18 10:36:58 +00:00
identity := processes . New ( Info {
Name : "identity/" + process . Info . Name ,
Executable : "identity" ,
Directory : process . Directory ,
Address : "" ,
} )
identity . Arguments = Arguments {
"setup" : {
2019-01-22 12:35:48 +00:00
"--identity-dir" , process . Directory ,
2019-01-23 11:36:19 +00:00
"--concurrency" , "1" ,
"--difficulty" , "8" ,
2019-01-24 15:41:16 +00:00
"create" , "." ,
2019-01-18 10:36:58 +00:00
} ,
}
}
// create directories for all processes
for _ , process := range processes . List {
if err := os . MkdirAll ( process . Directory , folderPermissions ) ; err != nil {
return nil , err
}
}
return processes , nil
}
2019-02-06 12:47:00 +00:00
// readConfigString reads from dir/config.yaml flagName returns the value in `into`
func readConfigString ( into * string , dir , flagName string ) error {
vip := viper . New ( )
vip . AddConfigPath ( dir )
if err := vip . ReadInConfig ( ) ; err != nil {
return err
}
if v := vip . GetString ( flagName ) ; v != "" {
* into = v
}
return nil
}
2019-12-05 20:42:12 +00:00
// namespacedDatabaseURL returns an equivalent database url with the given namespace
// so that a database opened with the url does not conflict with other databases
// opened with a different namespace.
func namespacedDatabaseURL ( dbURL , namespace string ) ( string , error ) {
parsed , err := url . Parse ( dbURL )
if err != nil {
return "" , err
}
switch dbutil . ImplementationForScheme ( parsed . Scheme ) {
case dbutil . Postgres :
return pgutil . ConnstrWithSchema ( dbURL , namespace ) , nil
case dbutil . Cockroach :
parsed . Path += "/" + namespace
return parsed . String ( ) , nil
default :
return "" , errs . New ( "unable to namespace db url: %q" , dbURL )
}
}