github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/cmd/puppeth/wizard_intro.go (about)

     1  //  Copyright 2018 The go-ethereum Authors
     2  //  Copyright 2019 The go-aigar Authors
     3  //  This file is part of the go-aigar library.
     4  //
     5  //  The go-aigar library is free software: you can redistribute it and/or modify
     6  //  it under the terms of the GNU Lesser General Public License as published by
     7  //  the Free Software Foundation, either version 3 of the License, or
     8  //  (at your option) any later version.
     9  //
    10  //  The go-aigar library is distributed in the hope that it will be useful,
    11  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  //  GNU Lesser General Public License for more details.
    14  //
    15  //  You should have received a copy of the GNU Lesser General Public License
    16  //  along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package main
    19  
    20  import (
    21  	"bufio"
    22  	"encoding/json"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  	"sync"
    29  
    30  	"github.com/AigarNetwork/aigar/log"
    31  )
    32  
    33  // makeWizard creates and returns a new puppeth wizard.
    34  func makeWizard(network string) *wizard {
    35  	return &wizard{
    36  		network: network,
    37  		conf: config{
    38  			Servers: make(map[string][]byte),
    39  		},
    40  		servers:  make(map[string]*sshClient),
    41  		services: make(map[string][]string),
    42  		in:       bufio.NewReader(os.Stdin),
    43  	}
    44  }
    45  
    46  // run displays some useful infos to the user, starting on the journey of
    47  // setting up a new or managing an existing Ethereum private network.
    48  func (w *wizard) run() {
    49  	fmt.Println("+-----------------------------------------------------------+")
    50  	fmt.Println("| Welcome to puppeth, your Ethereum private network manager |")
    51  	fmt.Println("|                                                           |")
    52  	fmt.Println("| This tool lets you create a new Ethereum network down to  |")
    53  	fmt.Println("| the genesis block, bootnodes, miners and ethstats servers |")
    54  	fmt.Println("| without the hassle that it would normally entail.         |")
    55  	fmt.Println("|                                                           |")
    56  	fmt.Println("| Puppeth uses SSH to dial in to remote servers, and builds |")
    57  	fmt.Println("| its network components out of Docker containers using the |")
    58  	fmt.Println("| docker-compose toolset.                                   |")
    59  	fmt.Println("+-----------------------------------------------------------+")
    60  	fmt.Println()
    61  
    62  	// Make sure we have a good network name to work with	fmt.Println()
    63  	// Docker accepts hyphens in image names, but doesn't like it for container names
    64  	if w.network == "" {
    65  		fmt.Println("Please specify a network name to administer (no spaces, hyphens or capital letters please)")
    66  		for {
    67  			w.network = w.readString()
    68  			if !strings.Contains(w.network, " ") && !strings.Contains(w.network, "-") && strings.ToLower(w.network) == w.network {
    69  				fmt.Printf("\nSweet, you can set this via --network=%s next time!\n\n", w.network)
    70  				break
    71  			}
    72  			log.Error("I also like to live dangerously, still no spaces, hyphens or capital letters")
    73  		}
    74  	}
    75  	log.Info("Administering Ethereum network", "name", w.network)
    76  
    77  	// Load initial configurations and connect to all live servers
    78  	w.conf.path = filepath.Join(os.Getenv("HOME"), ".puppeth", w.network)
    79  
    80  	blob, err := ioutil.ReadFile(w.conf.path)
    81  	if err != nil {
    82  		log.Warn("No previous configurations found", "path", w.conf.path)
    83  	} else if err := json.Unmarshal(blob, &w.conf); err != nil {
    84  		log.Crit("Previous configuration corrupted", "path", w.conf.path, "err", err)
    85  	} else {
    86  		// Dial all previously known servers concurrently
    87  		var pend sync.WaitGroup
    88  		for server, pubkey := range w.conf.Servers {
    89  			pend.Add(1)
    90  
    91  			go func(server string, pubkey []byte) {
    92  				defer pend.Done()
    93  
    94  				log.Info("Dialing previously configured server", "server", server)
    95  				client, err := dial(server, pubkey)
    96  				if err != nil {
    97  					log.Error("Previous server unreachable", "server", server, "err", err)
    98  				}
    99  				w.lock.Lock()
   100  				w.servers[server] = client
   101  				w.lock.Unlock()
   102  			}(server, pubkey)
   103  		}
   104  		pend.Wait()
   105  		w.networkStats()
   106  	}
   107  	// Basics done, loop ad infinitum about what to do
   108  	for {
   109  		fmt.Println()
   110  		fmt.Println("What would you like to do? (default = stats)")
   111  		fmt.Println(" 1. Show network stats")
   112  		if w.conf.Genesis == nil {
   113  			fmt.Println(" 2. Configure new genesis")
   114  		} else {
   115  			fmt.Println(" 2. Manage existing genesis")
   116  		}
   117  		if len(w.servers) == 0 {
   118  			fmt.Println(" 3. Track new remote server")
   119  		} else {
   120  			fmt.Println(" 3. Manage tracked machines")
   121  		}
   122  		if len(w.services) == 0 {
   123  			fmt.Println(" 4. Deploy network components")
   124  		} else {
   125  			fmt.Println(" 4. Manage network components")
   126  		}
   127  
   128  		choice := w.read()
   129  		switch {
   130  		case choice == "" || choice == "1":
   131  			w.networkStats()
   132  
   133  		case choice == "2":
   134  			if w.conf.Genesis == nil {
   135  				fmt.Println()
   136  				fmt.Println("What would you like to do? (default = create)")
   137  				fmt.Println(" 1. Create new genesis from scratch")
   138  				fmt.Println(" 2. Import already existing genesis")
   139  
   140  				choice := w.read()
   141  				switch {
   142  				case choice == "" || choice == "1":
   143  					w.makeGenesis()
   144  				case choice == "2":
   145  					w.importGenesis()
   146  				default:
   147  					log.Error("That's not something I can do")
   148  				}
   149  			} else {
   150  				w.manageGenesis()
   151  			}
   152  		case choice == "3":
   153  			if len(w.servers) == 0 {
   154  				if w.makeServer() != "" {
   155  					w.networkStats()
   156  				}
   157  			} else {
   158  				w.manageServers()
   159  			}
   160  		case choice == "4":
   161  			if len(w.services) == 0 {
   162  				w.deployComponent()
   163  			} else {
   164  				w.manageComponents()
   165  			}
   166  		default:
   167  			log.Error("That's not something I can do")
   168  		}
   169  	}
   170  }