aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/puppeth/wizard_network.go
blob: c0ddcc2a3c91bd1dd0dfe1133f9471ec57149ea7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// 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 (
    "fmt"
    "strings"

    "github.com/ethereum/go-ethereum/log"
)

// manageServers displays a list of servers the user can disconnect from, and an
// option to connect to new servers.
func (w *wizard) manageServers() {
    // List all the servers we can disconnect, along with an entry to connect a new one
    fmt.Println()

    servers := w.conf.servers()
    for i, server := range servers {
        fmt.Printf(" %d. Disconnect %s\n", i+1, server)
    }
    fmt.Printf(" %d. Connect another server\n", len(w.conf.Servers)+1)

    choice := w.readInt()
    if choice < 0 || choice > len(w.conf.Servers)+1 {
        log.Error("Invalid server choice, aborting")
        return
    }
    // If the user selected an existing server, drop it
    if choice <= len(w.conf.Servers) {
        server := servers[choice-1]
        client := w.servers[server]

        delete(w.servers, server)
        if client != nil {
            client.Close()
        }
        delete(w.conf.Servers, server)
        w.conf.flush()

        log.Info("Disconnected existing server", "server", server)
        w.networkStats()
        return
    }
    // If the user requested connecting a new server, do it
    if w.makeServer() != "" {
        w.networkStats()
    }
}

// makeServer reads a single line from stdin and interprets it as
// username:identity@hostname to connect to. It tries to establish a
// new SSH session and also executing some baseline validations.
//
// If connection succeeds, the server is added to the wizards configs!
func (w *wizard) makeServer() string {
    fmt.Println()
    fmt.Println("What is the remote server's address ([username[:identity]@]hostname[:port])?")

    // Read and dial the server to ensure docker is present
    input := w.readString()

    client, err := dial(input, nil)
    if err != nil {
        log.Error("Server not ready for puppeth", "err", err)
        return ""
    }
    // All checks passed, start tracking the server
    w.servers[input] = client
    w.conf.Servers[input] = client.pubkey
    w.conf.flush()

    return input
}

// selectServer lists the user all the currnetly known servers to choose from,
// also granting the option to add a new one.
func (w *wizard) selectServer() string {
    // List the available server to the user and wait for a choice
    fmt.Println()
    fmt.Println("Which server do you want to interact with?")

    servers := w.conf.servers()
    for i, server := range servers {
        fmt.Printf(" %d. %s\n", i+1, server)
    }
    fmt.Printf(" %d. Connect another server\n", len(w.conf.Servers)+1)

    choice := w.readInt()
    if choice < 0 || choice > len(w.conf.Servers)+1 {
        log.Error("Invalid server choice, aborting")
        return ""
    }
    // If the user requested connecting to a new server, go for it
    if choice <= len(w.conf.Servers) {
        return servers[choice-1]
    }
    return w.makeServer()
}

// manageComponents displays a list of network components the user can tear down
// and an option
func (w *wizard) manageComponents() {
    // List all the componens we can tear down, along with an entry to deploy a new one
    fmt.Println()

    var serviceHosts, serviceNames []string
    for server, services := range w.services {
        for _, service := range services {
            serviceHosts = append(serviceHosts, server)
            serviceNames = append(serviceNames, service)

            fmt.Printf(" %d. Tear down %s on %s\n", len(serviceHosts), strings.Title(service), server)
        }
    }
    fmt.Printf(" %d. Deploy new network component\n", len(serviceHosts)+1)

    choice := w.readInt()
    if choice < 0 || choice > len(serviceHosts)+1 {
        log.Error("Invalid component choice, aborting")
        return
    }
    // If the user selected an existing service, destroy it
    if choice <= len(serviceHosts) {
        // Figure out the service to destroy and execute it
        service := serviceNames[choice-1]
        server := serviceHosts[choice-1]
        client := w.servers[server]

        if out, err := tearDown(client, w.network, service, true); err != nil {
            log.Error("Failed to tear down component", "err", err)
            if len(out) > 0 {
                fmt.Printf("%s\n", out)
            }
            return
        }
        // Clean up any references to it from out state
        services := w.services[server]
        for i, name := range services {
            if name == service {
                w.services[server] = append(services[:i], services[i+1:]...)
                if len(w.services[server]) == 0 {
                    delete(w.services, server)
                }
            }
        }
        log.Info("Torn down existing component", "server", server, "service", service)
        return
    }
    // If the user requested deploying a new component, do it
    w.deployComponent()
}

// deployComponent displays a list of network components the user can deploy and
// guides through the process.
func (w *wizard) deployComponent() {
    // Print all the things we can deploy and wait or user choice
    fmt.Println()
    fmt.Println("What would you like to deploy? (recommended order)")
    fmt.Println(" 1. Ethstats  - Network monitoring tool")
    fmt.Println(" 2. Bootnode  - Entry point of the network")
    fmt.Println(" 3. Sealer    - Full node minting new blocks")
    fmt.Println(" 4. Explorer  - Chain analysis webservice (ethash only)")
    fmt.Println(" 5. Wallet    - Browser wallet for quick sends")
    fmt.Println(" 6. Faucet    - Crypto faucet to give away funds")
    fmt.Println(" 7. Dashboard - Website listing above web-services")

    switch w.read() {
    case "1":
        w.deployEthstats()
    case "2":
        w.deployNode(true)
    case "3":
        w.deployNode(false)
    case "4":
        w.deployExplorer()
    case "5":
        w.deployWallet()
    case "6":
        w.deployFaucet()
    case "7":
        w.deployDashboard()
    default:
        log.Error("That's not something I can do")
    }
}