aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/puppeth/wizard_netstats.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/puppeth/wizard_netstats.go')
-rw-r--r--cmd/puppeth/wizard_netstats.go235
1 files changed, 235 insertions, 0 deletions
diff --git a/cmd/puppeth/wizard_netstats.go b/cmd/puppeth/wizard_netstats.go
new file mode 100644
index 000000000..c2a933a55
--- /dev/null
+++ b/cmd/puppeth/wizard_netstats.go
@@ -0,0 +1,235 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of go-ethereum.
+//
+// go-ethereum is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// go-ethereum is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/olekukonko/tablewriter"
+)
+
+// networkStats verifies the status of network components and generates a protip
+// configuration set to give users hints on how to do various tasks.
+func (w *wizard) networkStats(tips bool) {
+ if len(w.servers) == 0 {
+ log.Error("No remote machines to gather stats from")
+ return
+ }
+ protips := new(protips)
+
+ // Iterate over all the specified hosts and check their status
+ stats := tablewriter.NewWriter(os.Stdout)
+ stats.SetHeader([]string{"Server", "IP", "Status", "Service", "Details"})
+ stats.SetColWidth(128)
+
+ for _, server := range w.conf.Servers {
+ client := w.servers[server]
+ logger := log.New("server", server)
+ logger.Info("Starting remote server health-check")
+
+ // If the server is not connected, try to connect again
+ if client == nil {
+ conn, err := dial(server)
+ if err != nil {
+ logger.Error("Failed to establish remote connection", "err", err)
+ stats.Append([]string{server, "", err.Error(), "", ""})
+ continue
+ }
+ client = conn
+ }
+ // Client connected one way or another, run health-checks
+ services := make(map[string]string)
+ logger.Debug("Checking for nginx availability")
+ if infos, err := checkNginx(client, w.network); err != nil {
+ if err != ErrServiceUnknown {
+ services["nginx"] = err.Error()
+ }
+ } else {
+ services["nginx"] = infos.String()
+ }
+ logger.Debug("Checking for ethstats availability")
+ if infos, err := checkEthstats(client, w.network); err != nil {
+ if err != ErrServiceUnknown {
+ services["ethstats"] = err.Error()
+ }
+ } else {
+ services["ethstats"] = infos.String()
+ protips.ethstats = infos.config
+ }
+ logger.Debug("Checking for bootnode availability")
+ if infos, err := checkNode(client, w.network, true); err != nil {
+ if err != ErrServiceUnknown {
+ services["bootnode"] = err.Error()
+ }
+ } else {
+ services["bootnode"] = infos.String()
+
+ protips.genesis = string(infos.genesis)
+ protips.bootFull = append(protips.bootFull, infos.enodeFull)
+ if infos.enodeLight != "" {
+ protips.bootLight = append(protips.bootLight, infos.enodeLight)
+ }
+ }
+ logger.Debug("Checking for sealnode availability")
+ if infos, err := checkNode(client, w.network, false); err != nil {
+ if err != ErrServiceUnknown {
+ services["sealnode"] = err.Error()
+ }
+ } else {
+ services["sealnode"] = infos.String()
+ protips.genesis = string(infos.genesis)
+ }
+ logger.Debug("Checking for faucet availability")
+ if infos, err := checkFaucet(client, w.network); err != nil {
+ if err != ErrServiceUnknown {
+ services["faucet"] = err.Error()
+ }
+ } else {
+ services["faucet"] = infos.String()
+ }
+ logger.Debug("Checking for dashboard availability")
+ if infos, err := checkDashboard(client, w.network); err != nil {
+ if err != ErrServiceUnknown {
+ services["dashboard"] = err.Error()
+ }
+ } else {
+ services["dashboard"] = infos.String()
+ }
+ // All status checks complete, report and check next server
+ delete(w.services, server)
+ for service := range services {
+ w.services[server] = append(w.services[server], service)
+ }
+ server, address := client.server, client.address
+ for service, status := range services {
+ stats.Append([]string{server, address, "online", service, status})
+ server, address = "", ""
+ }
+ if len(services) == 0 {
+ stats.Append([]string{server, address, "online", "", ""})
+ }
+ }
+ // If a genesis block was found, load it into our configs
+ if protips.genesis != "" {
+ genesis := new(core.Genesis)
+ if err := json.Unmarshal([]byte(protips.genesis), genesis); err != nil {
+ log.Error("Failed to parse remote genesis", "err", err)
+ } else {
+ w.conf.genesis = genesis
+ protips.network = genesis.Config.ChainId.Int64()
+ }
+ }
+ if protips.ethstats != "" {
+ w.conf.ethstats = protips.ethstats
+ }
+ w.conf.bootFull = protips.bootFull
+ w.conf.bootLight = protips.bootLight
+
+ // Print any collected stats and return
+ if !tips {
+ stats.Render()
+ } else {
+ protips.print(w.network)
+ }
+}
+
+// protips contains a collection of network infos to report pro-tips
+// based on.
+type protips struct {
+ genesis string
+ network int64
+ bootFull []string
+ bootLight []string
+ ethstats string
+}
+
+// print analyzes the network information available and prints a collection of
+// pro tips for the user's consideration.
+func (p *protips) print(network string) {
+ // If a known genesis block is available, display it and prepend an init command
+ fullinit, lightinit := "", ""
+ if p.genesis != "" {
+ fullinit = fmt.Sprintf("geth --datadir=$HOME/.%s init %s.json && ", network, network)
+ lightinit = fmt.Sprintf("geth --datadir=$HOME/.%s --light init %s.json && ", network, network)
+ }
+ // If an ethstats server is available, add the ethstats flag
+ statsflag := ""
+ if p.ethstats != "" {
+ if strings.Contains(p.ethstats, " ") {
+ statsflag = fmt.Sprintf(` --ethstats="yournode:%s"`, p.ethstats)
+ } else {
+ statsflag = fmt.Sprintf(` --ethstats=yournode:%s`, p.ethstats)
+ }
+ }
+ // If bootnodes have been specified, add the bootnode flag
+ bootflagFull := ""
+ if len(p.bootFull) > 0 {
+ bootflagFull = fmt.Sprintf(` --bootnodes %s`, strings.Join(p.bootFull, ","))
+ }
+ bootflagLight := ""
+ if len(p.bootLight) > 0 {
+ bootflagLight = fmt.Sprintf(` --bootnodes %s`, strings.Join(p.bootLight, ","))
+ }
+ // Assemble all the known pro-tips
+ var tasks, tips []string
+
+ tasks = append(tasks, "Run an archive node with historical data")
+ tips = append(tips, fmt.Sprintf("%sgeth --networkid=%d --datadir=$HOME/.%s --cache=1024%s%s", fullinit, p.network, network, statsflag, bootflagFull))
+
+ tasks = append(tasks, "Run a full node with recent data only")
+ tips = append(tips, fmt.Sprintf("%sgeth --networkid=%d --datadir=$HOME/.%s --cache=512 --fast%s%s", fullinit, p.network, network, statsflag, bootflagFull))
+
+ tasks = append(tasks, "Run a light node with on demand retrievals")
+ tips = append(tips, fmt.Sprintf("%sgeth --networkid=%d --datadir=$HOME/.%s --light%s%s", lightinit, p.network, network, statsflag, bootflagLight))
+
+ tasks = append(tasks, "Run an embedded node with constrained memory")
+ tips = append(tips, fmt.Sprintf("%sgeth --networkid=%d --datadir=$HOME/.%s --cache=32 --light%s%s", lightinit, p.network, network, statsflag, bootflagLight))
+
+ // If the tips are short, display in a table
+ short := true
+ for _, tip := range tips {
+ if len(tip) > 100 {
+ short = false
+ break
+ }
+ }
+ fmt.Println()
+ if short {
+ howto := tablewriter.NewWriter(os.Stdout)
+ howto.SetHeader([]string{"Fun tasks for you", "Tips on how to"})
+ howto.SetColWidth(100)
+
+ for i := 0; i < len(tasks); i++ {
+ howto.Append([]string{tasks[i], tips[i]})
+ }
+ howto.Render()
+ return
+ }
+ // Meh, tips got ugly, split into many lines
+ for i := 0; i < len(tasks); i++ {
+ fmt.Println(tasks[i])
+ fmt.Println(strings.Repeat("-", len(tasks[i])))
+ fmt.Println(tips[i])
+ fmt.Println()
+ fmt.Println()
+ }
+}