mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
p2p/adapters: Add "exec" node adapter
Signed-off-by: Lewis Marshall <lewis@lmars.net>
This commit is contained in:
parent
4c6648ef49
commit
4807103338
14 changed files with 768 additions and 60 deletions
246
p2p/adapters/exec.go
Normal file
246
p2p/adapters/exec.go
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
package adapters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
// serviceFunc returns a node.ServiceConstructor which can be used to boot
|
||||
// devp2p nodes
|
||||
type serviceFunc func(id *NodeId) node.ServiceConstructor
|
||||
|
||||
// serviceFuncs is a map of registered services which are used to boot devp2p
|
||||
// nodes
|
||||
var serviceFuncs = make(map[string]serviceFunc)
|
||||
|
||||
// RegisterService registers the given serviceFunc which can then be used to
|
||||
// start a devp2p node with the given name
|
||||
func RegisterService(name string, f serviceFunc) {
|
||||
if _, exists := serviceFuncs[name]; exists {
|
||||
panic(fmt.Sprintf("node service already exists: %q", name))
|
||||
}
|
||||
serviceFuncs[name] = f
|
||||
}
|
||||
|
||||
// ExecNode is a NodeAdapter which starts the node by exec'ing the current
|
||||
// binary and running a registered serviceFunc
|
||||
type ExecNode struct {
|
||||
ID *NodeId
|
||||
Service string
|
||||
Dir string
|
||||
Config *node.Config
|
||||
Cmd *exec.Cmd
|
||||
Client *rpc.Client
|
||||
Info *p2p.NodeInfo
|
||||
}
|
||||
|
||||
// NewExecNode creates a new ExecNode which will run the given service using a
|
||||
// sub-directory of the given baseDir
|
||||
func NewExecNode(id *NodeId, service, baseDir string) (*ExecNode, error) {
|
||||
if _, exists := serviceFuncs[service]; !exists {
|
||||
return nil, fmt.Errorf("unknown node service %q", service)
|
||||
}
|
||||
|
||||
// create the node directory using the first 12 characters of the ID
|
||||
dir := filepath.Join(baseDir, id.String()[0:12])
|
||||
if err := os.Mkdir(dir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("error creating node directory: %s", err)
|
||||
}
|
||||
|
||||
// generate the config
|
||||
conf := node.DefaultConfig
|
||||
conf.DataDir = filepath.Join(dir, "data")
|
||||
conf.IPCPath = filepath.Join(dir, "ipc.sock")
|
||||
conf.P2P.ListenAddr = "127.0.0.1:0"
|
||||
conf.P2P.NoDiscovery = true
|
||||
conf.P2P.NAT = nil
|
||||
|
||||
return &ExecNode{
|
||||
ID: id,
|
||||
Service: service,
|
||||
Dir: dir,
|
||||
Config: &conf,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Addr returns the node's enode URL
|
||||
func (n *ExecNode) Addr() []byte {
|
||||
if n.Info == nil {
|
||||
return nil
|
||||
}
|
||||
return []byte(n.Info.Enode)
|
||||
}
|
||||
|
||||
// Start exec's the node passing the ID and service as command line arguments
|
||||
// and the node config encoded as JSON in the _P2P_NODE_CONFIG environment
|
||||
// variable
|
||||
func (n *ExecNode) Start() (err error) {
|
||||
if n.Cmd != nil {
|
||||
return errors.New("already started")
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.Error("node failed to start", "err", err)
|
||||
n.Stop()
|
||||
}
|
||||
}()
|
||||
|
||||
// encode the config
|
||||
conf, err := json.Marshal(n.Config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating node config: %s", err)
|
||||
}
|
||||
|
||||
// start the node
|
||||
cmd := &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: []string{"p2p-node", n.Service, n.ID.String()},
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
Env: append(os.Environ(), fmt.Sprintf("_P2P_NODE_CONFIG=%s", conf)),
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("error starting node: %s", err)
|
||||
}
|
||||
n.Cmd = cmd
|
||||
|
||||
// create the RPC client
|
||||
for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) {
|
||||
n.Client, err = rpc.Dial(n.Config.IPCPath)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if n.Client == nil {
|
||||
return fmt.Errorf("error creating IPC client: %s", err)
|
||||
}
|
||||
|
||||
// load info
|
||||
var info p2p.NodeInfo
|
||||
if err := n.Client.Call(&info, "admin_nodeInfo"); err != nil {
|
||||
return fmt.Errorf("error getting node info: %s", err)
|
||||
}
|
||||
n.Info = &info
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the node by first sending SIGTERM and then SIGKILL if the node
|
||||
// doesn't stop within 5s
|
||||
func (n *ExecNode) Stop() error {
|
||||
if n.Cmd == nil {
|
||||
return nil
|
||||
}
|
||||
defer func() {
|
||||
n.Cmd = nil
|
||||
}()
|
||||
|
||||
if n.Client != nil {
|
||||
n.Client.Close()
|
||||
n.Client = nil
|
||||
n.Info = nil
|
||||
}
|
||||
|
||||
if err := n.Cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||
return n.Cmd.Process.Kill()
|
||||
}
|
||||
waitErr := make(chan error)
|
||||
go func() {
|
||||
waitErr <- n.Cmd.Wait()
|
||||
}()
|
||||
select {
|
||||
case err := <-waitErr:
|
||||
return err
|
||||
case <-time.After(5 * time.Second):
|
||||
return n.Cmd.Process.Kill()
|
||||
}
|
||||
}
|
||||
|
||||
// Connect connects the node to the given addr by calling the Admin.AddPeer
|
||||
// IPC method
|
||||
func (n *ExecNode) Connect(addr []byte) error {
|
||||
if n.Client == nil {
|
||||
return errors.New("node not started")
|
||||
}
|
||||
return n.Client.Call(nil, "admin_addPeer", string(addr))
|
||||
}
|
||||
|
||||
// Disconnect disconnects the node from the given addr by calling the
|
||||
// Admin.RemovePeer IPC method
|
||||
func (n *ExecNode) Disconnect(addr []byte) error {
|
||||
if n.Client == nil {
|
||||
return errors.New("node not started")
|
||||
}
|
||||
return n.Client.Call(nil, "admin_removePeer", string(addr))
|
||||
}
|
||||
|
||||
func init() {
|
||||
// register a reexec function to start a devp2p node when the current
|
||||
// binary is executed as "p2p-node"
|
||||
reexec.Register("p2p-node", execP2PNode)
|
||||
}
|
||||
|
||||
// execP2PNode starts a devp2p node when the current binary is executed with
|
||||
// argv[0] being "p2p-node", reading the service / ID from argv[1] / argv[2]
|
||||
// and the node config from the _P2P_NODE_CONFIG environment variable
|
||||
func execP2PNode() {
|
||||
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.LogfmtFormat()))
|
||||
glogger.Verbosity(log.LvlInfo)
|
||||
log.Root().SetHandler(glogger)
|
||||
|
||||
// read the service and ID from argv
|
||||
serviceName := os.Args[1]
|
||||
id := NewNodeIdFromHex(os.Args[2])
|
||||
|
||||
// decode the config
|
||||
confEnv := os.Getenv("_P2P_NODE_CONFIG")
|
||||
if confEnv == "" {
|
||||
log.Crit("missing _P2P_NODE_CONFIG")
|
||||
}
|
||||
var conf node.Config
|
||||
if err := json.Unmarshal([]byte(confEnv), &conf); err != nil {
|
||||
log.Crit("error decoding _P2P_NODE_CONFIG", "err", err)
|
||||
}
|
||||
|
||||
// lookup the service constructor
|
||||
service, exists := serviceFuncs[serviceName]
|
||||
if !exists {
|
||||
log.Crit(fmt.Sprintf("unknown node service %q", serviceName))
|
||||
}
|
||||
|
||||
// start the devp2p stack
|
||||
stack, err := node.New(&conf)
|
||||
if err != nil {
|
||||
log.Crit("error creating node", "err", err)
|
||||
}
|
||||
if err := stack.Register(service(id)); err != nil {
|
||||
log.Crit("error registering service", "err", err)
|
||||
}
|
||||
if err := stack.Start(); err != nil {
|
||||
log.Crit("error starting node", "err", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
sigc := make(chan os.Signal, 1)
|
||||
signal.Notify(sigc, syscall.SIGTERM)
|
||||
defer signal.Stop(sigc)
|
||||
<-sigc
|
||||
log.Info("Received SIGTERM, shutting down...")
|
||||
stack.Stop()
|
||||
}()
|
||||
|
||||
stack.Wait()
|
||||
}
|
||||
|
|
@ -66,12 +66,16 @@ func NewSimNode(id *NodeId, n Network) *SimNode {
|
|||
}
|
||||
}
|
||||
|
||||
func (self *SimNode) LocalAddr() []byte {
|
||||
func (self *SimNode) Addr() []byte {
|
||||
return self.Id.Bytes()
|
||||
}
|
||||
|
||||
func (self *SimNode) ParseAddr(p []byte, s string) ([]byte, error) {
|
||||
return p, nil
|
||||
func (self *SimNode) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SimNode) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SimNode) GetPeer(id *NodeId) *Peer {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func (self *NodeId) MarshalJSON() (out []byte, err error) {
|
|||
|
||||
func (self *NodeId) UnmarshalJSON(value []byte) error {
|
||||
s := string(value)
|
||||
h, err := discover.HexID(s)
|
||||
h, err := discover.HexID(s[1 : len(s)-1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -64,20 +64,17 @@ func (self *NodeId) Label() string {
|
|||
}
|
||||
|
||||
type NodeAdapter interface {
|
||||
Connect([]byte) error
|
||||
Disconnect([]byte) error
|
||||
// Disconnect(*p2p.Peer, p2p.MsgReadWriter)
|
||||
Addr() []byte
|
||||
Start() error
|
||||
Stop() error
|
||||
Connect(addr []byte) error
|
||||
Disconnect(addr []byte) error
|
||||
}
|
||||
|
||||
type ProtocolRunner interface {
|
||||
RunProtocol(id *NodeId, rw, rrw p2p.MsgReadWriter, p *Peer) error
|
||||
}
|
||||
|
||||
type StartAdapter interface {
|
||||
Start() error
|
||||
Stop() error
|
||||
}
|
||||
|
||||
type Reporter interface {
|
||||
DidConnect(*NodeId, *NodeId) error
|
||||
DidDisconnect(*NodeId, *NodeId) error
|
||||
|
|
|
|||
|
|
@ -424,11 +424,6 @@ func (self *Network) NewNode(conf *NodeConfig) error {
|
|||
func (self *Network) Config() *NetworkConfig {
|
||||
return self.conf
|
||||
}
|
||||
func (self *Network) NewSimNode(conf *NodeConfig) adapters.NodeAdapter {
|
||||
id := conf.Id
|
||||
na := adapters.NewSimNode(id, self)
|
||||
return na
|
||||
}
|
||||
|
||||
// newConn adds a new connection to the network
|
||||
// it errors if the respective nodes do not exist
|
||||
|
|
@ -469,12 +464,8 @@ func (self *Network) Start(id *adapters.NodeId) error {
|
|||
return fmt.Errorf("node %v already up", id)
|
||||
}
|
||||
log.Trace(fmt.Sprintf("starting node %v: %v adapter %v", id, node.Up, node.Adapter()))
|
||||
sa, ok := node.Adapter().(adapters.StartAdapter)
|
||||
if ok {
|
||||
err := sa.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := node.Adapter().Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
node.Up = true
|
||||
log.Info(fmt.Sprintf("started node %v: %v", id, node.Up))
|
||||
|
|
@ -496,12 +487,8 @@ func (self *Network) Stop(id *adapters.NodeId) error {
|
|||
if !node.Up {
|
||||
return fmt.Errorf("node %v already down", id)
|
||||
}
|
||||
sa, ok := node.Adapter().(adapters.StartAdapter)
|
||||
if ok {
|
||||
err := sa.Stop()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := node.Adapter().Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
node.Up = false
|
||||
log.Info(fmt.Sprintf("stop node %v: %v", id, node.Up))
|
||||
|
|
@ -539,9 +526,9 @@ func (self *Network) Connect(oneId, otherId *adapters.NodeId) error {
|
|||
// to this method with connect = false to avoid infinite recursion
|
||||
// this is not relevant for nodes starting up (which can only be externally triggered)
|
||||
if rev {
|
||||
err = conn.other.na.Connect(oneId.Bytes())
|
||||
err = conn.other.na.Connect(conn.one.na.Addr())
|
||||
} else {
|
||||
err = conn.one.na.Connect(otherId.Bytes())
|
||||
err = conn.one.na.Connect(conn.other.na.Addr())
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -679,3 +666,19 @@ func (self *Network) getConn(oneId, otherId *adapters.NodeId) *Conn {
|
|||
}
|
||||
return self.Conns[i]
|
||||
}
|
||||
|
||||
func (self *Network) Shutdown() {
|
||||
// disconnect all nodes
|
||||
for _, conn := range self.Conns {
|
||||
if err := self.Disconnect(conn.One, conn.Other); err != nil {
|
||||
log.Warn(fmt.Sprintf("error disconnecting %s from %s", conn.One.Label(), conn.Other.Label()), "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// stop all nodes
|
||||
for _, node := range self.Nodes {
|
||||
if err := node.na.Stop(); err != nil {
|
||||
log.Warn(fmt.Sprintf("error stopping node %s", node.Id.Label()), "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,85 @@ package discovery_test
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
p2pnode "github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/adapters"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/simulations"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/swarm/network"
|
||||
)
|
||||
|
||||
func TestDiscoverySimulation(t *testing.T) {
|
||||
// serviceName is used with the exec adapter so the exec'd binary knows which
|
||||
// service to execute
|
||||
const serviceName = "discovery"
|
||||
|
||||
func init() {
|
||||
// register the discovery service which will run as a devp2p
|
||||
// protocol when using the exec adapter
|
||||
adapters.RegisterService(serviceName, discoveryService)
|
||||
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
|
||||
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// reexec a service if we have been exec'd by the exec adapter
|
||||
if reexec.Init() {
|
||||
return
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestDiscoverySimulationExecAdapter(t *testing.T) {
|
||||
baseDir, err := ioutil.TempDir("", "swarm-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(baseDir)
|
||||
|
||||
setup := func(net *simulations.Network, trigger chan *adapters.NodeId) {
|
||||
var ids []*adapters.NodeId
|
||||
|
||||
// TODO: get events from the devp2p node
|
||||
time.AfterFunc(5*time.Second, func() {
|
||||
for _, id := range ids {
|
||||
trigger <- id
|
||||
}
|
||||
})
|
||||
|
||||
net.SetNaf(func(conf *simulations.NodeConfig) adapters.NodeAdapter {
|
||||
node, err := adapters.NewExecNode(conf.Id, serviceName, baseDir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ids = append(ids, conf.Id)
|
||||
return node
|
||||
})
|
||||
}
|
||||
|
||||
testDiscoverySimulation(t, setup)
|
||||
}
|
||||
|
||||
func TestDiscoverySimulationSimAdapter(t *testing.T) {
|
||||
setup := func(net *simulations.Network, trigger chan *adapters.NodeId) {
|
||||
net.SetNaf(func(conf *simulations.NodeConfig) adapters.NodeAdapter {
|
||||
return newSimNode(conf.Id, net, trigger)
|
||||
})
|
||||
}
|
||||
|
||||
testDiscoverySimulation(t, setup)
|
||||
}
|
||||
|
||||
func testDiscoverySimulation(t *testing.T, setup func(net *simulations.Network, trigger chan *adapters.NodeId)) {
|
||||
// create 10 node network
|
||||
nodeCount := 10
|
||||
trigger := make(chan *adapters.NodeId)
|
||||
|
|
@ -20,12 +89,8 @@ func TestDiscoverySimulation(t *testing.T) {
|
|||
Id: "0",
|
||||
Backend: true,
|
||||
})
|
||||
nodes := make(map[*adapters.NodeId]*node, nodeCount)
|
||||
net.SetNaf(func(conf *simulations.NodeConfig) adapters.NodeAdapter {
|
||||
node := newNode(conf.Id, net, trigger)
|
||||
nodes[conf.Id] = node
|
||||
return node
|
||||
})
|
||||
defer net.Shutdown()
|
||||
setup(net, trigger)
|
||||
ids := adapters.RandomNodeIds(nodeCount)
|
||||
for _, id := range ids {
|
||||
net.NewNode(&simulations.NodeConfig{Id: id})
|
||||
|
|
@ -57,8 +122,8 @@ func TestDiscoverySimulation(t *testing.T) {
|
|||
default:
|
||||
}
|
||||
|
||||
node, ok := nodes[id]
|
||||
if !ok {
|
||||
node := net.GetNode(id)
|
||||
if node == nil {
|
||||
return false, fmt.Errorf("unknown node: %s", id)
|
||||
}
|
||||
|
||||
|
|
@ -97,25 +162,37 @@ func TestDiscoverySimulation(t *testing.T) {
|
|||
|
||||
type node struct {
|
||||
*network.Hive
|
||||
adapters.NodeAdapter
|
||||
*adapters.SimNode
|
||||
|
||||
id *adapters.NodeId
|
||||
network *simulations.Network
|
||||
trigger chan *adapters.NodeId
|
||||
id *adapters.NodeId
|
||||
trigger chan *adapters.NodeId
|
||||
protocol *p2p.Protocol
|
||||
connectPeer func(string) error
|
||||
}
|
||||
|
||||
func newNode(id *adapters.NodeId, net *simulations.Network, trigger chan *adapters.NodeId) *node {
|
||||
func newSimNode(id *adapters.NodeId, net *simulations.Network, trigger chan *adapters.NodeId) *node {
|
||||
node := newNode(id)
|
||||
|
||||
node.SimNode = adapters.NewSimNode(id, net)
|
||||
node.Run = node.protocol.Run
|
||||
|
||||
node.trigger = trigger
|
||||
|
||||
node.connectPeer = func(s string) error {
|
||||
return node.Connect(adapters.NewNodeIdFromHex(s).Bytes())
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func newNode(id *adapters.NodeId) *node {
|
||||
addr := network.NewPeerAddrFromNodeId(id)
|
||||
kademlia := newKademlia(addr.OverlayAddr())
|
||||
hive := newHive(kademlia)
|
||||
codeMap := network.BzzCodeMap(network.DiscoveryMsgs...)
|
||||
nodeAdapter := adapters.NewSimNode(id, net)
|
||||
node := &node{
|
||||
Hive: hive,
|
||||
NodeAdapter: nodeAdapter,
|
||||
id: id,
|
||||
network: net,
|
||||
trigger: trigger,
|
||||
Hive: hive,
|
||||
id: id,
|
||||
}
|
||||
services := func(peer network.Peer) error {
|
||||
discoveryPeer := network.NewDiscovery(peer, kademlia)
|
||||
|
|
@ -125,7 +202,7 @@ func newNode(id *adapters.NodeId, net *simulations.Network, trigger chan *adapte
|
|||
})
|
||||
return nil
|
||||
}
|
||||
nodeAdapter.Run = network.Bzz(addr.OverlayAddr(), addr.UnderlayAddr(), codeMap, services, nil, nil).Run
|
||||
node.protocol = network.Bzz(addr.OverlayAddr(), addr.UnderlayAddr(), codeMap, services, nil, nil)
|
||||
return node
|
||||
}
|
||||
|
||||
|
|
@ -168,14 +245,6 @@ func (n *node) Remove(peer network.Peer) {
|
|||
n.triggerCheck()
|
||||
}
|
||||
|
||||
func (n *node) RunProtocol(id *adapters.NodeId, rw, rrw p2p.MsgReadWriter, peer *adapters.Peer) error {
|
||||
return n.NodeAdapter.(adapters.ProtocolRunner).RunProtocol(id, rw, rrw, peer)
|
||||
}
|
||||
|
||||
func (n *node) connectPeer(s string) error {
|
||||
return n.network.Connect(n.id, adapters.NewNodeIdFromHex(s))
|
||||
}
|
||||
|
||||
func (n *node) hiveKeepAlive() <-chan time.Time {
|
||||
return time.Tick(time.Second)
|
||||
}
|
||||
|
|
@ -184,3 +253,38 @@ func (n *node) triggerCheck() {
|
|||
// TODO: rate limit the trigger?
|
||||
go func() { n.trigger <- n.id }()
|
||||
}
|
||||
|
||||
func discoveryService(id *adapters.NodeId) p2pnode.ServiceConstructor {
|
||||
return func(ctx *p2pnode.ServiceContext) (p2pnode.Service, error) {
|
||||
node := newNode(id)
|
||||
return &p2pService{node}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type p2pService struct {
|
||||
node *node
|
||||
}
|
||||
|
||||
func (s *p2pService) Protocols() []p2p.Protocol {
|
||||
return []p2p.Protocol{*s.node.protocol}
|
||||
}
|
||||
|
||||
func (s *p2pService) APIs() []rpc.API {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *p2pService) Start(server *p2p.Server) error {
|
||||
s.node.connectPeer = func(url string) error {
|
||||
node, err := discover.ParseNode(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid node URL: %v", err)
|
||||
}
|
||||
server.AddPeer(node)
|
||||
return nil
|
||||
}
|
||||
return s.node.Start()
|
||||
}
|
||||
|
||||
func (s *p2pService) Stop() error {
|
||||
return s.node.Stop()
|
||||
}
|
||||
|
|
|
|||
191
vendor/github.com/docker/docker/LICENSE
generated
vendored
Normal file
191
vendor/github.com/docker/docker/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2013-2017 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
19
vendor/github.com/docker/docker/NOTICE
generated
vendored
Normal file
19
vendor/github.com/docker/docker/NOTICE
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Docker
|
||||
Copyright 2012-2017 Docker, Inc.
|
||||
|
||||
This product includes software developed at Docker, Inc. (https://www.docker.com).
|
||||
|
||||
This product contains software (https://github.com/kr/pty) developed
|
||||
by Keith Rarick, licensed under the MIT License.
|
||||
|
||||
The following is courtesy of our legal counsel:
|
||||
|
||||
|
||||
Use and transfer of Docker may be subject to certain restrictions by the
|
||||
United States and other governments.
|
||||
It is your responsibility to ensure that your use and/or transfer does not
|
||||
violate applicable laws.
|
||||
|
||||
For more information, please see https://www.bis.doc.gov
|
||||
|
||||
See also https://www.apache.org/dev/crypto.html and/or seek legal counsel.
|
||||
5
vendor/github.com/docker/docker/pkg/reexec/README.md
generated
vendored
Normal file
5
vendor/github.com/docker/docker/pkg/reexec/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# reexec
|
||||
|
||||
The `reexec` package facilitates the busybox style reexec of the docker binary that we require because
|
||||
of the forking limitations of using Go. Handlers can be registered with a name and the argv 0 of
|
||||
the exec of the binary will be used to find and execute custom init paths.
|
||||
28
vendor/github.com/docker/docker/pkg/reexec/command_linux.go
generated
vendored
Normal file
28
vendor/github.com/docker/docker/pkg/reexec/command_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// +build linux
|
||||
|
||||
package reexec
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Self returns the path to the current process's binary.
|
||||
// Returns "/proc/self/exe".
|
||||
func Self() string {
|
||||
return "/proc/self/exe"
|
||||
}
|
||||
|
||||
// Command returns *exec.Cmd which has Path as current binary. Also it setting
|
||||
// SysProcAttr.Pdeathsig to SIGTERM.
|
||||
// This will use the in-memory version (/proc/self/exe) of the current binary,
|
||||
// it is thus safe to delete or replace the on-disk binary (os.Args[0]).
|
||||
func Command(args ...string) *exec.Cmd {
|
||||
return &exec.Cmd{
|
||||
Path: Self(),
|
||||
Args: args,
|
||||
SysProcAttr: &syscall.SysProcAttr{
|
||||
Pdeathsig: syscall.SIGTERM,
|
||||
},
|
||||
}
|
||||
}
|
||||
23
vendor/github.com/docker/docker/pkg/reexec/command_unix.go
generated
vendored
Normal file
23
vendor/github.com/docker/docker/pkg/reexec/command_unix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// +build freebsd solaris darwin
|
||||
|
||||
package reexec
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// Self returns the path to the current process's binary.
|
||||
// Uses os.Args[0].
|
||||
func Self() string {
|
||||
return naiveSelf()
|
||||
}
|
||||
|
||||
// Command returns *exec.Cmd which has Path as current binary.
|
||||
// For example if current binary is "docker" at "/usr/bin/", then cmd.Path will
|
||||
// be set to "/usr/bin/docker".
|
||||
func Command(args ...string) *exec.Cmd {
|
||||
return &exec.Cmd{
|
||||
Path: Self(),
|
||||
Args: args,
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go
generated
vendored
Normal file
12
vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// +build !linux,!windows,!freebsd,!solaris,!darwin
|
||||
|
||||
package reexec
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// Command is unsupported on operating systems apart from Linux, Windows, Solaris and Darwin.
|
||||
func Command(args ...string) *exec.Cmd {
|
||||
return nil
|
||||
}
|
||||
23
vendor/github.com/docker/docker/pkg/reexec/command_windows.go
generated
vendored
Normal file
23
vendor/github.com/docker/docker/pkg/reexec/command_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// +build windows
|
||||
|
||||
package reexec
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// Self returns the path to the current process's binary.
|
||||
// Uses os.Args[0].
|
||||
func Self() string {
|
||||
return naiveSelf()
|
||||
}
|
||||
|
||||
// Command returns *exec.Cmd which has Path as current binary.
|
||||
// For example if current binary is "docker.exe" at "C:\", then cmd.Path will
|
||||
// be set to "C:\docker.exe".
|
||||
func Command(args ...string) *exec.Cmd {
|
||||
return &exec.Cmd{
|
||||
Path: Self(),
|
||||
Args: args,
|
||||
}
|
||||
}
|
||||
47
vendor/github.com/docker/docker/pkg/reexec/reexec.go
generated
vendored
Normal file
47
vendor/github.com/docker/docker/pkg/reexec/reexec.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package reexec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var registeredInitializers = make(map[string]func())
|
||||
|
||||
// Register adds an initialization func under the specified name
|
||||
func Register(name string, initializer func()) {
|
||||
if _, exists := registeredInitializers[name]; exists {
|
||||
panic(fmt.Sprintf("reexec func already registered under name %q", name))
|
||||
}
|
||||
|
||||
registeredInitializers[name] = initializer
|
||||
}
|
||||
|
||||
// Init is called as the first part of the exec process and returns true if an
|
||||
// initialization function was called.
|
||||
func Init() bool {
|
||||
initializer, exists := registeredInitializers[os.Args[0]]
|
||||
if exists {
|
||||
initializer()
|
||||
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func naiveSelf() string {
|
||||
name := os.Args[0]
|
||||
if filepath.Base(name) == name {
|
||||
if lp, err := exec.LookPath(name); err == nil {
|
||||
return lp
|
||||
}
|
||||
}
|
||||
// handle conversion of relative paths to absolute
|
||||
if absName, err := filepath.Abs(name); err == nil {
|
||||
return absName
|
||||
}
|
||||
// if we couldn't get absolute name, return original
|
||||
// (NOTE: Go only errors on Abs() if os.Getwd fails)
|
||||
return name
|
||||
}
|
||||
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
|
|
@ -74,6 +74,12 @@
|
|||
"revision": "2268707a8f0843315e2004ee4f1d021dc08baedf",
|
||||
"revisionTime": "2017-02-01T22:58:49Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "lutCa+IVM60R1OYBm9RtDAW50Ys=",
|
||||
"path": "github.com/docker/docker/pkg/reexec",
|
||||
"revision": "83ee902ecc3790c33c1e2d87334074436056bb49",
|
||||
"revisionTime": "2017-04-22T21:51:12Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "zYnPsNAVm1/ViwCkN++dX2JQhBo=",
|
||||
"path": "github.com/edsrzf/mmap-go",
|
||||
|
|
|
|||
Loading…
Reference in a new issue