github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/cmd/puppeth/module_ethstats.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of go-wtc. 3 // 4 // go-wtc is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-wtc is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-wtc. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bytes" 21 "fmt" 22 "math/rand" 23 "path/filepath" 24 "strings" 25 "text/template" 26 27 "github.com/wtc/go-wtc/log" 28 ) 29 30 // ethstatsDockerfile is the Dockerfile required to build an ethstats backend 31 // and associated monitoring site. 32 var ethstatsDockerfile = ` 33 FROM mhart/alpine-node:latest 34 35 RUN \ 36 apk add --update git && \ 37 git clone --depth=1 https://github.com/karalabe/eth-netstats && \ 38 apk del git && rm -rf /var/cache/apk/* && \ 39 \ 40 cd /eth-netstats && npm install && npm install -g grunt-cli && grunt 41 42 WORKDIR /eth-netstats 43 EXPOSE 3000 44 45 RUN echo 'module.exports = {trusted: [{{.Trusted}}], banned: [{{.Banned}}], reserved: ["yournode"]};' > lib/utils/config.js 46 47 CMD ["npm", "start"] 48 ` 49 50 // ethstatsComposefile is the docker-compose.yml file required to deploy and 51 // maintain an ethstats monitoring site. 52 var ethstatsComposefile = ` 53 version: '2' 54 services: 55 ethstats: 56 build: . 57 image: {{.Network}}/ethstats{{if not .VHost}} 58 ports: 59 - "{{.Port}}:3000"{{end}} 60 environment: 61 - WS_SECRET={{.Secret}}{{if .VHost}} 62 - VIRTUAL_HOST={{.VHost}}{{end}}{{if .Banned}} 63 - BANNED={{.Banned}}{{end}} 64 logging: 65 driver: "json-file" 66 options: 67 max-size: "1m" 68 max-file: "10" 69 restart: always 70 ` 71 72 // deployEthstats deploys a new ethstats container to a remote machine via SSH, 73 // docker and docker-compose. If an instance with the specified network name 74 // already exists there, it will be overwritten! 75 func deployEthstats(client *sshClient, network string, port int, secret string, vhost string, trusted []string, banned []string) ([]byte, error) { 76 // Generate the content to upload to the server 77 workdir := fmt.Sprintf("%d", rand.Int63()) 78 files := make(map[string][]byte) 79 80 trustedLabels := make([]string, len(trusted)) 81 for i, address := range trusted { 82 trustedLabels[i] = fmt.Sprintf("\"%s\"", address) 83 } 84 bannedLabels := make([]string, len(banned)) 85 for i, address := range banned { 86 bannedLabels[i] = fmt.Sprintf("\"%s\"", address) 87 } 88 89 dockerfile := new(bytes.Buffer) 90 template.Must(template.New("").Parse(ethstatsDockerfile)).Execute(dockerfile, map[string]interface{}{ 91 "Trusted": strings.Join(trustedLabels, ", "), 92 "Banned": strings.Join(bannedLabels, ", "), 93 }) 94 files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() 95 96 composefile := new(bytes.Buffer) 97 template.Must(template.New("").Parse(ethstatsComposefile)).Execute(composefile, map[string]interface{}{ 98 "Network": network, 99 "Port": port, 100 "Secret": secret, 101 "VHost": vhost, 102 "Banned": strings.Join(banned, ","), 103 }) 104 files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() 105 106 // Upload the deployment files to the remote server (and clean up afterwards) 107 if out, err := client.Upload(files); err != nil { 108 return out, err 109 } 110 defer client.Run("rm -rf " + workdir) 111 112 // Build and deploy the ethstats service 113 return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build", workdir, network)) 114 } 115 116 // ethstatsInfos is returned from an ethstats status check to allow reporting 117 // various configuration parameters. 118 type ethstatsInfos struct { 119 host string 120 port int 121 secret string 122 config string 123 banned []string 124 } 125 126 // String implements the stringer interface. 127 func (info *ethstatsInfos) String() string { 128 return fmt.Sprintf("host=%s, port=%d, secret=%s, banned=%v", info.host, info.port, info.secret, info.banned) 129 } 130 131 // checkEthstats does a health-check against an ethstats server to verify whether 132 // it's running, and if yes, gathering a collection of useful infos about it. 133 func checkEthstats(client *sshClient, network string) (*ethstatsInfos, error) { 134 // Inspect a possible ethstats container on the host 135 infos, err := inspectContainer(client, fmt.Sprintf("%s_ethstats_1", network)) 136 if err != nil { 137 return nil, err 138 } 139 if !infos.running { 140 return nil, ErrServiceOffline 141 } 142 // Resolve the port from the host, or the reverse proxy 143 port := infos.portmap["3000/tcp"] 144 if port == 0 { 145 if proxy, _ := checkNginx(client, network); proxy != nil { 146 port = proxy.port 147 } 148 } 149 if port == 0 { 150 return nil, ErrNotExposed 151 } 152 // Resolve the host from the reverse-proxy and configure the connection string 153 host := infos.envvars["VIRTUAL_HOST"] 154 if host == "" { 155 host = client.server 156 } 157 secret := infos.envvars["WS_SECRET"] 158 config := fmt.Sprintf("%s@%s", secret, host) 159 if port != 80 && port != 443 { 160 config += fmt.Sprintf(":%d", port) 161 } 162 // Retrieve the IP blacklist 163 banned := strings.Split(infos.envvars["BANNED"], ",") 164 165 // Run a sanity check to see if the port is reachable 166 if err = checkPort(host, port); err != nil { 167 log.Warn("Ethstats service seems unreachable", "server", host, "port", port, "err", err) 168 } 169 // Container available, assemble and return the useful infos 170 return ðstatsInfos{ 171 host: host, 172 port: port, 173 secret: secret, 174 config: config, 175 banned: banned, 176 }, nil 177 }