-
Notifications
You must be signed in to change notification settings - Fork 19.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cmd/puppeth: your Ethereum private network manager
- Loading branch information
Showing
67 changed files
with
20,893 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// 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" | ||
"errors" | ||
"fmt" | ||
"net" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/ethereum/go-ethereum/log" | ||
) | ||
|
||
var ( | ||
// ErrServiceUnknown is returned when a service container doesn't exist. | ||
ErrServiceUnknown = errors.New("service unknown") | ||
|
||
// ErrServiceOffline is returned when a service container exists, but it is not | ||
// running. | ||
ErrServiceOffline = errors.New("service offline") | ||
|
||
// ErrServiceUnreachable is returned when a service container is running, but | ||
// seems to not respond to communication attempts. | ||
ErrServiceUnreachable = errors.New("service unreachable") | ||
|
||
// ErrNotExposed is returned if a web-service doesn't have an exposed port, nor | ||
// a reverse-proxy in front of it to forward requests. | ||
ErrNotExposed = errors.New("service not exposed, nor proxied") | ||
) | ||
|
||
// containerInfos is a heavily reduced version of the huge inspection dataset | ||
// returned from docker inspect, parsed into a form easily usable by puppeth. | ||
type containerInfos struct { | ||
running bool // Flag whether the container is running currently | ||
envvars map[string]string // Collection of environmental variables set on the container | ||
portmap map[string]int // Port mapping from internal port/proto combos to host binds | ||
volumes map[string]string // Volume mount points from container to host directories | ||
} | ||
|
||
// inspectContainer runs docker inspect against a running container | ||
func inspectContainer(client *sshClient, container string) (*containerInfos, error) { | ||
// Check whether there's a container running for the service | ||
out, err := client.Run(fmt.Sprintf("docker inspect %s", container)) | ||
if err != nil { | ||
return nil, ErrServiceUnknown | ||
} | ||
// If yes, extract various configuration options | ||
type inspection struct { | ||
State struct { | ||
Running bool | ||
} | ||
Mounts []struct { | ||
Source string | ||
Destination string | ||
} | ||
Config struct { | ||
Env []string | ||
} | ||
HostConfig struct { | ||
PortBindings map[string][]map[string]string | ||
} | ||
} | ||
var inspects []inspection | ||
if err = json.Unmarshal(out, &inspects); err != nil { | ||
return nil, err | ||
} | ||
inspect := inspects[0] | ||
|
||
// Infos retrieved, parse the above into something meaningful | ||
infos := &containerInfos{ | ||
running: inspect.State.Running, | ||
envvars: make(map[string]string), | ||
portmap: make(map[string]int), | ||
volumes: make(map[string]string), | ||
} | ||
for _, envvar := range inspect.Config.Env { | ||
if parts := strings.Split(envvar, "="); len(parts) == 2 { | ||
infos.envvars[parts[0]] = parts[1] | ||
} | ||
} | ||
for portname, details := range inspect.HostConfig.PortBindings { | ||
if len(details) > 0 { | ||
port, _ := strconv.Atoi(details[0]["HostPort"]) | ||
infos.portmap[portname] = port | ||
} | ||
} | ||
for _, mount := range inspect.Mounts { | ||
infos.volumes[mount.Destination] = mount.Source | ||
} | ||
return infos, err | ||
} | ||
|
||
// tearDown connects to a remote machine via SSH and terminates docker containers | ||
// running with the specified name in the specified network. | ||
func tearDown(client *sshClient, network string, service string, purge bool) ([]byte, error) { | ||
// Tear down the running (or paused) container | ||
out, err := client.Run(fmt.Sprintf("docker rm -f %s_%s_1", network, service)) | ||
if err != nil { | ||
return out, err | ||
} | ||
// If requested, purge the associated docker image too | ||
if purge { | ||
return client.Run(fmt.Sprintf("docker rmi %s/%s", network, service)) | ||
} | ||
return nil, nil | ||
} | ||
|
||
// resolve retrieves the hostname a service is running on either by returning the | ||
// actual server name and port, or preferably an nginx virtual host if available. | ||
func resolve(client *sshClient, network string, service string, port int) (string, error) { | ||
// Inspect the service to get various configurations from it | ||
infos, err := inspectContainer(client, fmt.Sprintf("%s_%s_1", network, service)) | ||
if err != nil { | ||
return "", err | ||
} | ||
if !infos.running { | ||
return "", ErrServiceOffline | ||
} | ||
// Container online, extract any environmental variables | ||
if vhost := infos.envvars["VIRTUAL_HOST"]; vhost != "" { | ||
return vhost, nil | ||
} | ||
return fmt.Sprintf("%s:%d", client.server, port), nil | ||
} | ||
|
||
// checkPort tries to connect to a remote host on a given | ||
func checkPort(host string, port int) error { | ||
log.Trace("Verifying remote TCP connectivity", "server", host, "port", port) | ||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Second) | ||
if err != nil { | ||
return err | ||
} | ||
conn.Close() | ||
return nil | ||
} |
Oops, something went wrong.