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 }