github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/cmd/puppeth/module.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:31</date> 10 //</624342603155902464> 11 12 13 package main 14 15 import ( 16 "encoding/json" 17 "errors" 18 "fmt" 19 "net" 20 "strconv" 21 "strings" 22 "time" 23 24 "github.com/ethereum/go-ethereum/log" 25 ) 26 27 var ( 28 //当服务容器不存在时,返回errServiceUnknown。 29 ErrServiceUnknown = errors.New("service unknown") 30 31 //存在服务容器时返回errServiceOffline,但不存在 32 //跑步。 33 ErrServiceOffline = errors.New("service offline") 34 35 //当服务容器正在运行时返回errServiceUnreachable,但是 36 //似乎对沟通尝试没有反应。 37 ErrServiceUnreachable = errors.New("service unreachable") 38 39 //如果Web服务没有公开的端口,则返回errnotexposed,或者 40 //它前面的反向代理来转发请求。 41 ErrNotExposed = errors.New("service not exposed, nor proxied") 42 ) 43 44 //ContainerInfos是大型检验数据集的一个大大简化的版本。 45 //从Docker-Inspect返回,被puppeth解析成易于使用的形式。 46 type containerInfos struct { 47 running bool //标记容器当前是否正在运行 48 envvars map[string]string //容器上设置的环境变量集合 49 portmap map[string]int //从内部端口/协议组合到主机绑定的端口映射 50 volumes map[string]string //从容器到主机目录的卷装入点 51 } 52 53 //InspectContainer运行Docker根据正在运行的容器进行检查 54 func inspectContainer(client *sshClient, container string) (*containerInfos, error) { 55 //检查是否有正在运行服务的容器 56 out, err := client.Run(fmt.Sprintf("docker inspect %s", container)) 57 if err != nil { 58 return nil, ErrServiceUnknown 59 } 60 //如果是,则提取各种配置选项 61 type inspection struct { 62 State struct { 63 Running bool 64 } 65 Mounts []struct { 66 Source string 67 Destination string 68 } 69 Config struct { 70 Env []string 71 } 72 HostConfig struct { 73 PortBindings map[string][]map[string]string 74 } 75 } 76 var inspects []inspection 77 if err = json.Unmarshal(out, &inspects); err != nil { 78 return nil, err 79 } 80 inspect := inspects[0] 81 82 //检索到的信息,将上面的内容解析为有意义的内容 83 infos := &containerInfos{ 84 running: inspect.State.Running, 85 envvars: make(map[string]string), 86 portmap: make(map[string]int), 87 volumes: make(map[string]string), 88 } 89 for _, envvar := range inspect.Config.Env { 90 if parts := strings.Split(envvar, "="); len(parts) == 2 { 91 infos.envvars[parts[0]] = parts[1] 92 } 93 } 94 for portname, details := range inspect.HostConfig.PortBindings { 95 if len(details) > 0 { 96 port, _ := strconv.Atoi(details[0]["HostPort"]) 97 infos.portmap[portname] = port 98 } 99 } 100 for _, mount := range inspect.Mounts { 101 infos.volumes[mount.Destination] = mount.Source 102 } 103 return infos, err 104 } 105 106 //TearDown通过ssh连接到远程计算机并终止Docker容器 107 //在指定网络中以指定名称运行。 108 func tearDown(client *sshClient, network string, service string, purge bool) ([]byte, error) { 109 //拆下正在运行(或暂停)的容器 110 out, err := client.Run(fmt.Sprintf("docker rm -f %s_%s_1", network, service)) 111 if err != nil { 112 return out, err 113 } 114 //如果需要,也清除关联的Docker映像 115 if purge { 116 return client.Run(fmt.Sprintf("docker rmi %s/%s", network, service)) 117 } 118 return nil, nil 119 } 120 121 //resolve通过返回 122 //实际的服务器名称和端口,或者最好是nginx虚拟主机(如果可用)。 123 func resolve(client *sshClient, network string, service string, port int) (string, error) { 124 //检查服务以从中获取各种配置 125 infos, err := inspectContainer(client, fmt.Sprintf("%s_%s_1", network, service)) 126 if err != nil { 127 return "", err 128 } 129 if !infos.running { 130 return "", ErrServiceOffline 131 } 132 //在线容器,提取任何环境变量 133 if vhost := infos.envvars["VIRTUAL_HOST"]; vhost != "" { 134 return vhost, nil 135 } 136 return fmt.Sprintf("%s:%d", client.server, port), nil 137 } 138 139 //checkport尝试连接到给定主机上的远程主机 140 func checkPort(host string, port int) error { 141 log.Trace("Verifying remote TCP connectivity", "server", host, "port", port) 142 conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Second) 143 if err != nil { 144 return err 145 } 146 conn.Close() 147 return nil 148 } 149