diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 3ca5044811..ca86e6e078 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -7,6 +7,7 @@ ### Features ⚒ #### General +- \#2383 Add E2E Tests for checking Livepeer on-chain interactions (@leszko) #### Broadcaster diff --git a/cmd/devtool/devtool.go b/cmd/devtool/devtool.go index 7e272ad85e..7fd951a068 100644 --- a/cmd/devtool/devtool.go +++ b/cmd/devtool/devtool.go @@ -1,46 +1,23 @@ package main import ( - "bytes" - "context" "flag" "fmt" + "github.com/golang/glog" + "github.com/livepeer/go-livepeer/cmd/devtool/devtool" "io" "io/ioutil" - "math/big" "os" "path/filepath" "strconv" "strings" - "time" - - "github.com/ethereum/go-ethereum/accounts/keystore" - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/console" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" - "github.com/livepeer/go-livepeer/eth" - - "github.com/golang/glog" -) - -const ( - passphrase = "" ) var ( - ethTxTimeout = 5 * time.Minute - endpoint = "http://localhost:8545/" - gethMiningAccount = "87da6a8c6e9eff15d703fc2773e32f6af8dbe301" - gethMiningAccountOverride = false - ethController = "0x04B9De88c81cda06165CF65a908e5f1EFBB9493B" - ethControllerOverride = false - serviceHost = "127.0.0.1" - serviceURI = "https://127.0.0.1:" - cliPort = 7935 - mediaPort = 8935 - rtmpPort = 1935 + serviceHost = "127.0.0.1" + cliPort = 7935 + mediaPort = 8935 + rtmpPort = 1935 ) func main() { @@ -52,20 +29,22 @@ func main() { svcHost := flag.String("svchost", "127.0.0.1", "default service host") flag.Parse() + + cfg := devtool.NewDevtoolConfig() if *endpointAddr != "" { - endpoint = *endpointAddr + cfg.Endpoint = *endpointAddr } if *miningAccountFlag != "" { - gethMiningAccount = *miningAccountFlag - gethMiningAccountOverride = true + cfg.GethMiningAccount = *miningAccountFlag + cfg.GethMiningAccountOverride = true } if *ethControllerFlag != "" { - ethController = *ethControllerFlag - ethControllerOverride = true + cfg.EthController = *ethControllerFlag + cfg.EthControllerOverride = true } if *svcHost != "" { serviceHost = *svcHost - serviceURI = fmt.Sprintf("https://%s:", serviceHost) + cfg.ServiceURI = fmt.Sprintf("https://%s:", serviceHost) } args := flag.Args() goodToGo := false @@ -100,7 +79,7 @@ func main() { nodeIndex = int(i) } } - serviceURI += strconv.Itoa(mediaPort + nodeIndex) + cfg.ServiceURI += strconv.Itoa(mediaPort + nodeIndex) mediaPort += nodeIndex cliPort += nodeIndex * 2 // Because we need different CLI ports for the Orchestrator and Transcoder scripts rtmpPort += nodeIndex @@ -114,7 +93,8 @@ func main() { defer os.RemoveAll(tmp) tempKeystoreDir := filepath.Join(tmp, "keystore") - acc := createKey(tempKeystoreDir) + acc := devtool.CreateKey(tempKeystoreDir) + cfg.Account = acc glog.Infof("Using account %s", acc) glog.Infof("Using svchost %s", serviceHost) dataDir := filepath.Join(*baseDataDir, t+"_"+acc) @@ -128,9 +108,23 @@ func main() { if err != nil { glog.Fatal(err) } - remoteConsole(acc) - ethSetup(acc, keystoreDir, isBroadcaster) - createRunScript(acc, dataDir, serviceHost, isBroadcaster) + cfg.KeystoreDir = keystoreDir + cfg.IsBroadcaster = isBroadcaster + devtool, err := devtool.Init(cfg) + if err != nil { + glog.Error(err) + } + defer devtool.Close() + + if cfg.IsBroadcaster { + err = devtool.FundBroadcaster() + } else { + err = devtool.InitializeOrchestrator(cfg) + } + if err != nil { + glog.Error(err) + } + createRunScript(devtool.EthController, dataDir, serviceHost, cfg) if !isBroadcaster { cliPort += 1 tDataDir := filepath.Join(*baseDataDir, "transcoder_"+acc) @@ -151,184 +145,6 @@ func getNodeType(isBroadcaster bool) string { return t } -func ethSetup(ethAcctAddr, keystoreDir string, isBroadcaster bool) { - time.Sleep(3 * time.Second) - //Set up eth client - backend, err := ethclient.Dial(endpoint) - if err != nil { - glog.Errorf("Failed to connect to Ethereum client: %v", err) - return - } - glog.Infof("Using controller address %s", ethController) - - gpm := eth.NewGasPriceMonitor(backend, 5*time.Second, big.NewInt(0), nil) - - // Start gas price monitor - _, err = gpm.Start(context.Background()) - if err != nil { - glog.Errorf("error starting gas price monitor: %v", err) - return - } - defer gpm.Stop() - - chainID, err := backend.ChainID(context.Background()) - if err != nil { - glog.Errorf("Failed to get chain ID from remote ethereum node: %v", err) - return - } - - am, err := eth.NewAccountManager(ethcommon.HexToAddress(ethAcctAddr), keystoreDir, chainID, passphrase) - if err != nil { - glog.Errorf("Error creating Ethereum account manager: %v", err) - return - } - - if err := am.Unlock(passphrase); err != nil { - glog.Errorf("Error unlocking Ethereum account: %v", err) - return - } - - maxTxReplacements := 0 - tm := eth.NewTransactionManager(backend, gpm, am, ethTxTimeout, maxTxReplacements) - go tm.Start() - defer tm.Stop() - - ethCfg := eth.LivepeerEthClientConfig{ - AccountManager: am, - ControllerAddr: ethcommon.HexToAddress(ethController), - EthClient: backend, - GasPriceMonitor: gpm, - TransactionManager: tm, - Signer: types.LatestSignerForChainID(chainID), - CheckTxTimeout: time.Duration(int64(ethTxTimeout) * int64(maxTxReplacements+1)), - } - - client, err := eth.NewClient(ethCfg) - if err != nil { - glog.Errorf("Failed to create Livepeer Ethereum client: %v", err) - return - } - - if err := client.SetGasInfo(0); err != nil { - glog.Errorf("Failed to set gas info on Livepeer Ethereum Client: %v", err) - return - } - - if isBroadcaster { - amount := new(big.Int).Mul(big.NewInt(100), new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) - - glog.Infof("Funding deposit with %v", amount) - glog.Infof("Funding reserve with %v", amount) - - tx, err := client.FundDepositAndReserve(amount, amount) - if err != nil { - glog.Error(err) - return - } - if err := client.CheckTx(tx); err != nil { - glog.Error(err) - return - } - - glog.Info("Done funding deposit and reserve") - } else { - glog.Infof("Requesting tokens from faucet") - - tx, err := client.Request() - if err != nil { - glog.Errorf("Error requesting tokens from faucet: %v", err) - return - } - - err = client.CheckTx(tx) - if err != nil { - glog.Errorf("Error requesting tokens from faucet: %v", err) - return - } - glog.Info("Done requesting tokens.") - time.Sleep(4 * time.Second) - - // XXX TODO curl -X "POST" http://localhost:$transcoderCliPort/initializeRound - time.Sleep(3 * time.Second) - for { - currentRound, err := client.CurrentRound() - if err != nil { - glog.Errorf("Error getting current round: %v", err) - return - } - if currentRound.Int64() > 1 { - break - } - // first round is initialized and locked, need to wait - glog.Info("Waiting will first round ended.") - time.Sleep(4 * time.Second) - } - tx, err = client.InitializeRound() - // ErrRoundInitialized - if err != nil { - if err.Error() != "ErrRoundInitialized" { - glog.Errorf("Error initializing round: %v", err) - return - } - } else { - err = client.CheckTx(tx) - if err != nil { - glog.Errorf("Error initializng round: %v", err) - return - } - } - glog.Info("Done initializing round.") - glog.Info("Activating transcoder") - // curl -d "blockRewardCut=10&feeShare=5&amount=500" --data-urlencode "serviceURI=https://$transcoderServiceAddr" \ - // -H "Content-Type: application/x-www-form-urlencoded" \ - // -X "POST" http://localhost:$transcoderCliPort/activateTranscoder\ - var amount *big.Int = big.NewInt(int64(500)) - glog.Infof("Bonding %v to %s", amount, ethAcctAddr) - - tx, err = client.Bond(amount, ethcommon.HexToAddress(ethAcctAddr)) - if err != nil { - glog.Error(err) - return - } - - err = client.CheckTx(tx) - if err != nil { - glog.Error("=== Bonding failed") - glog.Error(err) - return - } - glog.Infof("Registering transcoder %v", ethAcctAddr) - - tx, err = client.Transcoder(eth.FromPerc(10), eth.FromPerc(5)) - if err == eth.ErrCurrentRoundLocked { - // wait for next round and retry - } - if err != nil { - glog.Error(err) - return - } - - err = client.CheckTx(tx) - if err != nil { - glog.Error(err) - return - } - - glog.Infof("Storing service URI %v in service registry...", serviceURI) - - tx, err = client.SetServiceURI(serviceURI) - if err != nil { - glog.Error(err) - return - } - - err = client.CheckTx(tx) - if err != nil { - glog.Error(err) - } - } -} - func createTranscoderRunScript(ethAcctAddr, dataDir, serviceHost string) { args := []string{ "./livepeer", @@ -343,14 +159,14 @@ func createTranscoderRunScript(ethAcctAddr, dataDir, serviceHost string) { writeScript(fName, args...) } -func createRunScript(ethAcctAddr, dataDir, serviceHost string, isBroadcaster bool) { +func createRunScript(ethController string, dataDir, serviceHost string, cfg devtool.DevtoolConfig) { args := []string{ "./livepeer", "-v 99", "-ethController " + ethController, "-datadir ./" + dataDir, - "-ethAcctAddr " + ethAcctAddr, - "-ethUrl " + endpoint, + "-ethAcctAddr " + cfg.Account, + "-ethUrl " + cfg.Endpoint, "-ethPassword \"\"", "-network=devenv", "-blockPollingInterval 1", @@ -360,7 +176,7 @@ func createRunScript(ethAcctAddr, dataDir, serviceHost string, isBroadcaster boo fmt.Sprintf("-httpAddr %s:%d", serviceHost, mediaPort), } - if !isBroadcaster { + if !cfg.IsBroadcaster { args = append( args, "-initializeRound=true", @@ -370,11 +186,11 @@ func createRunScript(ethAcctAddr, dataDir, serviceHost string, isBroadcaster boo "-pricePerUnit 1", ) - fName := fmt.Sprintf("run_%s_standalone_%s.sh", getNodeType(isBroadcaster), ethAcctAddr) + fName := fmt.Sprintf("run_%s_standalone_%s.sh", getNodeType(cfg.IsBroadcaster), cfg.Account) writeScript(fName, args...) args = append(args, "-transcoder=true") - fName = fmt.Sprintf("run_%s_with_transcoder_%s.sh", getNodeType(isBroadcaster), ethAcctAddr) + fName = fmt.Sprintf("run_%s_with_transcoder_%s.sh", getNodeType(cfg.IsBroadcaster), cfg.Account) writeScript(fName, args...) } else { args = append( @@ -383,7 +199,7 @@ func createRunScript(ethAcctAddr, dataDir, serviceHost string, isBroadcaster boo fmt.Sprintf("-rtmpAddr %s:%d", serviceHost, rtmpPort), ) - fName := fmt.Sprintf("run_%s_%s.sh", getNodeType(isBroadcaster), ethAcctAddr) + fName := fmt.Sprintf("run_%s_%s.sh", getNodeType(cfg.IsBroadcaster), cfg.Account) writeScript(fName, args...) } } @@ -401,93 +217,6 @@ func writeScript(fName string, args ...string) { } } -func createKey(keystoreDir string) string { - keyStore := keystore.NewKeyStore(keystoreDir, keystore.StandardScryptN, keystore.StandardScryptP) - - account, err := keyStore.NewAccount(passphrase) - if err != nil { - glog.Fatal(err) - } - glog.Infof("Using ETH account: %v", account.Address.Hex()) - return account.Address.Hex() -} - -func remoteConsole(destAccountAddr string) error { - broadcasterGeth := "0161e041aad467a890839d5b08b138c1e6373072" - if destAccountAddr != "" { - broadcasterGeth = destAccountAddr - } - - client, err := rpc.Dial(endpoint) - if err != nil { - glog.Fatalf("Unable to attach to remote geth: %v", err) - } - // get mining account - if !gethMiningAccountOverride { - var accounts []string - err = client.Call(&accounts, "eth_accounts") - if err != nil { - glog.Fatalf("Error finding mining account: %v", err) - } - if len(accounts) == 0 { - glog.Fatal("Can't find mining account") - } - gethMiningAccount = accounts[0] - glog.Infof("Found mining account: %s", gethMiningAccount) - } - - tmp, err := ioutil.TempDir("", "console") - if err != nil { - glog.Fatalf("Can't create temporary directory: %v", err) - } - defer os.RemoveAll(tmp) - - printer := new(bytes.Buffer) - - config := console.Config{ - DataDir: tmp, - Client: client, - Printer: printer, - } - - console, err := console.New(config) - if err != nil { - glog.Fatalf("Failed to start the JavaScript console: %v", err) - } - defer console.Stop(false) - - if !ethControllerOverride { - // f9a6cf519167d81bc5cb3d26c60c0c9a19704aa908c148e82a861b570f4cd2d7 - SetContractInfo event - getEthControllerScript := ` - var logs = []; - var filter = web3.eth.filter({ fromBlock: 0, toBlock: "latest", - topics: ["0xf9a6cf519167d81bc5cb3d26c60c0c9a19704aa908c148e82a861b570f4cd2d7"]}); - filter.get(function(error, result){ - logs.push(result); - }); - console.log(logs[0][0].address);'' - ` - glog.Infof("Running eth script: %s", getEthControllerScript) - console.Evaluate(getEthControllerScript) - if printer.Len() == 0 { - glog.Fatal("Can't find deployed controller") - } - ethController = strings.Split(printer.String(), "\n")[0] - - glog.Infof("Found controller address: %s", ethController) - } - - script := fmt.Sprintf("eth.sendTransaction({from: \"%s\", to: \"%s\", value: web3.toWei(834, \"ether\")})", - gethMiningAccount, broadcasterGeth) - glog.Infof("Running eth script: %s", script) - - console.Evaluate(script) - - time.Sleep(3 * time.Second) - - return err -} - func moveDir(src, dst string) error { info, err := os.Lstat(src) if err != nil { diff --git a/cmd/devtool/devtool/devtool_utils.go b/cmd/devtool/devtool/devtool_utils.go new file mode 100644 index 0000000000..d89e8a14e3 --- /dev/null +++ b/cmd/devtool/devtool/devtool_utils.go @@ -0,0 +1,370 @@ +package devtool + +import ( + "bytes" + "context" + "errors" + "fmt" + "github.com/ethereum/go-ethereum/accounts/keystore" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/console" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + "github.com/golang/glog" + "github.com/livepeer/go-livepeer/eth" + "io/ioutil" + "math/big" + "os" + "strings" + "time" +) + +const ( + passphrase = "" + ethTxTimeout = 5 * time.Minute +) + +type DevtoolConfig struct { + Endpoint string + GethMiningAccount string + GethMiningAccountOverride bool + EthController string + EthControllerOverride bool + ServiceURI string + Account string + KeystoreDir string + IsBroadcaster bool +} + +func NewDevtoolConfig() DevtoolConfig { + return DevtoolConfig{ + Endpoint: "http://localhost:8545/", + GethMiningAccount: "87da6a8c6e9eff15d703fc2773e32f6af8dbe301", + EthController: "0x04B9De88c81cda06165CF65a908e5f1EFBB9493B", + ServiceURI: "https://127.0.0.1:", + } +} + +type Devtool struct { + EthController string + Client eth.LivepeerEthClient + gpm *eth.GasPriceMonitor + tm *eth.TransactionManager +} + +func Init(cfg DevtoolConfig) (Devtool, error) { + ethController, err := RemoteConsole(cfg) + if err != nil { + return Devtool{}, err + } + cfg.EthController = ethController + client, gpm, tm, err := EthSetup(cfg) + if err != nil { + return Devtool{}, err + } + return Devtool{EthController: ethController, Client: client, gpm: gpm, tm: tm}, nil +} + +func RemoteConsole(cfg DevtoolConfig) (string, error) { + broadcasterGeth := "0161e041aad467a890839d5b08b138c1e6373072" + if cfg.Account != "" { + broadcasterGeth = cfg.Account + } + + client, err := rpc.Dial(cfg.Endpoint) + if err != nil { + glog.Fatalf("Unable to attach to remote geth: %v", err) + return "", err + } + // get mining account + gethMiningAccount := cfg.GethMiningAccount + if !cfg.GethMiningAccountOverride { + var accounts []string + err = client.Call(&accounts, "eth_accounts") + if err != nil { + glog.Fatalf("Error finding mining account: %v", err) + return "", err + } + if len(accounts) == 0 { + glog.Fatal("Can't find mining account") + return "", errors.New("can't find mining account") + } + gethMiningAccount = accounts[0] + glog.Infof("Found mining account: %s", gethMiningAccount) + } + + tmp, err := ioutil.TempDir("", "console") + if err != nil { + glog.Fatalf("Can't create temporary directory: %v", err) + return "", err + } + defer os.RemoveAll(tmp) + + printer := new(bytes.Buffer) + + config := console.Config{ + DataDir: tmp, + Client: client, + Printer: printer, + } + + console, err := console.New(config) + if err != nil { + glog.Fatalf("Failed to start the JavaScript console: %v", err) + return "", err + } + defer console.Stop(false) + + ethController := cfg.EthController + if !cfg.EthControllerOverride { + // f9a6cf519167d81bc5cb3d26c60c0c9a19704aa908c148e82a861b570f4cd2d7 - SetContractInfo event + getEthControllerScript := ` + var logs = []; + var filter = web3.eth.filter({ fromBlock: 0, toBlock: "latest", + topics: ["0xf9a6cf519167d81bc5cb3d26c60c0c9a19704aa908c148e82a861b570f4cd2d7"]}); + filter.get(function(error, result){ + logs.push(result); + }); + console.log(logs[0][0].address);'' + ` + glog.Infof("Running eth script: %s", getEthControllerScript) + console.Evaluate(getEthControllerScript) + if printer.Len() == 0 { + glog.Fatal("Can't find deployed controller") + return "", errors.New("can't find deployed controller") + } + ethController = strings.Split(printer.String(), "\n")[0] + + glog.Infof("Found controller address: %s", ethController) + } + + script := fmt.Sprintf("eth.sendTransaction({from: \"%s\", to: \"%s\", value: web3.toWei(834, \"ether\")})", + gethMiningAccount, broadcasterGeth) + glog.Infof("Running eth script: %s", script) + + console.Evaluate(script) + + time.Sleep(3 * time.Second) + + return ethController, nil +} + +func EthSetup(cfg DevtoolConfig) (eth.LivepeerEthClient, *eth.GasPriceMonitor, *eth.TransactionManager, error) { + //Set up eth client + backend, err := ethclient.Dial(cfg.Endpoint) + if err != nil { + glog.Errorf("Failed to connect to Ethereum client: %v", err) + return nil, nil, nil, err + } + glog.Infof("Using controller address %s", cfg.EthController) + + gpm := eth.NewGasPriceMonitor(backend, 5*time.Second, big.NewInt(0), nil) + + // Start gas price monitor + _, err = gpm.Start(context.Background()) + if err != nil { + glog.Errorf("error starting gas price monitor: %v", err) + return nil, nil, nil, err + } + + chainID, err := backend.ChainID(context.Background()) + if err != nil { + glog.Errorf("Failed to get chain ID from remote ethereum node: %v", err) + return nil, nil, nil, err + } + + am, err := eth.NewAccountManager(ethcommon.HexToAddress(cfg.Account), cfg.KeystoreDir, chainID, passphrase) + if err != nil { + glog.Errorf("Error creating Ethereum account manager: %v", err) + return nil, nil, nil, err + } + + if err := am.Unlock(passphrase); err != nil { + glog.Errorf("Error unlocking Ethereum account: %v", err) + return nil, nil, nil, err + } + + maxTxReplacements := 0 + tm := eth.NewTransactionManager(backend, gpm, am, ethTxTimeout, maxTxReplacements) + go tm.Start() + + ethCfg := eth.LivepeerEthClientConfig{ + AccountManager: am, + ControllerAddr: ethcommon.HexToAddress(cfg.EthController), + EthClient: backend, + GasPriceMonitor: gpm, + TransactionManager: tm, + Signer: types.LatestSignerForChainID(chainID), + CheckTxTimeout: time.Duration(int64(ethTxTimeout) * int64(maxTxReplacements+1)), + } + + lpEth, err := eth.NewClient(ethCfg) + if err != nil { + glog.Errorf("Failed to create Livepeer Ethereum client: %v", err) + return nil, nil, nil, err + } + + if err := lpEth.SetGasInfo(0); err != nil { + glog.Errorf("Failed to set gas info on Livepeer Ethereum Client: %v", err) + return nil, nil, nil, err + } + + return lpEth, gpm, tm, nil +} + +func (d *Devtool) FundBroadcaster() error { + amount := new(big.Int).Mul(big.NewInt(100), new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) + + glog.Infof("Funding deposit with %v", amount) + glog.Infof("Funding reserve with %v", amount) + + tx, err := d.Client.FundDepositAndReserve(amount, amount) + if err != nil { + glog.Error(err) + return err + } + if err := d.Client.CheckTx(tx); err != nil { + glog.Error(err) + return err + } + + glog.Info("Done funding deposit and reserve") + return nil +} + +func (d *Devtool) InitializeOrchestrator(cfg DevtoolConfig) error { + if err := d.RequestTokens(); err != nil { + return err + } + if err := d.InitializeRound(); err != nil { + return err + } + if err := d.RegisterOrchestrator(cfg); err != nil { + return err + } + return nil +} + +func (d *Devtool) RequestTokens() error { + glog.Infof("Requesting tokens from faucet") + + tx, err := d.Client.Request() + if err != nil { + glog.Errorf("Error requesting tokens from faucet: %v", err) + return err + } + + err = d.Client.CheckTx(tx) + if err != nil { + glog.Errorf("Error requesting tokens from faucet: %v", err) + return err + } + glog.Info("Done requesting tokens.") + return nil +} + +func (d *Devtool) InitializeRound() error { + // XXX TODO curl -X "POST" http://localhost:$transcoderCliPort/initializeRound + time.Sleep(7 * time.Second) + for { + currentRound, err := d.Client.CurrentRound() + if err != nil { + glog.Errorf("Error getting current round: %v", err) + return err + } + if currentRound.Int64() > 1 { + break + } + // first round is initialized and locked, need to wait + glog.Info("Waiting will first round ended.") + time.Sleep(4 * time.Second) + } + tx, err := d.Client.InitializeRound() + // ErrRoundInitialized + if err != nil { + if err.Error() != "ErrRoundInitialized" { + glog.Errorf("Error initializing round: %v", err) + return err + } + } else { + err = d.Client.CheckTx(tx) + if err != nil { + glog.Errorf("Error initializng round: %v", err) + return err + } + } + glog.Info("Done initializing round.") + return nil +} + +func (d *Devtool) RegisterOrchestrator(cfg DevtoolConfig) error { + glog.Info("Activating orchestrator") + // curl -d "blockRewardCut=10&feeShare=5&amount=500" --data-urlencode "serviceURI=https://$transcoderServiceAddr" \ + // -H "Content-Type: application/x-www-form-urlencoded" \ + // -X "POST" http://localhost:$transcoderCliPort/activateTranscoder\ + var amount *big.Int = big.NewInt(int64(500)) + glog.Infof("Bonding %v to %s", amount, cfg.Account) + + tx, err := d.Client.Bond(amount, ethcommon.HexToAddress(cfg.Account)) + if err != nil { + glog.Error(err) + return err + } + + err = d.Client.CheckTx(tx) + if err != nil { + glog.Error("=== Bonding failed") + glog.Error(err) + return err + } + glog.Infof("Registering transcoder %v", cfg.Account) + + tx, err = d.Client.Transcoder(eth.FromPerc(10), eth.FromPerc(5)) + if err == eth.ErrCurrentRoundLocked { + // wait for next round and retry + } + if err != nil { + glog.Error(err) + return err + } + + err = d.Client.CheckTx(tx) + if err != nil { + glog.Error(err) + return err + } + + glog.Infof("Storing service URI %v in service registry...", cfg.ServiceURI) + + tx, err = d.Client.SetServiceURI(cfg.ServiceURI) + if err != nil { + glog.Error(err) + return err + } + + err = d.Client.CheckTx(tx) + if err != nil { + glog.Error(err) + return err + } + + glog.Info("Done activating orchestrator.") + return nil +} + +func (d *Devtool) Close() { + d.gpm.Stop() + d.tm.Stop() +} + +func CreateKey(keystoreDir string) string { + keyStore := keystore.NewKeyStore(keystoreDir, keystore.StandardScryptN, keystore.StandardScryptP) + + account, err := keyStore.NewAccount(passphrase) + if err != nil { + glog.Fatal(err) + } + glog.Infof("Using ETH account: %v", account.Address.Hex()) + return account.Address.Hex() +} diff --git a/cmd/livepeer/livepeer.go b/cmd/livepeer/livepeer.go index 47155c204b..ada1aa465c 100644 --- a/cmd/livepeer/livepeer.go +++ b/cmd/livepeer/livepeer.go @@ -5,135 +5,21 @@ package main import ( "context" - "errors" "flag" "fmt" - "io/ioutil" - "math/big" - "net" - "net/http" - "net/url" + "github.com/livepeer/go-livepeer/cmd/livepeer/starter" "os" "os/signal" - "os/user" - - "path/filepath" "runtime" - "strings" "time" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" - "github.com/livepeer/go-livepeer/build" - "github.com/livepeer/go-livepeer/pm" - "github.com/livepeer/go-livepeer/server" - "github.com/livepeer/livepeer-data/pkg/event" "github.com/livepeer/livepeer-data/pkg/mistconnector" "github.com/peterbourgon/ff/v3" - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" "github.com/golang/glog" - "github.com/livepeer/go-livepeer/common" "github.com/livepeer/go-livepeer/core" - "github.com/livepeer/go-livepeer/discovery" - "github.com/livepeer/go-livepeer/drivers" - "github.com/livepeer/go-livepeer/eth" - "github.com/livepeer/go-livepeer/eth/blockwatch" - "github.com/livepeer/go-livepeer/eth/watchers" - "github.com/livepeer/go-livepeer/verification" - "github.com/livepeer/lpms/ffmpeg" - - lpmon "github.com/livepeer/go-livepeer/monitor" -) - -var ( - ErrKeygen = errors.New("ErrKeygen") - - // The timeout for ETH RPC calls - ethRPCTimeout = 20 * time.Second - // The maximum blocks for the block watcher to retain - blockWatcherRetentionLimit = 20 - - // Estimate of the gas required to redeem a PM ticket on L1 Ethereum - redeemGasL1 = 350000 - // Estimate of the gas required to redeem a PM ticket on L2 Arbitrum - redeemGasL2 = 1200000 - // The multiplier on the transaction cost to use for PM ticket faceValue - txCostMultiplier = 100 - - // The interval at which to clean up cached max float values for PM senders and balances per stream - cleanupInterval = 1 * time.Minute - // The time to live for cached max float values for PM senders (else they will be cleaned up) in seconds - smTTL = 60 // 1 minute ) -const RtmpPort = "1935" -const RpcPort = "8935" -const CliPort = "7935" - -type LivepeerConfig struct { - network *string - rtmpAddr *string - cliAddr *string - httpAddr *string - serviceAddr *string - orchAddr *string - verifierURL *string - ethController *string - verifierPath *string - localVerify *bool - httpIngest *bool - orchestrator *bool - transcoder *bool - broadcaster *bool - orchSecret *string - transcodingOptions *string - maxAttempts *int - selectRandFreq *float64 - maxSessions *int - currentManifest *bool - nvidia *string - netint *string - testTranscoder *bool - sceneClassificationModelPath *string - ethAcctAddr *string - ethPassword *string - ethKeystorePath *string - ethOrchAddr *string - ethUrl *string - txTimeout *time.Duration - maxTxReplacements *int - gasLimit *int - minGasPrice *int64 - maxGasPrice *int - initializeRound *bool - ticketEV *string - maxTicketEV *string - depositMultiplier *int - pricePerUnit *int - maxPricePerUnit *int - pixelsPerUnit *int - autoAdjustPrice *bool - blockPollingInterval *int - redeemer *bool - redeemerAddr *string - reward *bool - monitor *bool - metricsPerStream *bool - metricsExposeClientIP *bool - metadataQueueUri *string - metadataAmqpExchange *string - metadataPublishTimeout *time.Duration - datadir *string - objectstore *string - recordstore *string - authWebhookURL *string - orchWebhookURL *string - detectionWebhookURL *string -} - func main() { // Override the default flag set since there are dependencies that // incorrectly add their own flags (specifically, due to the 'testing' @@ -188,7 +74,7 @@ func main() { lc := make(chan struct{}) go func() { - StartLivepeer(ctx, cfg) + starter.StartLivepeer(ctx, cfg) lc <- struct{}{} }() @@ -203,1299 +89,112 @@ func main() { } } -// DefaultLivepeerConfig creates LivepeerConfig exactly the same as when no flags are passed to the livepeer process. -func DefaultLivepeerConfig() LivepeerConfig { - // Network & Addresses: - defaultNetwork := "offchain" - defaultRtmpAddr := "127.0.0.1:" + RtmpPort - defaultCliAddr := "127.0.0.1:" + CliPort - defaultHttpAddr := "" - defaultServiceAddr := "" - defaultOrchAddr := "" - defaultVerifierURL := "" - defaultVerifierPath := "" - - // Transcoding: - defaultOrchestrator := false - defaultTranscoder := false - defaultBroadcaster := false - defaultOrchSecret := "" - defaultTranscodingOptions := "P240p30fps16x9,P360p30fps16x9" - defaultMaxAttempts := 3 - defaultSelectRandFreq := 0.3 - defaultMaxSessions := 10 - defaultCurrentManifest := false - defaultNvidia := "" - defaultNetint := "" - defaultTestTranscoder := true - defaultSceneClassificationModelPath := "" - - // Onchain: - defaultEthAcctAddr := "" - defaultEthPassword := "" - defaultEthKeystorePath := "" - defaultEthOrchAddr := "" - defaultEthUrl := "" - defaultTxTimeout := 5 * time.Minute - defaultMaxTxReplacements := 1 - defaultGasLimit := 0 - defaultMaxGasPrice := 0 - defaultEthController := "" - defaultInitializeRound := false - defaultTicketEV := "1000000000000" - defaultMaxTicketEV := "3000000000000" - defaultDepositMultiplier := 1 - defaultMaxPricePerUnit := 0 - defaultPixelsPerUnit := 1 - defaultAutoAdjustPrice := true - defaultBlockPollingInterval := 5 - defaultRedeemer := false - defaultRedeemerAddr := "" - defaultMonitor := false - defaultMetricsPerStream := false - defaultMetricsExposeClientIP := false - defaultMetadataQueueUri := "" - defaultMetadataAmqpExchange := "lp_golivepeer_metadata" - defaultMetadataPublishTimeout := 1 * time.Second - - // Storage: - defaultDatadir := "" - defaultObjectstore := "" - defaultRecordstore := "" - - // API - defaultAuthWebhookURL := "" - defaultOrchWebhookURL := "" - defaultDetectionWebhookURL := "" - - return LivepeerConfig{ - // Network & Addresses: - network: &defaultNetwork, - rtmpAddr: &defaultRtmpAddr, - cliAddr: &defaultCliAddr, - httpAddr: &defaultHttpAddr, - serviceAddr: &defaultServiceAddr, - orchAddr: &defaultOrchAddr, - verifierURL: &defaultVerifierURL, - verifierPath: &defaultVerifierPath, - - // Transcoding: - orchestrator: &defaultOrchestrator, - transcoder: &defaultTranscoder, - broadcaster: &defaultBroadcaster, - orchSecret: &defaultOrchSecret, - transcodingOptions: &defaultTranscodingOptions, - maxAttempts: &defaultMaxAttempts, - selectRandFreq: &defaultSelectRandFreq, - maxSessions: &defaultMaxSessions, - currentManifest: &defaultCurrentManifest, - nvidia: &defaultNvidia, - netint: &defaultNetint, - testTranscoder: &defaultTestTranscoder, - sceneClassificationModelPath: &defaultSceneClassificationModelPath, - - // Onchain: - ethAcctAddr: &defaultEthAcctAddr, - ethPassword: &defaultEthPassword, - ethKeystorePath: &defaultEthKeystorePath, - ethOrchAddr: &defaultEthOrchAddr, - ethUrl: &defaultEthUrl, - txTimeout: &defaultTxTimeout, - maxTxReplacements: &defaultMaxTxReplacements, - gasLimit: &defaultGasLimit, - maxGasPrice: &defaultMaxGasPrice, - ethController: &defaultEthController, - initializeRound: &defaultInitializeRound, - ticketEV: &defaultTicketEV, - maxTicketEV: &defaultMaxTicketEV, - depositMultiplier: &defaultDepositMultiplier, - maxPricePerUnit: &defaultMaxPricePerUnit, - pixelsPerUnit: &defaultPixelsPerUnit, - autoAdjustPrice: &defaultAutoAdjustPrice, - blockPollingInterval: &defaultBlockPollingInterval, - redeemer: &defaultRedeemer, - redeemerAddr: &defaultRedeemerAddr, - monitor: &defaultMonitor, - metricsPerStream: &defaultMetricsPerStream, - metricsExposeClientIP: &defaultMetricsExposeClientIP, - metadataQueueUri: &defaultMetadataQueueUri, - metadataAmqpExchange: &defaultMetadataAmqpExchange, - metadataPublishTimeout: &defaultMetadataPublishTimeout, - - // Storage: - datadir: &defaultDatadir, - objectstore: &defaultObjectstore, - recordstore: &defaultRecordstore, - - // API - authWebhookURL: &defaultAuthWebhookURL, - orchWebhookURL: &defaultOrchWebhookURL, - detectionWebhookURL: &defaultDetectionWebhookURL, - } -} - -func parseLivepeerConfig() LivepeerConfig { - cfg := DefaultLivepeerConfig() +func parseLivepeerConfig() starter.LivepeerConfig { + cfg := starter.DefaultLivepeerConfig() // Network & Addresses: - cfg.network = flag.String("network", *cfg.network, "Network to connect to") - cfg.rtmpAddr = flag.String("rtmpAddr", *cfg.rtmpAddr, "Address to bind for RTMP commands") - cfg.cliAddr = flag.String("cliAddr", *cfg.cliAddr, "Address to bind for CLI commands") - cfg.httpAddr = flag.String("httpAddr", *cfg.httpAddr, "Address to bind for HTTP commands") - cfg.serviceAddr = flag.String("serviceAddr", *cfg.serviceAddr, "Orchestrator only. Overrides the on-chain serviceURI that broadcasters can use to contact this node; may be an IP or hostname.") - cfg.orchAddr = flag.String("orchAddr", *cfg.orchAddr, "Comma-separated list of orchestrators to connect to") - cfg.verifierURL = flag.String("verifierUrl", *cfg.verifierURL, "URL of the verifier to use") - cfg.verifierPath = flag.String("verifierPath", *cfg.verifierPath, "Path to verifier shared volume") - cfg.localVerify = flag.Bool("localVerify", true, "Set to true to enable local verification i.e. pixel count and signature verification.") - cfg.httpIngest = flag.Bool("httpIngest", true, "Set to true to enable HTTP ingest") + cfg.Network = flag.String("network", *cfg.Network, "Network to connect to") + cfg.RtmpAddr = flag.String("rtmpAddr", *cfg.RtmpAddr, "Address to bind for RTMP commands") + cfg.CliAddr = flag.String("cliAddr", *cfg.CliAddr, "Address to bind for CLI commands") + cfg.HttpAddr = flag.String("httpAddr", *cfg.HttpAddr, "Address to bind for HTTP commands") + cfg.ServiceAddr = flag.String("serviceAddr", *cfg.ServiceAddr, "Orchestrator only. Overrides the on-chain serviceURI that broadcasters can use to contact this node; may be an IP or hostname.") + cfg.OrchAddr = flag.String("orchAddr", *cfg.OrchAddr, "Comma-separated list of orchestrators to connect to") + cfg.VerifierURL = flag.String("verifierUrl", *cfg.VerifierURL, "URL of the verifier to use") + cfg.VerifierPath = flag.String("verifierPath", *cfg.VerifierPath, "Path to verifier shared volume") + cfg.LocalVerify = flag.Bool("localVerify", true, "Set to true to enable local verification i.e. pixel count and signature verification.") + cfg.HttpIngest = flag.Bool("httpIngest", true, "Set to true to enable HTTP ingest") // Transcoding: - cfg.orchestrator = flag.Bool("orchestrator", *cfg.orchestrator, "Set to true to be an orchestrator") - cfg.transcoder = flag.Bool("transcoder", *cfg.transcoder, "Set to true to be a transcoder") - cfg.broadcaster = flag.Bool("broadcaster", *cfg.broadcaster, "Set to true to be a broadcaster") - cfg.orchSecret = flag.String("orchSecret", *cfg.orchSecret, "Shared secret with the orchestrator as a standalone transcoder") - cfg.transcodingOptions = flag.String("transcodingOptions", *cfg.transcodingOptions, "Transcoding options for broadcast job, or path to json config") - cfg.maxAttempts = flag.Int("maxAttempts", *cfg.maxAttempts, "Maximum transcode attempts") - cfg.selectRandFreq = flag.Float64("selectRandFreq", *cfg.selectRandFreq, "Frequency to randomly select unknown orchestrators (on-chain mode only)") - cfg.maxSessions = flag.Int("maxSessions", *cfg.maxSessions, "Maximum number of concurrent transcoding sessions for Orchestrator, maximum number or RTMP streams for Broadcaster, or maximum capacity for transcoder") - cfg.currentManifest = flag.Bool("currentManifest", *cfg.currentManifest, "Expose the currently active ManifestID as \"/stream/current.m3u8\"") - cfg.nvidia = flag.String("nvidia", *cfg.nvidia, "Comma-separated list of Nvidia GPU device IDs (or \"all\" for all available devices)") - cfg.netint = flag.String("netint", *cfg.netint, "Comma-separated list of NetInt device GUIDs (or \"all\" for all available devices)") - cfg.testTranscoder = flag.Bool("testTranscoder", *cfg.testTranscoder, "Test Nvidia GPU transcoding at startup") - cfg.sceneClassificationModelPath = flag.String("sceneClassificationModelPath", *cfg.sceneClassificationModelPath, "Path to scene classification model") + cfg.Orchestrator = flag.Bool("orchestrator", *cfg.Orchestrator, "Set to true to be an orchestrator") + cfg.Transcoder = flag.Bool("transcoder", *cfg.Transcoder, "Set to true to be a transcoder") + cfg.Broadcaster = flag.Bool("broadcaster", *cfg.Broadcaster, "Set to true to be a broadcaster") + cfg.OrchSecret = flag.String("orchSecret", *cfg.OrchSecret, "Shared secret with the orchestrator as a standalone transcoder") + cfg.TranscodingOptions = flag.String("transcodingOptions", *cfg.TranscodingOptions, "Transcoding options for broadcast job, or path to json config") + cfg.MaxAttempts = flag.Int("maxAttempts", *cfg.MaxAttempts, "Maximum transcode attempts") + cfg.SelectRandFreq = flag.Float64("selectRandFreq", *cfg.SelectRandFreq, "Frequency to randomly select unknown orchestrators (on-chain mode only)") + cfg.MaxSessions = flag.Int("maxSessions", *cfg.MaxSessions, "Maximum number of concurrent transcoding sessions for Orchestrator, maximum number or RTMP streams for Broadcaster, or maximum capacity for transcoder") + cfg.CurrentManifest = flag.Bool("currentManifest", *cfg.CurrentManifest, "Expose the currently active ManifestID as \"/stream/current.m3u8\"") + cfg.Nvidia = flag.String("nvidia", *cfg.Nvidia, "Comma-separated list of Nvidia GPU device IDs (or \"all\" for all available devices)") + cfg.Netint = flag.String("netint", *cfg.Netint, "Comma-separated list of NetInt device GUIDs (or \"all\" for all available devices)") + cfg.TestTranscoder = flag.Bool("testTranscoder", *cfg.TestTranscoder, "Test Nvidia GPU transcoding at startup") + cfg.SceneClassificationModelPath = flag.String("sceneClassificationModelPath", *cfg.SceneClassificationModelPath, "Path to scene classification model") // Onchain: - cfg.ethAcctAddr = flag.String("ethAcctAddr", *cfg.ethAcctAddr, "Existing Eth account address") - cfg.ethPassword = flag.String("ethPassword", *cfg.ethPassword, "Password for existing Eth account address") - cfg.ethKeystorePath = flag.String("ethKeystorePath", *cfg.ethKeystorePath, "Path for the Eth Key") - cfg.ethOrchAddr = flag.String("ethOrchAddr", *cfg.ethOrchAddr, "ETH address of an on-chain registered orchestrator") - cfg.ethUrl = flag.String("ethUrl", *cfg.ethUrl, "Ethereum node JSON-RPC URL") - cfg.txTimeout = flag.Duration("transactionTimeout", *cfg.txTimeout, "Amount of time to wait for an Ethereum transaction to confirm before timing out") - cfg.maxTxReplacements = flag.Int("maxTransactionReplacements", *cfg.maxTxReplacements, "Number of times to automatically replace pending Ethereum transactions") - cfg.gasLimit = flag.Int("gasLimit", *cfg.gasLimit, "Gas limit for ETH transactions") - cfg.minGasPrice = flag.Int64("minGasPrice", 0, "Minimum gas price (priority fee + base fee) for ETH transactions in wei, 10 Gwei = 10000000000") - cfg.maxGasPrice = flag.Int("maxGasPrice", *cfg.maxGasPrice, "Maximum gas price (priority fee + base fee) for ETH transactions in wei, 40 Gwei = 40000000000") - cfg.ethController = flag.String("ethController", *cfg.ethController, "Protocol smart contract address") - cfg.initializeRound = flag.Bool("initializeRound", *cfg.initializeRound, "Set to true if running as a transcoder and the node should automatically initialize new rounds") - cfg.ticketEV = flag.String("ticketEV", *cfg.ticketEV, "The expected value for PM tickets") + cfg.EthAcctAddr = flag.String("ethAcctAddr", *cfg.EthAcctAddr, "Existing Eth account address") + cfg.EthPassword = flag.String("ethPassword", *cfg.EthPassword, "Password for existing Eth account address") + cfg.EthKeystorePath = flag.String("ethKeystorePath", *cfg.EthKeystorePath, "Path for the Eth Key") + cfg.EthOrchAddr = flag.String("ethOrchAddr", *cfg.EthOrchAddr, "ETH address of an on-chain registered orchestrator") + cfg.EthUrl = flag.String("ethUrl", *cfg.EthUrl, "Ethereum node JSON-RPC URL") + cfg.TxTimeout = flag.Duration("transactionTimeout", *cfg.TxTimeout, "Amount of time to wait for an Ethereum transaction to confirm before timing out") + cfg.MaxTxReplacements = flag.Int("maxTransactionReplacements", *cfg.MaxTxReplacements, "Number of times to automatically replace pending Ethereum transactions") + cfg.GasLimit = flag.Int("gasLimit", *cfg.GasLimit, "Gas limit for ETH transactions") + cfg.MinGasPrice = flag.Int64("minGasPrice", 0, "Minimum gas price (priority fee + base fee) for ETH transactions in wei, 10 Gwei = 10000000000") + cfg.MaxGasPrice = flag.Int("maxGasPrice", *cfg.MaxGasPrice, "Maximum gas price (priority fee + base fee) for ETH transactions in wei, 40 Gwei = 40000000000") + cfg.EthController = flag.String("ethController", *cfg.EthController, "Protocol smart contract address") + cfg.InitializeRound = flag.Bool("initializeRound", *cfg.InitializeRound, "Set to true if running as a transcoder and the node should automatically initialize new rounds") + cfg.TicketEV = flag.String("ticketEV", *cfg.TicketEV, "The expected value for PM tickets") // Broadcaster max acceptable ticket EV - cfg.maxTicketEV = flag.String("maxTicketEV", *cfg.maxTicketEV, "The maximum acceptable expected value for PM tickets") + cfg.MaxTicketEV = flag.String("maxTicketEV", *cfg.MaxTicketEV, "The maximum acceptable expected value for PM tickets") // Broadcaster deposit multiplier to determine max acceptable ticket faceValue - cfg.depositMultiplier = flag.Int("depositMultiplier", *cfg.depositMultiplier, "The deposit multiplier used to determine max acceptable faceValue for PM tickets") + cfg.DepositMultiplier = flag.Int("depositMultiplier", *cfg.DepositMultiplier, "The deposit multiplier used to determine max acceptable faceValue for PM tickets") // Orchestrator base pricing info - cfg.pricePerUnit = flag.Int("pricePerUnit", 0, "The price per 'pixelsPerUnit' amount pixels") + cfg.PricePerUnit = flag.Int("pricePerUnit", 0, "The price per 'pixelsPerUnit' amount pixels") // Broadcaster max acceptable price - cfg.maxPricePerUnit = flag.Int("maxPricePerUnit", *cfg.maxPricePerUnit, "The maximum transcoding price (in wei) per 'pixelsPerUnit' a broadcaster is willing to accept. If not set explicitly, broadcaster is willing to accept ANY price") + cfg.MaxPricePerUnit = flag.Int("maxPricePerUnit", *cfg.MaxPricePerUnit, "The maximum transcoding price (in wei) per 'pixelsPerUnit' a broadcaster is willing to accept. If not set explicitly, broadcaster is willing to accept ANY price") // Unit of pixels for both O's basePriceInfo and B's MaxBroadcastPrice - cfg.pixelsPerUnit = flag.Int("pixelsPerUnit", *cfg.pixelsPerUnit, "Amount of pixels per unit. Set to '> 1' to have smaller price granularity than 1 wei / pixel") - cfg.autoAdjustPrice = flag.Bool("autoAdjustPrice", *cfg.autoAdjustPrice, "Enable/disable automatic price adjustments based on the overhead for redeeming tickets") + cfg.PixelsPerUnit = flag.Int("pixelsPerUnit", *cfg.PixelsPerUnit, "Amount of pixels per unit. Set to '> 1' to have smaller price granularity than 1 wei / pixel") + cfg.AutoAdjustPrice = flag.Bool("autoAdjustPrice", *cfg.AutoAdjustPrice, "Enable/disable automatic price adjustments based on the overhead for redeeming tickets") // Interval to poll for blocks - cfg.blockPollingInterval = flag.Int("blockPollingInterval", *cfg.blockPollingInterval, "Interval in seconds at which different blockchain event services poll for blocks") + cfg.BlockPollingInterval = flag.Int("blockPollingInterval", *cfg.BlockPollingInterval, "Interval in seconds at which different blockchain event services poll for blocks") // Redemption service - cfg.redeemer = flag.Bool("redeemer", *cfg.redeemer, "Set to true to run a ticket redemption service") - cfg.redeemerAddr = flag.String("redeemerAddr", *cfg.redeemerAddr, "URL of the ticket redemption service to use") + cfg.Redeemer = flag.Bool("redeemer", *cfg.Redeemer, "Set to true to run a ticket redemption service") + cfg.RedeemerAddr = flag.String("redeemerAddr", *cfg.RedeemerAddr, "URL of the ticket redemption service to use") // Reward service - cfg.reward = flag.Bool("reward", false, "Set to true to run a reward service") + cfg.Reward = flag.Bool("reward", false, "Set to true to run a reward service") // Metrics & logging: - cfg.monitor = flag.Bool("monitor", *cfg.monitor, "Set to true to send performance metrics") - cfg.metricsPerStream = flag.Bool("metricsPerStream", *cfg.metricsPerStream, "Set to true to group performance metrics per stream") - cfg.metricsExposeClientIP = flag.Bool("metricsClientIP", *cfg.metricsExposeClientIP, "Set to true to expose client's IP in metrics") - cfg.metadataQueueUri = flag.String("metadataQueueUri", *cfg.metadataQueueUri, "URI for message broker to send operation metadata") - cfg.metadataAmqpExchange = flag.String("metadataAmqpExchange", *cfg.metadataAmqpExchange, "Name of AMQP exchange to send operation metadata") - cfg.metadataPublishTimeout = flag.Duration("metadataPublishTimeout", *cfg.metadataPublishTimeout, "Max time to wait in background for publishing operation metadata events") + cfg.Monitor = flag.Bool("monitor", *cfg.Monitor, "Set to true to send performance metrics") + cfg.MetricsPerStream = flag.Bool("metricsPerStream", *cfg.MetricsPerStream, "Set to true to group performance metrics per stream") + cfg.MetricsExposeClientIP = flag.Bool("metricsClientIP", *cfg.MetricsExposeClientIP, "Set to true to expose client's IP in metrics") + cfg.MetadataQueueUri = flag.String("metadataQueueUri", *cfg.MetadataQueueUri, "URI for message broker to send operation metadata") + cfg.MetadataAmqpExchange = flag.String("metadataAmqpExchange", *cfg.MetadataAmqpExchange, "Name of AMQP exchange to send operation metadata") + cfg.MetadataPublishTimeout = flag.Duration("metadataPublishTimeout", *cfg.MetadataPublishTimeout, "Max time to wait in background for publishing operation metadata events") // Storage: - cfg.datadir = flag.String("datadir", *cfg.datadir, "Directory that data is stored in") - cfg.objectstore = flag.String("objectStore", *cfg.objectstore, "url of primary object store") - cfg.recordstore = flag.String("recordStore", *cfg.recordstore, "url of object store for recordings") + cfg.Datadir = flag.String("datadir", *cfg.Datadir, "Directory that data is stored in") + cfg.Objectstore = flag.String("objectStore", *cfg.Objectstore, "url of primary object store") + cfg.Recordstore = flag.String("recordStore", *cfg.Recordstore, "url of object store for recordings") // API - cfg.authWebhookURL = flag.String("authWebhookUrl", *cfg.authWebhookURL, "RTMP authentication webhook URL") - cfg.orchWebhookURL = flag.String("orchWebhookUrl", *cfg.orchWebhookURL, "Orchestrator discovery callback URL") - cfg.detectionWebhookURL = flag.String("detectionWebhookUrl", *cfg.detectionWebhookURL, "(Experimental) Detection results callback URL") + cfg.AuthWebhookURL = flag.String("authWebhookUrl", *cfg.AuthWebhookURL, "RTMP authentication webhook URL") + cfg.OrchWebhookURL = flag.String("orchWebhookUrl", *cfg.OrchWebhookURL, "Orchestrator discovery callback URL") + cfg.DetectionWebhookURL = flag.String("detectionWebhookUrl", *cfg.DetectionWebhookURL, "(Experimental) Detection results callback URL") return cfg } // updateNilsForUnsetFlags changes some cfg fields to nil if they were not explicitly set with flags. // For some flags, the behavior is different whether the value is default or not set by the user at all. -func updateNilsForUnsetFlags(cfg LivepeerConfig) LivepeerConfig { +func updateNilsForUnsetFlags(cfg starter.LivepeerConfig) starter.LivepeerConfig { res := cfg isFlagSet := make(map[string]bool) flag.Visit(func(f *flag.Flag) { isFlagSet[f.Name] = true }) if !isFlagSet["minGasPrice"] { - res.minGasPrice = nil + res.MinGasPrice = nil } if !isFlagSet["pricePerUnit"] { - res.pricePerUnit = nil + res.PricePerUnit = nil } if !isFlagSet["reward"] { - res.reward = nil + res.Reward = nil } if !isFlagSet["httpIngest"] { - res.httpIngest = nil + res.HttpIngest = nil } if !isFlagSet["localVerify"] { - res.localVerify = nil - } - - return res -} - -func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { - if *cfg.maxSessions <= 0 { - glog.Fatal("-maxSessions must be greater than zero") - return - } - - if *cfg.netint != "" && *cfg.nvidia != "" { - glog.Fatal("both -netint and -nvidia arguments specified, this is not supported") - return - } - - blockPollingTime := time.Duration(*cfg.blockPollingInterval) * time.Second - - type NetworkConfig struct { - ethController string - minGasPrice int64 - redeemGas int - } - - configOptions := map[string]*NetworkConfig{ - "rinkeby": { - ethController: "0x9a9827455911a858E55f07911904fACC0D66027E", - redeemGas: redeemGasL1, - }, - "arbitrum-one-rinkeby": { - ethController: "0x9ceC649179e2C7Ab91688271bcD09fb707b3E574", - redeemGas: redeemGasL2, - }, - "mainnet": { - ethController: "0xf96d54e490317c557a967abfa5d6e33006be69b3", - minGasPrice: int64(params.GWei), - redeemGas: redeemGasL1, - }, - "arbitrum-one-mainnet": { - ethController: "0xD8E8328501E9645d16Cf49539efC04f734606ee4", - redeemGas: redeemGasL2, - }, - } - - // If multiple orchAddr specified, ensure other necessary flags present and clean up list - orchURLs := parseOrchAddrs(*cfg.orchAddr) - - // Setting config options based on specified network - var redeemGas int - minGasPrice := int64(0) - if cfg.minGasPrice != nil { - minGasPrice = *cfg.minGasPrice - } - if netw, ok := configOptions[*cfg.network]; ok { - if *cfg.ethController == "" { - *cfg.ethController = netw.ethController - } - - if cfg.minGasPrice == nil { - minGasPrice = netw.minGasPrice - } - - redeemGas = netw.redeemGas - - glog.Infof("***Livepeer is running on the %v network: %v***", *cfg.network, *cfg.ethController) - } else { - redeemGas = redeemGasL1 - glog.Infof("***Livepeer is running on the %v network***", *cfg.network) - } - - if *cfg.datadir == "" { - homedir := os.Getenv("HOME") - if homedir == "" { - usr, err := user.Current() - if err != nil { - glog.Fatalf("Cannot find current user: %v", err) - } - homedir = usr.HomeDir - } - *cfg.datadir = filepath.Join(homedir, ".lpData", *cfg.network) - } - - //Make sure datadir is present - if _, err := os.Stat(*cfg.datadir); os.IsNotExist(err) { - glog.Infof("Creating data dir: %v", *cfg.datadir) - if err = os.MkdirAll(*cfg.datadir, 0755); err != nil { - glog.Errorf("Error creating datadir: %v", err) - } - } - - //Set up DB - dbh, err := common.InitDB(*cfg.datadir + "/lpdb.sqlite3") - if err != nil { - glog.Errorf("Error opening DB: %v", err) - return - } - defer dbh.Close() - - n, err := core.NewLivepeerNode(nil, *cfg.datadir, dbh) - if err != nil { - glog.Errorf("Error creating livepeer node: %v", err) - } - - if *cfg.orchSecret != "" { - n.OrchSecret, _ = common.GetPass(*cfg.orchSecret) - } - - var transcoderCaps []core.Capability - if *cfg.transcoder { - core.WorkDir = *cfg.datadir - accel := ffmpeg.Software - var devicesStr string - if *cfg.nvidia != "" { - accel = ffmpeg.Nvidia - devicesStr = *cfg.nvidia - } - if *cfg.netint != "" { - accel = ffmpeg.Netint - devicesStr = *cfg.netint - } - if accel != ffmpeg.Software { - accelName := ffmpeg.AccelerationNameLookup[accel] - tf, dtf, err := core.GetTranscoderFactoryByAccel(accel) - if err != nil { - glog.Fatalf("Error unsupported acceleration: %v", err) - } - // Get a list of device ids - devices, err := common.ParseAccelDevices(devicesStr, accel) - glog.Infof("%v devices: %v", accelName, devices) - if err != nil { - glog.Fatalf("Error while parsing '-%v %v' flag: %v", strings.ToLower(accelName), devices, err) - } - glog.Infof("Transcoding on these %v devices: %v", accelName, devices) - // Test transcoding with specified device - if *cfg.testTranscoder { - transcoderCaps, err = core.TestTranscoderCapabilities(devices, tf) - if err != nil { - glog.Fatal(err) - return - } - } - // FIXME: Short-term hack to pre-load the detection models on every device - if accel == ffmpeg.Nvidia && *cfg.sceneClassificationModelPath != "" { - detectorProfile := ffmpeg.DSceneAdultSoccer - detectorProfile.ModelPath = *cfg.sceneClassificationModelPath - core.DetectorProfile = &detectorProfile - for _, d := range devices { - tc, err := core.NewNvidiaTranscoderWithDetector(&detectorProfile, d) - if err != nil { - glog.Fatalf("Could not initialize detector") - } - defer tc.Stop() - } - } - // Initialize LB transcoder - n.Transcoder = core.NewLoadBalancingTranscoder(devices, tf, dtf) - } else { - // for local software mode, enable all capabilities - transcoderCaps = append(core.DefaultCapabilities(), core.OptionalCapabilities()...) - n.Transcoder = core.NewLocalTranscoder(*cfg.datadir) - } - } - - if *cfg.redeemer { - n.NodeType = core.RedeemerNode - } else if *cfg.orchestrator { - n.NodeType = core.OrchestratorNode - if !*cfg.transcoder { - n.TranscoderManager = core.NewRemoteTranscoderManager() - n.Transcoder = n.TranscoderManager - } - } else if *cfg.transcoder { - n.NodeType = core.TranscoderNode - } else if *cfg.broadcaster { - n.NodeType = core.BroadcasterNode - } else if (cfg.reward == nil || !*cfg.reward) && !*cfg.initializeRound { - glog.Fatalf("No services enabled; must be at least one of -broadcaster, -transcoder, -orchestrator, -redeemer, -reward or -initializeRound") - } - - lpmon.NodeID = *cfg.ethAcctAddr - if lpmon.NodeID != "" { - lpmon.NodeID += "-" - } - hn, _ := os.Hostname() - lpmon.NodeID += hn - - if *cfg.monitor { - if *cfg.metricsExposeClientIP { - *cfg.metricsPerStream = true - } - lpmon.Enabled = true - lpmon.PerStreamMetrics = *cfg.metricsPerStream - lpmon.ExposeClientIP = *cfg.metricsExposeClientIP - nodeType := lpmon.Default - switch n.NodeType { - case core.BroadcasterNode: - nodeType = lpmon.Broadcaster - case core.OrchestratorNode: - nodeType = lpmon.Orchestrator - case core.TranscoderNode: - nodeType = lpmon.Transcoder - case core.RedeemerNode: - nodeType = lpmon.Redeemer - } - lpmon.InitCensus(nodeType, core.LivepeerVersion) - } - - watcherErr := make(chan error) - serviceErr := make(chan error) - var timeWatcher *watchers.TimeWatcher - if *cfg.network == "offchain" { - glog.Infof("***Livepeer is in off-chain mode***") - - if err := checkOrStoreChainID(dbh, big.NewInt(0)); err != nil { - glog.Error(err) - return - } - - } else { - var keystoreDir string - if _, err := os.Stat(*cfg.ethKeystorePath); !os.IsNotExist(err) { - keystoreDir, _ = filepath.Split(*cfg.ethKeystorePath) - } else { - keystoreDir = filepath.Join(*cfg.datadir, "keystore") - } - - if keystoreDir == "" { - glog.Errorf("Cannot find keystore directory") - return - } - - //Get the Eth client connection information - if *cfg.ethUrl == "" { - glog.Fatal("Need to specify an Ethereum node JSON-RPC URL using -ethUrl") - } - - //Set up eth client - backend, err := ethclient.Dial(*cfg.ethUrl) - if err != nil { - glog.Errorf("Failed to connect to Ethereum client: %v", err) - return - } - - chainID, err := backend.ChainID(ctx) - if err != nil { - glog.Errorf("failed to get chain ID from remote ethereum node: %v", err) - return - } - - if !build.ChainSupported(chainID.Int64()) { - glog.Errorf("node does not support chainID = %v right now", chainID) - return - } - - if err := checkOrStoreChainID(dbh, chainID); err != nil { - glog.Error(err) - return - } - - var bigMaxGasPrice *big.Int - if *cfg.maxGasPrice > 0 { - bigMaxGasPrice = big.NewInt(int64(*cfg.maxGasPrice)) - } - - gpm := eth.NewGasPriceMonitor(backend, blockPollingTime, big.NewInt(minGasPrice), bigMaxGasPrice) - // Start gas price monitor - _, err = gpm.Start(ctx) - if err != nil { - glog.Errorf("Error starting gas price monitor: %v", err) - return - } - defer gpm.Stop() - - am, err := eth.NewAccountManager(ethcommon.HexToAddress(*cfg.ethAcctAddr), keystoreDir, chainID, *cfg.ethPassword) - if err != nil { - glog.Errorf("Error creating Ethereum account manager: %v", err) - return - } - - if err := am.Unlock(*cfg.ethPassword); err != nil { - glog.Errorf("Error unlocking Ethereum account: %v", err) - return - } - - tm := eth.NewTransactionManager(backend, gpm, am, *cfg.txTimeout, *cfg.maxTxReplacements) - go tm.Start() - defer tm.Stop() - - ethCfg := eth.LivepeerEthClientConfig{ - AccountManager: am, - ControllerAddr: ethcommon.HexToAddress(*cfg.ethController), - EthClient: backend, - GasPriceMonitor: gpm, - TransactionManager: tm, - Signer: types.LatestSignerForChainID(chainID), - CheckTxTimeout: time.Duration(int64(*cfg.txTimeout) * int64(*cfg.maxTxReplacements+1)), - } - - client, err := eth.NewClient(ethCfg) - if err != nil { - glog.Errorf("Failed to create Livepeer Ethereum client: %v", err) - return - } - - if err := client.SetGasInfo(uint64(*cfg.gasLimit)); err != nil { - glog.Errorf("Failed to set gas info on Livepeer Ethereum Client: %v", err) - return - } - if err := client.SetMaxGasPrice(bigMaxGasPrice); err != nil { - glog.Errorf("Failed to set max gas price: %v", err) - return - } - - n.Eth = client - - addrMap := n.Eth.ContractAddresses() - - // Initialize block watcher that will emit logs used by event watchers - blockWatcherClient, err := blockwatch.NewRPCClient(*cfg.ethUrl, ethRPCTimeout) - if err != nil { - glog.Errorf("Failed to setup blockwatch client: %v", err) - return - } - topics := watchers.FilterTopics() - - blockWatcherCfg := blockwatch.Config{ - Store: n.Database, - PollingInterval: blockPollingTime, - StartBlockDepth: rpc.LatestBlockNumber, - BlockRetentionLimit: blockWatcherRetentionLimit, - WithLogs: true, - Topics: topics, - Client: blockWatcherClient, - } - // Wait until all event watchers have been initialized before starting the block watcher - blockWatcher := blockwatch.New(blockWatcherCfg) - - timeWatcher, err = watchers.NewTimeWatcher(addrMap["RoundsManager"], blockWatcher, n.Eth) - if err != nil { - glog.Errorf("Failed to setup roundswatcher: %v", err) - return - } - - timeWatcherErr := make(chan error, 1) - go func() { - if err := timeWatcher.Watch(); err != nil { - timeWatcherErr <- fmt.Errorf("roundswatcher failed to start watching for events: %v", err) - } - }() - defer timeWatcher.Stop() - - // Initialize unbonding watcher to update the DB with latest state of the node's unbonding locks - unbondingWatcher, err := watchers.NewUnbondingWatcher(n.Eth.Account().Address, addrMap["BondingManager"], blockWatcher, n.Database) - if err != nil { - glog.Errorf("Failed to setup unbonding watcher: %v", err) - return - } - // Start unbonding watcher (logs will not be received until the block watcher is started) - go unbondingWatcher.Watch() - defer unbondingWatcher.Stop() - - senderWatcher, err := watchers.NewSenderWatcher(addrMap["TicketBroker"], blockWatcher, n.Eth, timeWatcher) - if err != nil { - glog.Errorf("Failed to setup senderwatcher: %v", err) - return - } - go senderWatcher.Watch() - defer senderWatcher.Stop() - - orchWatcher, err := watchers.NewOrchestratorWatcher(addrMap["BondingManager"], blockWatcher, dbh, n.Eth, timeWatcher) - if err != nil { - glog.Errorf("Failed to setup orchestrator watcher: %v", err) - return - } - go orchWatcher.Watch() - defer orchWatcher.Stop() - - serviceRegistryWatcher, err := watchers.NewServiceRegistryWatcher(addrMap["ServiceRegistry"], blockWatcher, dbh, n.Eth) - if err != nil { - glog.Errorf("Failed to set up service registry watcher: %v", err) - return - } - go serviceRegistryWatcher.Watch() - defer serviceRegistryWatcher.Stop() - - n.Balances = core.NewAddressBalances(cleanupInterval) - defer n.Balances.StopCleanup() - - // By default the ticket recipient is the node's address - // If the address of an on-chain registered orchestrator is provided, then it should be specified as the ticket recipient - recipientAddr := n.Eth.Account().Address - if *cfg.ethOrchAddr != "" { - recipientAddr = ethcommon.HexToAddress(*cfg.ethOrchAddr) - } - - smCfg := &pm.LocalSenderMonitorConfig{ - Claimant: recipientAddr, - CleanupInterval: cleanupInterval, - TTL: smTTL, - RedeemGas: redeemGas, - SuggestGasPrice: client.Backend().SuggestGasPrice, - RPCTimeout: ethRPCTimeout, - } - - if *cfg.orchestrator { - // Set price per pixel base info - if *cfg.pixelsPerUnit <= 0 { - // Can't divide by 0 - panic(fmt.Errorf("-pixelsPerUnit must be > 0, provided %d", *cfg.pixelsPerUnit)) - } - if cfg.pricePerUnit == nil { - // Prevent orchestrators from unknowingly providing free transcoding - panic(fmt.Errorf("-pricePerUnit must be set")) - } - if *cfg.pricePerUnit < 0 { - panic(fmt.Errorf("-pricePerUnit must be >= 0, provided %d", *cfg.pricePerUnit)) - } - n.SetBasePrice(big.NewRat(int64(*cfg.pricePerUnit), int64(*cfg.pixelsPerUnit))) - glog.Infof("Price: %d wei for %d pixels\n ", *cfg.pricePerUnit, *cfg.pixelsPerUnit) - - n.AutoAdjustPrice = *cfg.autoAdjustPrice - - ev, _ := new(big.Int).SetString(*cfg.ticketEV, 10) - if ev == nil { - glog.Errorf("-ticketEV must be a valid integer, but %v provided. Restart the node with a different valid value for -ticketEV", *cfg.ticketEV) - return - } - - if ev.Cmp(big.NewInt(0)) < 0 { - glog.Errorf("-ticketEV must be greater than 0, but %v provided. Restart the node with a different valid value for -ticketEV", *cfg.ticketEV) - return - } - - if err := setupOrchestrator(n, recipientAddr); err != nil { - glog.Errorf("Error setting up orchestrator: %v", err) - return - } - - sigVerifier := &pm.DefaultSigVerifier{} - validator := pm.NewValidator(sigVerifier, timeWatcher) - - var sm pm.SenderMonitor - if *cfg.redeemerAddr != "" { - *cfg.redeemerAddr = defaultAddr(*cfg.redeemerAddr, "127.0.0.1", RpcPort) - rc, err := server.NewRedeemerClient(*cfg.redeemerAddr, senderWatcher, timeWatcher) - if err != nil { - glog.Error("Unable to start redeemer client: ", err) - return - } - sm = rc - } else { - sm = pm.NewSenderMonitor(smCfg, n.Eth, senderWatcher, timeWatcher, n.Database) - } - - // Start sender monitor - sm.Start() - defer sm.Stop() - - cfg := pm.TicketParamsConfig{ - EV: ev, - RedeemGas: redeemGas, - TxCostMultiplier: txCostMultiplier, - } - n.Recipient, err = pm.NewRecipient( - recipientAddr, - n.Eth, - validator, - gpm, - sm, - timeWatcher, - cfg, - ) - if err != nil { - glog.Errorf("Error setting up PM recipient: %v", err) - return - } - } - - if n.NodeType == core.BroadcasterNode { - ev, _ := new(big.Rat).SetString(*cfg.maxTicketEV) - if ev == nil { - panic(fmt.Errorf("-maxTicketEV must be a valid rational number, but %v provided. Restart the node with a valid value for -maxTicketEV", *cfg.maxTicketEV)) - } - - if ev.Cmp(big.NewRat(0, 1)) < 0 { - panic(fmt.Errorf("-maxTicketEV must not be negative, but %v provided. Restart the node with a valid value for -maxTicketEV", *cfg.maxTicketEV)) - } - - if *cfg.depositMultiplier <= 0 { - panic(fmt.Errorf("-depositMultiplier must be greater than 0, but %v provided. Restart the node with a valid value for -depositMultiplier", *cfg.depositMultiplier)) - } - - // Fetch and cache broadcaster on-chain info - info, err := senderWatcher.GetSenderInfo(n.Eth.Account().Address) - if err != nil { - glog.Error("Failed to get broadcaster on-chain info: ", err) - return - } - glog.Info("Broadcaster Deposit: ", eth.FormatUnits(info.Deposit, "ETH")) - glog.Info("Broadcaster Reserve: ", eth.FormatUnits(info.Reserve.FundsRemaining, "ETH")) - - n.Sender = pm.NewSender(n.Eth, timeWatcher, senderWatcher, ev, *cfg.depositMultiplier) - - if *cfg.pixelsPerUnit <= 0 { - // Can't divide by 0 - panic(fmt.Errorf("The amount of pixels per unit must be greater than 0, provided %d instead\n", *cfg.pixelsPerUnit)) - } - if *cfg.maxPricePerUnit > 0 { - server.BroadcastCfg.SetMaxPrice(big.NewRat(int64(*cfg.maxPricePerUnit), int64(*cfg.pixelsPerUnit))) - } else { - glog.Infof("Maximum transcoding price per pixel is not greater than 0: %v, broadcaster is currently set to accept ANY price.\n", *cfg.maxPricePerUnit) - glog.Infoln("To update the broadcaster's maximum acceptable transcoding price per pixel, use the CLI or restart the broadcaster with the appropriate 'maxPricePerUnit' and 'pixelsPerUnit' values") - } - } - - if n.NodeType == core.RedeemerNode { - if err := setupOrchestrator(n, recipientAddr); err != nil { - glog.Errorf("Error setting up orchestrator: %v", err) - return - } - - r, err := server.NewRedeemer( - recipientAddr, - n.Eth, - pm.NewSenderMonitor(smCfg, n.Eth, senderWatcher, timeWatcher, n.Database), - ) - if err != nil { - glog.Errorf("Unable to create redeemer: %v", err) - return - } - - *cfg.httpAddr = defaultAddr(*cfg.httpAddr, "127.0.0.1", RpcPort) - url, err := url.ParseRequestURI("https://" + *cfg.httpAddr) - if err != nil { - glog.Error("Could not parse redeemer URI: ", err) - return - } - - go func() { - if err := r.Start(url, n.WorkDir); err != nil { - serviceErr <- err - return - } - }() - defer r.Stop() - glog.Infof("Redeemer started on %v", *cfg.httpAddr) - } - - var reward bool - if cfg.reward == nil { - // If the node address is an on-chain registered address, start the reward service - t, err := n.Eth.GetTranscoder(n.Eth.Account().Address) - if err != nil { - glog.Error(err) - return - } - if t.Status == "Registered" { - reward = true - } else { - reward = false - } - } - - if reward { - // Start reward service - // The node will only call reward if it is active in the current round - rs := eth.NewRewardService(n.Eth, timeWatcher) - go func() { - if err := rs.Start(ctx); err != nil { - serviceErr <- err - } - return - }() - defer rs.Stop() - } - - if *cfg.initializeRound { - // Start round initializer - // The node will only initialize rounds if it in the upcoming active set for the round - initializer := eth.NewRoundInitializer(n.Eth, timeWatcher) - go func() { - if err := initializer.Start(); err != nil { - serviceErr <- err - } - return - }() - defer initializer.Stop() - } - - blockWatchCtx, cancel := context.WithCancel(ctx) - defer cancel() - - // Backfill events that the node has missed since its last seen block. This method will block - // and the node will not continue setup until it finishes - if err := blockWatcher.BackfillEventsIfNeeded(blockWatchCtx); err != nil { - glog.Errorf("Failed to backfill events: %v", err) - return - } - - blockWatcherErr := make(chan error, 1) - go func() { - if err := blockWatcher.Watch(blockWatchCtx); err != nil { - blockWatcherErr <- fmt.Errorf("block watcher error: %v", err) - } - }() - - go func() { - var err error - select { - case err = <-timeWatcherErr: - case err = <-blockWatcherErr: - } - - watcherErr <- err - }() - } - - if *cfg.objectstore != "" { - prepared, err := drivers.PrepareOSURL(*cfg.objectstore) - if err != nil { - glog.Error("Error creating object store driver: ", err) - return - } - drivers.NodeStorage, err = drivers.ParseOSURL(prepared, false) - if err != nil { - glog.Error("Error creating object store driver: ", err) - return - } - } - - if *cfg.recordstore != "" { - prepared, err := drivers.PrepareOSURL(*cfg.recordstore) - if err != nil { - glog.Error("Error creating recordings object store driver: ", err) - return - } - drivers.RecordStorage, err = drivers.ParseOSURL(prepared, true) - if err != nil { - glog.Error("Error creating recordings object store driver: ", err) - return - } - } - - core.MaxSessions = *cfg.maxSessions - if lpmon.Enabled { - lpmon.MaxSessions(core.MaxSessions) - } - - if *cfg.authWebhookURL != "" { - parsedUrl, err := validateURL(*cfg.authWebhookURL) - if err != nil { - glog.Fatal("Error setting auth webhook URL ", err) - } - glog.Info("Using auth webhook URL ", parsedUrl.Redacted()) - server.AuthWebhookURL = parsedUrl - } - - if *cfg.detectionWebhookURL != "" { - parsedUrl, err := validateURL(*cfg.detectionWebhookURL) - if err != nil { - glog.Fatal("Error setting detection webhook URL ", err) - } - glog.Info("Using detection webhook URL ", parsedUrl.Redacted()) - server.DetectionWebhookURL = parsedUrl - } - httpIngest := true - - if n.NodeType == core.BroadcasterNode { - // default lpms listener for broadcaster; same as default rpc port - // TODO provide an option to disable this? - *cfg.rtmpAddr = defaultAddr(*cfg.rtmpAddr, "127.0.0.1", RtmpPort) - *cfg.httpAddr = defaultAddr(*cfg.httpAddr, "127.0.0.1", RpcPort) - - bcast := core.NewBroadcaster(n) - - // When the node is on-chain mode always cache the on-chain orchestrators and poll for updates - // Right now we rely on the DBOrchestratorPoolCache constructor to do this. Consider separating the logic - // caching/polling from the logic for fetching orchestrators during discovery - if *cfg.network != "offchain" { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - dbOrchPoolCache, err := discovery.NewDBOrchestratorPoolCache(ctx, n, timeWatcher) - if err != nil { - glog.Errorf("Could not create orchestrator pool with DB cache: %v", err) - } - - n.OrchestratorPool = dbOrchPoolCache - } - - // Set up orchestrator discovery - if *cfg.orchWebhookURL != "" { - whurl, err := validateURL(*cfg.orchWebhookURL) - if err != nil { - glog.Fatal("Error setting orch webhook URL ", err) - } - glog.Info("Using orchestrator webhook URL ", whurl) - n.OrchestratorPool = discovery.NewWebhookPool(bcast, whurl) - } else if len(orchURLs) > 0 { - n.OrchestratorPool = discovery.NewOrchestratorPool(bcast, orchURLs, common.Score_Trusted) - } - - if n.OrchestratorPool == nil { - // Not a fatal error; may continue operating in segment-only mode - glog.Error("No orchestrator specified; transcoding will not happen") - } - - isLocalHTTP, err := isLocalURL("https://" + *cfg.httpAddr) - if err != nil { - glog.Errorf("Error checking for local -httpAddr: %v", err) - return - } - if cfg.httpIngest != nil { - httpIngest = *cfg.httpIngest - } - if cfg.httpIngest == nil && !isLocalHTTP && server.AuthWebhookURL == nil { - glog.Warning("HTTP ingest is disabled because -httpAddr is publicly accessible. To enable, configure -authWebhookUrl or use the -httpIngest flag") - httpIngest = false - } - - // Disable local verification when running in off-chain mode - // To enable, set -localVerify or -verifierURL - localVerify := true - if cfg.localVerify != nil { - localVerify = *cfg.localVerify - } - if cfg.localVerify == nil && *cfg.network == "offchain" { - localVerify = false - } - - if *cfg.verifierURL != "" { - _, err := validateURL(*cfg.verifierURL) - if err != nil { - glog.Fatal("Error setting verifier URL ", err) - } - glog.Info("Using the Epic Labs classifier for verification at ", *cfg.verifierURL) - server.Policy = &verification.Policy{Retries: 2, Verifier: &verification.EpicClassifier{Addr: *cfg.verifierURL}} - - // Set the verifier path. Remove once [1] is implemented! - // [1] https://github.com/livepeer/verification-classifier/issues/64 - if drivers.NodeStorage == nil && *cfg.verifierPath == "" { - glog.Fatal("Requires a path to the verifier shared volume when local storage is in use; use -verifierPath or -objectStore") - } - verification.VerifierPath = *cfg.verifierPath - } else if localVerify { - glog.Info("Local verification enabled") - server.Policy = &verification.Policy{Retries: 2} - } - - // Set max transcode attempts. <=0 is OK; it just means "don't transcode" - server.MaxAttempts = *cfg.maxAttempts - server.SelectRandFreq = *cfg.selectRandFreq - - } else if n.NodeType == core.OrchestratorNode { - suri, err := getServiceURI(n, *cfg.serviceAddr) - if err != nil { - glog.Fatal("Error getting service URI: ", err) - } - n.SetServiceURI(suri) - // if http addr is not provided, listen to all ifaces - // take the port to listen to from the service URI - *cfg.httpAddr = defaultAddr(*cfg.httpAddr, "", n.GetServiceURI().Port()) - - if *cfg.sceneClassificationModelPath != "" { - // Only enable experimental capabilities if scene classification model is actually loaded - transcoderCaps = append(transcoderCaps, core.ExperimentalCapabilities()...) - } - if !*cfg.transcoder && n.OrchSecret == "" { - glog.Fatal("Running an orchestrator requires an -orchSecret for standalone mode or -transcoder for orchestrator+transcoder mode") - } - } - n.Capabilities = core.NewCapabilities(transcoderCaps, core.MandatoryOCapabilities()) - *cfg.cliAddr = defaultAddr(*cfg.cliAddr, "127.0.0.1", CliPort) - - if drivers.NodeStorage == nil { - // base URI will be empty for broadcasters; that's OK - drivers.NodeStorage = drivers.NewMemoryDriver(n.GetServiceURI()) - } - - if *cfg.metadataPublishTimeout > 0 { - server.MetadataPublishTimeout = *cfg.metadataPublishTimeout - } - if *cfg.metadataQueueUri != "" { - uri, err := url.ParseRequestURI(*cfg.metadataQueueUri) - if err != nil { - glog.Fatalf("Error parsing -metadataQueueUri: err=%q", err) - } - switch uri.Scheme { - case "amqp", "amqps": - uriStr, exchange, keyNs := *cfg.metadataQueueUri, *cfg.metadataAmqpExchange, n.NodeType.String() - server.MetadataQueue, err = event.NewAMQPExchangeProducer(context.Background(), uriStr, exchange, keyNs) - if err != nil { - glog.Fatalf("Error establishing AMQP connection: err=%q", err) - } - default: - glog.Fatalf("Unsupported scheme in -metadataUri: %s", uri.Scheme) - } - } - - //Create Livepeer Node - - //Set up the media server - s, err := server.NewLivepeerServer(*cfg.rtmpAddr, n, httpIngest, *cfg.transcodingOptions) - if err != nil { - glog.Fatal("Error creating Livepeer server err=", err) - } - - ec := make(chan error) - tc := make(chan struct{}) - wc := make(chan struct{}) - msCtx, cancel := context.WithCancel(ctx) - defer cancel() - - if *cfg.currentManifest { - glog.Info("Current ManifestID will be available over ", *cfg.httpAddr) - s.ExposeCurrentManifest = *cfg.currentManifest - } - - go func() { - s.StartCliWebserver(*cfg.cliAddr) - close(wc) - }() - if n.NodeType != core.RedeemerNode { - go func() { - ec <- s.StartMediaServer(msCtx, *cfg.httpAddr) - }() - } - - go func() { - if core.OrchestratorNode != n.NodeType { - return - } - - orch := core.NewOrchestrator(s.LivepeerNode, timeWatcher) - - go func() { - server.StartTranscodeServer(orch, *cfg.httpAddr, s.HTTPMux, n.WorkDir, n.TranscoderManager != nil) - tc <- struct{}{} - }() - - // check whether or not the orchestrator is available - time.Sleep(2 * time.Second) - orchAvail := server.CheckOrchestratorAvailability(orch) - if !orchAvail { - // shut down orchestrator - glog.Infof("Orchestrator not available at %v; shutting down", orch.ServiceURI()) - tc <- struct{}{} - } - - }() - - if n.NodeType == core.TranscoderNode { - if n.OrchSecret == "" { - glog.Fatal("Missing -orchSecret") - } - if len(orchURLs) <= 0 { - glog.Fatal("Missing -orchAddr") - } - - go server.RunTranscoder(n, orchURLs[0].Host, *cfg.maxSessions, transcoderCaps) - } - - switch n.NodeType { - case core.OrchestratorNode: - glog.Infof("***Livepeer Running in Orchestrator Mode***") - case core.BroadcasterNode: - glog.Infof("***Livepeer Running in Broadcaster Mode***") - glog.Infof("Video Ingest Endpoint - rtmp://%v", *cfg.rtmpAddr) - case core.TranscoderNode: - glog.Infof("**Liveepeer Running in Transcoder Mode***") - case core.RedeemerNode: - glog.Infof("**Livepeer Running in Redeemer Mode**") - } - - select { - case err := <-watcherErr: - glog.Error(err) - return - case err := <-ec: - glog.Infof("Error from media server: %v", err) - return - case err := <-serviceErr: - if err != nil { - glog.Fatalf("Error starting service: %v", err) - } - case <-tc: - glog.Infof("Orchestrator server shut down") - case <-wc: - glog.Infof("CLI webserver shut down") - return - case <-msCtx.Done(): - glog.Infof("MediaServer Done()") - return - case <-ctx.Done(): - return + res.LocalVerify = nil } -} -func parseOrchAddrs(addrs string) []*url.URL { - var res []*url.URL - if len(addrs) > 0 { - for _, addr := range strings.Split(addrs, ",") { - addr = strings.TrimSpace(addr) - addr = defaultAddr(addr, "127.0.0.1", RpcPort) - if !strings.HasPrefix(addr, "http") { - addr = "https://" + addr - } - uri, err := url.ParseRequestURI(addr) - if err != nil { - glog.Error("Could not parse orchestrator URI: ", err) - continue - } - res = append(res, uri) - } - } return res } - -func validateURL(u string) (*url.URL, error) { - if u == "" { - return nil, nil - } - p, err := url.ParseRequestURI(u) - if err != nil { - return nil, err - } - if p.Scheme != "http" && p.Scheme != "https" { - return nil, errors.New("URL should be HTTP or HTTPS") - } - return p, nil -} - -func isLocalURL(u string) (bool, error) { - uri, err := url.ParseRequestURI(u) - if err != nil { - return false, err - } - - hostname := uri.Hostname() - if net.ParseIP(hostname).IsLoopback() || hostname == "localhost" { - return true, nil - } - - return false, nil -} - -// ServiceURI checking steps: -// If passed in via -serviceAddr: return that -// Else: get inferred address. -// If offchain: return inferred address -// Else: get on-chain sURI -// If on-chain sURI mismatches inferred address: print warning -// Return on-chain sURI -func getServiceURI(n *core.LivepeerNode, serviceAddr string) (*url.URL, error) { - // Passed in via CLI - if serviceAddr != "" { - return url.ParseRequestURI("https://" + serviceAddr) - } - - // Infer address - // TODO probably should put this (along w wizard GETs) into common code - resp, err := http.Get("https://api.ipify.org?format=text") - if err != nil { - glog.Errorf("Could not look up public IP err=%q", err) - return nil, err - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - glog.Errorf("Could not look up public IP err=%q", err) - return nil, err - } - addr := "https://" + strings.TrimSpace(string(body)) + ":" + RpcPort - inferredUri, err := url.ParseRequestURI(addr) - if err != nil { - glog.Errorf("Could not look up public IP err=%q", err) - return nil, err - } - if n.Eth == nil { - // we won't be looking up onchain sURI so use the inferred one - return inferredUri, err - } - - // On-chain lookup and matching with inferred public address - addr, err = n.Eth.GetServiceURI(n.Eth.Account().Address) - if err != nil { - glog.Errorf("Could not get service URI; orchestrator may be unreachable err=%q", err) - return nil, err - } - ethUri, err := url.ParseRequestURI(addr) - if err != nil { - glog.Errorf("Could not parse service URI; orchestrator may be unreachable err=%q", err) - ethUri, _ = url.ParseRequestURI("http://127.0.0.1:" + RpcPort) - } - if ethUri.Hostname() != inferredUri.Hostname() || ethUri.Port() != inferredUri.Port() { - glog.Errorf("Service address %v did not match discovered address %v; set the correct address in livepeer_cli or use -serviceAddr", ethUri, inferredUri) - } - return ethUri, nil -} - -func setupOrchestrator(n *core.LivepeerNode, ethOrchAddr ethcommon.Address) error { - // add orchestrator to DB - orch, err := n.Eth.GetTranscoder(ethOrchAddr) - if err != nil { - return err - } - - err = n.Database.UpdateOrch(&common.DBOrch{ - EthereumAddr: ethOrchAddr.Hex(), - ActivationRound: common.ToInt64(orch.ActivationRound), - DeactivationRound: common.ToInt64(orch.DeactivationRound), - }) - if err != nil { - return err - } - - if !orch.Active { - glog.Infof("Orchestrator %v is inactive", ethOrchAddr.Hex()) - } else { - glog.Infof("Orchestrator %v is active", ethOrchAddr.Hex()) - } - - return nil -} - -func defaultAddr(addr, defaultHost, defaultPort string) string { - if addr == "" { - return defaultHost + ":" + defaultPort - } - if addr[0] == ':' { - return defaultHost + addr - } - // not IPv6 safe - if !strings.Contains(addr, ":") { - return addr + ":" + defaultPort - } - return addr -} - -func checkOrStoreChainID(dbh *common.DB, chainID *big.Int) error { - expectedChainID, err := dbh.ChainID() - if err != nil { - return err - } - - if expectedChainID == nil { - // No chainID stored yet - // Store the provided chainID and skip the check - if err := dbh.SetChainID(chainID); err != nil { - return err - } - - return nil - } - - if expectedChainID.Cmp(chainID) != 0 { - return fmt.Errorf("expecting chainID of %v, but got %v. Did you change networks without changing network name or datadir?", expectedChainID, chainID) - } - - return nil -} diff --git a/cmd/livepeer/starter/starter.go b/cmd/livepeer/starter/starter.go new file mode 100644 index 0000000000..4806022fe7 --- /dev/null +++ b/cmd/livepeer/starter/starter.go @@ -0,0 +1,1309 @@ +package starter + +import ( + "context" + "errors" + "fmt" + "github.com/golang/glog" + "github.com/livepeer/go-livepeer/core" + "os" + "os/user" + "time" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + "github.com/livepeer/go-livepeer/build" + "github.com/livepeer/go-livepeer/common" + "github.com/livepeer/go-livepeer/discovery" + "github.com/livepeer/go-livepeer/drivers" + "github.com/livepeer/go-livepeer/eth" + "github.com/livepeer/go-livepeer/eth/blockwatch" + "github.com/livepeer/go-livepeer/eth/watchers" + lpmon "github.com/livepeer/go-livepeer/monitor" + "github.com/livepeer/go-livepeer/pm" + "github.com/livepeer/go-livepeer/server" + "github.com/livepeer/go-livepeer/verification" + "github.com/livepeer/livepeer-data/pkg/event" + "github.com/livepeer/lpms/ffmpeg" + "io/ioutil" + "math/big" + "net" + "net/http" + "net/url" + "path/filepath" + "strings" +) + +var ( + // The timeout for ETH RPC calls + ethRPCTimeout = 20 * time.Second + // The maximum blocks for the block watcher to retain + blockWatcherRetentionLimit = 20 + + // Estimate of the gas required to redeem a PM ticket on L1 Ethereum + redeemGasL1 = 350000 + // Estimate of the gas required to redeem a PM ticket on L2 Arbitrum + redeemGasL2 = 1200000 + // The multiplier on the transaction cost to use for PM ticket faceValue + txCostMultiplier = 100 + + // The interval at which to clean up cached max float values for PM senders and balances per stream + cleanupInterval = 1 * time.Minute + // The time to live for cached max float values for PM senders (else they will be cleaned up) in seconds + smTTL = 60 // 1 minute +) + +const RtmpPort = "1935" +const RpcPort = "8935" +const CliPort = "7935" + +type LivepeerConfig struct { + Network *string + RtmpAddr *string + CliAddr *string + HttpAddr *string + ServiceAddr *string + OrchAddr *string + VerifierURL *string + EthController *string + VerifierPath *string + LocalVerify *bool + HttpIngest *bool + Orchestrator *bool + Transcoder *bool + Broadcaster *bool + OrchSecret *string + TranscodingOptions *string + MaxAttempts *int + SelectRandFreq *float64 + MaxSessions *int + CurrentManifest *bool + Nvidia *string + Netint *string + TestTranscoder *bool + SceneClassificationModelPath *string + EthAcctAddr *string + EthPassword *string + EthKeystorePath *string + EthOrchAddr *string + EthUrl *string + TxTimeout *time.Duration + MaxTxReplacements *int + GasLimit *int + MinGasPrice *int64 + MaxGasPrice *int + InitializeRound *bool + TicketEV *string + MaxTicketEV *string + DepositMultiplier *int + PricePerUnit *int + MaxPricePerUnit *int + PixelsPerUnit *int + AutoAdjustPrice *bool + BlockPollingInterval *int + Redeemer *bool + RedeemerAddr *string + Reward *bool + Monitor *bool + MetricsPerStream *bool + MetricsExposeClientIP *bool + MetadataQueueUri *string + MetadataAmqpExchange *string + MetadataPublishTimeout *time.Duration + Datadir *string + Objectstore *string + Recordstore *string + AuthWebhookURL *string + OrchWebhookURL *string + DetectionWebhookURL *string +} + +// DefaultLivepeerConfig creates LivepeerConfig exactly the same as when no flags are passed to the livepeer process. +func DefaultLivepeerConfig() LivepeerConfig { + // Network & Addresses: + defaultNetwork := "offchain" + defaultRtmpAddr := "127.0.0.1:" + RtmpPort + defaultCliAddr := "127.0.0.1:" + CliPort + defaultHttpAddr := "" + defaultServiceAddr := "" + defaultOrchAddr := "" + defaultVerifierURL := "" + defaultVerifierPath := "" + + // Transcoding: + defaultOrchestrator := false + defaultTranscoder := false + defaultBroadcaster := false + defaultOrchSecret := "" + defaultTranscodingOptions := "P240p30fps16x9,P360p30fps16x9" + defaultMaxAttempts := 3 + defaultSelectRandFreq := 0.3 + defaultMaxSessions := 10 + defaultCurrentManifest := false + defaultNvidia := "" + defaultNetint := "" + defaultTestTranscoder := true + defaultSceneClassificationModelPath := "" + + // Onchain: + defaultEthAcctAddr := "" + defaultEthPassword := "" + defaultEthKeystorePath := "" + defaultEthOrchAddr := "" + defaultEthUrl := "" + defaultTxTimeout := 5 * time.Minute + defaultMaxTxReplacements := 1 + defaultGasLimit := 0 + defaultMaxGasPrice := 0 + defaultEthController := "" + defaultInitializeRound := false + defaultTicketEV := "1000000000000" + defaultMaxTicketEV := "3000000000000" + defaultDepositMultiplier := 1 + defaultMaxPricePerUnit := 0 + defaultPixelsPerUnit := 1 + defaultAutoAdjustPrice := true + defaultBlockPollingInterval := 5 + defaultRedeemer := false + defaultRedeemerAddr := "" + defaultMonitor := false + defaultMetricsPerStream := false + defaultMetricsExposeClientIP := false + defaultMetadataQueueUri := "" + defaultMetadataAmqpExchange := "lp_golivepeer_metadata" + defaultMetadataPublishTimeout := 1 * time.Second + + // Storage: + defaultDatadir := "" + defaultObjectstore := "" + defaultRecordstore := "" + + // API + defaultAuthWebhookURL := "" + defaultOrchWebhookURL := "" + defaultDetectionWebhookURL := "" + + return LivepeerConfig{ + // Network & Addresses: + Network: &defaultNetwork, + RtmpAddr: &defaultRtmpAddr, + CliAddr: &defaultCliAddr, + HttpAddr: &defaultHttpAddr, + ServiceAddr: &defaultServiceAddr, + OrchAddr: &defaultOrchAddr, + VerifierURL: &defaultVerifierURL, + VerifierPath: &defaultVerifierPath, + + // Transcoding: + Orchestrator: &defaultOrchestrator, + Transcoder: &defaultTranscoder, + Broadcaster: &defaultBroadcaster, + OrchSecret: &defaultOrchSecret, + TranscodingOptions: &defaultTranscodingOptions, + MaxAttempts: &defaultMaxAttempts, + SelectRandFreq: &defaultSelectRandFreq, + MaxSessions: &defaultMaxSessions, + CurrentManifest: &defaultCurrentManifest, + Nvidia: &defaultNvidia, + Netint: &defaultNetint, + TestTranscoder: &defaultTestTranscoder, + SceneClassificationModelPath: &defaultSceneClassificationModelPath, + + // Onchain: + EthAcctAddr: &defaultEthAcctAddr, + EthPassword: &defaultEthPassword, + EthKeystorePath: &defaultEthKeystorePath, + EthOrchAddr: &defaultEthOrchAddr, + EthUrl: &defaultEthUrl, + TxTimeout: &defaultTxTimeout, + MaxTxReplacements: &defaultMaxTxReplacements, + GasLimit: &defaultGasLimit, + MaxGasPrice: &defaultMaxGasPrice, + EthController: &defaultEthController, + InitializeRound: &defaultInitializeRound, + TicketEV: &defaultTicketEV, + MaxTicketEV: &defaultMaxTicketEV, + DepositMultiplier: &defaultDepositMultiplier, + MaxPricePerUnit: &defaultMaxPricePerUnit, + PixelsPerUnit: &defaultPixelsPerUnit, + AutoAdjustPrice: &defaultAutoAdjustPrice, + BlockPollingInterval: &defaultBlockPollingInterval, + Redeemer: &defaultRedeemer, + RedeemerAddr: &defaultRedeemerAddr, + Monitor: &defaultMonitor, + MetricsPerStream: &defaultMetricsPerStream, + MetricsExposeClientIP: &defaultMetricsExposeClientIP, + MetadataQueueUri: &defaultMetadataQueueUri, + MetadataAmqpExchange: &defaultMetadataAmqpExchange, + MetadataPublishTimeout: &defaultMetadataPublishTimeout, + + // Storage: + Datadir: &defaultDatadir, + Objectstore: &defaultObjectstore, + Recordstore: &defaultRecordstore, + + // API + AuthWebhookURL: &defaultAuthWebhookURL, + OrchWebhookURL: &defaultOrchWebhookURL, + DetectionWebhookURL: &defaultDetectionWebhookURL, + } +} + +func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { + if *cfg.MaxSessions <= 0 { + glog.Fatal("-maxSessions must be greater than zero") + return + } + + if *cfg.Netint != "" && *cfg.Nvidia != "" { + glog.Fatal("both -netint and -nvidia arguments specified, this is not supported") + return + } + + blockPollingTime := time.Duration(*cfg.BlockPollingInterval) * time.Second + + type NetworkConfig struct { + ethController string + minGasPrice int64 + redeemGas int + } + + configOptions := map[string]*NetworkConfig{ + "rinkeby": { + ethController: "0x9a9827455911a858E55f07911904fACC0D66027E", + redeemGas: redeemGasL1, + }, + "arbitrum-one-rinkeby": { + ethController: "0x9ceC649179e2C7Ab91688271bcD09fb707b3E574", + redeemGas: redeemGasL2, + }, + "mainnet": { + ethController: "0xf96d54e490317c557a967abfa5d6e33006be69b3", + minGasPrice: int64(params.GWei), + redeemGas: redeemGasL1, + }, + "arbitrum-one-mainnet": { + ethController: "0xD8E8328501E9645d16Cf49539efC04f734606ee4", + redeemGas: redeemGasL2, + }, + } + + // If multiple orchAddr specified, ensure other necessary flags present and clean up list + orchURLs := parseOrchAddrs(*cfg.OrchAddr) + + // Setting config options based on specified network + var redeemGas int + minGasPrice := int64(0) + if cfg.MinGasPrice != nil { + minGasPrice = *cfg.MinGasPrice + } + if netw, ok := configOptions[*cfg.Network]; ok { + if *cfg.EthController == "" { + *cfg.EthController = netw.ethController + } + + if cfg.MinGasPrice == nil { + minGasPrice = netw.minGasPrice + } + + redeemGas = netw.redeemGas + + glog.Infof("***Livepeer is running on the %v network: %v***", *cfg.Network, *cfg.EthController) + } else { + redeemGas = redeemGasL1 + glog.Infof("***Livepeer is running on the %v network***", *cfg.Network) + } + + if *cfg.Datadir == "" { + homedir := os.Getenv("HOME") + if homedir == "" { + usr, err := user.Current() + if err != nil { + glog.Fatalf("Cannot find current user: %v", err) + } + homedir = usr.HomeDir + } + *cfg.Datadir = filepath.Join(homedir, ".lpData", *cfg.Network) + } + + //Make sure datadir is present + if _, err := os.Stat(*cfg.Datadir); os.IsNotExist(err) { + glog.Infof("Creating data dir: %v", *cfg.Datadir) + if err = os.MkdirAll(*cfg.Datadir, 0755); err != nil { + glog.Errorf("Error creating datadir: %v", err) + } + } + + //Set up DB + dbh, err := common.InitDB(*cfg.Datadir + "/lpdb.sqlite3") + if err != nil { + glog.Errorf("Error opening DB: %v", err) + return + } + defer dbh.Close() + + n, err := core.NewLivepeerNode(nil, *cfg.Datadir, dbh) + if err != nil { + glog.Errorf("Error creating livepeer node: %v", err) + } + + if *cfg.OrchSecret != "" { + n.OrchSecret, _ = common.GetPass(*cfg.OrchSecret) + } + + var transcoderCaps []core.Capability + if *cfg.Transcoder { + core.WorkDir = *cfg.Datadir + accel := ffmpeg.Software + var devicesStr string + if *cfg.Nvidia != "" { + accel = ffmpeg.Nvidia + devicesStr = *cfg.Nvidia + } + if *cfg.Netint != "" { + accel = ffmpeg.Netint + devicesStr = *cfg.Netint + } + if accel != ffmpeg.Software { + accelName := ffmpeg.AccelerationNameLookup[accel] + tf, dtf, err := core.GetTranscoderFactoryByAccel(accel) + if err != nil { + glog.Fatalf("Error unsupported acceleration: %v", err) + } + // Get a list of device ids + devices, err := common.ParseAccelDevices(devicesStr, accel) + glog.Infof("%v devices: %v", accelName, devices) + if err != nil { + glog.Fatalf("Error while parsing '-%v %v' flag: %v", strings.ToLower(accelName), devices, err) + } + glog.Infof("Transcoding on these %v devices: %v", accelName, devices) + // Test transcoding with specified device + if *cfg.TestTranscoder { + transcoderCaps, err = core.TestTranscoderCapabilities(devices, tf) + if err != nil { + glog.Fatal(err) + return + } + } + // FIXME: Short-term hack to pre-load the detection models on every device + if accel == ffmpeg.Nvidia && *cfg.SceneClassificationModelPath != "" { + detectorProfile := ffmpeg.DSceneAdultSoccer + detectorProfile.ModelPath = *cfg.SceneClassificationModelPath + core.DetectorProfile = &detectorProfile + for _, d := range devices { + tc, err := core.NewNvidiaTranscoderWithDetector(&detectorProfile, d) + if err != nil { + glog.Fatalf("Could not initialize detector") + } + defer tc.Stop() + } + } + // Initialize LB transcoder + n.Transcoder = core.NewLoadBalancingTranscoder(devices, tf, dtf) + } else { + // for local software mode, enable all capabilities + transcoderCaps = append(core.DefaultCapabilities(), core.OptionalCapabilities()...) + n.Transcoder = core.NewLocalTranscoder(*cfg.Datadir) + } + } + + if *cfg.Redeemer { + n.NodeType = core.RedeemerNode + } else if *cfg.Orchestrator { + n.NodeType = core.OrchestratorNode + if !*cfg.Transcoder { + n.TranscoderManager = core.NewRemoteTranscoderManager() + n.Transcoder = n.TranscoderManager + } + } else if *cfg.Transcoder { + n.NodeType = core.TranscoderNode + } else if *cfg.Broadcaster { + n.NodeType = core.BroadcasterNode + } else if (cfg.Reward == nil || !*cfg.Reward) && !*cfg.InitializeRound { + glog.Fatalf("No services enabled; must be at least one of -broadcaster, -transcoder, -orchestrator, -redeemer, -reward or -initializeRound") + } + + lpmon.NodeID = *cfg.EthAcctAddr + if lpmon.NodeID != "" { + lpmon.NodeID += "-" + } + hn, _ := os.Hostname() + lpmon.NodeID += hn + + if *cfg.Monitor { + if *cfg.MetricsExposeClientIP { + *cfg.MetricsPerStream = true + } + lpmon.Enabled = true + lpmon.PerStreamMetrics = *cfg.MetricsPerStream + lpmon.ExposeClientIP = *cfg.MetricsExposeClientIP + nodeType := lpmon.Default + switch n.NodeType { + case core.BroadcasterNode: + nodeType = lpmon.Broadcaster + case core.OrchestratorNode: + nodeType = lpmon.Orchestrator + case core.TranscoderNode: + nodeType = lpmon.Transcoder + case core.RedeemerNode: + nodeType = lpmon.Redeemer + } + lpmon.InitCensus(nodeType, core.LivepeerVersion) + } + + watcherErr := make(chan error) + serviceErr := make(chan error) + var timeWatcher *watchers.TimeWatcher + if *cfg.Network == "offchain" { + glog.Infof("***Livepeer is in off-chain mode***") + + if err := checkOrStoreChainID(dbh, big.NewInt(0)); err != nil { + glog.Error(err) + return + } + + } else { + var keystoreDir string + if _, err := os.Stat(*cfg.EthKeystorePath); !os.IsNotExist(err) { + keystoreDir, _ = filepath.Split(*cfg.EthKeystorePath) + } else { + keystoreDir = filepath.Join(*cfg.Datadir, "keystore") + } + + if keystoreDir == "" { + glog.Errorf("Cannot find keystore directory") + return + } + + //Get the Eth client connection information + if *cfg.EthUrl == "" { + glog.Fatal("Need to specify an Ethereum node JSON-RPC URL using -ethUrl") + } + + //Set up eth client + backend, err := ethclient.Dial(*cfg.EthUrl) + if err != nil { + glog.Errorf("Failed to connect to Ethereum client: %v", err) + return + } + + chainID, err := backend.ChainID(ctx) + if err != nil { + glog.Errorf("failed to get chain ID from remote ethereum node: %v", err) + return + } + + if !build.ChainSupported(chainID.Int64()) { + glog.Errorf("node does not support chainID = %v right now", chainID) + return + } + + if err := checkOrStoreChainID(dbh, chainID); err != nil { + glog.Error(err) + return + } + + var bigMaxGasPrice *big.Int + if *cfg.MaxGasPrice > 0 { + bigMaxGasPrice = big.NewInt(int64(*cfg.MaxGasPrice)) + } + + gpm := eth.NewGasPriceMonitor(backend, blockPollingTime, big.NewInt(minGasPrice), bigMaxGasPrice) + // Start gas price monitor + _, err = gpm.Start(ctx) + if err != nil { + glog.Errorf("Error starting gas price monitor: %v", err) + return + } + defer gpm.Stop() + + am, err := eth.NewAccountManager(ethcommon.HexToAddress(*cfg.EthAcctAddr), keystoreDir, chainID, *cfg.EthPassword) + if err != nil { + glog.Errorf("Error creating Ethereum account manager: %v", err) + return + } + + if err := am.Unlock(*cfg.EthPassword); err != nil { + glog.Errorf("Error unlocking Ethereum account: %v", err) + return + } + + tm := eth.NewTransactionManager(backend, gpm, am, *cfg.TxTimeout, *cfg.MaxTxReplacements) + go tm.Start() + defer tm.Stop() + + ethCfg := eth.LivepeerEthClientConfig{ + AccountManager: am, + ControllerAddr: ethcommon.HexToAddress(*cfg.EthController), + EthClient: backend, + GasPriceMonitor: gpm, + TransactionManager: tm, + Signer: types.LatestSignerForChainID(chainID), + CheckTxTimeout: time.Duration(int64(*cfg.TxTimeout) * int64(*cfg.MaxTxReplacements+1)), + } + + client, err := eth.NewClient(ethCfg) + if err != nil { + glog.Errorf("Failed to create Livepeer Ethereum client: %v", err) + return + } + + if err := client.SetGasInfo(uint64(*cfg.GasLimit)); err != nil { + glog.Errorf("Failed to set gas info on Livepeer Ethereum Client: %v", err) + return + } + if err := client.SetMaxGasPrice(bigMaxGasPrice); err != nil { + glog.Errorf("Failed to set max gas price: %v", err) + return + } + + n.Eth = client + + addrMap := n.Eth.ContractAddresses() + + // Initialize block watcher that will emit logs used by event watchers + blockWatcherClient, err := blockwatch.NewRPCClient(*cfg.EthUrl, ethRPCTimeout) + if err != nil { + glog.Errorf("Failed to setup blockwatch client: %v", err) + return + } + topics := watchers.FilterTopics() + + blockWatcherCfg := blockwatch.Config{ + Store: n.Database, + PollingInterval: blockPollingTime, + StartBlockDepth: rpc.LatestBlockNumber, + BlockRetentionLimit: blockWatcherRetentionLimit, + WithLogs: true, + Topics: topics, + Client: blockWatcherClient, + } + // Wait until all event watchers have been initialized before starting the block watcher + blockWatcher := blockwatch.New(blockWatcherCfg) + + timeWatcher, err = watchers.NewTimeWatcher(addrMap["RoundsManager"], blockWatcher, n.Eth) + if err != nil { + glog.Errorf("Failed to setup roundswatcher: %v", err) + return + } + + timeWatcherErr := make(chan error, 1) + go func() { + if err := timeWatcher.Watch(); err != nil { + timeWatcherErr <- fmt.Errorf("roundswatcher failed to start watching for events: %v", err) + } + }() + defer timeWatcher.Stop() + + // Initialize unbonding watcher to update the DB with latest state of the node's unbonding locks + unbondingWatcher, err := watchers.NewUnbondingWatcher(n.Eth.Account().Address, addrMap["BondingManager"], blockWatcher, n.Database) + if err != nil { + glog.Errorf("Failed to setup unbonding watcher: %v", err) + return + } + // Start unbonding watcher (logs will not be received until the block watcher is started) + go unbondingWatcher.Watch() + defer unbondingWatcher.Stop() + + senderWatcher, err := watchers.NewSenderWatcher(addrMap["TicketBroker"], blockWatcher, n.Eth, timeWatcher) + if err != nil { + glog.Errorf("Failed to setup senderwatcher: %v", err) + return + } + go senderWatcher.Watch() + defer senderWatcher.Stop() + + orchWatcher, err := watchers.NewOrchestratorWatcher(addrMap["BondingManager"], blockWatcher, dbh, n.Eth, timeWatcher) + if err != nil { + glog.Errorf("Failed to setup orchestrator watcher: %v", err) + return + } + go orchWatcher.Watch() + defer orchWatcher.Stop() + + serviceRegistryWatcher, err := watchers.NewServiceRegistryWatcher(addrMap["ServiceRegistry"], blockWatcher, dbh, n.Eth) + if err != nil { + glog.Errorf("Failed to set up service registry watcher: %v", err) + return + } + go serviceRegistryWatcher.Watch() + defer serviceRegistryWatcher.Stop() + + n.Balances = core.NewAddressBalances(cleanupInterval) + defer n.Balances.StopCleanup() + + // By default the ticket recipient is the node's address + // If the address of an on-chain registered orchestrator is provided, then it should be specified as the ticket recipient + recipientAddr := n.Eth.Account().Address + if *cfg.EthOrchAddr != "" { + recipientAddr = ethcommon.HexToAddress(*cfg.EthOrchAddr) + } + + smCfg := &pm.LocalSenderMonitorConfig{ + Claimant: recipientAddr, + CleanupInterval: cleanupInterval, + TTL: smTTL, + RedeemGas: redeemGas, + SuggestGasPrice: client.Backend().SuggestGasPrice, + RPCTimeout: ethRPCTimeout, + } + + if *cfg.Orchestrator { + // Set price per pixel base info + if *cfg.PixelsPerUnit <= 0 { + // Can't divide by 0 + panic(fmt.Errorf("-pixelsPerUnit must be > 0, provided %d", *cfg.PixelsPerUnit)) + } + if cfg.PricePerUnit == nil { + // Prevent orchestrators from unknowingly providing free transcoding + panic(fmt.Errorf("-pricePerUnit must be set")) + } + if *cfg.PricePerUnit < 0 { + panic(fmt.Errorf("-pricePerUnit must be >= 0, provided %d", *cfg.PricePerUnit)) + } + n.SetBasePrice(big.NewRat(int64(*cfg.PricePerUnit), int64(*cfg.PixelsPerUnit))) + glog.Infof("Price: %d wei for %d pixels\n ", *cfg.PricePerUnit, *cfg.PixelsPerUnit) + + n.AutoAdjustPrice = *cfg.AutoAdjustPrice + + ev, _ := new(big.Int).SetString(*cfg.TicketEV, 10) + if ev == nil { + glog.Errorf("-ticketEV must be a valid integer, but %v provided. Restart the node with a different valid value for -ticketEV", *cfg.TicketEV) + return + } + + if ev.Cmp(big.NewInt(0)) < 0 { + glog.Errorf("-ticketEV must be greater than 0, but %v provided. Restart the node with a different valid value for -ticketEV", *cfg.TicketEV) + return + } + + if err := setupOrchestrator(n, recipientAddr); err != nil { + glog.Errorf("Error setting up orchestrator: %v", err) + return + } + + sigVerifier := &pm.DefaultSigVerifier{} + validator := pm.NewValidator(sigVerifier, timeWatcher) + + var sm pm.SenderMonitor + if *cfg.RedeemerAddr != "" { + *cfg.RedeemerAddr = defaultAddr(*cfg.RedeemerAddr, "127.0.0.1", RpcPort) + rc, err := server.NewRedeemerClient(*cfg.RedeemerAddr, senderWatcher, timeWatcher) + if err != nil { + glog.Error("Unable to start redeemer client: ", err) + return + } + sm = rc + } else { + sm = pm.NewSenderMonitor(smCfg, n.Eth, senderWatcher, timeWatcher, n.Database) + } + + // Start sender monitor + sm.Start() + defer sm.Stop() + + cfg := pm.TicketParamsConfig{ + EV: ev, + RedeemGas: redeemGas, + TxCostMultiplier: txCostMultiplier, + } + n.Recipient, err = pm.NewRecipient( + recipientAddr, + n.Eth, + validator, + gpm, + sm, + timeWatcher, + cfg, + ) + if err != nil { + glog.Errorf("Error setting up PM recipient: %v", err) + return + } + } + + if n.NodeType == core.BroadcasterNode { + ev, _ := new(big.Rat).SetString(*cfg.MaxTicketEV) + if ev == nil { + panic(fmt.Errorf("-maxTicketEV must be a valid rational number, but %v provided. Restart the node with a valid value for -maxTicketEV", *cfg.MaxTicketEV)) + } + + if ev.Cmp(big.NewRat(0, 1)) < 0 { + panic(fmt.Errorf("-maxTicketEV must not be negative, but %v provided. Restart the node with a valid value for -maxTicketEV", *cfg.MaxTicketEV)) + } + + if *cfg.DepositMultiplier <= 0 { + panic(fmt.Errorf("-depositMultiplier must be greater than 0, but %v provided. Restart the node with a valid value for -depositMultiplier", *cfg.DepositMultiplier)) + } + + // Fetch and cache broadcaster on-chain info + info, err := senderWatcher.GetSenderInfo(n.Eth.Account().Address) + if err != nil { + glog.Error("Failed to get broadcaster on-chain info: ", err) + return + } + glog.Info("Broadcaster Deposit: ", eth.FormatUnits(info.Deposit, "ETH")) + glog.Info("Broadcaster Reserve: ", eth.FormatUnits(info.Reserve.FundsRemaining, "ETH")) + + n.Sender = pm.NewSender(n.Eth, timeWatcher, senderWatcher, ev, *cfg.DepositMultiplier) + + if *cfg.PixelsPerUnit <= 0 { + // Can't divide by 0 + panic(fmt.Errorf("The amount of pixels per unit must be greater than 0, provided %d instead\n", *cfg.PixelsPerUnit)) + } + if *cfg.MaxPricePerUnit > 0 { + server.BroadcastCfg.SetMaxPrice(big.NewRat(int64(*cfg.MaxPricePerUnit), int64(*cfg.PixelsPerUnit))) + } else { + glog.Infof("Maximum transcoding price per pixel is not greater than 0: %v, broadcaster is currently set to accept ANY price.\n", *cfg.MaxPricePerUnit) + glog.Infoln("To update the broadcaster's maximum acceptable transcoding price per pixel, use the CLI or restart the broadcaster with the appropriate 'maxPricePerUnit' and 'pixelsPerUnit' values") + } + } + + if n.NodeType == core.RedeemerNode { + if err := setupOrchestrator(n, recipientAddr); err != nil { + glog.Errorf("Error setting up orchestrator: %v", err) + return + } + + r, err := server.NewRedeemer( + recipientAddr, + n.Eth, + pm.NewSenderMonitor(smCfg, n.Eth, senderWatcher, timeWatcher, n.Database), + ) + if err != nil { + glog.Errorf("Unable to create redeemer: %v", err) + return + } + + *cfg.HttpAddr = defaultAddr(*cfg.HttpAddr, "127.0.0.1", RpcPort) + url, err := url.ParseRequestURI("https://" + *cfg.HttpAddr) + if err != nil { + glog.Error("Could not parse redeemer URI: ", err) + return + } + + go func() { + if err := r.Start(url, n.WorkDir); err != nil { + serviceErr <- err + return + } + }() + defer r.Stop() + glog.Infof("Redeemer started on %v", *cfg.HttpAddr) + } + + var reward bool + if cfg.Reward == nil { + // If the node address is an on-chain registered address, start the reward service + t, err := n.Eth.GetTranscoder(n.Eth.Account().Address) + if err != nil { + glog.Error(err) + return + } + if t.Status == "Registered" { + reward = true + } else { + reward = false + } + } + + if reward { + // Start reward service + // The node will only call reward if it is active in the current round + rs := eth.NewRewardService(n.Eth, timeWatcher) + go func() { + if err := rs.Start(ctx); err != nil { + serviceErr <- err + } + return + }() + defer rs.Stop() + } + + if *cfg.InitializeRound { + // Start round initializer + // The node will only initialize rounds if it in the upcoming active set for the round + initializer := eth.NewRoundInitializer(n.Eth, timeWatcher) + go func() { + if err := initializer.Start(); err != nil { + serviceErr <- err + } + return + }() + defer initializer.Stop() + } + + blockWatchCtx, cancel := context.WithCancel(ctx) + defer cancel() + + // Backfill events that the node has missed since its last seen block. This method will block + // and the node will not continue setup until it finishes + if err := blockWatcher.BackfillEventsIfNeeded(blockWatchCtx); err != nil { + glog.Errorf("Failed to backfill events: %v", err) + return + } + + blockWatcherErr := make(chan error, 1) + go func() { + if err := blockWatcher.Watch(blockWatchCtx); err != nil { + blockWatcherErr <- fmt.Errorf("block watcher error: %v", err) + } + }() + + go func() { + var err error + select { + case err = <-timeWatcherErr: + case err = <-blockWatcherErr: + } + + watcherErr <- err + }() + } + + if *cfg.Objectstore != "" { + prepared, err := drivers.PrepareOSURL(*cfg.Objectstore) + if err != nil { + glog.Error("Error creating object store driver: ", err) + return + } + drivers.NodeStorage, err = drivers.ParseOSURL(prepared, false) + if err != nil { + glog.Error("Error creating object store driver: ", err) + return + } + } + + if *cfg.Recordstore != "" { + prepared, err := drivers.PrepareOSURL(*cfg.Recordstore) + if err != nil { + glog.Error("Error creating recordings object store driver: ", err) + return + } + drivers.RecordStorage, err = drivers.ParseOSURL(prepared, true) + if err != nil { + glog.Error("Error creating recordings object store driver: ", err) + return + } + } + + core.MaxSessions = *cfg.MaxSessions + if lpmon.Enabled { + lpmon.MaxSessions(core.MaxSessions) + } + + if *cfg.AuthWebhookURL != "" { + parsedUrl, err := validateURL(*cfg.AuthWebhookURL) + if err != nil { + glog.Fatal("Error setting auth webhook URL ", err) + } + glog.Info("Using auth webhook URL ", parsedUrl.Redacted()) + server.AuthWebhookURL = parsedUrl + } + + if *cfg.DetectionWebhookURL != "" { + parsedUrl, err := validateURL(*cfg.DetectionWebhookURL) + if err != nil { + glog.Fatal("Error setting detection webhook URL ", err) + } + glog.Info("Using detection webhook URL ", parsedUrl.Redacted()) + server.DetectionWebhookURL = parsedUrl + } + httpIngest := true + + if n.NodeType == core.BroadcasterNode { + // default lpms listener for broadcaster; same as default rpc port + // TODO provide an option to disable this? + *cfg.RtmpAddr = defaultAddr(*cfg.RtmpAddr, "127.0.0.1", RtmpPort) + *cfg.HttpAddr = defaultAddr(*cfg.HttpAddr, "127.0.0.1", RpcPort) + + bcast := core.NewBroadcaster(n) + + // When the node is on-chain mode always cache the on-chain orchestrators and poll for updates + // Right now we rely on the DBOrchestratorPoolCache constructor to do this. Consider separating the logic + // caching/polling from the logic for fetching orchestrators during discovery + if *cfg.Network != "offchain" { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + dbOrchPoolCache, err := discovery.NewDBOrchestratorPoolCache(ctx, n, timeWatcher) + if err != nil { + glog.Errorf("Could not create orchestrator pool with DB cache: %v", err) + } + + n.OrchestratorPool = dbOrchPoolCache + } + + // Set up orchestrator discovery + if *cfg.OrchWebhookURL != "" { + whurl, err := validateURL(*cfg.OrchWebhookURL) + if err != nil { + glog.Fatal("Error setting orch webhook URL ", err) + } + glog.Info("Using orchestrator webhook URL ", whurl) + n.OrchestratorPool = discovery.NewWebhookPool(bcast, whurl) + } else if len(orchURLs) > 0 { + n.OrchestratorPool = discovery.NewOrchestratorPool(bcast, orchURLs, common.Score_Trusted) + } + + if n.OrchestratorPool == nil { + // Not a fatal error; may continue operating in segment-only mode + glog.Error("No orchestrator specified; transcoding will not happen") + } + + isLocalHTTP, err := isLocalURL("https://" + *cfg.HttpAddr) + if err != nil { + glog.Errorf("Error checking for local -httpAddr: %v", err) + return + } + if cfg.HttpIngest != nil { + httpIngest = *cfg.HttpIngest + } + if cfg.HttpIngest == nil && !isLocalHTTP && server.AuthWebhookURL == nil { + glog.Warning("HTTP ingest is disabled because -httpAddr is publicly accessible. To enable, configure -authWebhookUrl or use the -httpIngest flag") + httpIngest = false + } + + // Disable local verification when running in off-chain mode + // To enable, set -localVerify or -verifierURL + localVerify := true + if cfg.LocalVerify != nil { + localVerify = *cfg.LocalVerify + } + if cfg.LocalVerify == nil && *cfg.Network == "offchain" { + localVerify = false + } + + if *cfg.VerifierURL != "" { + _, err := validateURL(*cfg.VerifierURL) + if err != nil { + glog.Fatal("Error setting verifier URL ", err) + } + glog.Info("Using the Epic Labs classifier for verification at ", *cfg.VerifierURL) + server.Policy = &verification.Policy{Retries: 2, Verifier: &verification.EpicClassifier{Addr: *cfg.VerifierURL}} + + // Set the verifier path. Remove once [1] is implemented! + // [1] https://github.com/livepeer/verification-classifier/issues/64 + if drivers.NodeStorage == nil && *cfg.VerifierPath == "" { + glog.Fatal("Requires a path to the verifier shared volume when local storage is in use; use -verifierPath or -objectStore") + } + verification.VerifierPath = *cfg.VerifierPath + } else if localVerify { + glog.Info("Local verification enabled") + server.Policy = &verification.Policy{Retries: 2} + } + + // Set max transcode attempts. <=0 is OK; it just means "don't transcode" + server.MaxAttempts = *cfg.MaxAttempts + server.SelectRandFreq = *cfg.SelectRandFreq + + } else if n.NodeType == core.OrchestratorNode { + suri, err := getServiceURI(n, *cfg.ServiceAddr) + if err != nil { + glog.Fatal("Error getting service URI: ", err) + } + n.SetServiceURI(suri) + // if http addr is not provided, listen to all ifaces + // take the port to listen to from the service URI + *cfg.HttpAddr = defaultAddr(*cfg.HttpAddr, "", n.GetServiceURI().Port()) + + if *cfg.SceneClassificationModelPath != "" { + // Only enable experimental capabilities if scene classification model is actually loaded + transcoderCaps = append(transcoderCaps, core.ExperimentalCapabilities()...) + } + if !*cfg.Transcoder && n.OrchSecret == "" { + glog.Fatal("Running an orchestrator requires an -orchSecret for standalone mode or -transcoder for orchestrator+transcoder mode") + } + } + n.Capabilities = core.NewCapabilities(transcoderCaps, core.MandatoryOCapabilities()) + *cfg.CliAddr = defaultAddr(*cfg.CliAddr, "127.0.0.1", CliPort) + + if drivers.NodeStorage == nil { + // base URI will be empty for broadcasters; that's OK + drivers.NodeStorage = drivers.NewMemoryDriver(n.GetServiceURI()) + } + + if *cfg.MetadataPublishTimeout > 0 { + server.MetadataPublishTimeout = *cfg.MetadataPublishTimeout + } + if *cfg.MetadataQueueUri != "" { + uri, err := url.ParseRequestURI(*cfg.MetadataQueueUri) + if err != nil { + glog.Fatalf("Error parsing -metadataQueueUri: err=%q", err) + } + switch uri.Scheme { + case "amqp", "amqps": + uriStr, exchange, keyNs := *cfg.MetadataQueueUri, *cfg.MetadataAmqpExchange, n.NodeType.String() + server.MetadataQueue, err = event.NewAMQPExchangeProducer(context.Background(), uriStr, exchange, keyNs) + if err != nil { + glog.Fatalf("Error establishing AMQP connection: err=%q", err) + } + default: + glog.Fatalf("Unsupported scheme in -metadataUri: %s", uri.Scheme) + } + } + + //Create Livepeer Node + + //Set up the media server + s, err := server.NewLivepeerServer(*cfg.RtmpAddr, n, httpIngest, *cfg.TranscodingOptions) + if err != nil { + glog.Fatal("Error creating Livepeer server err=", err) + } + + ec := make(chan error) + tc := make(chan struct{}) + wc := make(chan struct{}) + msCtx, cancel := context.WithCancel(ctx) + defer cancel() + + if *cfg.CurrentManifest { + glog.Info("Current ManifestID will be available over ", *cfg.HttpAddr) + s.ExposeCurrentManifest = *cfg.CurrentManifest + } + + go func() { + s.StartCliWebserver(*cfg.CliAddr) + close(wc) + }() + if n.NodeType != core.RedeemerNode { + go func() { + ec <- s.StartMediaServer(msCtx, *cfg.HttpAddr) + }() + } + + go func() { + if core.OrchestratorNode != n.NodeType { + return + } + + orch := core.NewOrchestrator(s.LivepeerNode, timeWatcher) + + go func() { + server.StartTranscodeServer(orch, *cfg.HttpAddr, s.HTTPMux, n.WorkDir, n.TranscoderManager != nil) + tc <- struct{}{} + }() + + // check whether or not the orchestrator is available + time.Sleep(2 * time.Second) + orchAvail := server.CheckOrchestratorAvailability(orch) + if !orchAvail { + // shut down orchestrator + glog.Infof("Orchestrator not available at %v; shutting down", orch.ServiceURI()) + tc <- struct{}{} + } + + }() + + if n.NodeType == core.TranscoderNode { + if n.OrchSecret == "" { + glog.Fatal("Missing -orchSecret") + } + if len(orchURLs) <= 0 { + glog.Fatal("Missing -orchAddr") + } + + go server.RunTranscoder(n, orchURLs[0].Host, *cfg.MaxSessions, transcoderCaps) + } + + switch n.NodeType { + case core.OrchestratorNode: + glog.Infof("***Livepeer Running in Orchestrator Mode***") + case core.BroadcasterNode: + glog.Infof("***Livepeer Running in Broadcaster Mode***") + glog.Infof("Video Ingest Endpoint - rtmp://%v", *cfg.RtmpAddr) + case core.TranscoderNode: + glog.Infof("**Liveepeer Running in Transcoder Mode***") + case core.RedeemerNode: + glog.Infof("**Livepeer Running in Redeemer Mode**") + } + + select { + case err := <-watcherErr: + glog.Error(err) + return + case err := <-ec: + glog.Infof("Error from media server: %v", err) + return + case err := <-serviceErr: + if err != nil { + glog.Fatalf("Error starting service: %v", err) + } + case <-tc: + glog.Infof("Orchestrator server shut down") + case <-wc: + glog.Infof("CLI webserver shut down") + return + case <-msCtx.Done(): + glog.Infof("MediaServer Done()") + return + case <-ctx.Done(): + return + } +} + +func parseOrchAddrs(addrs string) []*url.URL { + var res []*url.URL + if len(addrs) > 0 { + for _, addr := range strings.Split(addrs, ",") { + addr = strings.TrimSpace(addr) + addr = defaultAddr(addr, "127.0.0.1", RpcPort) + if !strings.HasPrefix(addr, "http") { + addr = "https://" + addr + } + uri, err := url.ParseRequestURI(addr) + if err != nil { + glog.Error("Could not parse orchestrator URI: ", err) + continue + } + res = append(res, uri) + } + } + return res +} + +func validateURL(u string) (*url.URL, error) { + if u == "" { + return nil, nil + } + p, err := url.ParseRequestURI(u) + if err != nil { + return nil, err + } + if p.Scheme != "http" && p.Scheme != "https" { + return nil, errors.New("URL should be HTTP or HTTPS") + } + return p, nil +} + +func isLocalURL(u string) (bool, error) { + uri, err := url.ParseRequestURI(u) + if err != nil { + return false, err + } + + hostname := uri.Hostname() + if net.ParseIP(hostname).IsLoopback() || hostname == "localhost" { + return true, nil + } + + return false, nil +} + +// ServiceURI checking steps: +// If passed in via -serviceAddr: return that +// Else: get inferred address. +// If offchain: return inferred address +// Else: get on-chain sURI +// If on-chain sURI mismatches inferred address: print warning +// Return on-chain sURI +func getServiceURI(n *core.LivepeerNode, serviceAddr string) (*url.URL, error) { + // Passed in via CLI + if serviceAddr != "" { + return url.ParseRequestURI("https://" + serviceAddr) + } + + // Infer address + // TODO probably should put this (along w wizard GETs) into common code + resp, err := http.Get("https://api.ipify.org?format=text") + if err != nil { + glog.Errorf("Could not look up public IP err=%q", err) + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + glog.Errorf("Could not look up public IP err=%q", err) + return nil, err + } + addr := "https://" + strings.TrimSpace(string(body)) + ":" + RpcPort + inferredUri, err := url.ParseRequestURI(addr) + if err != nil { + glog.Errorf("Could not look up public IP err=%q", err) + return nil, err + } + if n.Eth == nil { + // we won't be looking up onchain sURI so use the inferred one + return inferredUri, err + } + + // On-chain lookup and matching with inferred public address + addr, err = n.Eth.GetServiceURI(n.Eth.Account().Address) + if err != nil { + glog.Errorf("Could not get service URI; orchestrator may be unreachable err=%q", err) + return nil, err + } + ethUri, err := url.ParseRequestURI(addr) + if err != nil { + glog.Errorf("Could not parse service URI; orchestrator may be unreachable err=%q", err) + ethUri, _ = url.ParseRequestURI("http://127.0.0.1:" + RpcPort) + } + if ethUri.Hostname() != inferredUri.Hostname() || ethUri.Port() != inferredUri.Port() { + glog.Errorf("Service address %v did not match discovered address %v; set the correct address in livepeer_cli or use -serviceAddr", ethUri, inferredUri) + } + return ethUri, nil +} + +func setupOrchestrator(n *core.LivepeerNode, ethOrchAddr ethcommon.Address) error { + // add orchestrator to DB + orch, err := n.Eth.GetTranscoder(ethOrchAddr) + if err != nil { + return err + } + + err = n.Database.UpdateOrch(&common.DBOrch{ + EthereumAddr: ethOrchAddr.Hex(), + ActivationRound: common.ToInt64(orch.ActivationRound), + DeactivationRound: common.ToInt64(orch.DeactivationRound), + }) + if err != nil { + return err + } + + if !orch.Active { + glog.Infof("Orchestrator %v is inactive", ethOrchAddr.Hex()) + } else { + glog.Infof("Orchestrator %v is active", ethOrchAddr.Hex()) + } + + return nil +} + +func defaultAddr(addr, defaultHost, defaultPort string) string { + if addr == "" { + return defaultHost + ":" + defaultPort + } + if addr[0] == ':' { + return defaultHost + addr + } + // not IPv6 safe + if !strings.Contains(addr, ":") { + return addr + ":" + defaultPort + } + return addr +} + +func checkOrStoreChainID(dbh *common.DB, chainID *big.Int) error { + expectedChainID, err := dbh.ChainID() + if err != nil { + return err + } + + if expectedChainID == nil { + // No chainID stored yet + // Store the provided chainID and skip the check + if err := dbh.SetChainID(chainID); err != nil { + return err + } + + return nil + } + + if expectedChainID.Cmp(chainID) != 0 { + return fmt.Errorf("expecting chainID of %v, but got %v. Did you change networks without changing network name or datadir?", expectedChainID, chainID) + } + + return nil +} diff --git a/cmd/livepeer/livepeer_test.go b/cmd/livepeer/starter/starter_test.go similarity index 99% rename from cmd/livepeer/livepeer_test.go rename to cmd/livepeer/starter/starter_test.go index 264362a43a..3adb36282a 100644 --- a/cmd/livepeer/livepeer_test.go +++ b/cmd/livepeer/starter/starter_test.go @@ -1,4 +1,4 @@ -package main +package starter import ( "errors" diff --git a/go.mod b/go.mod index a5a4038059..87c10debe6 100644 --- a/go.mod +++ b/go.mod @@ -29,10 +29,10 @@ require ( github.com/prometheus/tsdb v0.10.0 // indirect github.com/rjeczalik/notify v0.9.2 // indirect github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 // indirect - github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.7.0 + github.com/testcontainers/testcontainers-go v0.12.0 github.com/tyler-smith/go-bip39 v1.0.2 // indirect - github.com/urfave/cli v1.20.0 + github.com/urfave/cli v1.22.2 go.opencensus.io v0.23.0 go.uber.org/goleak v1.0.0 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect diff --git a/go.sum b/go.sum index b96584d69d..13693bf49f 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -47,21 +48,57 @@ contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/Flaque/filet v0.0.0-20201012163910-45f684403088 h1:PnnQln5IGbhLeJOi6hVs+lCeF+B1dRfFKPGXUAez0Ww= +github.com/Flaque/filet v0.0.0-20201012163910-45f684403088/go.mod h1:TK+jB3mBs+8ZMWhU5BqZKnZWJ1MrLo8etNVg51ueTBo= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3 h1:mw6pDQqv38/WGF1cO/jF5t/jyAJ2yi7CmtFLLO5tGFI= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16 h1:8/auA4LFIZFTGrqfKhGBSXwM6/4X1fHa/xniyEHu8ac= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= @@ -74,6 +111,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -83,6 +121,8 @@ github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VT github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.33.11 h1:A7b3mNKbh/0zrhnNN/KxWD0YZJw2RImnjFXWOquYKB4= github.com/aws/aws-sdk-go v1.33.11/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= @@ -94,14 +134,21 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7 github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= @@ -115,6 +162,10 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -126,22 +177,115 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 h1:hkGVFjz+plgr5UfxZUTPFbUFIF/Km6/s+RVRIRHLrrY= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4 h1:zjz4MOAOFgdBlwid2nNUlJ3YLpVi/97L36lfMYJex60= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -153,18 +297,43 @@ github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14y github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.11+incompatible h1:OqzI/g/W54LczvhnccGqniFoQghHx3pklbLuhfXpqGo= +github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48 h1:iZOop7pqsg+56twTopWgwCGxdB5SI2yDO8Ti7eTRliQ= github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -174,21 +343,27 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/go-ethereum v1.10.14 h1:EJ/ucQzFlgKgwblIwU8R6ABnZ9kgUnIG2+Q1tiSrt4M= github.com/ethereum/go-ethereum v1.10.14/go.mod h1:W3yfrFyL9C1pHcwY5hmRHVDaorTiQxhYBkKyu5mEDHw= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= @@ -197,6 +372,7 @@ github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -205,29 +381,52 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU= github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= @@ -282,6 +481,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -300,6 +500,8 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -307,20 +509,31 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -347,6 +560,10 @@ github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSa github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= @@ -359,6 +576,7 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jaypipes/ghw v0.9.0 h1:TWF4wNIGtZcgDJaiNcFgby5BR8s2ixcUe0ydxNO2McY= @@ -368,14 +586,18 @@ github.com/jaypipes/pcidb v1.0.0/go.mod h1:TnYUvqhPBzCKnH34KrIX22kAeEbDCSRJ9cqLR github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -389,25 +611,30 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559 h1:0VWDXPNE0brOek1Q8bLfzKkvOzwbQE/snjGojlCr8CY= github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -420,15 +647,16 @@ github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded h1:ZQlvR5RB4nfT+cO github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded/go.mod h1:xkDdm+akniYxVT9KW1Y2Y7Hso6aW+rZObz3nrA9yTHw= github.com/livepeer/livepeer-data v0.4.11 h1:Sv+ss8e4vcscnMWLxcRJ2g3sNIHyQ3RzCtgEelfGPzw= github.com/livepeer/livepeer-data v0.4.11/go.mod h1:VIbJRdyH2Tas8EgLVkP79IPMepFDOv0dgHYLEZsCaf4= -github.com/livepeer/lpms v0.0.0-20220322090848-7c772da19b33 h1:EQdk2TS3EdyIBv7gKuSNbOsWoJc/60Yk1grgZP1iDCE= -github.com/livepeer/lpms v0.0.0-20220322090848-7c772da19b33/go.mod h1:Hr/JhxxPDipOVd4ZrGYWrdJfpVF8/SEI0nNr2ctAlkM= github.com/livepeer/lpms v0.0.0-20220420001659-1d700dd80073 h1:1NxBmwq89Ts93DTIW3iLMqf24S3+uU4YnDZbsYfrH+k= github.com/livepeer/lpms v0.0.0-20220420001659-1d700dd80073/go.mod h1:Hr/JhxxPDipOVd4ZrGYWrdJfpVF8/SEI0nNr2ctAlkM= github.com/livepeer/m3u8 v0.11.1 h1:VkUJzfNTyjy9mqsgp5JPvouwna8wGZMvd/gAfT5FinU= github.com/livepeer/m3u8 v0.11.1/go.mod h1:IUqAtwWPAG2CblfQa4SVzTQoDcEMPyfNOaBSxqHMS04= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -443,15 +671,20 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -464,36 +697,89 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM= +github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -503,6 +789,7 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/ff v1.7.0 h1:hknvTgsh90jNBIjPq7xeq32Y9AmSbpXvjrFW4sJwW+A= github.com/peterbourgon/ff v1.7.0/go.mod h1:/KKxnU5cBj4w21jEMj4Rway/kslRP6XAOHh7CH8AyAM= github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM= @@ -515,6 +802,7 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -523,17 +811,22 @@ github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUI github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -541,10 +834,16 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -558,33 +857,53 @@ github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1 github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -592,10 +911,13 @@ github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw= github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -605,23 +927,44 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/testcontainers/testcontainers-go v0.12.0 h1:SK0NryGHIx7aifF6YqReORL18aGAA4bsDPtikDVCEyg= +github.com/testcontainers/testcontainers-go v0.12.0/go.mod h1:SIndOQXZng0IW8iWU1Js0ynrfZ8xcxrTtDfF6rD2pxs= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -629,9 +972,16 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -641,26 +991,34 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= @@ -711,20 +1069,27 @@ golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -745,6 +1110,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -753,6 +1119,7 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211108170745-6635138e15ea/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -795,23 +1162,36 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -824,14 +1204,23 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -846,11 +1235,14 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211109184856-51b60fd695b3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -865,12 +1257,15 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -885,7 +1280,9 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -941,6 +1338,7 @@ gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -972,11 +1370,13 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= @@ -987,6 +1387,7 @@ google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1006,6 +1407,7 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1016,10 +1418,14 @@ google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -1048,25 +1454,37 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1079,7 +1497,11 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1090,9 +1512,26 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= pgregory.net/rapid v0.4.0 h1:/boyXNQlDs1pmk7g1b9u2KrYqXnqjj0ARUDsZj5kapg= pgregory.net/rapid v0.4.0/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/test.sh b/test.sh index 422ee67dff..09157030db 100755 --- a/test.sh +++ b/test.sh @@ -2,9 +2,8 @@ set -eux -#Test script to run all the tests for continuous integration - -go test -coverprofile cover.out ./... +# Test script to run all the tests except of e2e tests for continuous integration +go test -coverprofile cover.out $(go list ./... | grep -v 'test/e2e') cd core # Be more strict with load balancer tests: run with race detector enabled diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go new file mode 100644 index 0000000000..49a35afe6e --- /dev/null +++ b/test/e2e/e2e.go @@ -0,0 +1,204 @@ +package e2e + +import ( + "bytes" + "context" + "fmt" + "github.com/livepeer/go-livepeer/cmd/devtool/devtool" + "github.com/livepeer/go-livepeer/cmd/livepeer/starter" + "github.com/livepeer/go-livepeer/eth" + "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go" + "io/ioutil" + "net/http" + "net/url" + "path/filepath" + "sync" + "testing" + "time" +) + +// Start Geth Docker container helpers +type gethContainer struct { + testcontainers.Container + URI string + webServerURI string +} + +func setupGeth(t *testing.T) *gethContainer { + ctx := context.TODO() + req := testcontainers.ContainerRequest{ + Image: "livepeer/geth-with-livepeer-protocol:streamflow", + ExposedPorts: []string{"8546/tcp", "8545/tcp"}, + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + require.NoError(t, err) + + ip, err := container.Host(ctx) + require.NoError(t, err) + + mappedPort, err := container.MappedPort(ctx, "8545") + require.NoError(t, err) + + mappedPortWebServer, err := container.MappedPort(ctx, "8546") + require.NoError(t, err) + + uri := fmt.Sprintf("http://%s:%s", ip, mappedPort.Port()) + webServerUri := fmt.Sprintf("http://%s:%s", ip, mappedPortWebServer.Port()) + + return &gethContainer{Container: container, URI: uri, webServerURI: webServerUri} +} + +func terminateGeth(t *testing.T, geth *gethContainer) { + err := geth.Terminate(context.TODO()) + require.NoError(t, err) +} + +// Start Livepeer helpers +var ( + httpPort = 8935 + cliPort = 7935 + rtmpPort = 1935 + mu sync.Mutex +) + +type livepeer struct { + dev *devtool.Devtool + cfg *starter.LivepeerConfig + ready chan struct{} +} + +func lpCfg() starter.LivepeerConfig { + mu.Lock() + serviceAddr := fmt.Sprintf("127.0.0.1:%d", httpPort) + httpPort++ + cliAddr := fmt.Sprintf("127.0.0.1:%d", cliPort) + cliPort++ + rtmpAddr := fmt.Sprintf("127.0.0.1:%d", rtmpPort) + rtmpPort++ + mu.Unlock() + + ethPassword := "" + network := "devnet" + blockPollingInterval := 1 + pricePerUnit := 1 + initializeRound := true + + cfg := starter.DefaultLivepeerConfig() + cfg.ServiceAddr = &serviceAddr + cfg.HttpAddr = &serviceAddr + cfg.CliAddr = &cliAddr + cfg.RtmpAddr = &rtmpAddr + cfg.EthPassword = ðPassword + cfg.Network = &network + cfg.BlockPollingInterval = &blockPollingInterval + cfg.PricePerUnit = &pricePerUnit + cfg.InitializeRound = &initializeRound + return cfg +} + +func startLivepeer(t *testing.T, lpCfg starter.LivepeerConfig, geth *gethContainer) *livepeer { + datadir := t.TempDir() + keystoreDir := filepath.Join(datadir, "keystore") + acc := devtool.CreateKey(keystoreDir) + devCfg := devtool.NewDevtoolConfig() + devCfg.Endpoint = geth.URI + devCfg.Account = acc + devCfg.KeystoreDir = keystoreDir + + dev, err := devtool.Init(devCfg) + require.NoError(t, err) + + err = dev.RequestTokens() + require.NoError(t, err) + + err = dev.InitializeRound() + require.NoError(t, err) + + lpCfg.EthUrl = &geth.URI + lpCfg.Datadir = &datadir + lpCfg.EthController = &dev.EthController + lpCfg.EthAcctAddr = &devCfg.Account + + go func() { + starter.StartLivepeer(context.TODO(), lpCfg) + }() + + ready := make(chan struct{}) + go func() { + statusEndpoint := fmt.Sprintf("http://%s/status", *lpCfg.CliAddr) + var statusCode int + for statusCode != 200 { + time.Sleep(200 * time.Millisecond) + resp, err := http.Get(statusEndpoint) + if err == nil { + statusCode = resp.StatusCode + } + } + ready <- struct{}{} + }() + + return &livepeer{dev: &dev, cfg: &lpCfg, ready: ready} +} + +func (l *livepeer) stop() { + l.dev.Close() +} + +// Other helpers +func waitForNextRound(t *testing.T, lpEth eth.LivepeerEthClient) { + r, err := lpEth.CurrentRound() + require.NoError(t, err) + + for { + nr, err := lpEth.CurrentRound() + require.NoError(t, err) + + if nr.Cmp(r) > 0 { + return + } + time.Sleep(500 * time.Millisecond) + } +} + +func boolPointer(b bool) *bool { + return &b +} + +func httpPostWithParams(url string, val url.Values) (string, bool) { + return httpPostWithParamsHeaders(url, val, map[string]string{}) +} + +func httpPostWithParamsHeaders(url string, val url.Values, headers map[string]string) (string, bool) { + var body *bytes.Buffer + if val != nil { + body = bytes.NewBufferString(val.Encode()) + } else { + body = bytes.NewBufferString("") + } + req, err := http.NewRequest("POST", url, body) + if err != nil { + return "", false + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + for k, v := range headers { + req.Header.Set(k, v) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", false + } + + defer resp.Body.Close() + result, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", false + } + + return string(result), resp.StatusCode >= 200 && resp.StatusCode < 300 +} diff --git a/test/e2e/register_orchestrator_test.go b/test/e2e/register_orchestrator_test.go new file mode 100644 index 0000000000..11921ef273 --- /dev/null +++ b/test/e2e/register_orchestrator_test.go @@ -0,0 +1,77 @@ +package e2e + +import ( + "fmt" + "github.com/livepeer/go-livepeer/eth" + "github.com/stretchr/testify/require" + "math/big" + "net/url" + "testing" + "time" +) + +func TestRegisterOrchestrator(t *testing.T) { + // given + geth := setupGeth(t) + defer terminateGeth(t, geth) + + o := startOrchestrator(t, geth) + lpEth := o.dev.Client + defer o.stop() + <-o.ready + + // when + registerOrchestrator(o) + waitForNextRound(t, lpEth) + + // then + assertOrchestratorRegisteredAndActivated(t, lpEth) +} + +func startOrchestrator(t *testing.T, geth *gethContainer) *livepeer { + lpCfg := lpCfg() + lpCfg.Orchestrator = boolPointer(true) + lpCfg.Transcoder = boolPointer(true) + return startLivepeer(t, lpCfg, geth) +} + +const ( + pricePerUnit = 1 + pixelsPerUnit = 10 + rewardCut = 30.0 + feeShare = 50.0 + lptStake = 50 +) + +func registerOrchestrator(o *livepeer) { + val := url.Values{ + "pricePerUnit": {fmt.Sprintf("%d", pricePerUnit)}, + "pixelsPerUnit": {fmt.Sprintf("%d", pixelsPerUnit)}, + "blockRewardCut": {fmt.Sprintf("%v", rewardCut)}, + "feeShare": {fmt.Sprintf("%v", feeShare)}, + "serviceURI": {fmt.Sprintf("http://%v", o.cfg.HttpAddr)}, + "amount": {fmt.Sprintf("%d", lptStake)}, + } + + for { + if _, ok := httpPostWithParams(fmt.Sprintf("http://%s/activateOrchestrator", *o.cfg.CliAddr), val); ok { + return + } + time.Sleep(200 * time.Millisecond) + } +} + +func assertOrchestratorRegisteredAndActivated(t *testing.T, lpEth eth.LivepeerEthClient) { + require := require.New(t) + + transPool, err := lpEth.TranscoderPool() + + require.NoError(err) + require.Len(transPool, 1) + trans := transPool[0] + require.True(trans.Active) + require.Equal("Registered", trans.Status) + require.Equal(big.NewInt(lptStake), trans.DelegatedStake) + require.Equal(eth.FromPerc(feeShare), trans.FeeShare) + require.Equal(eth.FromPerc(rewardCut), trans.RewardCut) +} diff --git a/test_e2e.sh b/test_e2e.sh new file mode 100755 index 0000000000..772a8fc961 --- /dev/null +++ b/test_e2e.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -eux + +go test $(go list ./... | grep 'test/e2e') --timeout 10m