diff --git a/p2p/adapters/exec.go b/p2p/adapters/exec.go new file mode 100644 index 000000000000..398a1c99e8c6 --- /dev/null +++ b/p2p/adapters/exec.go @@ -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() +} diff --git a/p2p/adapters/inproc.go b/p2p/adapters/inproc.go index 60efac3b48ee..221b1b232873 100644 --- a/p2p/adapters/inproc.go +++ b/p2p/adapters/inproc.go @@ -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 { diff --git a/p2p/adapters/types.go b/p2p/adapters/types.go index f85b8523e5a6..361821752825 100644 --- a/p2p/adapters/types.go +++ b/p2p/adapters/types.go @@ -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 diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go index 3a33fcb6e9e5..52002d08423c 100644 --- a/p2p/simulations/network.go +++ b/p2p/simulations/network.go @@ -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) + } + } +} diff --git a/swarm/network/simulations/discovery/discovery_test.go b/swarm/network/simulations/discovery/discovery_test.go index 3e93e9093b54..72871d2c3555 100644 --- a/swarm/network/simulations/discovery/discovery_test.go +++ b/swarm/network/simulations/discovery/discovery_test.go @@ -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() +} diff --git a/vendor/github.com/docker/docker/LICENSE b/vendor/github.com/docker/docker/LICENSE new file mode 100644 index 000000000000..9c8e20ab85c1 --- /dev/null +++ b/vendor/github.com/docker/docker/LICENSE @@ -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. diff --git a/vendor/github.com/docker/docker/NOTICE b/vendor/github.com/docker/docker/NOTICE new file mode 100644 index 000000000000..0c74e15b057f --- /dev/null +++ b/vendor/github.com/docker/docker/NOTICE @@ -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. diff --git a/vendor/github.com/docker/docker/pkg/reexec/README.md b/vendor/github.com/docker/docker/pkg/reexec/README.md new file mode 100644 index 000000000000..6658f69b69d7 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/reexec/README.md @@ -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. diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_linux.go b/vendor/github.com/docker/docker/pkg/reexec/command_linux.go new file mode 100644 index 000000000000..34ae2a9dcdab --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/reexec/command_linux.go @@ -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, + }, + } +} diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_unix.go b/vendor/github.com/docker/docker/pkg/reexec/command_unix.go new file mode 100644 index 000000000000..778a720e3b91 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/reexec/command_unix.go @@ -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, + } +} diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go b/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go new file mode 100644 index 000000000000..76edd824273e --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go @@ -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 +} diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_windows.go b/vendor/github.com/docker/docker/pkg/reexec/command_windows.go new file mode 100644 index 000000000000..ca871c4227ed --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/reexec/command_windows.go @@ -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, + } +} diff --git a/vendor/github.com/docker/docker/pkg/reexec/reexec.go b/vendor/github.com/docker/docker/pkg/reexec/reexec.go new file mode 100644 index 000000000000..c56671d91927 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/reexec/reexec.go @@ -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 +} diff --git a/vendor/vendor.json b/vendor/vendor.json index d79c80a67ac3..68823d1052a7 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -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",