From d0ca14bb599d9a292189f76449a5accea570cf6e Mon Sep 17 00:00:00 2001 From: Yves Blusseau <90z7oey02@sneakemail.com> Date: Wed, 24 Feb 2016 13:43:32 +0100 Subject: [PATCH 001/799] Fix bad order of iptables filter rules Rules with ctstate RELATED,ESTABLISHED must be create before same rules without ctstate. Signed-off-by: Yves Blusseau <90z7oey02@sneakemail.com> --- drivers/bridge/setup_ip_tables.go | 6 ------ drivers/bridge/setup_ip_tables_test.go | 2 +- iptables/iptables.go | 20 ++++++++++++++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/bridge/setup_ip_tables.go b/drivers/bridge/setup_ip_tables.go index 78ab10f053..810fe26d2e 100644 --- a/drivers/bridge/setup_ip_tables.go +++ b/drivers/bridge/setup_ip_tables.go @@ -136,7 +136,6 @@ func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, hairp hpNatRule = iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "MASQUERADE"}} skipDNAT = iptRule{table: iptables.Nat, chain: DockerChain, preArgs: []string{"-t", "nat"}, args: []string{"-i", bridgeIface, "-j", "RETURN"}} outRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}} - inRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}} ) // Set NAT. @@ -169,11 +168,6 @@ func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, hairp return err } - // Set Accept on incoming packets for existing connections. - if err := programChainRule(inRule, "ACCEPT INCOMING", enable); err != nil { - return err - } - return nil } diff --git a/drivers/bridge/setup_ip_tables_test.go b/drivers/bridge/setup_ip_tables_test.go index 983f225f36..50c97622e8 100644 --- a/drivers/bridge/setup_ip_tables_test.go +++ b/drivers/bridge/setup_ip_tables_test.go @@ -25,8 +25,8 @@ func TestProgramIPTable(t *testing.T) { }{ {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-d", "127.1.2.3", "-i", "lo", "-o", "lo", "-j", "DROP"}}, "Test Loopback"}, {iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", iptablesTestBridgeIP, "!", "-o", DefaultBridgeName, "-j", "MASQUERADE"}}, "NAT Test"}, - {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test ACCEPT NON_ICC OUTGOING"}, {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", DefaultBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}, "Test ACCEPT INCOMING"}, + {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test ACCEPT NON_ICC OUTGOING"}, {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test enable ICC"}, {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "DROP"}}, "Test disable ICC"}, } diff --git a/iptables/iptables.go b/iptables/iptables.go index f6ddaed775..1d00c4b9c9 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -181,6 +181,26 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err } } + establish := []string{ + "-o", bridgeName, + "-m", "conntrack", + "--ctstate", "RELATED,ESTABLISHED", + "-j", "ACCEPT"} + if !Exists(Filter, "FORWARD", establish...) && enable { + insert := append([]string{string(Insert), "FORWARD"}, establish...) + if output, err := Raw(insert...); err != nil { + return err + } else if len(output) != 0 { + return fmt.Errorf("Could not create establish rule to %s: %s", c.Table, output) + } + } else if Exists(Filter, "FORWARD", establish...) && !enable { + del := append([]string{string(Delete), "FORWARD"}, establish...) + if output, err := Raw(del...); err != nil { + return err + } else if len(output) != 0 { + return fmt.Errorf("Could not delete establish rule from %s: %s", c.Table, output) + } + } } return nil } From 8eae2f31b9dcb13c87dc023ceeb62eea4c19edc4 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 25 May 2016 15:02:44 -0700 Subject: [PATCH 002/799] Separate pool parsing from pool auto-allocation - In default ipam driver. Also improve error message in case no good pool is found Signed-off-by: Alessandro Boch --- ipam/allocator.go | 49 +++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/ipam/allocator.go b/ipam/allocator.go index c059d447d7..c259a05283 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -199,12 +199,22 @@ func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) { // RequestPool returns an address pool along with its unique id. func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6) -retry: - k, nw, ipr, pdf, err := a.parsePoolRequest(addressSpace, pool, subPool, v6) + + k, nw, ipr, err := a.parsePoolRequest(addressSpace, pool, subPool, v6) if err != nil { return "", nil, nil, types.InternalErrorf("failed to parse pool request for address space %q pool %q subpool %q: %v", addressSpace, pool, subPool, err) } + pdf := k == nil + +retry: + if pdf { + if nw, err = a.getPredefinedPool(addressSpace, v6); err != nil { + return "", nil, nil, err + } + k = &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String()} + } + if err := a.refresh(addressSpace); err != nil { return "", nil, nil, err } @@ -279,39 +289,36 @@ func (a *Allocator) getAddrSpace(as string) (*addrSpace, error) { return aSpace, nil } -func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *AddressRange, bool, error) { +func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *AddressRange, error) { var ( nw *net.IPNet ipr *AddressRange err error - pdf = false ) if addressSpace == "" { - return nil, nil, nil, false, ipamapi.ErrInvalidAddressSpace + return nil, nil, nil, ipamapi.ErrInvalidAddressSpace } if pool == "" && subPool != "" { - return nil, nil, nil, false, ipamapi.ErrInvalidSubPool + return nil, nil, nil, ipamapi.ErrInvalidSubPool } - if pool != "" { - if _, nw, err = net.ParseCIDR(pool); err != nil { - return nil, nil, nil, false, ipamapi.ErrInvalidPool - } - if subPool != "" { - if ipr, err = getAddressRange(subPool, nw); err != nil { - return nil, nil, nil, false, err - } - } - } else { - if nw, err = a.getPredefinedPool(addressSpace, v6); err != nil { - return nil, nil, nil, false, err + if pool == "" { + return nil, nil, nil, nil + } + + if _, nw, err = net.ParseCIDR(pool); err != nil { + return nil, nil, nil, ipamapi.ErrInvalidPool + } + + if subPool != "" { + if ipr, err = getAddressRange(subPool, nw); err != nil { + return nil, nil, nil, err } - pdf = true } - return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, ipr, pdf, nil + return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, ipr, nil } func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error { @@ -406,7 +413,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) } } - return nil, types.NotFoundErrorf("could not find an available predefined network") + return nil, types.NotFoundErrorf("could not find an available non-overlapping address pool among the defaults to auto assign to the network") } // RequestAddress returns an address from the specified pool ID From 8acef98c5fac86f62e216eda69ae44a4c7a90ba9 Mon Sep 17 00:00:00 2001 From: allencloud Date: Thu, 2 Jun 2016 13:37:39 +0800 Subject: [PATCH 003/799] use grep to find a/an misuse Signed-off-by: allencloud --- api/api_test.go | 2 +- client/network.go | 2 +- cmd/dnet/dnet.go | 2 +- datastore/datastore.go | 8 ++++---- docs/ipam.md | 2 +- driverapi/driverapi.go | 2 +- drivers/ipvlan/ipvlan_setup.go | 2 +- drivers/ipvlan/ipvlan_setup_test.go | 8 ++++---- drivers/macvlan/macvlan_setup_test.go | 8 ++++---- drivers/remote/driver_test.go | 2 +- hostdiscovery/hostdiscovery_test.go | 4 ++-- ipamapi/contract.go | 2 +- ipams/remote/remote_test.go | 2 +- ipamutils/utils.go | 4 ++-- ipvs/ipvs.go | 2 +- libnetwork_test.go | 8 ++++---- netutils/utils.go | 2 +- network.go | 4 ++-- options/options.go | 2 +- service_linux.go | 4 ++-- types/types.go | 2 +- 21 files changed, 37 insertions(+), 37 deletions(-) diff --git a/api/api_test.go b/api/api_test.go index e78e7c108e..c944cc0ff7 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -2304,7 +2304,7 @@ func (nip *notimpl) NotImplemented() {} type inter struct{} func (it *inter) Error() string { - return "I am a internal error" + return "I am an internal error" } func (it *inter) Internal() {} diff --git a/client/network.go b/client/network.go index b8437b2984..1edc43086e 100644 --- a/client/network.go +++ b/client/network.go @@ -207,7 +207,7 @@ func (cli *NetworkCli) CmdNetworkInfo(chain string, args ...string) error { } // Helper function to predict if a string is a name or id or partial-id -// This provides a best-effort mechanism to identify a id with the help of GET Filter APIs +// This provides a best-effort mechanism to identify an id with the help of GET Filter APIs // Being a UI, its most likely that name will be used by the user, which is used to lookup // the corresponding ID. If ID is not found, this function will assume that the passed string // is an ID by itself. diff --git a/cmd/dnet/dnet.go b/cmd/dnet/dnet.go index 885691f009..2ee5722a0d 100644 --- a/cmd/dnet/dnet.go +++ b/cmd/dnet/dnet.go @@ -287,7 +287,7 @@ func startTestDriver() error { mux := http.NewServeMux() server := httptest.NewServer(mux) if server == nil { - return fmt.Errorf("Failed to start a HTTP Server") + return fmt.Errorf("Failed to start an HTTP Server") } mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { diff --git a/datastore/datastore.go b/datastore/datastore.go index 49affc7883..149510dd5a 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -62,13 +62,13 @@ type datastore struct { sync.Mutex } -// KVObject is Key/Value interface used by objects to be part of the DataStore +// KVObject is Key/Value interface used by objects to be part of the DataStore type KVObject interface { - // Key method lets an object to provide the Key to be used in KV Store + // Key method lets an object provide the Key to be used in KV Store Key() []string - // KeyPrefix method lets an object to return immediate parent key that can be used for tree walk + // KeyPrefix method lets an object return immediate parent key that can be used for tree walk KeyPrefix() []string - // Value method lets an object to marshal its content to be stored in the KV store + // Value method lets an object marshal its content to be stored in the KV store Value() []byte // SetValue is used by the datastore to set the object's value when loaded from the data store. SetValue([]byte) error diff --git a/docs/ipam.md b/docs/ipam.md index 84e5b9bf79..cf3918cca9 100644 --- a/docs/ipam.md +++ b/docs/ipam.md @@ -116,7 +116,7 @@ During registration, the remote driver will receive a POST message to the URL `/ ### RequestPool -This API is for registering a address pool with the IPAM driver. Multiple identical calls must return the same result. +This API is for registering an address pool with the IPAM driver. Multiple identical calls must return the same result. It is the IPAM driver's responsibility to keep a reference count for the pool. ```go diff --git a/driverapi/driverapi.go b/driverapi/driverapi.go index f555246ceb..ccb7936e2a 100644 --- a/driverapi/driverapi.go +++ b/driverapi/driverapi.go @@ -115,7 +115,7 @@ type InterfaceNameInfo interface { // JoinInfo represents a set of resources that the driver has the ability to provide during // join time. type JoinInfo interface { - // InterfaceName returns a InterfaceNameInfo go interface to facilitate + // InterfaceName returns an InterfaceNameInfo go interface to facilitate // setting the names for the interface. InterfaceName() InterfaceNameInfo diff --git a/drivers/ipvlan/ipvlan_setup.go b/drivers/ipvlan/ipvlan_setup.go index 60d3d965ca..4269378b4a 100644 --- a/drivers/ipvlan/ipvlan_setup.go +++ b/drivers/ipvlan/ipvlan_setup.go @@ -31,7 +31,7 @@ func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) { if err != nil { return "", fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", ipvlanType, parent, err) } - // Create a ipvlan link + // Create an ipvlan link ipvlan := &netlink.IPVlan{ LinkAttrs: netlink.LinkAttrs{ Name: containerIfName, diff --git a/drivers/ipvlan/ipvlan_setup_test.go b/drivers/ipvlan/ipvlan_setup_test.go index 098a6ecd73..15f9a155c7 100644 --- a/drivers/ipvlan/ipvlan_setup_test.go +++ b/drivers/ipvlan/ipvlan_setup_test.go @@ -15,7 +15,7 @@ func TestValidateLink(t *testing.T) { if ok := parentExists(validIface); !ok { t.Fatalf("failed validating loopback %s", validIface) } - // test a invalid parent interface validation + // test an invalid parent interface validation if ok := parentExists(invalidIface); ok { t.Fatalf("failed to invalidate interface %s", invalidIface) } @@ -33,17 +33,17 @@ func TestValidateSubLink(t *testing.T) { if err != nil { t.Fatalf("failed subinterface validation: %v", err) } - // test a invalid vid with a valid parent link + // test an invalid vid with a valid parent link _, _, err = parseVlan(invalidSubIface1) if err == nil { t.Fatalf("failed subinterface validation test: %s", invalidSubIface1) } - // test a valid vid with a valid parent link with a invalid delimiter + // test a valid vid with a valid parent link with an invalid delimiter _, _, err = parseVlan(invalidSubIface2) if err == nil { t.Fatalf("failed subinterface validation test: %v", invalidSubIface2) } - // test a invalid parent link with a valid vid + // test an invalid parent link with a valid vid _, _, err = parseVlan(invalidSubIface3) if err == nil { t.Fatalf("failed subinterface validation test: %v", invalidSubIface3) diff --git a/drivers/macvlan/macvlan_setup_test.go b/drivers/macvlan/macvlan_setup_test.go index 49a8780c88..796b01d376 100644 --- a/drivers/macvlan/macvlan_setup_test.go +++ b/drivers/macvlan/macvlan_setup_test.go @@ -15,7 +15,7 @@ func TestValidateLink(t *testing.T) { if ok := parentExists(validIface); !ok { t.Fatalf("failed validating loopback %s", validIface) } - // test a invalid parent interface validation + // test an invalid parent interface validation if ok := parentExists(invalidIface); ok { t.Fatalf("failed to invalidate interface %s", invalidIface) } @@ -33,17 +33,17 @@ func TestValidateSubLink(t *testing.T) { if err != nil { t.Fatalf("failed subinterface validation: %v", err) } - // test a invalid vid with a valid parent link + // test an invalid vid with a valid parent link _, _, err = parseVlan(invalidSubIface1) if err == nil { t.Fatalf("failed subinterface validation test: %s", invalidSubIface1) } - // test a valid vid with a valid parent link with a invalid delimiter + // test a valid vid with a valid parent link with an invalid delimiter _, _, err = parseVlan(invalidSubIface2) if err == nil { t.Fatalf("failed subinterface validation test: %v", invalidSubIface2) } - // test a invalid parent link with a valid vid + // test an invalid parent link with a valid vid _, _, err = parseVlan(invalidSubIface3) if err == nil { t.Fatalf("failed subinterface validation test: %v", invalidSubIface3) diff --git a/drivers/remote/driver_test.go b/drivers/remote/driver_test.go index 8d055732a4..efc82e439f 100644 --- a/drivers/remote/driver_test.go +++ b/drivers/remote/driver_test.go @@ -46,7 +46,7 @@ func setupPlugin(t *testing.T, name string, mux *http.ServeMux) func() { server := httptest.NewServer(mux) if server == nil { - t.Fatal("Failed to start a HTTP Server") + t.Fatal("Failed to start an HTTP Server") } if err := ioutil.WriteFile(fmt.Sprintf("/etc/docker/plugins/%s.spec", name), []byte(server.URL), 0644); err != nil { diff --git a/hostdiscovery/hostdiscovery_test.go b/hostdiscovery/hostdiscovery_test.go index 79fad02ae7..417e27d9a1 100644 --- a/hostdiscovery/hostdiscovery_test.go +++ b/hostdiscovery/hostdiscovery_test.go @@ -30,7 +30,7 @@ func TestDiff(t *testing.T) { updated = mapset.NewSetFromSlice([]interface{}{addedIP}) added, removed = diff(existing, updated) if len(removed) != 2 { - t.Fatalf("Diff failed for an remove update. Expecting 2 element, but got %d elements", len(removed)) + t.Fatalf("Diff failed for a remove update. Expecting 2 element, but got %d elements", len(removed)) } if len(added) != 1 { t.Fatalf("Diff failed for add use-case. Expecting 1 element, but got %d elements", len(added)) @@ -46,7 +46,7 @@ func TestAddedCallback(t *testing.T) { removed := false hd.processCallback(update, func() {}, func(hosts []net.IP) { added = true }, func(hosts []net.IP) { removed = true }) if !added { - t.Fatalf("Expecting a Added callback notification. But none received") + t.Fatalf("Expecting an Added callback notification. But none received") } } diff --git a/ipamapi/contract.go b/ipamapi/contract.go index 513e482349..3e42f0f8cd 100644 --- a/ipamapi/contract.go +++ b/ipamapi/contract.go @@ -27,7 +27,7 @@ const ( type Callback interface { // RegisterIpamDriver provides a way for Remote drivers to dynamically register with libnetwork RegisterIpamDriver(name string, driver Ipam) error - // RegisterIpamDriverWithCapabilities provides a way for Remote drivers to dynamically register with libnetwork and specify cpaabilities + // RegisterIpamDriverWithCapabilities provides a way for Remote drivers to dynamically register with libnetwork and specify capabilities RegisterIpamDriverWithCapabilities(name string, driver Ipam, capability *Capability) error } diff --git a/ipams/remote/remote_test.go b/ipams/remote/remote_test.go index 3c6cc4bfa9..4017ad63c7 100644 --- a/ipams/remote/remote_test.go +++ b/ipams/remote/remote_test.go @@ -42,7 +42,7 @@ func setupPlugin(t *testing.T, name string, mux *http.ServeMux) func() { server := httptest.NewServer(mux) if server == nil { - t.Fatal("Failed to start a HTTP Server") + t.Fatal("Failed to start an HTTP Server") } if err := ioutil.WriteFile(fmt.Sprintf("/etc/docker/plugins/%s.spec", name), []byte(server.URL), 0644); err != nil { diff --git a/ipamutils/utils.go b/ipamutils/utils.go index 798a3afa3e..bca4e9e519 100644 --- a/ipamutils/utils.go +++ b/ipamutils/utils.go @@ -1,4 +1,4 @@ -// Package ipamutils provides utililty functions for ipam management +// Package ipamutils provides utility functions for ipam management package ipamutils import ( @@ -17,7 +17,7 @@ var ( initNetworksOnce sync.Once ) -// InitNetworks initializes the pre-defined networks used by the built-in IP allocator +// InitNetworks initializes the pre-defined networks used by the built-in IP allocator func InitNetworks() { initNetworksOnce.Do(func() { PredefinedBroadNetworks = initBroadPredefinedNetworks() diff --git a/ipvs/ipvs.go b/ipvs/ipvs.go index 8f0a0ab89a..dd0169cdc7 100644 --- a/ipvs/ipvs.go +++ b/ipvs/ipvs.go @@ -94,7 +94,7 @@ func (i *Handle) DelService(s *Service) error { return i.doCmd(s, nil, ipvsCmdDelService) } -// NewDestination creates an new real server in the passed ipvs +// NewDestination creates a new real server in the passed ipvs // service which should already be existing in the passed handle. func (i *Handle) NewDestination(s *Service, d *Destination) error { return i.doCmd(s, d, ipvsCmdNewDest) diff --git a/libnetwork_test.go b/libnetwork_test.go index b63ff0f801..d17d796648 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -1115,7 +1115,7 @@ func TestEndpointJoin(t *testing.T) { } if info.Sandbox() == nil { - t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key") + t.Fatalf("Expected a non-empty sandbox key for a joined endpoint. Instead found an empty sandbox key") } // Check endpoint provided container information @@ -1314,7 +1314,7 @@ func externalKeyTest(t *testing.T, reexec bool) { t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created") } } else { - // Setting an non-existing key (namespace) must fail + // Setting a non-existing key (namespace) must fail if err := sbox.SetKey("this-must-fail"); err == nil { t.Fatalf("Setkey must fail if the corresponding namespace is not created") } @@ -2018,7 +2018,7 @@ func TestInvalidRemoteDriver(t *testing.T) { mux := http.NewServeMux() server := httptest.NewServer(mux) if server == nil { - t.Fatal("Failed to start a HTTP Server") + t.Fatal("Failed to start an HTTP Server") } defer server.Close() @@ -2069,7 +2069,7 @@ func TestValidRemoteDriver(t *testing.T) { mux := http.NewServeMux() server := httptest.NewServer(mux) if server == nil { - t.Fatal("Failed to start a HTTP Server") + t.Fatal("Failed to start an HTTP Server") } defer server.Close() diff --git a/netutils/utils.go b/netutils/utils.go index 62287efcc9..65449d3dee 100644 --- a/netutils/utils.go +++ b/netutils/utils.go @@ -170,7 +170,7 @@ func ReverseIP(IP string) string { return strings.Join(reverseIP, ".") } -// ParseAlias parses and validates the specified string as a alias format (name:alias) +// ParseAlias parses and validates the specified string as an alias format (name:alias) func ParseAlias(val string) (string, string, error) { if val == "" { return "", "", fmt.Errorf("empty string specified for alias") diff --git a/network.go b/network.go index 7cad9f0dc7..ea26ad88e8 100644 --- a/network.go +++ b/network.go @@ -1141,7 +1141,7 @@ func (n *network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, preferredPo } // If the network belongs to global scope or the pool was - // explicitely chosen or it is invalid, do not perform the overlap check. + // explicitly chosen or it is invalid, do not perform the overlap check. if n.Scope() == datastore.GlobalScope || preferredPool != "" || !types.IsIPNetValid(pool) { return poolID, pool, meta, nil } @@ -1165,7 +1165,7 @@ func (n *network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, preferredPo }() // If this is a preferred pool request and the network - // is local scope and there is a overlap, we fail the + // is local scope and there is an overlap, we fail the // network creation right here. The pool will be // released in the defer. if preferredPool != "" { diff --git a/options/options.go b/options/options.go index 8512ce83f3..06d8ae5902 100644 --- a/options/options.go +++ b/options/options.go @@ -41,7 +41,7 @@ func (e TypeMismatchError) Error() string { return fmt.Sprintf("type mismatch, field %s require type %v, actual type %v", e.Field, e.ExpectType, e.ActualType) } -// Generic is an basic type to store arbitrary settings. +// Generic is a basic type to store arbitrary settings. type Generic map[string]interface{} // NewGeneric returns a new Generic instance. diff --git a/service_linux.go b/service_linux.go index be163d268d..8b55eafdf5 100644 --- a/service_linux.go +++ b/service_linux.go @@ -225,7 +225,7 @@ func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, rmService bool) { func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, addService bool) { i, err := ipvs.New(sb.Key()) if err != nil { - logrus.Errorf("Failed to create a ipvs handle for sbox %s: %v", sb.Key(), err) + logrus.Errorf("Failed to create an ipvs handle for sbox %s: %v", sb.Key(), err) return } defer i.Close() @@ -267,7 +267,7 @@ func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, addService bool) func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, rmService bool) { i, err := ipvs.New(sb.Key()) if err != nil { - logrus.Errorf("Failed to create a ipvs handle for sbox %s: %v", sb.Key(), err) + logrus.Errorf("Failed to create an ipvs handle for sbox %s: %v", sb.Key(), err) return } defer i.Close() diff --git a/types/types.go b/types/types.go index c249d4b5bb..eedc3e4a1d 100644 --- a/types/types.go +++ b/types/types.go @@ -226,7 +226,7 @@ const ( UDP = 17 ) -// Protocol represents a IP protocol number +// Protocol represents an IP protocol number type Protocol uint8 func (p Protocol) String() string { From 21c5a6281bc824a8b1eea9f8d7adc3c9e35ae0c8 Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 22 Jun 2016 14:20:30 +0800 Subject: [PATCH 004/799] fix typos Signed-off-by: bin liu --- drivers/macvlan/macvlan_state.go | 2 +- hostdiscovery/hostdiscovery_api.go | 2 +- ipams/remote/api/api.go | 2 +- netutils/utils_linux.go | 4 ++-- osl/interface_linux.go | 2 +- sandbox_dns_unix.go | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/macvlan/macvlan_state.go b/drivers/macvlan/macvlan_state.go index dd2a60ce4b..8ac3d282f9 100644 --- a/drivers/macvlan/macvlan_state.go +++ b/drivers/macvlan/macvlan_state.go @@ -31,7 +31,7 @@ func (d *driver) deleteNetwork(nid string) { d.Unlock() } -// getNetworks Safely returns a slice of existng networks +// getNetworks Safely returns a slice of existing networks func (d *driver) getNetworks() []*network { d.Lock() defer d.Unlock() diff --git a/hostdiscovery/hostdiscovery_api.go b/hostdiscovery/hostdiscovery_api.go index b9c17250ce..f0ca40e31f 100644 --- a/hostdiscovery/hostdiscovery_api.go +++ b/hostdiscovery/hostdiscovery_api.go @@ -15,7 +15,7 @@ type LeaveCallback func(entries []net.IP) type HostDiscovery interface { //Watch Node join and leave cluster events Watch(activeCallback ActiveCallback, joinCallback JoinCallback, leaveCallback LeaveCallback) error - // StopDiscovery stops the discovery perocess + // StopDiscovery stops the discovery process StopDiscovery() error // Fetch returns a list of host IPs that are currently discovered Fetch() []net.IP diff --git a/ipams/remote/api/api.go b/ipams/remote/api/api.go index 394f2c5b18..23f3eda7d1 100644 --- a/ipams/remote/api/api.go +++ b/ipams/remote/api/api.go @@ -26,7 +26,7 @@ type GetCapabilityResponse struct { RequiresRequestReplay bool } -// ToCapability converts the capability response into the internal ipam driver capaility structure +// ToCapability converts the capability response into the internal ipam driver capability structure func (capRes GetCapabilityResponse) ToCapability() *ipamapi.Capability { return &ipamapi.Capability{ RequiresMACAddress: capRes.RequiresMACAddress, diff --git a/netutils/utils_linux.go b/netutils/utils_linux.go index 7781bc6a09..4a03a3a15a 100644 --- a/netutils/utils_linux.go +++ b/netutils/utils_linux.go @@ -63,7 +63,7 @@ func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, err // ElectInterfaceAddresses looks for an interface on the OS with the // specified name and returns its IPv4 and IPv6 addresses in CIDR -// form. If the interface does not exist, it chooses from a predifined +// form. If the interface does not exist, it chooses from a predefined // list the first IPv4 address which does not conflict with other // interfaces on the system. func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { @@ -94,7 +94,7 @@ func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { } if link == nil || v4Net == nil { - // Choose from predifined broad networks + // Choose from predefined broad networks v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) if err != nil { return nil, nil, err diff --git a/osl/interface_linux.go b/osl/interface_linux.go index 63fcf5561d..c8477df7c8 100644 --- a/osl/interface_linux.go +++ b/osl/interface_linux.go @@ -131,7 +131,7 @@ func (i *nwIface) Remove() error { nlh := n.nlHandle n.Unlock() - // Find the network inteerface identified by the DstName attribute. + // Find the network interface identified by the DstName attribute. iface, err := nlh.LinkByName(i.DstName()) if err != nil { return err diff --git a/sandbox_dns_unix.go b/sandbox_dns_unix.go index 735708563f..a385f3d4c9 100644 --- a/sandbox_dns_unix.go +++ b/sandbox_dns_unix.go @@ -282,7 +282,7 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error { } // Embedded DNS server has to be enabled for this sandbox. Rebuild the container's -// resolv.conf by doing the follwing +// resolv.conf by doing the following // - Save the external name servers in resolv.conf in the sandbox // - Add only the embedded server's IP to container's resolv.conf // - If the embedded server needs any resolv.conf options add it to the current list From cfd285917075cb3d2653856716b306a875d254d9 Mon Sep 17 00:00:00 2001 From: Lee Calcote Date: Fri, 1 Jul 2016 11:00:56 -0500 Subject: [PATCH 005/799] docs/ipam.md: spelling error Changed "lifecyle" to "lifecycle". Signed-off-by: Lee Calcote --- docs/ipam.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ipam.md b/docs/ipam.md index 2fa06d0b19..aa2175506e 100644 --- a/docs/ipam.md +++ b/docs/ipam.md @@ -1,6 +1,6 @@ # IPAM Driver -During the Network and Endpoints lifecyle, the CNM model controls the IP address assignment for network and endpoint interfaces via the IPAM driver(s). +During the Network and Endpoints lifecycle, the CNM model controls the IP address assignment for network and endpoint interfaces via the IPAM driver(s). Libnetwork has a default, built-in IPAM driver and allows third party IPAM drivers to be dynamically plugged. On network creation, the user can specify which IPAM driver libnetwork needs to use for the network's IP address management. This document explains the APIs with which the IPAM driver needs to comply, and the corresponding HTTPS request/response body relevant for remote drivers. From 492c949929ec49b8b5a34e5d60e1e859857a3dfc Mon Sep 17 00:00:00 2001 From: Erich Cordoba Date: Thu, 21 Jul 2016 23:37:54 -0500 Subject: [PATCH 006/799] Remove commented code from libnetwork_test.go Signed-off-by: Erich Cordoba --- libnetwork_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/libnetwork_test.go b/libnetwork_test.go index 134391fbb6..f14d2cb1e9 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -52,8 +52,6 @@ func TestMain(m *testing.M) { os.Exit(1) } - //libnetwork.SetTestDataStore(controller, datastore.NewCustomDataStore(datastore.NewMockStore())) - x := m.Run() controller.Stop() os.Exit(x) From 8c72dab7167dc934e9dd57d773331fb15fa6a27d Mon Sep 17 00:00:00 2001 From: Jordi Massaguer Pla Date: Tue, 31 May 2016 17:12:13 +0200 Subject: [PATCH 007/799] add s390x arch build info at the netlink_deprecated_linux bridge driver Signed-off-by: Jordi Massaguer Pla --- drivers/bridge/netlink_deprecated_linux_notarm.go | 2 +- drivers/bridge/netlink_deprecated_linux_s390x.go | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 drivers/bridge/netlink_deprecated_linux_s390x.go diff --git a/drivers/bridge/netlink_deprecated_linux_notarm.go b/drivers/bridge/netlink_deprecated_linux_notarm.go index df526952f7..0852d0f165 100644 --- a/drivers/bridge/netlink_deprecated_linux_notarm.go +++ b/drivers/bridge/netlink_deprecated_linux_notarm.go @@ -1,4 +1,4 @@ -// +build !arm,!ppc64,!ppc64le +// +build !arm,!ppc64,!ppc64le,!s390x package bridge diff --git a/drivers/bridge/netlink_deprecated_linux_s390x.go b/drivers/bridge/netlink_deprecated_linux_s390x.go new file mode 100644 index 0000000000..2d9abdc2ce --- /dev/null +++ b/drivers/bridge/netlink_deprecated_linux_s390x.go @@ -0,0 +1,7 @@ +// +build s390x + +package bridge + +func ifrDataByte(b byte) uint8 { + return uint8(b) +} From 1473ea56da7d094a4c53d78499844c23142601d8 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 25 Jul 2016 12:02:30 -0700 Subject: [PATCH 008/799] Check for advertise IP when deriving ipsec nodes - We need to compare the node notification IP with the advertise address otherwise when the advertise address is different from the local address (this is for the public address outside of the host that maps 1-to-1 to the local private address) the local IP will be acocunted as an ipsec host and extra states will be programmed for it. Signed-off-by: Alessandro Boch --- drivers/overlay/encryption.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/overlay/encryption.go b/drivers/overlay/encryption.go index 6a97149af0..6c8573bbf4 100644 --- a/drivers/overlay/encryption.go +++ b/drivers/overlay/encryption.go @@ -95,7 +95,7 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal switch { case isLocal: if err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool { - if !lIP.Equal(pEntry.vtep) { + if !aIP.Equal(pEntry.vtep) { nodes[pEntry.vtep.String()] = pEntry.vtep } return false From 822b7c232141931b8067185a376b6a600ea8db40 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 25 Jul 2016 16:23:53 -0700 Subject: [PATCH 009/799] Fix bug in ipsec key rotation - which would leave a stale state behind at each key rotation. Signed-off-by: Alessandro Boch --- drivers/overlay/encryption.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/overlay/encryption.go b/drivers/overlay/encryption.go index 6a97149af0..1dbd63b677 100644 --- a/drivers/overlay/encryption.go +++ b/drivers/overlay/encryption.go @@ -488,7 +488,7 @@ func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, if delIdx != -1 { // -rSA0 - programSA(rIP, lIP, spis[delIdx], nil, reverse, false) + programSA(lIP, rIP, spis[delIdx], nil, reverse, false) } if newIdx > -1 { From cc5d7eaba56d4c85a2f285d4060eb9e7bb65c142 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 26 Jul 2016 04:31:54 -0700 Subject: [PATCH 010/799] Do not create network entry in networkdb for the local node based on table event from peer Signed-off-by: Santhosh Manohar --- networkdb/delegate.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/networkdb/delegate.go b/networkdb/delegate.go index 216027905f..ebdea42533 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -25,6 +25,10 @@ func (nDB *NetworkDB) handleNetworkEvent(nEvent *NetworkEvent) bool { nDB.Lock() defer nDB.Unlock() + if nEvent.NodeName == nDB.config.NodeName { + return false + } + nodeNetworks, ok := nDB.networks[nEvent.NodeName] if !ok { // We haven't heard about this node at all. Ignore the leave From aa0d3903c6fe5df99b517ce7b061f0f86cf293b6 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Wed, 27 Jul 2016 00:55:46 -0700 Subject: [PATCH 011/799] Better error handling in restoring sandbox states Signed-off-by: Madhu Venugopal --- sandbox.go | 6 ++++++ sandbox_store.go | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/sandbox.go b/sandbox.go index a4a8933e28..a0667b46aa 100644 --- a/sandbox.go +++ b/sandbox.go @@ -726,6 +726,12 @@ func (sb *sandbox) restoreOslSandbox() error { joinInfo := ep.joinInfo i := ep.iface ep.Unlock() + + if i == nil { + log.Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID()) + continue + } + ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes)) if i.addrv6 != nil && i.addrv6.IP.To16() != nil { ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6)) diff --git a/sandbox_store.go b/sandbox_store.go index 5b963e71c3..58a939c3ea 100644 --- a/sandbox_store.go +++ b/sandbox_store.go @@ -245,6 +245,10 @@ func (c *controller) sandboxCleanup(activeSandboxes map[string]interface{}) { ep = &endpoint{id: eps.Eid, network: n, sandboxID: sbs.ID} } } + if _, ok := activeSandboxes[sb.ID()]; ok && err != nil { + logrus.Errorf("failed to restore endpoint %s in %s for container %s due to %v", eps.Eid, eps.Nid, sb.ContainerID(), err) + continue + } heap.Push(&sb.endpoints, ep) } From 5e7bf83ab07c197d1bef6ec073d9f19ce59e3eb2 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 28 Jul 2016 11:33:21 -0700 Subject: [PATCH 012/799] Check for isAgent() outside the network lock to avoid deadlocks Signed-off-by: Madhu Venugopal --- network.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/network.go b/network.go index 71cbced580..8d620644e6 100644 --- a/network.go +++ b/network.go @@ -702,12 +702,13 @@ func (n *network) driver(load bool) (driverapi.Driver, error) { } c := n.getController() + isAgent := c.isAgent() n.Lock() // If load is not required, driver, cap and err may all be nil if cap != nil { n.scope = cap.DataScope } - if c.isAgent() || n.dynamic { + if isAgent || n.dynamic { // If we are running in agent mode then all networks // in libnetwork are local scope regardless of the // backing driver. From 618f80aa35a11bc31b376ec0a1589f4aadf55fb6 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 29 Jul 2016 10:45:48 +0200 Subject: [PATCH 013/799] Fix crash when remote plugin returns empty address string If a remote plugin returns an empty string in response to RequestAddress(), the internal helper will return nil which will crash libnetwork in several places. Treat an empty string as a new error ipamapi.ErrNoIPReturned. Signed-off-by: Thomas Graf --- ipamapi/contract.go | 1 + ipams/remote/remote.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ipamapi/contract.go b/ipamapi/contract.go index e7845f28e7..3563d70c08 100644 --- a/ipamapi/contract.go +++ b/ipamapi/contract.go @@ -46,6 +46,7 @@ var ( ErrOverlapPool = types.ForbiddenErrorf("Address pool overlaps with existing pool on this address space") ErrNoAvailablePool = types.NoServiceErrorf("No available pool") ErrNoAvailableIPs = types.NoServiceErrorf("No available addresses on this pool") + ErrNoIPReturned = types.NoServiceErrorf("No address returned") ErrIPAlreadyAllocated = types.ForbiddenErrorf("Address already in use") ErrIPOutOfRange = types.BadRequestErrorf("Requested address is out of range") ErrPoolOverlap = types.ForbiddenErrorf("Pool overlaps with other one on this address space") diff --git a/ipams/remote/remote.go b/ipams/remote/remote.go index 799a2e77f4..4ad3287e66 100644 --- a/ipams/remote/remote.go +++ b/ipams/remote/remote.go @@ -111,6 +111,8 @@ func (a *allocator) RequestAddress(poolID string, address net.IP, options map[st } if res.Address != "" { retAddress, err = types.ParseCIDR(res.Address) + } else { + return nil, nil, ipamapi.ErrNoIPReturned } return retAddress, res.Data, err } From 594d18b8022fc07b974e8be6e6b0b3a51071a1b4 Mon Sep 17 00:00:00 2001 From: allencloud Date: Sat, 30 Jul 2016 02:21:10 +0800 Subject: [PATCH 014/799] fix typo in comments and log Signed-off-by: allencloud --- controller.go | 2 +- default_gateway.go | 4 ++-- drivers/bridge/bridge.go | 2 +- network.go | 2 +- service_linux.go | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/controller.go b/controller.go index e79d010614..912f7da941 100644 --- a/controller.go +++ b/controller.go @@ -97,7 +97,7 @@ type NetworkController interface { // Sandboxes returns the list of Sandbox(s) managed by this controller. Sandboxes() []Sandbox - // WlakSandboxes uses the provided function to walk the Sandbox(s) managed by this controller. + // WalkSandboxes uses the provided function to walk the Sandbox(s) managed by this controller. WalkSandboxes(walker SandboxWalker) // SandboxByID returns the Sandbox which has the passed id. If not found, a types.NotFoundError is returned. diff --git a/default_gateway.go b/default_gateway.go index 31cf86d1d4..2f2e284ff1 100644 --- a/default_gateway.go +++ b/default_gateway.go @@ -14,7 +14,7 @@ const ( var procGwNetwork = make(chan (bool), 1) /* - libnetwork creates a bridge network "docker_gw_bridge" for provding + libnetwork creates a bridge network "docker_gw_bridge" for providing default gateway for the containers if none of the container's endpoints have GW set by the driver. ICC is set to false for the GW_bridge network. @@ -29,7 +29,7 @@ var procGwNetwork = make(chan (bool), 1) func (sb *sandbox) setupDefaultGW() error { - // check if the conitainer already has a GW endpoint + // check if the container already has a GW endpoint if ep := sb.getEndpointInGWNetwork(); ep != nil { return nil } diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index d2b1d24829..8410eb037a 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -564,7 +564,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d } d.Unlock() - // Parse and validate the config. It should not conflict with existing networks' config + // Parse and validate the config. It should not be conflict with existing networks' config config, err := parseNetworkOptions(id, option) if err != nil { return err diff --git a/network.go b/network.go index 71cbced580..80641de0a0 100644 --- a/network.go +++ b/network.go @@ -1206,7 +1206,7 @@ func (n *network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, preferredPo }() // If this is a preferred pool request and the network - // is local scope and there is a overlap, we fail the + // is local scope and there is an overlap, we fail the // network creation right here. The pool will be // released in the defer. if preferredPool != "" { diff --git a/service_linux.go b/service_linux.go index fc8e4fcbe6..d2fbc2b069 100644 --- a/service_linux.go +++ b/service_linux.go @@ -316,7 +316,7 @@ func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*P i, err := ipvs.New(sb.Key()) if err != nil { - logrus.Errorf("Failed to create a ipvs handle for sbox %s: %v", sb.Key(), err) + logrus.Errorf("Failed to create an ipvs handle for sbox %s: %v", sb.Key(), err) return } defer i.Close() @@ -371,7 +371,7 @@ func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po i, err := ipvs.New(sb.Key()) if err != nil { - logrus.Errorf("Failed to create a ipvs handle for sbox %s: %v", sb.Key(), err) + logrus.Errorf("Failed to create an ipvs handle for sbox %s: %v", sb.Key(), err) return } defer i.Close() From e8fbb2fdb4a020540b5018a4804d3298c9b59957 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 31 Jul 2016 00:28:21 +0200 Subject: [PATCH 015/799] portmapper: touch iptables only for IPv4 split out of https://github.com/docker/docker/pull/20315 in order to fix https://github.com/docker/docker/issues/11518 Signed-off-by: Michael Stapelberg --- portmapper/mapper.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/portmapper/mapper.go b/portmapper/mapper.go index 0bf7630557..6a1bb08ffb 100644 --- a/portmapper/mapper.go +++ b/portmapper/mapper.go @@ -134,16 +134,20 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart, } containerIP, containerPort := getIPAndPort(m.container) - if err := pm.forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { - return nil, err + if hostIP.To4() != nil { + if err := pm.forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { + return nil, err + } } cleanup := func() error { // need to undo the iptables rules before we return m.userlandProxy.Stop() - pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) - if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil { - return err + if hostIP.To4() != nil { + pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) + if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil { + return err + } } return nil From 57d620393d27d04dafd947bc7e933c1c476fdc1f Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 1 Aug 2016 08:06:13 -0700 Subject: [PATCH 016/799] Allow reattempt of overlay network sbox join - if failure happened during restore endpoint phase Signed-off-by: Alessandro Boch --- drivers/overlay/overlay.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index 5b52a15c63..59877dd1ac 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -90,7 +90,20 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { } } - d.restoreEndpoints() + if err := d.restoreEndpoints(); err != nil { + logrus.Warnf("Failure during overlay endpoints restore: %v", err) + } + + // If an error happened when the network join the sandbox during the endpoints restore + // we should reset it now along with the once variable, so that subsequent endpoint joins + // outside of the restore path can potentially fix the network join and succeed. + for nid, n := range d.networks { + if n.initErr != nil { + logrus.Infof("resetting init error and once variable for network %s after unsuccesful endpoint restore: %v", nid, n.initErr) + n.initErr = nil + n.once = &sync.Once{} + } + } return dc.RegisterDriver(networkType, d, c) } From 344aa2f668998495fd992a7135678c684d6079ad Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Tue, 2 Aug 2016 14:06:41 -0700 Subject: [PATCH 017/799] Ensure drivertable entries in joininfo is uptodate The CopyTo function for joininfo is not copying the driver table entries which then is missing when the endpoint is re-read for the store cache. Signed-off-by: Jana Radhakrishnan --- endpoint_info.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/endpoint_info.go b/endpoint_info.go index 60f15518e7..1042ddaa8f 100644 --- a/endpoint_info.go +++ b/endpoint_info.go @@ -463,6 +463,8 @@ func (epj *endpointJoinInfo) CopyTo(dstEpj *endpointJoinInfo) error { dstEpj.disableGatewayService = epj.disableGatewayService dstEpj.StaticRoutes = make([]*types.StaticRoute, len(epj.StaticRoutes)) copy(dstEpj.StaticRoutes, epj.StaticRoutes) + dstEpj.driverTableEntries = make([]*tableEntry, len(epj.driverTableEntries)) + copy(dstEpj.driverTableEntries, epj.driverTableEntries) dstEpj.gw = types.GetIPCopy(epj.gw) dstEpj.gw = types.GetIPCopy(epj.gw6) return nil From c191ea7a14f33a50d6715388898a92bc243ead26 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Tue, 2 Aug 2016 14:19:22 -0700 Subject: [PATCH 018/799] Make sure to not remove backends on stale notices Sometimes you may get stale backend removal notices from gossip due to some lingering state. If a stale backend notice is received and it is already processed in this node ignore it rather than processing it. Signed-off-by: Jana Radhakrishnan --- service_linux.go | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/service_linux.go b/service_linux.go index d2fbc2b069..7c5fb6fc88 100644 --- a/service_linux.go +++ b/service_linux.go @@ -139,21 +139,6 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in } c.Unlock() - // Delete the special "tasks.svc_name" backend record. - n.(*network).deleteSvcRecords("tasks."+name, ip, nil, false) - for _, alias := range aliases { - n.(*network).deleteSvcRecords("tasks."+alias, ip, nil, false) - } - - // If we are doing DNS RR add the endpoint IP to DNS record - // right away. - if len(vip) == 0 { - n.(*network).deleteSvcRecords(name, ip, nil, false) - for _, alias := range aliases { - n.(*network).deleteSvcRecords(alias, ip, nil, false) - } - } - s.Lock() lb, ok := s.loadBalancers[nid] if !ok { @@ -161,6 +146,12 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in return nil } + _, ok = lb.backEnds[eid] + if !ok { + s.Unlock() + return nil + } + delete(lb.backEnds, eid) if len(lb.backEnds) == 0 { // All the backends for this service have been @@ -184,6 +175,21 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in } s.Unlock() + // Delete the special "tasks.svc_name" backend record. + n.(*network).deleteSvcRecords("tasks."+name, ip, nil, false) + for _, alias := range aliases { + n.(*network).deleteSvcRecords("tasks."+alias, ip, nil, false) + } + + // If we are doing DNS RR add the endpoint IP to DNS record + // right away. + if len(vip) == 0 { + n.(*network).deleteSvcRecords(name, ip, nil, false) + for _, alias := range aliases { + n.(*network).deleteSvcRecords(alias, ip, nil, false) + } + } + // Remove the DNS record for VIP only if we are removing the service if rmService && len(vip) != 0 { n.(*network).deleteSvcRecords(name, vip, nil, false) From 92337b412ef09e7a71cb2af64459da849d7c122b Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Tue, 2 Aug 2016 18:34:10 -0700 Subject: [PATCH 019/799] Check size of keys slice If not enough keys are provided to SetKeys, this may cause a panic. This should not cause problems with the current integration in Docker 1.12.0, but the panic might happen loading data created by an earlier version, or data that is corrupted somehow. Add a length check to be defensive. Signed-off-by: Aaron Lehmann --- agent.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/agent.go b/agent.go index 0e498cf84f..33041cc9ea 100644 --- a/agent.go +++ b/agent.go @@ -136,10 +136,16 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { } } - key, tag := c.getPrimaryKeyTag(subsysGossip) + key, tag, err := c.getPrimaryKeyTag(subsysGossip) + if err != nil { + return err + } a.networkDB.SetPrimaryKey(key) - key, tag = c.getPrimaryKeyTag(subsysIPSec) + key, tag, err = c.getPrimaryKeyTag(subsysIPSec) + if err != nil { + return err + } drvEnc.Primary = key drvEnc.PrimaryTag = tag @@ -289,9 +295,9 @@ func (c *controller) getKeys(subsys string) ([][]byte, []uint64) { return keys, tags } -// getPrimaryKeyTag returns the primary key for a given subsytem from the +// getPrimaryKeyTag returns the primary key for a given subsystem from the // list of sorted key and the associated tag -func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64) { +func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64, error) { sort.Sort(ByTime(c.keys)) keys := []*types.EncryptionKey{} for _, key := range c.keys { @@ -299,7 +305,10 @@ func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64) { keys = append(keys, key) } } - return keys[1].Key, keys[1].LamportTime + if len(keys) < 2 { + return nil, 0, fmt.Errorf("primary key for subsystem %s not found", subsys) + } + return keys[1].Key, keys[1].LamportTime, nil } func (c *controller) agentInit(bindAddrOrInterface, advertiseAddr string) error { From 07ce2718854e3d44db6660d449ab83a6b7252bae Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 2 Aug 2016 20:10:54 -0700 Subject: [PATCH 020/799] Godep update for gogo/protobuf components Signed-off-by: Santhosh Manohar --- Godeps/Godeps.json | 13 +- .../src/github.com/gogo/protobuf/LICENSE | 6 +- .../gogo/protobuf/gogoproto/Makefile | 6 +- .../github.com/gogo/protobuf/gogoproto/doc.go | 6 +- .../gogo/protobuf/gogoproto/gogo.pb.go | 6 +- .../gogo/protobuf/gogoproto/gogo.proto | 6 +- .../gogo/protobuf/gogoproto/helper.go | 4 +- .../github.com/gogo/protobuf/proto/clone.go | 14 +- .../github.com/gogo/protobuf/proto/decode.go | 34 +- .../gogo/protobuf/proto/decode_gogo.go | 6 +- .../github.com/gogo/protobuf/proto/encode.go | 60 ++- .../gogo/protobuf/proto/encode_gogo.go | 6 +- .../github.com/gogo/protobuf/proto/equal.go | 26 +- .../gogo/protobuf/proto/extensions.go | 409 +++++++++++++----- .../gogo/protobuf/proto/extensions_gogo.go | 88 +++- .../src/github.com/gogo/protobuf/proto/lib.go | 4 + .../gogo/protobuf/proto/lib_gogo.go | 6 +- .../gogo/protobuf/proto/message_set.go | 43 +- .../gogo/protobuf/proto/pointer_reflect.go | 7 +- .../gogo/protobuf/proto/pointer_unsafe.go | 6 +- .../protobuf/proto/pointer_unsafe_gogo.go | 6 +- .../gogo/protobuf/proto/properties.go | 53 ++- .../gogo/protobuf/proto/properties_gogo.go | 6 +- .../gogo/protobuf/proto/skip_gogo.go | 6 +- .../github.com/gogo/protobuf/proto/text.go | 82 ++-- .../gogo/protobuf/proto/text_gogo.go | 6 +- .../gogo/protobuf/proto/text_parser.go | 75 ++-- .../descriptor/descriptor.pb.go | 90 ++-- .../protoc-gen-gogo/descriptor/gostring.go | 35 +- .../protoc-gen-gogo/descriptor/helper.go | 4 +- 30 files changed, 743 insertions(+), 376 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 800e235921..892b3a2a26 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,7 @@ { "ImportPath": "github.com/docker/libnetwork", "GoVersion": "go1.5", + "GodepVersion": "v74", "Packages": [ "./..." ], @@ -241,18 +242,18 @@ }, { "ImportPath": "github.com/gogo/protobuf/gogoproto", - "Comment": "v0.2-17-gc18eea6", - "Rev": "c18eea6ad611eecf94a9ba38471f59706199409e" + "Comment": "v0.2-55-ge33835a", + "Rev": "e33835a643a970c11ac74f6333f5f6866387a101" }, { "ImportPath": "github.com/gogo/protobuf/proto", - "Comment": "v0.2-17-gc18eea6", - "Rev": "c18eea6ad611eecf94a9ba38471f59706199409e" + "Comment": "v0.2-55-ge33835a", + "Rev": "e33835a643a970c11ac74f6333f5f6866387a101" }, { "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/descriptor", - "Comment": "v0.2-17-gc18eea6", - "Rev": "c18eea6ad611eecf94a9ba38471f59706199409e" + "Comment": "v0.2-55-ge33835a", + "Rev": "e33835a643a970c11ac74f6333f5f6866387a101" }, { "ImportPath": "github.com/golang/protobuf/proto", diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/LICENSE b/Godeps/_workspace/src/github.com/gogo/protobuf/LICENSE index 335e38e19b..7be0cc7b62 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/LICENSE +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/LICENSE @@ -1,7 +1,7 @@ -Extensions for Protocol Buffers to create more go like structures. +Protocol Buffers for Go with Gadgets -Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -http://github.com/gogo/protobuf/gogoproto +Copyright (c) 2013, The GoGo Authors. All rights reserved. +http://github.com/gogo/protobuf Go support for Protocol Buffers - Google's data interchange format diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/Makefile b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/Makefile index 557f294933..395592a5da 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/Makefile +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/Makefile @@ -1,7 +1,7 @@ -# Extensions for Protocol Buffers to create more go like structures. +# Protocol Buffers for Go with Gadgets # -# Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -# http://github.com/gogo/protobuf/gogoproto +# Copyright (c) 2013, The GoGo Authors. All rights reserved. +# http://github.com/gogo/protobuf # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/doc.go b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/doc.go index f0424d4f8a..5ecfae1135 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/doc.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/doc.go @@ -1,7 +1,7 @@ -// Extensions for Protocol Buffers to create more go like structures. +// Protocol Buffers for Go with Gadgets // -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.pb.go b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.pb.go index f97c2338e7..ff355b9be4 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.pb.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.pb.go @@ -24,7 +24,9 @@ var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. -const _ = proto.GoGoProtoPackageIsVersion1 +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package var E_GoprotoEnumPrefix = &proto.ExtensionDesc{ ExtendedType: (*google_protobuf.EnumOptions)(nil), @@ -587,6 +589,8 @@ func init() { proto.RegisterExtension(E_Castvalue) } +func init() { proto.RegisterFile("gogo.proto", fileDescriptorGogo) } + var fileDescriptorGogo = []byte{ // 1096 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x97, 0xcb, 0x6f, 0xdc, 0x54, diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.proto b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.proto index e8e3edb61f..18a58c5d4c 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.proto +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.proto @@ -1,5 +1,7 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/helper.go b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/helper.go index 8c29dbc0e1..670021fedd 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/helper.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/helper.go @@ -1,4 +1,6 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. // http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/clone.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/clone.go index 79edb86119..5d4cba4b51 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/clone.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/clone.go @@ -84,14 +84,20 @@ func mergeStruct(out, in reflect.Value) { mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) } - if emIn, ok := in.Addr().Interface().(extensionsMap); ok { - emOut := out.Addr().Interface().(extensionsMap) - mergeExtension(emOut.ExtensionMap(), emIn.ExtensionMap()) - } else if emIn, ok := in.Addr().Interface().(extensionsBytes); ok { + if emIn, ok := in.Addr().Interface().(extensionsBytes); ok { emOut := out.Addr().Interface().(extensionsBytes) bIn := emIn.GetExtensions() bOut := emOut.GetExtensions() *bOut = append(*bOut, *bIn...) + } else if emIn, ok := extendable(in.Addr().Interface()); ok { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } } uf := in.FieldByName("XXX_unrecognized") diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode.go index cb5b213f9b..0d6634cc08 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode.go @@ -378,6 +378,11 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group wire := int(u & 0x7) if wire == WireEndGroup { if is_group { + if required > 0 { + // Not enough information to determine the exact field. + // (See below.) + return &RequiredNotSetError{"{Unknown}"} + } return nil // input is satisfied } return fmt.Errorf("proto: %s: wiretype end group for non-group", st) @@ -390,16 +395,20 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group if !ok { // Maybe it's an extension? if prop.extendable { - if e := structPointer_Interface(base, st).(extendableProto); isExtensionField(e, int32(tag)) { - if err = o.skip(st, tag, wire); err == nil { - if ee, eok := e.(extensionsMap); eok { - ext := ee.ExtensionMap()[int32(tag)] // may be missing - ext.enc = append(ext.enc, o.buf[oi:o.index]...) - ee.ExtensionMap()[int32(tag)] = ext - } else if ee, eok := e.(extensionsBytes); eok { - ext := ee.GetExtensions() + if e, eok := structPointer_Interface(base, st).(extensionsBytes); eok { + if isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + ext := e.GetExtensions() *ext = append(*ext, o.buf[oi:o.index]...) } + continue + } + } else if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + extmap := e.extensionsWrite() + ext := extmap[int32(tag)] // may be missing + ext.enc = append(ext.enc, o.buf[oi:o.index]...) + extmap[int32(tag)] = ext } continue } @@ -773,10 +782,11 @@ func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { } } keyelem, valelem := keyptr.Elem(), valptr.Elem() - if !keyelem.IsValid() || !valelem.IsValid() { - // We did not decode the key or the value in the map entry. - // Either way, it's an invalid map entry. - return fmt.Errorf("proto: bad map data: missing key/val") + if !keyelem.IsValid() { + keyelem = reflect.Zero(p.mtype.Key()) + } + if !valelem.IsValid() { + valelem = reflect.Zero(p.mtype.Elem()) } v.SetMapIndex(keyelem, valelem) diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode_gogo.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode_gogo.go index 603dabec3f..ecc63873e4 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode_gogo.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode_gogo.go @@ -1,5 +1,7 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode.go index 231b07401a..8c1b8fd1f6 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode.go @@ -64,8 +64,16 @@ var ( // a struct with a repeated field containing a nil element. errRepeatedHasNil = errors.New("proto: repeated field has nil element") + // errOneofHasNil is the error returned if Marshal is called with + // a struct with a oneof field containing a nil element. + errOneofHasNil = errors.New("proto: oneof field has nil value") + // ErrNil is the error returned if Marshal is called with nil. ErrNil = errors.New("proto: Marshal called with nil") + + // ErrTooLarge is the error returned if Marshal is called with a + // message that encodes to >2GB. + ErrTooLarge = errors.New("proto: message encodes to over 2 GB") ) // The fundamental encoders that put bytes on the wire. @@ -74,6 +82,10 @@ var ( const maxVarintBytes = 10 // maximum length of a varint +// maxMarshalSize is the largest allowed size of an encoded protobuf, +// since C++ and Java use signed int32s for the size. +const maxMarshalSize = 1<<31 - 1 + // EncodeVarint returns the varint encoding of x. // This is the format for the // int32, int64, uint32, uint64, bool, and enum @@ -273,6 +285,9 @@ func (p *Buffer) Marshal(pb Message) error { stats.Encode++ } + if len(p.buf) > maxMarshalSize { + return ErrTooLarge + } return err } @@ -1058,10 +1073,25 @@ func size_slice_struct_group(p *Properties, base structPointer) (n int) { // Encode an extension map. func (o *Buffer) enc_map(p *Properties, base structPointer) error { - v := *structPointer_ExtMap(base, p.field) - if err := encodeExtensionMap(v); err != nil { + exts := structPointer_ExtMap(base, p.field) + if err := encodeExtensionsMap(*exts); err != nil { + return err + } + + return o.enc_map_body(*exts) +} + +func (o *Buffer) enc_exts(p *Properties, base structPointer) error { + exts := structPointer_Extensions(base, p.field) + if err := encodeExtensions(exts); err != nil { return err } + v, _ := exts.extensionsRead() + + return o.enc_map_body(v) +} + +func (o *Buffer) enc_map_body(v map[int32]Extension) error { // Fast-path for common cases: zero or one extensions. if len(v) <= 1 { for _, e := range v { @@ -1084,8 +1114,13 @@ func (o *Buffer) enc_map(p *Properties, base structPointer) error { } func size_map(p *Properties, base structPointer) int { - v := *structPointer_ExtMap(base, p.field) - return sizeExtensionMap(v) + v := structPointer_ExtMap(base, p.field) + return extensionsMapSize(*v) +} + +func size_exts(p *Properties, base structPointer) int { + v := structPointer_Extensions(base, p.field) + return extensionsSize(v) } // Encode a map field. @@ -1114,7 +1149,7 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { return err } - if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil { + if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { return err } return nil @@ -1124,11 +1159,6 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { for _, key := range v.MapKeys() { val := v.MapIndex(key) - // The only illegal map entry values are nil message pointers. - if val.Kind() == reflect.Ptr && val.IsNil() { - return errors.New("proto: map has nil element") - } - keycopy.Set(key) valcopy.Set(val) @@ -1216,13 +1246,18 @@ func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { return err } } + if len(o.buf) > maxMarshalSize { + return ErrTooLarge + } } } // Do oneof fields. if prop.oneofMarshaler != nil { m := structPointer_Interface(base, prop.stype).(Message) - if err := prop.oneofMarshaler(m, o); err != nil { + if err := prop.oneofMarshaler(m, o); err == ErrNil { + return errOneofHasNil + } else if err != nil { return err } } @@ -1230,6 +1265,9 @@ func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { // Add unrecognized fields at the end. if prop.unrecField.IsValid() { v := *structPointer_Bytes(base, prop.unrecField) + if len(o.buf)+len(v) > maxMarshalSize { + return ErrTooLarge + } if len(v) > 0 { o.buf = append(o.buf, v...) } diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode_gogo.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode_gogo.go index f77cfb1eea..66e7e16303 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode_gogo.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode_gogo.go @@ -1,7 +1,7 @@ -// Extensions for Protocol Buffers to create more go like structures. +// Protocol Buffers for Go with Gadgets // -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Go support for Protocol Buffers - Google's data interchange format // diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/equal.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/equal.go index f5db1def3c..8b16f951c7 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/equal.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/equal.go @@ -121,9 +121,16 @@ func equalStruct(v1, v2 reflect.Value) bool { } } + if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_InternalExtensions") + if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { + return false + } + } + if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { em2 := v2.FieldByName("XXX_extensions") - if !equalExtensions(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { return false } } @@ -184,6 +191,13 @@ func equalAny(v1, v2 reflect.Value, prop *Properties) bool { } return true case reflect.Ptr: + // Maps may have nil values in them, so check for nil. + if v1.IsNil() && v2.IsNil() { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } return equalAny(v1.Elem(), v2.Elem(), prop) case reflect.Slice: if v1.Type().Elem().Kind() == reflect.Uint8 { @@ -223,8 +237,14 @@ func equalAny(v1, v2 reflect.Value, prop *Properties) bool { } // base is the struct type that the extensions are based on. -// em1 and em2 are extension maps. -func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool { +// x1 and x2 are InternalExtensions. +func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { + em1, _ := x1.extensionsRead() + em2, _ := x2.extensionsRead() + return equalExtMap(base, em1, em2) +} + +func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { if len(em1) != len(em2) { return false } diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions.go index 6180347e39..f7384baa87 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions.go @@ -52,23 +52,112 @@ type ExtensionRange struct { Start, End int32 // both inclusive } -// extendableProto is an interface implemented by any protocol buffer that may be extended. +// extendableProto is an interface implemented by any protocol buffer generated by the current +// proto compiler that may be extended. type extendableProto interface { Message ExtensionRangeArray() []ExtensionRange + extensionsWrite() map[int32]Extension + extensionsRead() (map[int32]Extension, sync.Locker) } -type extensionsMap interface { - extendableProto +// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous +// version of the proto compiler that may be extended. +type extendableProtoV1 interface { + Message + ExtensionRangeArray() []ExtensionRange ExtensionMap() map[int32]Extension } type extensionsBytes interface { - extendableProto + Message + ExtensionRangeArray() []ExtensionRange GetExtensions() *[]byte } +// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. +type extensionAdapter struct { + extendableProtoV1 +} + +func (e extensionAdapter) extensionsWrite() map[int32]Extension { + return e.ExtensionMap() +} + +func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + return e.ExtensionMap(), notLocker{} +} + +// notLocker is a sync.Locker whose Lock and Unlock methods are nops. +type notLocker struct{} + +func (n notLocker) Lock() {} +func (n notLocker) Unlock() {} + +// extendable returns the extendableProto interface for the given generated proto message. +// If the proto message has the old extension format, it returns a wrapper that implements +// the extendableProto interface. +func extendable(p interface{}) (extendableProto, bool) { + if ep, ok := p.(extendableProto); ok { + return ep, ok + } + if ep, ok := p.(extendableProtoV1); ok { + return extensionAdapter{ep}, ok + } + return nil, false +} + +// XXX_InternalExtensions is an internal representation of proto extensions. +// +// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, +// thus gaining the unexported 'extensions' method, which can be called only from the proto package. +// +// The methods of XXX_InternalExtensions are not concurrency safe in general, +// but calls to logically read-only methods such as has and get may be executed concurrently. +type XXX_InternalExtensions struct { + // The struct must be indirect so that if a user inadvertently copies a + // generated message and its embedded XXX_InternalExtensions, they + // avoid the mayhem of a copied mutex. + // + // The mutex serializes all logically read-only operations to p.extensionMap. + // It is up to the client to ensure that write operations to p.extensionMap are + // mutually exclusive with other accesses. + p *struct { + mu sync.Mutex + extensionMap map[int32]Extension + } +} + +// extensionsWrite returns the extension map, creating it on first use. +func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { + if e.p == nil { + e.p = new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }) + e.p.extensionMap = make(map[int32]Extension) + } + return e.p.extensionMap +} + +// extensionsRead returns the extensions map for read-only use. It may be nil. +// The caller must hold the returned mutex's lock when accessing Elements within the map. +func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { + if e.p == nil { + return nil, nil + } + return e.p.extensionMap, &e.p.mu +} + +type extensionRange interface { + Message + ExtensionRangeArray() []ExtensionRange +} + var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() +var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() +var extendableBytesType = reflect.TypeOf((*extensionsBytes)(nil)).Elem() +var extensionRangeType = reflect.TypeOf((*extensionRange)(nil)).Elem() // ExtensionDesc represents an extension specification. // Used in generated code from the protocol compiler. @@ -101,20 +190,23 @@ type Extension struct { } // SetRawExtension is for testing only. -func SetRawExtension(base extendableProto, id int32, b []byte) { - if ebase, ok := base.(extensionsMap); ok { - ebase.ExtensionMap()[id] = Extension{enc: b} - } else if ebase, ok := base.(extensionsBytes); ok { +func SetRawExtension(base Message, id int32, b []byte) { + if ebase, ok := base.(extensionsBytes); ok { clearExtension(base, id) ext := ebase.GetExtensions() *ext = append(*ext, b...) - } else { - panic("unreachable") + return + } + epb, ok := extendable(base) + if !ok { + return } + extmap := epb.extensionsWrite() + extmap[id] = Extension{enc: b} } // isExtensionField returns true iff the given field number is in an extension range. -func isExtensionField(pb extendableProto, field int32) bool { +func isExtensionField(pb extensionRange, field int32) bool { for _, er := range pb.ExtensionRangeArray() { if er.Start <= field && field <= er.End { return true @@ -125,8 +217,12 @@ func isExtensionField(pb extendableProto, field int32) bool { // checkExtensionTypes checks that the given extension is valid for pb. func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + var pbi interface{} = pb // Check the extended type. - if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b { + if ea, ok := pbi.(extensionAdapter); ok { + pbi = ea.extendableProtoV1 + } + if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) } // Check the range. @@ -172,43 +268,57 @@ func extensionProperties(ed *ExtensionDesc) *Properties { return prop } -// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m. -func encodeExtensionMap(m map[int32]Extension) error { +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensions(e *XXX_InternalExtensions) error { + m, mu := e.extensionsRead() + if m == nil { + return nil // fast path + } + mu.Lock() + defer mu.Unlock() + return encodeExtensionsMap(m) +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensionsMap(m map[int32]Extension) error { for k, e := range m { - err := encodeExtension(&e) - if err != nil { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { return err } + e.enc = p.buf m[k] = e } return nil } -func encodeExtension(e *Extension) error { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - return nil - } - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - p := NewBuffer(nil) - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - if err := props.enc(p, props, toStructPointer(x)); err != nil { - return err +func extensionsSize(e *XXX_InternalExtensions) (n int) { + m, mu := e.extensionsRead() + if m == nil { + return 0 } - e.enc = p.buf - return nil + mu.Lock() + defer mu.Unlock() + return extensionsMapSize(m) } -func sizeExtensionMap(m map[int32]Extension) (n int) { +func extensionsMapSize(m map[int32]Extension) (n int) { for _, e := range m { if e.value == nil || e.desc == nil { // Extension is only in its encoded form. @@ -233,12 +343,8 @@ func sizeExtensionMap(m map[int32]Extension) (n int) { } // HasExtension returns whether the given extension is present in pb. -func HasExtension(pb extendableProto, extension *ExtensionDesc) bool { - // TODO: Check types, field numbers, etc.? - if epb, doki := pb.(extensionsMap); doki { - _, ok := epb.ExtensionMap()[extension.Field] - return ok - } else if epb, doki := pb.(extensionsBytes); doki { +func HasExtension(pb Message, extension *ExtensionDesc) bool { + if epb, doki := pb.(extensionsBytes); doki { ext := epb.GetExtensions() buf := *ext o := 0 @@ -258,7 +364,19 @@ func HasExtension(pb extendableProto, extension *ExtensionDesc) bool { } return false } - panic("unreachable") + // TODO: Check types, field numbers, etc.? + epb, ok := extendable(pb) + if !ok { + return false + } + extmap, mu := epb.extensionsRead() + if extmap == nil { + return false + } + mu.Lock() + _, ok = extmap[extension.Field] + mu.Unlock() + return ok } func deleteExtension(pb extensionsBytes, theFieldNum int32, offset int) int { @@ -281,64 +399,32 @@ func deleteExtension(pb extensionsBytes, theFieldNum int32, offset int) int { return -1 } -func clearExtension(pb extendableProto, fieldNum int32) { - if epb, doki := pb.(extensionsMap); doki { - delete(epb.ExtensionMap(), fieldNum) - } else if epb, doki := pb.(extensionsBytes); doki { +// ClearExtension removes the given extension from pb. +func ClearExtension(pb Message, extension *ExtensionDesc) { + clearExtension(pb, extension.Field) +} + +func clearExtension(pb Message, fieldNum int32) { + if epb, doki := pb.(extensionsBytes); doki { offset := 0 for offset != -1 { offset = deleteExtension(epb, fieldNum, offset) } - } else { - panic("unreachable") + return + } + epb, ok := extendable(pb) + if !ok { + return } -} - -// ClearExtension removes the given extension from pb. -func ClearExtension(pb extendableProto, extension *ExtensionDesc) { // TODO: Check types, field numbers, etc.? - clearExtension(pb, extension.Field) + extmap := epb.extensionsWrite() + delete(extmap, fieldNum) } // GetExtension parses and returns the given extension of pb. -// If the extension is not present it returns ErrMissingExtension. -func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) { - if err := checkExtensionTypes(pb, extension); err != nil { - return nil, err - } - - if epb, doki := pb.(extensionsMap); doki { - emap := epb.ExtensionMap() - e, ok := emap[extension.Field] - if !ok { - // defaultExtensionValue returns the default value or - // ErrMissingExtension if there is no default. - return defaultExtensionValue(extension) - } - if e.value != nil { - // Already decoded. Check the descriptor, though. - if e.desc != extension { - // This shouldn't happen. If it does, it means that - // GetExtension was called twice with two different - // descriptors with the same field number. - return nil, errors.New("proto: descriptor conflict") - } - return e.value, nil - } - - v, err := decodeExtension(e.enc, extension) - if err != nil { - return nil, err - } - - // Remember the decoded version and drop the encoded version. - // That way it is safe to mutate what we return. - e.value = v - e.desc = extension - e.enc = nil - emap[extension.Field] = e - return e.value, nil - } else if epb, doki := pb.(extensionsBytes); doki { +// If the extension is not present and has no default value it returns ErrMissingExtension. +func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { + if epb, doki := pb.(extensionsBytes); doki { ext := epb.GetExtensions() o := 0 for o < len(*ext) { @@ -360,7 +446,50 @@ func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, er } return defaultExtensionValue(extension) } - panic("unreachable") + epb, ok := extendable(pb) + if !ok { + return nil, errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { + return nil, err + } + + emap, mu := epb.extensionsRead() + if emap == nil { + return defaultExtensionValue(extension) + } + mu.Lock() + defer mu.Unlock() + e, ok := emap[extension.Field] + if !ok { + // defaultExtensionValue returns the default value or + // ErrMissingExtension if there is no default. + return defaultExtensionValue(extension) + } + + if e.value != nil { + // Already decoded. Check the descriptor, though. + if e.desc != extension { + // This shouldn't happen. If it does, it means that + // GetExtension was called twice with two different + // descriptors with the same field number. + return nil, errors.New("proto: descriptor conflict") + } + return e.value, nil + } + + v, err := decodeExtension(e.enc, extension) + if err != nil { + return nil, err + } + + // Remember the decoded version and drop the encoded version. + // That way it is safe to mutate what we return. + e.value = v + e.desc = extension + e.enc = nil + emap[extension.Field] = e + return e.value, nil } // defaultExtensionValue returns the default value for extension. @@ -434,14 +563,9 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { // GetExtensions returns a slice of the extensions present in pb that are also listed in es. // The returned slice has the same length as es; missing extensions will appear as nil elements. func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { - epb, ok := pb.(extendableProto) - if !ok { - err = errors.New("proto: not an extendable proto") - return - } extensions = make([]interface{}, len(es)) for i, e := range es { - extensions[i], err = GetExtension(epb, e) + extensions[i], err = GetExtension(pb, e) if err == ErrMissingExtension { err = nil } @@ -452,9 +576,55 @@ func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, e return } +// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. +// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing +// just the Field field, which defines the extension's field number. +func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { + epb, ok := extendable(pb) + if !ok { + return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) + } + registeredExtensions := RegisteredExtensions(pb) + + emap, mu := epb.extensionsRead() + mu.Lock() + defer mu.Unlock() + extensions := make([]*ExtensionDesc, 0, len(emap)) + for extid, e := range emap { + desc := e.desc + if desc == nil { + desc = registeredExtensions[extid] + if desc == nil { + desc = &ExtensionDesc{Field: extid} + } + } + + extensions = append(extensions, desc) + } + return extensions, nil +} + // SetExtension sets the specified extension of pb to the specified value. -func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error { - if err := checkExtensionTypes(pb, extension); err != nil { +func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { + if epb, doki := pb.(extensionsBytes); doki { + ClearExtension(pb, extension) + ext := epb.GetExtensions() + et := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + p := NewBuffer(nil) + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + *ext = append(*ext, p.buf...) + return nil + } + epb, ok := extendable(pb) + if !ok { + return errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { return err } typ := reflect.TypeOf(extension.ExtensionType) @@ -469,26 +639,27 @@ func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{ if reflect.ValueOf(value).IsNil() { return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) } - return setExtension(pb, extension, value) + + extmap := epb.extensionsWrite() + extmap[extension.Field] = Extension{desc: extension, value: value} + return nil } -func setExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error { - if epb, doki := pb.(extensionsMap); doki { - epb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value} - } else if epb, doki := pb.(extensionsBytes); doki { - ClearExtension(pb, extension) +// ClearAllExtensions clears all extensions from pb. +func ClearAllExtensions(pb Message) { + if epb, doki := pb.(extensionsBytes); doki { ext := epb.GetExtensions() - et := reflect.TypeOf(extension.ExtensionType) - props := extensionProperties(extension) - p := NewBuffer(nil) - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(value)) - if err := props.enc(p, props, toStructPointer(x)); err != nil { - return err - } - *ext = append(*ext, p.buf...) + *ext = []byte{} + return + } + epb, ok := extendable(pb) + if !ok { + return + } + m := epb.extensionsWrite() + for k := range m { + delete(m, k) } - return nil } // A global registry of extensions. diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions_gogo.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions_gogo.go index 86b1fa2344..ea6478f009 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions_gogo.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions_gogo.go @@ -1,5 +1,7 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -33,9 +35,10 @@ import ( "reflect" "sort" "strings" + "sync" ) -func GetBoolExtension(pb extendableProto, extension *ExtensionDesc, ifnotset bool) bool { +func GetBoolExtension(pb Message, extension *ExtensionDesc, ifnotset bool) bool { if reflect.ValueOf(pb).IsNil() { return ifnotset } @@ -60,8 +63,12 @@ func (this *Extension) Compare(that *Extension) int { return bytes.Compare(this.enc, that.enc) } +func SizeOfInternalExtension(m extendableProto) (n int) { + return SizeOfExtensionMap(m.extensionsWrite()) +} + func SizeOfExtensionMap(m map[int32]Extension) (n int) { - return sizeExtensionMap(m) + return extensionsMapSize(m) } type sortableMapElem struct { @@ -94,6 +101,10 @@ func (this sortableExtensions) String() string { return "map[" + strings.Join(ss, ",") + "]" } +func StringFromInternalExtension(m extendableProto) string { + return StringFromExtensionsMap(m.extensionsWrite()) +} + func StringFromExtensionsMap(m map[int32]Extension) string { return newSortableExtensionsFromMap(m).String() } @@ -106,8 +117,12 @@ func StringFromExtensionsBytes(ext []byte) string { return StringFromExtensionsMap(m) } +func EncodeInternalExtension(m extendableProto, data []byte) (n int, err error) { + return EncodeExtensionMap(m.extensionsWrite(), data) +} + func EncodeExtensionMap(m map[int32]Extension, data []byte) (n int, err error) { - if err := encodeExtensionMap(m); err != nil { + if err := encodeExtensionsMap(m); err != nil { return 0, err } keys := make([]int, 0, len(m)) @@ -125,7 +140,7 @@ func GetRawExtension(m map[int32]Extension, id int32) ([]byte, error) { if m[id].value == nil || m[id].desc == nil { return m[id].enc, nil } - if err := encodeExtensionMap(m); err != nil { + if err := encodeExtensionsMap(m); err != nil { return nil, err } return m[id].enc, nil @@ -189,17 +204,44 @@ func NewExtension(e []byte) Extension { return ee } -func AppendExtension(e extendableProto, tag int32, buf []byte) { - if ee, eok := e.(extensionsMap); eok { - ext := ee.ExtensionMap()[int32(tag)] // may be missing - ext.enc = append(ext.enc, buf...) - ee.ExtensionMap()[int32(tag)] = ext - } else if ee, eok := e.(extensionsBytes); eok { +func AppendExtension(e Message, tag int32, buf []byte) { + if ee, eok := e.(extensionsBytes); eok { ext := ee.GetExtensions() *ext = append(*ext, buf...) + return + } + if ee, eok := e.(extendableProto); eok { + m := ee.extensionsWrite() + ext := m[int32(tag)] // may be missing + ext.enc = append(ext.enc, buf...) + m[int32(tag)] = ext } } +func encodeExtension(e *Extension) error { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + return nil + } + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + e.enc = p.buf + return nil +} + func (this Extension) GoString() string { if this.enc == nil { if err := encodeExtension(&this); err != nil { @@ -209,7 +251,7 @@ func (this Extension) GoString() string { return fmt.Sprintf("proto.NewExtension(%#v)", this.enc) } -func SetUnsafeExtension(pb extendableProto, fieldNum int32, value interface{}) error { +func SetUnsafeExtension(pb Message, fieldNum int32, value interface{}) error { typ := reflect.TypeOf(pb).Elem() ext, ok := extensionMaps[typ] if !ok { @@ -219,10 +261,10 @@ func SetUnsafeExtension(pb extendableProto, fieldNum int32, value interface{}) e if !ok { return errors.New("proto: bad extension number; not in declared ranges") } - return setExtension(pb, desc, value) + return SetExtension(pb, desc, value) } -func GetUnsafeExtension(pb extendableProto, fieldNum int32) (interface{}, error) { +func GetUnsafeExtension(pb Message, fieldNum int32) (interface{}, error) { typ := reflect.TypeOf(pb).Elem() ext, ok := extensionMaps[typ] if !ok { @@ -234,3 +276,19 @@ func GetUnsafeExtension(pb extendableProto, fieldNum int32) (interface{}, error) } return GetExtension(pb, desc) } + +func NewUnsafeXXX_InternalExtensions(m map[int32]Extension) XXX_InternalExtensions { + x := &XXX_InternalExtensions{ + p: new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }), + } + x.p.extensionMap = m + return *x +} + +func GetUnsafeExtensionsMap(extendable Message) map[int32]Extension { + pb := extendable.(extendableProto) + return pb.extensionsWrite() +} diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib.go index 2e35ae2d2a..2c30d70951 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib.go @@ -889,6 +889,10 @@ func isProto3Zero(v reflect.Value) bool { return false } +// ProtoPackageIsVersion2 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const GoGoProtoPackageIsVersion2 = true + // ProtoPackageIsVersion1 is referenced from generated protocol buffer files // to assert that that code is compatible with this version of the proto package. const GoGoProtoPackageIsVersion1 = true diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib_gogo.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib_gogo.go index a6c2c06b23..4b4f7c909e 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib_gogo.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib_gogo.go @@ -1,5 +1,7 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/message_set.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/message_set.go index e25e01e637..fd982decd6 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/message_set.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/message_set.go @@ -149,9 +149,21 @@ func skipVarint(buf []byte) []byte { // MarshalMessageSet encodes the extension map represented by m in the message set wire format. // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSet(m map[int32]Extension) ([]byte, error) { - if err := encodeExtensionMap(m); err != nil { - return nil, err +func MarshalMessageSet(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + if err := encodeExtensions(exts); err != nil { + return nil, err + } + m, _ = exts.extensionsRead() + case map[int32]Extension: + if err := encodeExtensionsMap(exts); err != nil { + return nil, err + } + m = exts + default: + return nil, errors.New("proto: not an extension map") } // Sort extension IDs to provide a deterministic encoding. @@ -178,7 +190,17 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) { // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. // It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error { +func UnmarshalMessageSet(buf []byte, exts interface{}) error { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m = exts.extensionsWrite() + case map[int32]Extension: + m = exts + default: + return errors.New("proto: not an extension map") + } + ms := new(messageSet) if err := Unmarshal(buf, ms); err != nil { return err @@ -209,7 +231,16 @@ func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error { // MarshalMessageSetJSON encodes the extension map represented by m in JSON format. // It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) { +func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m, _ = exts.extensionsRead() + case map[int32]Extension: + m = exts + default: + return nil, errors.New("proto: not an extension map") + } var b bytes.Buffer b.WriteByte('{') @@ -252,7 +283,7 @@ func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) { // UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. // It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSetJSON(buf []byte, m map[int32]Extension) error { +func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { // Common-case fast path. if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { return nil diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_reflect.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_reflect.go index 749919d250..fb512e2e16 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_reflect.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_reflect.go @@ -29,7 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build appengine +// +build appengine js // This file contains an implementation of proto field accesses using package reflect. // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can @@ -139,6 +139,11 @@ func structPointer_StringSlice(p structPointer, f field) *[]string { return structPointer_ifield(p, f).(*[]string) } +// Extensions returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return structPointer_ifield(p, f).(*XXX_InternalExtensions) +} + // ExtMap returns the address of an extension map field in the struct. func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { return structPointer_ifield(p, f).(*map[int32]Extension) diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe.go index e9be0fe92e..6b5567d47c 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe.go @@ -29,7 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build !appengine +// +build !appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. @@ -126,6 +126,10 @@ func structPointer_StringSlice(p structPointer, f field) *[]string { } // ExtMap returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) } diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go index 6bc85fa987..132ea4dfd9 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go @@ -1,5 +1,7 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties.go index 5e6a0b3ba7..3e4cad0381 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties.go @@ -1,7 +1,7 @@ -// Extensions for Protocol Buffers to create more go like structures. +// Protocol Buffers for Go with Gadgets // -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Go support for Protocol Buffers - Google's data interchange format // @@ -542,17 +542,13 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock p.dec = (*Buffer).dec_slice_int64 p.packedDec = (*Buffer).dec_slice_packed_int64 case reflect.Uint8: - p.enc = (*Buffer).enc_slice_byte p.dec = (*Buffer).dec_slice_byte - p.size = size_slice_byte - // This is a []byte, which is either a bytes field, - // or the value of a map field. In the latter case, - // we always encode an empty []byte, so we should not - // use the proto3 enc/size funcs. - // f == nil iff this is the key/value of a map field. - if p.proto3 && f != nil { + if p.proto3 { p.enc = (*Buffer).enc_proto3_slice_byte p.size = size_proto3_slice_byte + } else { + p.enc = (*Buffer).enc_slice_byte + p.size = size_slice_byte } case reflect.Float32, reflect.Float64: switch t2.Bits() { @@ -744,7 +740,9 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { propertiesMap[t] = prop // build properties - prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) + prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || + reflect.PtrTo(t).Implements(extendableProtoV1Type) || + reflect.PtrTo(t).Implements(extendableBytesType) prop.unrecField = invalidField prop.Prop = make([]*Properties, t.NumField()) prop.order = make([]int, t.NumField()) @@ -756,7 +754,11 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { name := f.Name p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) - if f.Name == "XXX_extensions" { // special case + if f.Name == "XXX_InternalExtensions" { // special case + p.enc = (*Buffer).enc_exts + p.dec = nil // not needed + p.size = size_exts + } else if f.Name == "XXX_extensions" { // special case if len(f.Tag.Get("protobuf")) > 0 { p.enc = (*Buffer).enc_ext_slice_byte p.dec = nil // not needed @@ -766,13 +768,14 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { p.dec = nil // not needed p.size = size_map } - } - if f.Name == "XXX_unrecognized" { // special case + } else if f.Name == "XXX_unrecognized" { // special case prop.unrecField = toField(&f) } - oneof := f.Tag.Get("protobuf_oneof") != "" // special case - if oneof { + oneof := f.Tag.Get("protobuf_oneof") // special case + if oneof != "" { isOneofMessage = true + // Oneof fields don't use the traditional protobuf tag. + p.OrigName = oneof } prop.Prop[i] = p prop.order[i] = i @@ -783,7 +786,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { } print("\n") } - if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && !oneof { + if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") } } @@ -921,3 +924,17 @@ func MessageName(x Message) string { return revProtoTypes[reflect.TypeOf(x)] } // MessageType returns the message type (pointer to struct) for a named message. func MessageType(name string) reflect.Type { return protoTypes[name] } + +// A registry of all linked proto files. +var ( + protoFiles = make(map[string][]byte) // file name => fileDescriptor +) + +// RegisterFile is called from generated code and maps from the +// full file name of a .proto file to its compressed FileDescriptorProto. +func RegisterFile(filename string, fileDescriptor []byte) { + protoFiles[filename] = fileDescriptor +} + +// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. +func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties_gogo.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties_gogo.go index 8daf9f7768..4607a97541 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties_gogo.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties_gogo.go @@ -1,5 +1,7 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/skip_gogo.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/skip_gogo.go index 4fe7e0815c..5a5fd93f7c 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/skip_gogo.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/skip_gogo.go @@ -1,5 +1,7 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text.go index e2b99b122d..b3e12e2684 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text.go @@ -1,7 +1,7 @@ -// Extensions for Protocol Buffers to create more go like structures. +// Protocol Buffers for Go with Gadgets // -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Go support for Protocol Buffers - Google's data interchange format // @@ -50,6 +50,7 @@ import ( "reflect" "sort" "strings" + "sync" ) var ( @@ -159,7 +160,7 @@ func (w *textWriter) indent() { w.ind++ } func (w *textWriter) unindent() { if w.ind == 0 { - log.Printf("proto: textWriter unindented too far") + log.Print("proto: textWriter unindented too far") return } w.ind-- @@ -335,7 +336,8 @@ func writeStruct(w *textWriter, sv reflect.Value) error { } inner := fv.Elem().Elem() // interface -> *T -> T tag := inner.Type().Field(0).Tag.Get("protobuf") - props.Parse(tag) // Overwrite the outer props. + props = new(Properties) // Overwrite the outer props var, but not its pointee. + props.Parse(tag) // Write the value in the oneof, not the oneof itself. fv = inner.Field(0) @@ -386,7 +388,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error { pv = reflect.New(sv.Type()) pv.Elem().Set(sv) } - if pv.Type().Implements(extendableProtoType) { + if pv.Type().Implements(extensionRangeType) { if err := writeExtensions(w, pv); err != nil { return err } @@ -634,28 +636,37 @@ func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // pv is assumed to be a pointer to a protocol message struct that is extendable. func writeExtensions(w *textWriter, pv reflect.Value) error { emap := extensionMaps[pv.Type().Elem()] - ep := pv.Interface().(extendableProto) + e := pv.Interface().(Message) - // Order the extensions by ID. - // This isn't strictly necessary, but it will give us - // canonical output, which will also make testing easier. var m map[int32]Extension - if em, ok := ep.(extensionsMap); ok { - m = em.ExtensionMap() - } else if em, ok := ep.(extensionsBytes); ok { + var mu sync.Locker + if em, ok := e.(extensionsBytes); ok { eb := em.GetExtensions() var err error m, err = BytesToExtensionsMap(*eb) if err != nil { return err } + mu = notLocker{} + } else if _, ok := e.(extendableProto); ok { + ep, _ := extendable(e) + m, mu = ep.extensionsRead() + if m == nil { + return nil + } } + // Order the extensions by ID. + // This isn't strictly necessary, but it will give us + // canonical output, which will also make testing easier. + + mu.Lock() ids := make([]int32, 0, len(m)) for id := range m { ids = append(ids, id) } sort.Sort(int32Slice(ids)) + mu.Unlock() for _, extNum := range ids { ext := m[extNum] @@ -671,7 +682,7 @@ func writeExtensions(w *textWriter, pv reflect.Value) error { continue } - pb, err := GetExtension(ep, desc) + pb, err := GetExtension(e, desc) if err != nil { return fmt.Errorf("failed getting extension: %v", err) } @@ -727,7 +738,14 @@ func (w *textWriter) writeIndent() { w.complete = false } -func marshalText(w io.Writer, pb Message, compact bool) error { +// TextMarshaler is a configurable text format marshaler. +type TextMarshaler struct { + Compact bool // use compact text format (one line). +} + +// Marshal writes a given protocol buffer in text format. +// The only errors returned are from w. +func (m *TextMarshaler) Marshal(w io.Writer, pb Message) error { val := reflect.ValueOf(pb) if pb == nil || val.IsNil() { w.Write([]byte("")) @@ -742,7 +760,7 @@ func marshalText(w io.Writer, pb Message, compact bool) error { aw := &textWriter{ w: ww, complete: true, - compact: compact, + compact: m.Compact, } if tm, ok := pb.(encoding.TextMarshaler); ok { @@ -769,25 +787,29 @@ func marshalText(w io.Writer, pb Message, compact bool) error { return nil } +// Text is the same as Marshal, but returns the string directly. +func (m *TextMarshaler) Text(pb Message) string { + var buf bytes.Buffer + m.Marshal(&buf, pb) + return buf.String() +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true} +) + +// TODO: consider removing some of the Marshal functions below. + // MarshalText writes a given protocol buffer in text format. // The only errors returned are from w. -func MarshalText(w io.Writer, pb Message) error { - return marshalText(w, pb, false) -} +func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } // MarshalTextString is the same as MarshalText, but returns the string directly. -func MarshalTextString(pb Message) string { - var buf bytes.Buffer - marshalText(&buf, pb, false) - return buf.String() -} +func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } // CompactText writes a given protocol buffer in compact text format (one line). -func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) } +func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } // CompactTextString is the same as CompactText, but returns the string directly. -func CompactTextString(pb Message) string { - var buf bytes.Buffer - marshalText(&buf, pb, true) - return buf.String() -} +func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_gogo.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_gogo.go index cdb23373c3..5892674197 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_gogo.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_gogo.go @@ -1,5 +1,7 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_parser.go b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_parser.go index 61b4bc8cc8..bcd732c3c4 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_parser.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_parser.go @@ -1,7 +1,7 @@ -// Extensions for Protocol Buffers to create more go like structures. +// Protocol Buffers for Go with Gadgets // -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. -// http://github.com/gogo/protobuf/gogoproto +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf // // Go support for Protocol Buffers - Google's data interchange format // @@ -519,7 +519,7 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { } reqFieldErr = err } - ep := sv.Addr().Interface().(extendableProto) + ep := sv.Addr().Interface().(Message) if !rep { SetExtension(ep, desc, ext.Interface()) } else { @@ -571,8 +571,9 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { // The map entry should be this sequence of tokens: // < key : KEY value : VALUE > - // Technically the "key" and "value" could come in any order, - // but in practice they won't. + // However, implementations may omit key or value, and technically + // we should support them in any order. See b/28924776 for a time + // this went wrong. tok := p.next() var terminator string @@ -584,32 +585,39 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { default: return p.errorf("expected '{' or '<', found %q", tok.value) } - if err := p.consumeToken("key"); err != nil { - return err - } - if err := p.consumeToken(":"); err != nil { - return err - } - if err := p.readAny(key, props.mkeyprop); err != nil { - return err - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - if err := p.consumeToken("value"); err != nil { - return err - } - if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { - return err - } - if err := p.readAny(val, props.mvalprop); err != nil { - return err - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - if err := p.consumeToken(terminator); err != nil { - return err + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + switch tok.value { + case "key": + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.mkeyprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + case "value": + if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.mvalprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + default: + p.back() + return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) + } } dst.SetMapIndex(key, val) @@ -632,7 +640,8 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { return err } reqFieldErr = err - } else if props.Required { + } + if props.Required { reqCount-- } diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/descriptor.pb.go b/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/descriptor.pb.go index 342d65a425..6b361d6a86 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/descriptor.pb.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/descriptor.pb.go @@ -41,7 +41,9 @@ var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. -const _ = proto.GoGoProtoPackageIsVersion1 +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package type FieldDescriptorProto_Type int32 @@ -955,9 +957,9 @@ type FileOptions struct { // suffixed package. JavananoUseDeprecatedPackage *bool `protobuf:"varint,38,opt,name=javanano_use_deprecated_package,json=javananoUseDeprecatedPackage" json:"javanano_use_deprecated_package,omitempty"` // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_extensions map[int32]proto.Extension `json:"-"` - XXX_unrecognized []byte `json:"-"` + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` } func (m *FileOptions) Reset() { *m = FileOptions{} } @@ -972,12 +974,6 @@ var extRange_FileOptions = []proto.ExtensionRange{ func (*FileOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_FileOptions } -func (m *FileOptions) ExtensionMap() map[int32]proto.Extension { - if m.XXX_extensions == nil { - m.XXX_extensions = make(map[int32]proto.Extension) - } - return m.XXX_extensions -} const Default_FileOptions_JavaMultipleFiles bool = false const Default_FileOptions_JavaGenerateEqualsAndHash bool = false @@ -1153,9 +1149,9 @@ type MessageOptions struct { // parser. MapEntry *bool `protobuf:"varint,7,opt,name=map_entry,json=mapEntry" json:"map_entry,omitempty"` // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_extensions map[int32]proto.Extension `json:"-"` - XXX_unrecognized []byte `json:"-"` + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` } func (m *MessageOptions) Reset() { *m = MessageOptions{} } @@ -1170,12 +1166,6 @@ var extRange_MessageOptions = []proto.ExtensionRange{ func (*MessageOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_MessageOptions } -func (m *MessageOptions) ExtensionMap() map[int32]proto.Extension { - if m.XXX_extensions == nil { - m.XXX_extensions = make(map[int32]proto.Extension) - } - return m.XXX_extensions -} const Default_MessageOptions_MessageSetWireFormat bool = false const Default_MessageOptions_NoStandardDescriptorAccessor bool = false @@ -1275,9 +1265,9 @@ type FieldOptions struct { // For Google-internal migration only. Do not use. Weak *bool `protobuf:"varint,10,opt,name=weak,def=0" json:"weak,omitempty"` // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_extensions map[int32]proto.Extension `json:"-"` - XXX_unrecognized []byte `json:"-"` + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` } func (m *FieldOptions) Reset() { *m = FieldOptions{} } @@ -1292,12 +1282,6 @@ var extRange_FieldOptions = []proto.ExtensionRange{ func (*FieldOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_FieldOptions } -func (m *FieldOptions) ExtensionMap() map[int32]proto.Extension { - if m.XXX_extensions == nil { - m.XXX_extensions = make(map[int32]proto.Extension) - } - return m.XXX_extensions -} const Default_FieldOptions_Ctype FieldOptions_CType = FieldOptions_STRING const Default_FieldOptions_Jstype FieldOptions_JSType = FieldOptions_JS_NORMAL @@ -1364,9 +1348,9 @@ type EnumOptions struct { // is a formalization for deprecating enums. Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_extensions map[int32]proto.Extension `json:"-"` - XXX_unrecognized []byte `json:"-"` + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` } func (m *EnumOptions) Reset() { *m = EnumOptions{} } @@ -1381,12 +1365,6 @@ var extRange_EnumOptions = []proto.ExtensionRange{ func (*EnumOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_EnumOptions } -func (m *EnumOptions) ExtensionMap() map[int32]proto.Extension { - if m.XXX_extensions == nil { - m.XXX_extensions = make(map[int32]proto.Extension) - } - return m.XXX_extensions -} const Default_EnumOptions_Deprecated bool = false @@ -1418,9 +1396,9 @@ type EnumValueOptions struct { // this is a formalization for deprecating enum values. Deprecated *bool `protobuf:"varint,1,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_extensions map[int32]proto.Extension `json:"-"` - XXX_unrecognized []byte `json:"-"` + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` } func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} } @@ -1435,12 +1413,6 @@ var extRange_EnumValueOptions = []proto.ExtensionRange{ func (*EnumValueOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_EnumValueOptions } -func (m *EnumValueOptions) ExtensionMap() map[int32]proto.Extension { - if m.XXX_extensions == nil { - m.XXX_extensions = make(map[int32]proto.Extension) - } - return m.XXX_extensions -} const Default_EnumValueOptions_Deprecated bool = false @@ -1465,9 +1437,9 @@ type ServiceOptions struct { // this is a formalization for deprecating services. Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_extensions map[int32]proto.Extension `json:"-"` - XXX_unrecognized []byte `json:"-"` + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` } func (m *ServiceOptions) Reset() { *m = ServiceOptions{} } @@ -1482,12 +1454,6 @@ var extRange_ServiceOptions = []proto.ExtensionRange{ func (*ServiceOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_ServiceOptions } -func (m *ServiceOptions) ExtensionMap() map[int32]proto.Extension { - if m.XXX_extensions == nil { - m.XXX_extensions = make(map[int32]proto.Extension) - } - return m.XXX_extensions -} const Default_ServiceOptions_Deprecated bool = false @@ -1512,9 +1478,9 @@ type MethodOptions struct { // this is a formalization for deprecating methods. Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_extensions map[int32]proto.Extension `json:"-"` - XXX_unrecognized []byte `json:"-"` + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` } func (m *MethodOptions) Reset() { *m = MethodOptions{} } @@ -1529,12 +1495,6 @@ var extRange_MethodOptions = []proto.ExtensionRange{ func (*MethodOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_MethodOptions } -func (m *MethodOptions) ExtensionMap() map[int32]proto.Extension { - if m.XXX_extensions == nil { - m.XXX_extensions = make(map[int32]proto.Extension) - } - return m.XXX_extensions -} const Default_MethodOptions_Deprecated bool = false @@ -1875,6 +1835,8 @@ func init() { proto.RegisterEnum("google.protobuf.FieldOptions_JSType", FieldOptions_JSType_name, FieldOptions_JSType_value) } +func init() { proto.RegisterFile("descriptor.proto", fileDescriptorDescriptor) } + var fileDescriptorDescriptor = []byte{ // 2192 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x58, 0x4f, 0x73, 0xdb, 0xd6, diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/gostring.go b/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/gostring.go index 76e2c95f9b..b08b81c107 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/gostring.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/gostring.go @@ -353,9 +353,7 @@ func (this *FileOptions) GoString() string { if this.UninterpretedOption != nil { s = append(s, "UninterpretedOption: "+fmt.Sprintf("%#v", this.UninterpretedOption)+",\n") } - if this.XXX_extensions != nil { - s = append(s, "XXX_extensions: "+extensionToGoStringDescriptor(this.XXX_extensions)+",\n") - } + s = append(s, "XXX_InternalExtensions: "+extensionToGoStringDescriptor(this)+",\n") if this.XXX_unrecognized != nil { s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") } @@ -383,9 +381,7 @@ func (this *MessageOptions) GoString() string { if this.UninterpretedOption != nil { s = append(s, "UninterpretedOption: "+fmt.Sprintf("%#v", this.UninterpretedOption)+",\n") } - if this.XXX_extensions != nil { - s = append(s, "XXX_extensions: "+extensionToGoStringDescriptor(this.XXX_extensions)+",\n") - } + s = append(s, "XXX_InternalExtensions: "+extensionToGoStringDescriptor(this)+",\n") if this.XXX_unrecognized != nil { s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") } @@ -419,9 +415,7 @@ func (this *FieldOptions) GoString() string { if this.UninterpretedOption != nil { s = append(s, "UninterpretedOption: "+fmt.Sprintf("%#v", this.UninterpretedOption)+",\n") } - if this.XXX_extensions != nil { - s = append(s, "XXX_extensions: "+extensionToGoStringDescriptor(this.XXX_extensions)+",\n") - } + s = append(s, "XXX_InternalExtensions: "+extensionToGoStringDescriptor(this)+",\n") if this.XXX_unrecognized != nil { s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") } @@ -443,9 +437,7 @@ func (this *EnumOptions) GoString() string { if this.UninterpretedOption != nil { s = append(s, "UninterpretedOption: "+fmt.Sprintf("%#v", this.UninterpretedOption)+",\n") } - if this.XXX_extensions != nil { - s = append(s, "XXX_extensions: "+extensionToGoStringDescriptor(this.XXX_extensions)+",\n") - } + s = append(s, "XXX_InternalExtensions: "+extensionToGoStringDescriptor(this)+",\n") if this.XXX_unrecognized != nil { s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") } @@ -464,9 +456,7 @@ func (this *EnumValueOptions) GoString() string { if this.UninterpretedOption != nil { s = append(s, "UninterpretedOption: "+fmt.Sprintf("%#v", this.UninterpretedOption)+",\n") } - if this.XXX_extensions != nil { - s = append(s, "XXX_extensions: "+extensionToGoStringDescriptor(this.XXX_extensions)+",\n") - } + s = append(s, "XXX_InternalExtensions: "+extensionToGoStringDescriptor(this)+",\n") if this.XXX_unrecognized != nil { s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") } @@ -485,9 +475,7 @@ func (this *ServiceOptions) GoString() string { if this.UninterpretedOption != nil { s = append(s, "UninterpretedOption: "+fmt.Sprintf("%#v", this.UninterpretedOption)+",\n") } - if this.XXX_extensions != nil { - s = append(s, "XXX_extensions: "+extensionToGoStringDescriptor(this.XXX_extensions)+",\n") - } + s = append(s, "XXX_InternalExtensions: "+extensionToGoStringDescriptor(this)+",\n") if this.XXX_unrecognized != nil { s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") } @@ -506,9 +494,7 @@ func (this *MethodOptions) GoString() string { if this.UninterpretedOption != nil { s = append(s, "UninterpretedOption: "+fmt.Sprintf("%#v", this.UninterpretedOption)+",\n") } - if this.XXX_extensions != nil { - s = append(s, "XXX_extensions: "+extensionToGoStringDescriptor(this.XXX_extensions)+",\n") - } + s = append(s, "XXX_InternalExtensions: "+extensionToGoStringDescriptor(this)+",\n") if this.XXX_unrecognized != nil { s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") } @@ -616,11 +602,12 @@ func valueToGoStringDescriptor(v interface{}, typ string) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv) } -func extensionToGoStringDescriptor(e map[int32]github_com_gogo_protobuf_proto.Extension) string { +func extensionToGoStringDescriptor(m github_com_gogo_protobuf_proto.Message) string { + e := github_com_gogo_protobuf_proto.GetUnsafeExtensionsMap(m) if e == nil { return "nil" } - s := "map[int32]proto.Extension{" + s := "proto.NewUnsafeXXX_InternalExtensions(map[int32]proto.Extension{" keys := make([]int, 0, len(e)) for k := range e { keys = append(keys, int(k)) @@ -630,6 +617,6 @@ func extensionToGoStringDescriptor(e map[int32]github_com_gogo_protobuf_proto.Ex for _, k := range keys { ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString()) } - s += strings.Join(ss, ",") + "}" + s += strings.Join(ss, ",") + "})" return s } diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/helper.go b/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/helper.go index ab170f913a..861f4d028d 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/helper.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/helper.go @@ -1,4 +1,6 @@ -// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. // http://github.com/gogo/protobuf // // Redistribution and use in source and binary forms, with or without From ee145e5b17b2eec715f22f22b3c2d195b05c85ef Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 2 Aug 2016 20:28:33 -0700 Subject: [PATCH 021/799] Add container short-id as an alias for swarm mode tasks Signed-off-by: Santhosh Manohar --- agent.go | 8 ++++ agent.pb.go | 107 +++++++++++++++++++++++++++++++++++++++------------- agent.proto | 3 ++ 3 files changed, 92 insertions(+), 26 deletions(-) diff --git a/agent.go b/agent.go index 0e498cf84f..55646f45e6 100644 --- a/agent.go +++ b/agent.go @@ -462,6 +462,7 @@ func (ep *endpoint) addToCluster() error { VirtualIP: ep.virtualIP.String(), IngressPorts: ingressPorts, Aliases: ep.svcAliases, + TaskAliases: ep.myAliases, EndpointIP: ep.Iface().Address().IP.String(), }) @@ -653,6 +654,7 @@ func (c *controller) handleEpTableEvent(ev events.Event) { ip := net.ParseIP(epRec.EndpointIP) ingressPorts := epRec.IngressPorts aliases := epRec.Aliases + taskaliases := epRec.TaskAliases if name == "" || ip == nil { logrus.Errorf("Invalid endpoint name/ip received while handling service table event %s", value) @@ -668,6 +670,9 @@ func (c *controller) handleEpTableEvent(ev events.Event) { } n.addSvcRecords(name, ip, nil, true) + for _, alias := range taskaliases { + n.addSvcRecords(alias, ip, nil, true) + } } else { if svcID != "" { if err := c.rmServiceBinding(svcName, svcID, nid, eid, vip, ingressPorts, aliases, ip); err != nil { @@ -677,5 +682,8 @@ func (c *controller) handleEpTableEvent(ev events.Event) { } n.deleteSvcRecords(name, ip, nil, true) + for _, alias := range taskaliases { + n.deleteSvcRecords(alias, ip, nil, true) + } } } diff --git a/agent.pb.go b/agent.pb.go index e9d2c8dee9..5b969232a7 100644 --- a/agent.pb.go +++ b/agent.pb.go @@ -74,6 +74,8 @@ type EndpointRecord struct { IngressPorts []*PortConfig `protobuf:"bytes,6,rep,name=ingress_ports,json=ingressPorts" json:"ingress_ports,omitempty"` // A list of aliases which are alternate names for the service Aliases []string `protobuf:"bytes,7,rep,name=aliases" json:"aliases,omitempty"` + // List of aliases task specific aliases + TaskAliases []string `protobuf:"bytes,8,rep,name=task_aliases,json=taskAliases" json:"task_aliases,omitempty"` } func (m *EndpointRecord) Reset() { *m = EndpointRecord{} } @@ -122,7 +124,7 @@ func (this *EndpointRecord) GoString() string { if this == nil { return "nil" } - s := make([]string, 0, 11) + s := make([]string, 0, 12) s = append(s, "&libnetwork.EndpointRecord{") s = append(s, "Name: "+fmt.Sprintf("%#v", this.Name)+",\n") s = append(s, "ServiceName: "+fmt.Sprintf("%#v", this.ServiceName)+",\n") @@ -133,6 +135,7 @@ func (this *EndpointRecord) GoString() string { s = append(s, "IngressPorts: "+fmt.Sprintf("%#v", this.IngressPorts)+",\n") } s = append(s, "Aliases: "+fmt.Sprintf("%#v", this.Aliases)+",\n") + s = append(s, "TaskAliases: "+fmt.Sprintf("%#v", this.TaskAliases)+",\n") s = append(s, "}") return strings.Join(s, "") } @@ -246,6 +249,21 @@ func (m *EndpointRecord) MarshalTo(data []byte) (int, error) { i += copy(data[i:], s) } } + if len(m.TaskAliases) > 0 { + for _, s := range m.TaskAliases { + data[i] = 0x42 + i++ + l = len(s) + for l >= 1<<7 { + data[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + data[i] = uint8(l) + i++ + i += copy(data[i:], s) + } + } return i, nil } @@ -350,6 +368,12 @@ func (m *EndpointRecord) Size() (n int) { n += 1 + l + sovAgent(uint64(l)) } } + if len(m.TaskAliases) > 0 { + for _, s := range m.TaskAliases { + l = len(s) + n += 1 + l + sovAgent(uint64(l)) + } + } return n } @@ -397,6 +421,7 @@ func (this *EndpointRecord) String() string { `EndpointIP:` + fmt.Sprintf("%v", this.EndpointIP) + `,`, `IngressPorts:` + strings.Replace(fmt.Sprintf("%v", this.IngressPorts), "PortConfig", "PortConfig", 1) + `,`, `Aliases:` + fmt.Sprintf("%v", this.Aliases) + `,`, + `TaskAliases:` + fmt.Sprintf("%v", this.TaskAliases) + `,`, `}`, }, "") return s @@ -656,6 +681,35 @@ func (m *EndpointRecord) Unmarshal(data []byte) error { } m.Aliases = append(m.Aliases, string(data[iNdEx:postIndex])) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TaskAliases", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAgent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAgent + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TaskAliases = append(m.TaskAliases, string(data[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAgent(data[iNdEx:]) @@ -919,30 +973,31 @@ var ( ) var fileDescriptorAgent = []byte{ - // 397 bytes of a gzipped FileDescriptorProto + // 413 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0xbf, 0xae, 0xd3, 0x30, - 0x14, 0xc6, 0x9b, 0xdb, 0x70, 0x6f, 0x73, 0xd2, 0x84, 0xca, 0x42, 0x28, 0xea, 0x90, 0x96, 0x4a, - 0x48, 0x1d, 0x50, 0x2a, 0x95, 0xb1, 0x5b, 0x5b, 0x86, 0x2c, 0x28, 0x32, 0x7f, 0xd6, 0x2a, 0x6d, - 0x4c, 0xb0, 0x08, 0x71, 0x64, 0xbb, 0x65, 0x65, 0x44, 0xbc, 0x03, 0x13, 0x23, 0x2f, 0xc2, 0xc8, - 0xc8, 0x84, 0x68, 0x57, 0x16, 0x1e, 0x01, 0xdb, 0x49, 0x5a, 0x21, 0x75, 0xb0, 0xe4, 0xfc, 0xce, - 0xef, 0x4b, 0x4e, 0x3e, 0x70, 0xd3, 0x9c, 0x94, 0x32, 0xaa, 0x38, 0x93, 0x0c, 0x41, 0x41, 0xb7, - 0x25, 0x91, 0x1f, 0x18, 0x7f, 0x37, 0x7c, 0x90, 0xb3, 0x9c, 0x19, 0x3c, 0xd3, 0xb7, 0xda, 0x98, - 0x7c, 0xbb, 0x01, 0xff, 0x59, 0x99, 0x55, 0x8c, 0x96, 0x12, 0x93, 0x1d, 0xe3, 0x19, 0x42, 0x60, - 0x97, 0xe9, 0x7b, 0x12, 0x58, 0x63, 0x6b, 0xea, 0x60, 0x73, 0x47, 0x8f, 0xa0, 0x2f, 0x08, 0x3f, - 0xd0, 0x1d, 0xd9, 0x98, 0xd9, 0x8d, 0x99, 0xb9, 0x0d, 0x7b, 0xae, 0x95, 0x27, 0x00, 0xad, 0x42, - 0xb3, 0xa0, 0xab, 0x85, 0xa5, 0x77, 0xfa, 0x35, 0x72, 0x5e, 0xd4, 0x34, 0x5e, 0x63, 0xa7, 0x11, - 0xe2, 0x4c, 0xdb, 0x07, 0xca, 0xe5, 0x3e, 0x2d, 0x36, 0xb4, 0x0a, 0xec, 0x8b, 0xfd, 0xba, 0xa6, - 0x71, 0x82, 0x9d, 0x46, 0x88, 0x2b, 0x34, 0x03, 0x97, 0x34, 0x4b, 0x6a, 0xfd, 0x9e, 0xd1, 0x7d, - 0xa5, 0x43, 0xbb, 0xbb, 0xf2, 0xa1, 0x55, 0x54, 0x60, 0x01, 0x1e, 0x2d, 0x73, 0x4e, 0x84, 0xd8, - 0x54, 0x8c, 0x4b, 0x11, 0xdc, 0x8e, 0xbb, 0x53, 0x77, 0xfe, 0x30, 0xba, 0x14, 0x12, 0x25, 0x6a, - 0xb0, 0x62, 0xe5, 0x1b, 0x9a, 0xe3, 0x7e, 0x23, 0x6b, 0x24, 0x50, 0x00, 0x77, 0x69, 0x41, 0x53, - 0x41, 0x44, 0x70, 0xa7, 0x62, 0x0e, 0x6e, 0x1f, 0x27, 0x7f, 0x2c, 0x80, 0x4b, 0xec, 0x6a, 0x53, - 0x0b, 0xe8, 0x99, 0x66, 0x77, 0xac, 0x30, 0x2d, 0xf9, 0xf3, 0xd1, 0xf5, 0x8f, 0x46, 0x49, 0xa3, - 0xe1, 0x73, 0x00, 0x8d, 0xc0, 0x95, 0x29, 0xcf, 0x89, 0x34, 0x5b, 0x9b, 0x12, 0x3d, 0x0c, 0x35, - 0xd2, 0x49, 0xf4, 0x18, 0xfc, 0x6a, 0xbf, 0x2d, 0xa8, 0x78, 0x4b, 0xb2, 0xda, 0xb1, 0x8d, 0xe3, - 0x9d, 0xa9, 0xd6, 0x26, 0x6b, 0xe8, 0xb5, 0x6f, 0x57, 0x7f, 0xd3, 0x7d, 0xb9, 0x4a, 0x06, 0x9d, - 0xe1, 0xfd, 0xcf, 0x5f, 0xc6, 0x6e, 0x8b, 0x15, 0xd2, 0x93, 0x57, 0xeb, 0x64, 0x60, 0xfd, 0x3f, - 0x51, 0x68, 0x68, 0x7f, 0xfa, 0x1a, 0x76, 0x96, 0xc1, 0xcf, 0x63, 0xd8, 0xf9, 0x7b, 0x0c, 0xad, - 0x8f, 0xa7, 0xd0, 0xfa, 0xae, 0xce, 0x0f, 0x75, 0x7e, 0xab, 0xb3, 0xbd, 0x35, 0x1b, 0x3f, 0xfd, - 0x17, 0x00, 0x00, 0xff, 0xff, 0xc5, 0x58, 0xc7, 0xbd, 0x6d, 0x02, 0x00, 0x00, + 0x14, 0x87, 0x9b, 0xdb, 0x70, 0x6f, 0x73, 0x72, 0x13, 0xae, 0x2c, 0x84, 0xa2, 0x0e, 0x69, 0xa9, + 0x84, 0x74, 0x07, 0x94, 0x2b, 0x95, 0xb1, 0x13, 0x6d, 0x19, 0xb2, 0xa0, 0xc8, 0xfc, 0x59, 0xa3, + 0xb4, 0x31, 0xc1, 0x6a, 0x88, 0x23, 0xdb, 0x2d, 0x2b, 0x23, 0xe2, 0x1d, 0x98, 0x78, 0x19, 0x26, + 0xc4, 0xc8, 0x84, 0x68, 0x57, 0x16, 0x1e, 0x01, 0xdb, 0x49, 0x5a, 0x21, 0x75, 0x38, 0x92, 0xf3, + 0xfd, 0xbe, 0xe3, 0x1c, 0x1f, 0x70, 0xb3, 0x82, 0x54, 0x32, 0xaa, 0x39, 0x93, 0x0c, 0x41, 0x49, + 0x57, 0x15, 0x91, 0x1f, 0x18, 0xdf, 0x0c, 0x1f, 0x14, 0xac, 0x60, 0x06, 0xdf, 0xe9, 0x53, 0x63, + 0x4c, 0xbe, 0x5f, 0x80, 0xff, 0xbc, 0xca, 0x6b, 0x46, 0x2b, 0x89, 0xc9, 0x9a, 0xf1, 0x1c, 0x21, + 0xb0, 0xab, 0xec, 0x3d, 0x09, 0xac, 0xb1, 0x75, 0xeb, 0x60, 0x73, 0x46, 0x8f, 0xe0, 0x5a, 0x10, + 0xbe, 0xa3, 0x6b, 0x92, 0x9a, 0xec, 0xc2, 0x64, 0x6e, 0xcb, 0x5e, 0x68, 0xe5, 0x09, 0x40, 0xa7, + 0xd0, 0x3c, 0xe8, 0x6b, 0x61, 0xee, 0x1d, 0x7e, 0x8d, 0x9c, 0x97, 0x0d, 0x8d, 0x97, 0xd8, 0x69, + 0x85, 0x38, 0xd7, 0xf6, 0x8e, 0x72, 0xb9, 0xcd, 0xca, 0x94, 0xd6, 0x81, 0x7d, 0xb2, 0xdf, 0x34, + 0x34, 0x4e, 0xb0, 0xd3, 0x0a, 0x71, 0x8d, 0xee, 0xc0, 0x25, 0xed, 0x90, 0x5a, 0xbf, 0x67, 0x74, + 0x5f, 0xe9, 0xd0, 0xcd, 0xae, 0x7c, 0xe8, 0x14, 0xd5, 0x30, 0x03, 0x8f, 0x56, 0x05, 0x27, 0x42, + 0xa4, 0x35, 0xe3, 0x52, 0x04, 0x97, 0xe3, 0xfe, 0xad, 0x3b, 0x7d, 0x18, 0x9d, 0x16, 0x12, 0x25, + 0x2a, 0x58, 0xb0, 0xea, 0x2d, 0x2d, 0xf0, 0x75, 0x2b, 0x6b, 0x24, 0x50, 0x00, 0x57, 0x59, 0x49, + 0x33, 0x41, 0x44, 0x70, 0xa5, 0xda, 0x1c, 0xdc, 0x7d, 0xea, 0x35, 0xc8, 0x4c, 0x6c, 0xd2, 0x2e, + 0x1e, 0x98, 0xd8, 0xd5, 0xec, 0x59, 0x83, 0x26, 0x7f, 0x2c, 0x80, 0xd3, 0xcd, 0x67, 0x97, 0x39, + 0x83, 0x81, 0x59, 0xfe, 0x9a, 0x95, 0x66, 0x91, 0xfe, 0x74, 0x74, 0x7e, 0xae, 0x28, 0x69, 0x35, + 0x7c, 0x6c, 0x40, 0x23, 0x50, 0xbf, 0xe3, 0x05, 0x91, 0xe6, 0x61, 0x66, 0xcf, 0x1e, 0x86, 0x06, + 0xe9, 0x4e, 0xf4, 0x18, 0xfc, 0x7a, 0xbb, 0x2a, 0xa9, 0x78, 0x47, 0xf2, 0xc6, 0xb1, 0x8d, 0xe3, + 0x1d, 0xa9, 0xd6, 0x26, 0x4b, 0x18, 0x74, 0xb7, 0xab, 0x07, 0xf7, 0x5f, 0x2d, 0x92, 0x9b, 0xde, + 0xf0, 0xfe, 0xe7, 0x2f, 0x63, 0xb7, 0xc3, 0x0a, 0xe9, 0xe4, 0xf5, 0x32, 0xb9, 0xb1, 0xfe, 0x4f, + 0x14, 0x1a, 0xda, 0x9f, 0xbe, 0x86, 0xbd, 0x79, 0xf0, 0x73, 0x1f, 0xf6, 0xfe, 0xee, 0x43, 0xeb, + 0xe3, 0x21, 0xb4, 0xbe, 0xa9, 0xfa, 0xa1, 0xea, 0xb7, 0xaa, 0xd5, 0xa5, 0x99, 0xf8, 0xe9, 0xbf, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x63, 0x1a, 0x0f, 0x90, 0x02, 0x00, 0x00, } diff --git a/agent.proto b/agent.proto index 2157ce40cd..0b7708e32b 100644 --- a/agent.proto +++ b/agent.proto @@ -34,6 +34,9 @@ message EndpointRecord { // A list of aliases which are alternate names for the service repeated string aliases = 7; + + // List of aliases task specific aliases + repeated string task_aliases = 8; } // PortConfig specifies an exposed port which can be From 51acb81d6fba10d6f1220be2dbfc56d0403f71b9 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Wed, 3 Aug 2016 05:29:32 -0700 Subject: [PATCH 022/799] Fix external DNS responses > 512 bytes getting dropped Signed-off-by: Santhosh Manohar --- resolver.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resolver.go b/resolver.go index e80eeccb41..8ba3860b70 100644 --- a/resolver.go +++ b/resolver.go @@ -361,7 +361,10 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { // Timeout has to be set for every IO operation. extConn.SetDeadline(time.Now().Add(extIOTimeout)) - co := &dns.Conn{Conn: extConn} + co := &dns.Conn{ + Conn: extConn, + UDPSize: uint16(maxSize), + } defer co.Close() // limits the number of outstanding concurrent queries. From 715bf563312caf67ece71e25c697395ebd1d8674 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Thu, 4 Aug 2016 14:20:54 -0700 Subject: [PATCH 023/799] Do not add ingress loadbalancer on service tasks Ingress loadbalancer is only required to be plumbed in ingress sandboxes of nodes which are the only mechanism to get traffix outside the cluster to tasks. Since the tasks are part of ingress network, these loadbalancers were getting added in all tasks which are exposing ports which is totally unnecessary resource usage. This PR avoids that. Signed-off-by: Jana Radhakrishnan --- service_linux.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/service_linux.go b/service_linux.go index 7c5fb6fc88..8ee105f60c 100644 --- a/service_linux.go +++ b/service_linux.go @@ -261,7 +261,7 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) { addService := true for _, ip := range lb.backEnds { sb.addLBBackend(ip, lb.vip, lb.fwMark, lb.service.ingressPorts, - eIP, gwIP, addService) + eIP, gwIP, addService, n.ingress) addService = false } lb.service.Unlock() @@ -284,7 +284,7 @@ func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po gwIP = ep.Iface().Address().IP } - sb.addLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, addService) + sb.addLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, addService, n.ingress) } return false @@ -307,7 +307,7 @@ func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Por gwIP = ep.Iface().Address().IP } - sb.rmLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, rmService) + sb.rmLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, rmService, n.ingress) } return false @@ -315,11 +315,15 @@ func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Por } // Add loadbalancer backend into one connected sandbox. -func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, gwIP net.IP, addService bool) { +func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, gwIP net.IP, addService bool, isIngressNetwork bool) { if sb.osSbox == nil { return } + if isIngressNetwork && !sb.ingress { + return + } + i, err := ipvs.New(sb.Key()) if err != nil { logrus.Errorf("Failed to create an ipvs handle for sbox %s: %v", sb.Key(), err) @@ -370,11 +374,15 @@ func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*P } // Remove loadbalancer backend from one connected sandbox. -func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, gwIP net.IP, rmService bool) { +func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, gwIP net.IP, rmService bool, isIngressNetwork bool) { if sb.osSbox == nil { return } + if isIngressNetwork && !sb.ingress { + return + } + i, err := ipvs.New(sb.Key()) if err != nil { logrus.Errorf("Failed to create an ipvs handle for sbox %s: %v", sb.Key(), err) From ceb7331ed91cbeac1108ed30d484120ffb666950 Mon Sep 17 00:00:00 2001 From: Matt Bajor Date: Thu, 4 Aug 2016 15:58:39 -0600 Subject: [PATCH 024/799] Fix typo in error message Signed-off-by: Matt Bajor --- drivers/overlay/peerdb.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/overlay/peerdb.go b/drivers/overlay/peerdb.go index 5c1afbf782..d6502c27cd 100644 --- a/drivers/overlay/peerdb.go +++ b/drivers/overlay/peerdb.go @@ -281,7 +281,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, // Add neighbor entry for the peer IP if err := sbox.AddNeighbor(peerIP, peerMac, sbox.NeighborOptions().LinkName(s.vxlanName)); err != nil { - return fmt.Errorf("could not add neigbor entry into the sandbox: %v", err) + return fmt.Errorf("could not add neighbor entry into the sandbox: %v", err) } // Add fdb entry to the bridge for the peer mac @@ -321,7 +321,7 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMas // Delete neighbor entry for the peer IP if err := sbox.DeleteNeighbor(peerIP, peerMac); err != nil { - return fmt.Errorf("could not delete neigbor entry into the sandbox: %v", err) + return fmt.Errorf("could not delete neighbor entry into the sandbox: %v", err) } if err := d.checkEncryption(nid, vtep, 0, false, false); err != nil { From 29c8a8775783b1d931cff2744232d6a3c1d4f112 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Thu, 4 Aug 2016 17:39:38 -0700 Subject: [PATCH 025/799] Make service LB work from self Make service loadbalancing to work from within one of the containers of the service. Currently this only works when the loadbalancer selects the current container. If another container of the same service is chosen, the connection times out. This fix adds a SNAT rule to change the source IP to the containers primary IP so that responses can be routed back to this container. Signed-off-by: Jana Radhakrishnan --- service_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_linux.go b/service_linux.go index 7c5fb6fc88..e0cf64bda9 100644 --- a/service_linux.go +++ b/service_linux.go @@ -710,7 +710,7 @@ func fwMarker() { os.Exit(4) } - if len(ingressPorts) != 0 && addDelOpt == "-A" { + if addDelOpt == "-A" { ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -j SNAT --to-source %s", os.Args[6])) if !iptables.Exists("nat", "POSTROUTING", ruleParams...) { rule := append(strings.Fields("-t nat -A POSTROUTING"), ruleParams...) From ab713a5fbd93fccfceb2ceb4399d7c9712c6abfb Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Wed, 3 Aug 2016 17:58:24 -0700 Subject: [PATCH 026/799] Remove unused key handling functions Signed-off-by: Santhosh Manohar --- agent.go | 82 --------------------------------------------------- controller.go | 18 +++++++++-- 2 files changed, 15 insertions(+), 85 deletions(-) diff --git a/agent.go b/agent.go index d33d00fa5d..7b68fd7c06 100644 --- a/agent.go +++ b/agent.go @@ -164,82 +164,6 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { return nil } -func (c *controller) handleKeyChangeV1(keys []*types.EncryptionKey) error { - drvEnc := discoverapi.DriverEncryptionUpdate{} - - // Find the new key and add it to the key ring - a := c.agent - for _, key := range keys { - same := false - for _, cKey := range c.keys { - if same = cKey.LamportTime == key.LamportTime; same { - break - } - } - if !same { - c.keys = append(c.keys, key) - if key.Subsystem == subsysGossip { - a.networkDB.SetKey(key.Key) - } - if key.Subsystem == subsysGossip /*subsysIPSec*/ { - drvEnc.Key = key.Key - drvEnc.Tag = key.LamportTime - } - break - } - } - // Find the deleted key. If the deleted key was the primary key, - // a new primary key should be set before removing if from keyring. - deleted := []byte{} - for i, cKey := range c.keys { - same := false - for _, key := range keys { - if same = key.LamportTime == cKey.LamportTime; same { - break - } - } - if !same { - if cKey.Subsystem == subsysGossip { - deleted = cKey.Key - } - if cKey.Subsystem == subsysGossip /*subsysIPSec*/ { - drvEnc.Prune = cKey.Key - drvEnc.PruneTag = cKey.LamportTime - } - c.keys = append(c.keys[:i], c.keys[i+1:]...) - break - } - } - - sort.Sort(ByTime(c.keys)) - for _, key := range c.keys { - if key.Subsystem == subsysGossip { - a.networkDB.SetPrimaryKey(key.Key) - break - } - } - for _, key := range c.keys { - if key.Subsystem == subsysGossip /*subsysIPSec*/ { - drvEnc.Primary = key.Key - drvEnc.PrimaryTag = key.LamportTime - break - } - } - if len(deleted) > 0 { - a.networkDB.RemoveKey(deleted) - } - - c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { - err := driver.DiscoverNew(discoverapi.EncryptionKeysUpdate, drvEnc) - if err != nil { - logrus.Warnf("Failed to update datapath keys in driver %s: %v", name, err) - } - return false - }) - - return nil -} - func (c *controller) agentSetup() error { clusterProvider := c.cfg.Daemon.ClusterProvider @@ -287,9 +211,6 @@ func (c *controller) getKeys(subsys string) ([][]byte, []uint64) { } } - if len(keys) < keyringSize { - return keys, tags - } keys[0], keys[1] = keys[1], keys[0] tags[0], tags[1] = tags[1], tags[0] return keys, tags @@ -305,9 +226,6 @@ func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64, error) { keys = append(keys, key) } } - if len(keys) < 2 { - return nil, 0, fmt.Errorf("primary key for subsystem %s not found", subsys) - } return keys[1].Key, keys[1].LamportTime, nil } diff --git a/controller.go b/controller.go index 912f7da941..382e64cdfb 100644 --- a/controller.go +++ b/controller.go @@ -250,6 +250,21 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error { clusterConfigAvailable := c.clusterConfigAvailable agent := c.agent c.Unlock() + + subsysKeys := make(map[string]int) + for _, key := range keys { + if key.Subsystem != subsysGossip && + key.Subsystem != subsysIPSec { + return fmt.Errorf("key received for unrecognized subsystem") + } + subsysKeys[key.Subsystem]++ + } + for s, count := range subsysKeys { + if count != keyringSize { + return fmt.Errorf("incorrect number of keys for susbsystem %v", s) + } + } + if len(existingKeys) == 0 { c.Lock() c.keys = keys @@ -269,9 +284,6 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error { c.Unlock() return nil } - if len(keys) < keyringSize { - return c.handleKeyChangeV1(keys) - } return c.handleKeyChange(keys) } From 203dd17115f3b5a1113f3e036466c0753f0225f9 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Fri, 5 Aug 2016 13:54:17 -0700 Subject: [PATCH 027/799] networkdb: fix data races in map access Signed-off-by: Alexander Morozov --- networkdb/delegate.go | 2 ++ networkdb/networkdb.go | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/networkdb/delegate.go b/networkdb/delegate.go index ebdea42533..a33ec58b6d 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -221,9 +221,11 @@ func (nDB *NetworkDB) handleBulkSync(buf []byte) { } var nodeAddr net.IP + nDB.RLock() if node, ok := nDB.nodes[bsm.NodeName]; ok { nodeAddr = node.Addr } + nDB.RUnlock() if err := nDB.bulkSyncNode(bsm.Networks, bsm.NodeName, false); err != nil { logrus.Errorf("Error in responding to bulk sync from node %s: %v", nodeAddr, err) diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 20bdc216ff..9859ab76d2 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -371,7 +371,10 @@ func (nDB *NetworkDB) JoinNetwork(nid string) error { nodeNetworks[nid] = &network{id: nid, ltime: ltime} nodeNetworks[nid].tableBroadcasts = &memberlist.TransmitLimitedQueue{ NumNodes: func() int { - return len(nDB.networkNodes[nid]) + nDB.RLock() + num := len(nDB.networkNodes[nid]) + nDB.RUnlock() + return num }, RetransmitMult: 4, } From e944b220c3696bc1db1ba96a910ae97c244a0822 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Fri, 5 Aug 2016 14:40:23 -0700 Subject: [PATCH 028/799] overlay: fix data race in map access Signed-off-by: Alexander Morozov --- drivers/overlay/ov_network.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/overlay/ov_network.go b/drivers/overlay/ov_network.go index bbd375cac3..78c8e8890e 100644 --- a/drivers/overlay/ov_network.go +++ b/drivers/overlay/ov_network.go @@ -664,17 +664,17 @@ func (d *driver) deleteNetwork(nid string) { func (d *driver) network(nid string) *network { d.Lock() - networks := d.networks + n, ok := d.networks[nid] d.Unlock() - - n, ok := networks[nid] if !ok { n = d.getNetworkFromStore(nid) if n != nil { n.driver = d n.endpoints = endpointTable{} n.once = &sync.Once{} - networks[nid] = n + d.Lock() + d.networks[nid] = n + d.Unlock() } } From 1fb56bcb555be54ed79b40973214df7ed6bc922f Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 8 Aug 2016 11:55:06 -0700 Subject: [PATCH 029/799] Fix spurious overlay errors Fixed certain spurious overlay errors which were not errors at all but showing up everytime service tasks are started in the engine. Also added a check to make sure a delete is valid by checking the incoming endpoint id wih the one in peerdb just to make sure if the delete from gossip is not stale. Signed-off-by: Jana Radhakrishnan --- agent.go | 5 ++++- drivers/overlay/ov_network.go | 4 ++++ drivers/overlay/peerdb.go | 20 +++++++++++++++++--- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/agent.go b/agent.go index d33d00fa5d..1f81be989f 100644 --- a/agent.go +++ b/agent.go @@ -550,7 +550,10 @@ func (n *network) addDriverWatches() { } c.agent.networkDB.WalkTable(tableName, func(nid, key string, value []byte) bool { - d.EventNotify(driverapi.Create, n.ID(), tableName, key, value) + if nid == n.ID() { + d.EventNotify(driverapi.Create, nid, tableName, key, value) + } + return false }) } diff --git a/drivers/overlay/ov_network.go b/drivers/overlay/ov_network.go index 78c8e8890e..4b4c0c417f 100644 --- a/drivers/overlay/ov_network.go +++ b/drivers/overlay/ov_network.go @@ -637,6 +637,10 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) { continue } + if !n.driver.isSerfAlive() { + continue + } + mac, IPmask, vtep, err := n.driver.resolvePeer(n.id, neigh.IP) if err != nil { logrus.Errorf("could not resolve peer %q: %v", neigh.IP, err) diff --git a/drivers/overlay/peerdb.go b/drivers/overlay/peerdb.go index 5c1afbf782..76d4dba1ed 100644 --- a/drivers/overlay/peerdb.go +++ b/drivers/overlay/peerdb.go @@ -168,14 +168,14 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask } func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, - peerMac net.HardwareAddr, vtep net.IP) { + peerMac net.HardwareAddr, vtep net.IP) bool { peerDbWg.Wait() d.peerDb.Lock() pMap, ok := d.peerDb.mp[nid] if !ok { d.peerDb.Unlock() - return + return false } d.peerDb.Unlock() @@ -185,8 +185,20 @@ func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPM } pMap.Lock() + + if pEntry, ok := pMap.mp[pKey.String()]; ok { + // Mismatched endpoint ID(possibly outdated). Do not + // delete peerdb + if pEntry.eid != eid { + pMap.Unlock() + return false + } + } + delete(pMap.mp, pKey.String()) pMap.Unlock() + + return true } func (d *driver) peerDbUpdateSandbox(nid string) { @@ -301,7 +313,9 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMas } if updateDb { - d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep) + if !d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep) { + return nil + } } n := d.network(nid) From 9ee9aa0947f77cf2c447da0af3e940666e87310e Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Wed, 10 Aug 2016 12:44:05 -0700 Subject: [PATCH 030/799] Cleanup networkdb state when the network is deleted locally Signed-off-by: Santhosh Manohar --- networkdb/cluster.go | 5 ++++- networkdb/delegate.go | 9 +++++++++ networkdb/networkdb.go | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 1424303e01..50661e1743 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -305,7 +305,10 @@ func (nDB *NetworkDB) gossip() { func (nDB *NetworkDB) bulkSyncTables() { var networks []string nDB.RLock() - for nid := range nDB.networks[nDB.config.NodeName] { + for nid, network := range nDB.networks[nDB.config.NodeName] { + if network.leaving { + continue + } networks = append(networks, nid) } nDB.RUnlock() diff --git a/networkdb/delegate.go b/networkdb/delegate.go index a33ec58b6d..98007516d4 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -75,6 +75,15 @@ func (nDB *NetworkDB) handleTableEvent(tEvent *TableEvent) bool { // time. nDB.tableClock.Witness(tEvent.LTime) + // Ignore the table events for networks that are in the process of going away + nDB.RLock() + networks := nDB.networks[nDB.config.NodeName] + network, ok := networks[tEvent.NetworkID] + nDB.RUnlock() + if !ok || network.leaving { + return true + } + if entry, err := nDB.getEntry(tEvent.TableName, tEvent.NetworkID, tEvent.Key); err == nil { // We have the latest state. Ignore the event // since it is stale. diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 9859ab76d2..f21e572e69 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -398,7 +398,8 @@ func (nDB *NetworkDB) JoinNetwork(nid string) error { // this event across the cluster. This triggers this node leaving the // sub-cluster of this network and as a result will no longer // participate in the network-scoped gossip and bulk sync for this -// network. +// network. Also remove all the table entries for this network from +// networkdb func (nDB *NetworkDB) LeaveNetwork(nid string) error { ltime := nDB.networkClock.Increment() if err := nDB.sendNetworkEvent(nid, NetworkEventTypeLeave, ltime); err != nil { @@ -407,6 +408,36 @@ func (nDB *NetworkDB) LeaveNetwork(nid string) error { nDB.Lock() defer nDB.Unlock() + var ( + paths []string + entries []*entry + ) + + nwWalker := func(path string, v interface{}) bool { + entry, ok := v.(*entry) + if !ok { + return false + } + paths = append(paths, path) + entries = append(entries, entry) + return false + } + + nDB.indexes[byNetwork].WalkPrefix(fmt.Sprintf("/%s", nid), nwWalker) + for _, path := range paths { + params := strings.Split(path[1:], "/") + tname := params[1] + key := params[2] + + if _, ok := nDB.indexes[byTable].Delete(fmt.Sprintf("/%s/%s/%s", tname, nid, key)); !ok { + logrus.Errorf("Could not delete entry in table %s with network id %s and key %s as it does not exist", tname, nid, key) + } + + if _, ok := nDB.indexes[byNetwork].Delete(fmt.Sprintf("/%s/%s/%s", nid, tname, key)); !ok { + logrus.Errorf("Could not delete entry in network %s with table name %s and key %s as it does not exist", nid, tname, key) + } + } + nodeNetworks, ok := nDB.networks[nDB.config.NodeName] if !ok { return fmt.Errorf("could not find self node for network %s while trying to leave", nid) From 23f61031f46987a44af00f23c0b3531497655a58 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Wed, 10 Aug 2016 17:44:33 -0700 Subject: [PATCH 031/799] For service name DNS resolution prioritize IP on user overlay network Signed-off-by: Santhosh Manohar --- sandbox.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/sandbox.go b/sandbox.go index a0667b46aa..ef082f2380 100644 --- a/sandbox.go +++ b/sandbox.go @@ -498,6 +498,38 @@ func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP, error) { return srv, ip, nil } +func getDynamicNwEndpoints(epList []*endpoint) []*endpoint { + eps := []*endpoint{} + for _, ep := range epList { + n := ep.getNetwork() + if n.dynamic && !n.ingress { + eps = append(eps, ep) + } + } + return eps +} + +func getIngressNwEndpoint(epList []*endpoint) *endpoint { + for _, ep := range epList { + n := ep.getNetwork() + if n.ingress { + return ep + } + } + return nil +} + +func getLocalNwEndpoints(epList []*endpoint) []*endpoint { + eps := []*endpoint{} + for _, ep := range epList { + n := ep.getNetwork() + if !n.dynamic && !n.ingress { + eps = append(eps, ep) + } + } + return eps +} + func (sb *sandbox) ResolveName(name string, ipType int) ([]net.IP, bool) { // Embedded server owns the docker network domain. Resolution should work // for both container_name and container_name.network_name @@ -528,6 +560,18 @@ func (sb *sandbox) ResolveName(name string, ipType int) ([]net.IP, bool) { } epList := sb.getConnectedEndpoints() + + // In swarm mode services with exposed ports are connected to user overlay + // network, ingress network and docker_gwbridge network. Name resolution + // should prioritize returning the VIP/IPs on user overlay network. + newList := []*endpoint{} + if !sb.controller.isDistributedControl() { + newList = append(newList, getDynamicNwEndpoints(epList)...) + newList = append(newList, getIngressNwEndpoint(epList)) + newList = append(newList, getLocalNwEndpoints(epList)...) + epList = newList + } + for i := 0; i < len(reqName); i++ { // First check for local container alias From f5c73b828132555385f4c8b167358555fd6c2b6e Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Thu, 11 Aug 2016 17:51:13 -0700 Subject: [PATCH 032/799] Fix a panic introduced by #1389 Signed-off-by: Santhosh Manohar --- sandbox.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sandbox.go b/sandbox.go index ef082f2380..8a659b038c 100644 --- a/sandbox.go +++ b/sandbox.go @@ -567,7 +567,10 @@ func (sb *sandbox) ResolveName(name string, ipType int) ([]net.IP, bool) { newList := []*endpoint{} if !sb.controller.isDistributedControl() { newList = append(newList, getDynamicNwEndpoints(epList)...) - newList = append(newList, getIngressNwEndpoint(epList)) + ingressEP := getIngressNwEndpoint(epList) + if ingressEP != nil { + newList = append(newList, ingressEP) + } newList = append(newList, getLocalNwEndpoints(epList)...) epList = newList } From 321f0bc2a50cbb79868d46a831fce8ceb62a13b6 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Fri, 12 Aug 2016 15:40:39 -0700 Subject: [PATCH 033/799] Relax SRV name validation and fix external SRV query handling Signed-off-by: Santhosh Manohar --- libnetwork_internal_test.go | 8 ++++---- resolver.go | 3 +++ sandbox.go | 8 ++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/libnetwork_internal_test.go b/libnetwork_internal_test.go index 000ba7e5e6..9eb7f6bab5 100644 --- a/libnetwork_internal_test.go +++ b/libnetwork_internal_test.go @@ -411,10 +411,10 @@ func TestSRVServiceQuery(t *testing.T) { t.Fatal(err) } - // Try resolving a service name with invalid protocol, should fail.. - _, _, err = ep.Info().Sandbox().ResolveService("_http._icmp.web.swarm") - if err == nil { - t.Fatal(err) + // Service name with invalid protocol name. Should fail without error + _, ip, err = ep.Info().Sandbox().ResolveService("_http._icmp.web.swarm") + if len(ip) != 0 { + t.Fatal("Valid response for invalid service name") } } diff --git a/resolver.go b/resolver.go index 8ba3860b70..b9eb4f3ff2 100644 --- a/resolver.go +++ b/resolver.go @@ -255,6 +255,9 @@ func (r *resolver) handleSRVQuery(svc string, query *dns.Msg) (*dns.Msg, error) if err != nil { return nil, err } + if len(srv) == 0 { + return nil, nil + } if len(srv) != len(ip) { return nil, fmt.Errorf("invalid reply for SRV query %s", svc) } diff --git a/sandbox.go b/sandbox.go index 8a659b038c..52e9bb6783 100644 --- a/sandbox.go +++ b/sandbox.go @@ -444,16 +444,16 @@ func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP, error) { log.Debugf("Service name To resolve: %v", name) + // There are DNS implementaions that allow SRV queries for names not in + // the format defined by RFC 2782. Hence specific validations checks are + // not done parts := strings.Split(name, ".") if len(parts) < 3 { - return nil, nil, fmt.Errorf("invalid service name, %s", name) + return nil, nil, nil } portName := parts[0] proto := parts[1] - if proto != "_tcp" && proto != "_udp" { - return nil, nil, fmt.Errorf("invalid protocol in service, %s", name) - } svcName := strings.Join(parts[2:], ".") for _, ep := range sb.getConnectedEndpoints() { From 7ae81d04edc021b2badcf82017484acb67b56701 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Mon, 15 Aug 2016 13:59:12 -0700 Subject: [PATCH 034/799] network: fix race in read access to map Signed-off-by: Alexander Morozov --- network.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network.go b/network.go index 5c83bef903..ffdc232486 100644 --- a/network.go +++ b/network.go @@ -1110,8 +1110,8 @@ func (n *network) getSvcRecords(ep *endpoint) []etchosts.Record { epName := ep.Name() n.ctrlr.Lock() + defer n.ctrlr.Unlock() sr, _ := n.ctrlr.svcRecords[n.id] - n.ctrlr.Unlock() for h, ip := range sr.svcMap { if strings.Split(h, ".")[0] == epName { From 52c022a556db883e638828b2286803a6eae1510c Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 15 Aug 2016 15:38:14 -0700 Subject: [PATCH 035/799] Add a narrower SNAT rule for LB egress The SNAT rules added for LB egress is broader and breaks load balancing if the service is connected to multiple networks. Make it conditional based on the subnet to which the network belongs so that the right SNAT rule gets matched when egressing the corresponding network. Signed-off-by: Jana Radhakrishnan --- service_linux.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/service_linux.go b/service_linux.go index 337d325207..9dc27f5578 100644 --- a/service_linux.go +++ b/service_linux.go @@ -647,7 +647,7 @@ func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*Port cmd := &exec.Cmd{ Path: reexec.Self(), - Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, eIP.IP.String()), + Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, eIP.String()), Stdout: os.Stdout, Stderr: os.Stderr, } @@ -719,7 +719,13 @@ func fwMarker() { } if addDelOpt == "-A" { - ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -j SNAT --to-source %s", os.Args[6])) + eIP, subnet, err := net.ParseCIDR(os.Args[6]) + if err != nil { + logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[6], err) + os.Exit(9) + } + + ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -d %s -j SNAT --to-source %s", subnet, eIP)) if !iptables.Exists("nat", "POSTROUTING", ruleParams...) { rule := append(strings.Fields("-t nat -A POSTROUTING"), ruleParams...) rules = append(rules, rule) From acd4edd197b9693b2beb61078b8aa0ddc9fa45a2 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 16 Aug 2016 17:37:33 -0700 Subject: [PATCH 036/799] Reset the encryption keys on swarm leave Signed-off-by: Santhosh Manohar --- agent.go | 3 +++ controller.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/agent.go b/agent.go index 5a7e028cd6..3265add3cb 100644 --- a/agent.go +++ b/agent.go @@ -328,7 +328,10 @@ func (c *controller) agentClose() { c.agent.epTblCancel() c.agent.networkDB.Close() + + c.Lock() c.agent = nil + c.Unlock() } func (n *network) isClusterEligible() bool { diff --git a/controller.go b/controller.go index f7997b94c9..3d7382bd36 100644 --- a/controller.go +++ b/controller.go @@ -307,13 +307,16 @@ func (c *controller) clusterAgentInit() { c.Lock() c.clusterConfigAvailable = false c.agentInitDone = make(chan struct{}) + c.keys = nil c.Unlock() if err := c.ingressSandbox.Delete(); err != nil { log.Warnf("Could not delete ingress sandbox while leaving: %v", err) } + c.Lock() c.ingressSandbox = nil + c.Unlock() n, err := c.NetworkByName("ingress") if err != nil { From 8e5e80f9f52d83a5db7314e30eca5210b08a4828 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 17 Aug 2016 13:48:51 -0700 Subject: [PATCH 037/799] Cleanup ingress network and sandbox on leave When a node leaves the swarm cluster, we should cleanup the ingress network and sandbox. This makes sure that when the next time the node joins the swarm it will be able to update the cluster with the right information. Signed-off-by: Jana Radhakrishnan --- controller.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/controller.go b/controller.go index 382e64cdfb..f7997b94c9 100644 --- a/controller.go +++ b/controller.go @@ -308,6 +308,24 @@ func (c *controller) clusterAgentInit() { c.clusterConfigAvailable = false c.agentInitDone = make(chan struct{}) c.Unlock() + + if err := c.ingressSandbox.Delete(); err != nil { + log.Warnf("Could not delete ingress sandbox while leaving: %v", err) + } + + c.ingressSandbox = nil + + n, err := c.NetworkByName("ingress") + if err != nil { + log.Warnf("Could not find ingress network while leaving: %v", err) + } + + if n != nil { + if err := n.Delete(); err != nil { + log.Warnf("Could not delete ingress network while leaving: %v", err) + } + } + c.agentClose() return } From dd3b13182af73152e0adb098242f5a063aae3671 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Thu, 18 Aug 2016 13:57:24 -0700 Subject: [PATCH 038/799] Ignore delete events for non-existent entries In networkdb we should ignore delete events for entries which doesn't exist in the db. This is always true because if the entry did not exist then the entry has been removed way earlier and got purged after the reap timer and this notification is very stale. Also there were duplicate delete notifications being sent to the clients. One when the actual delete event was received from gossip and later when the entry was getting reaped. The second notification is unnecessary and may cause issues with the clients if they are not coded for idempotency. Signed-off-by: Jana Radhakrishnan --- networkdb/cluster.go | 11 ++--------- networkdb/delegate.go | 20 +++++++++++++------- networkdb/networkdb.go | 2 ++ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 50661e1743..17563589dc 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -200,10 +200,7 @@ func (nDB *NetworkDB) reapNetworks() { } func (nDB *NetworkDB) reapTableEntries() { - var ( - paths []string - entries []*entry - ) + var paths []string now := time.Now() @@ -219,14 +216,12 @@ func (nDB *NetworkDB) reapTableEntries() { } paths = append(paths, path) - entries = append(entries, entry) return false }) nDB.RUnlock() nDB.Lock() - for i, path := range paths { - entry := entries[i] + for _, path := range paths { params := strings.Split(path[1:], "/") tname := params[0] nid := params[1] @@ -239,8 +234,6 @@ func (nDB *NetworkDB) reapTableEntries() { if _, ok := nDB.indexes[byNetwork].Delete(fmt.Sprintf("/%s/%s/%s", nid, tname, key)); !ok { logrus.Errorf("Could not delete entry in network %s with table name %s and key %s as it does not exist", nid, tname, key) } - - nDB.broadcaster.Write(makeEvent(opDelete, tname, nid, key, entry.value)) } nDB.Unlock() } diff --git a/networkdb/delegate.go b/networkdb/delegate.go index 98007516d4..e2fb6e8528 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -84,28 +84,34 @@ func (nDB *NetworkDB) handleTableEvent(tEvent *TableEvent) bool { return true } - if entry, err := nDB.getEntry(tEvent.TableName, tEvent.NetworkID, tEvent.Key); err == nil { + e, err := nDB.getEntry(tEvent.TableName, tEvent.NetworkID, tEvent.Key) + if err != nil && tEvent.Type == TableEventTypeDelete { + // If it is a delete event and we don't have the entry here nothing to do. + return false + } + + if err == nil { // We have the latest state. Ignore the event // since it is stale. - if entry.ltime >= tEvent.LTime { + if e.ltime >= tEvent.LTime { return false } } - entry := &entry{ + e = &entry{ ltime: tEvent.LTime, node: tEvent.NodeName, value: tEvent.Value, deleting: tEvent.Type == TableEventTypeDelete, } - if entry.deleting { - entry.deleteTime = time.Now() + if e.deleting { + e.deleteTime = time.Now() } nDB.Lock() - nDB.indexes[byTable].Insert(fmt.Sprintf("/%s/%s/%s", tEvent.TableName, tEvent.NetworkID, tEvent.Key), entry) - nDB.indexes[byNetwork].Insert(fmt.Sprintf("/%s/%s/%s", tEvent.NetworkID, tEvent.TableName, tEvent.Key), entry) + nDB.indexes[byTable].Insert(fmt.Sprintf("/%s/%s/%s", tEvent.TableName, tEvent.NetworkID, tEvent.Key), e) + nDB.indexes[byNetwork].Insert(fmt.Sprintf("/%s/%s/%s", tEvent.NetworkID, tEvent.TableName, tEvent.Key), e) nDB.Unlock() var op opType diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index f21e572e69..2597f898c5 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -326,6 +326,8 @@ func (nDB *NetworkDB) deleteNodeTableEntries(node string) { nDB.indexes[byTable].Insert(fmt.Sprintf("/%s/%s/%s", tname, nid, key), entry) nDB.indexes[byNetwork].Insert(fmt.Sprintf("/%s/%s/%s", nid, tname, key), entry) + + nDB.broadcaster.Write(makeEvent(opDelete, tname, nid, key, entry.value)) return false }) nDB.Unlock() From 0a5280df926bdb7b4483e0d1aacc10dff5417c75 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Fri, 19 Aug 2016 17:18:15 -0700 Subject: [PATCH 039/799] Ensure add newly joined node to networknodes In cases a node left the cluster and quickly rejoined before the node entry is expired by other nodes in the cluster, when the node rejoins we fail to add it to the quick lookup database. Fixed it. Signed-off-by: Jana Radhakrishnan --- networkdb/delegate.go | 3 ++- networkdb/networkdb.go | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/networkdb/delegate.go b/networkdb/delegate.go index 98007516d4..c306e0366d 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -53,6 +53,7 @@ func (nDB *NetworkDB) handleNetworkEvent(nEvent *NetworkEvent) bool { n.leaveTime = time.Now() } + nDB.addNetworkNode(nEvent.NetworkID, nEvent.NodeName) return true } @@ -66,7 +67,7 @@ func (nDB *NetworkDB) handleNetworkEvent(nEvent *NetworkEvent) bool { ltime: nEvent.LTime, } - nDB.networkNodes[nEvent.NetworkID] = append(nDB.networkNodes[nEvent.NetworkID], nEvent.NodeName) + nDB.addNetworkNode(nEvent.NetworkID, nEvent.NodeName) return true } diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index f21e572e69..a7aa9bd299 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -453,6 +453,20 @@ func (nDB *NetworkDB) LeaveNetwork(nid string) error { return nil } +// addNetworkNode adds the node to the list of nodes which participate +// in the passed network only if it is not already present. Caller +// should hold the NetworkDB lock while calling this +func (nDB *NetworkDB) addNetworkNode(nid string, nodeName string) { + nodes := nDB.networkNodes[nid] + for _, node := range nodes { + if node == nodeName { + return + } + } + + nDB.networkNodes[nid] = append(nDB.networkNodes[nid], nodeName) +} + // Deletes the node from the list of nodes which participate in the // passed network. Caller should hold the NetworkDB lock while calling // this From c98780f0d1d3c6ef267c59614aeb73e03a3b96f3 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Fri, 19 Aug 2016 17:57:58 -0700 Subject: [PATCH 040/799] Notify agentInitDone after joining the cluster Currently the initDone notification is provided immediately after initializing the cluster. This may be fine for the first manager. But for all subsequent nodes which join the cluster we need to wait until the node completes the joining to the gossip cluster inorder to synchronize the gossip network clock with other nodes. If we don't have uptodate clock the updates that this node provides to the cluster may be discarded by the other nodes if they have entries which are yet to be reaped but have a better clock. Signed-off-by: Jana Radhakrishnan --- agent.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/agent.go b/agent.go index 3265add3cb..499e2d5221 100644 --- a/agent.go +++ b/agent.go @@ -183,17 +183,20 @@ func (c *controller) agentSetup() error { } return false }) - - if c.agent != nil { - close(c.agentInitDone) - } } } + if remoteAddr != "" { if err := c.agentJoin(remoteAddr); err != nil { logrus.Errorf("Error in agentJoin : %v", err) + return nil } } + + if c.agent != nil { + close(c.agentInitDone) + } + return nil } From 0bd51967b86bde1a9041d4882f4780a5aa5b1606 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Fri, 19 Aug 2016 17:50:37 -0700 Subject: [PATCH 041/799] Cleanup service bindings when leaving cluster When leaving the entire gossip cluster or when leaving a network specific gossip cluster, we may not have had a chance to cleanup service bindings by way of gossip updates due to premature closure of gossip channel. Make sure to cleanup all service bindings since we are not participating in the cluster any more. Signed-off-by: Jana Radhakrishnan --- controller.go | 11 ++++++++++- network.go | 19 +++++++++++++------ service.go | 3 +++ service_linux.go | 41 +++++++++++++++++++++++++++++++++++++++-- service_unsupported.go | 3 +++ 5 files changed, 68 insertions(+), 9 deletions(-) diff --git a/controller.go b/controller.go index 3d7382bd36..b1094a3b95 100644 --- a/controller.go +++ b/controller.go @@ -310,6 +310,16 @@ func (c *controller) clusterAgentInit() { c.keys = nil c.Unlock() + // We are leaving the cluster. Make sure we + // close the gossip so that we stop all + // incoming gossip updates before cleaning up + // any remaining service bindings. But before + // deleting the networks since the networks + // should still be present when cleaning up + // service bindings + c.agentClose() + c.cleanupServiceBindings("") + if err := c.ingressSandbox.Delete(); err != nil { log.Warnf("Could not delete ingress sandbox while leaving: %v", err) } @@ -329,7 +339,6 @@ func (c *controller) clusterAgentInit() { } } - c.agentClose() return } } diff --git a/network.go b/network.go index ffdc232486..8c5cdf1d3f 100644 --- a/network.go +++ b/network.go @@ -756,6 +756,19 @@ func (n *network) delete(force bool) error { log.Warnf("Failed to update store after ipam release for network %s (%s): %v", n.Name(), n.ID(), err) } + // We are about to delete the network. Leave the gossip + // cluster for the network to stop all incoming network + // specific gossip updates before cleaning up all the service + // bindings for the network. But cleanup service binding + // before deleting the network from the store since service + // bindings cleanup requires the network in the store. + n.cancelDriverWatches() + if err = n.leaveCluster(); err != nil { + log.Errorf("Failed leaving network %s from the agent cluster: %v", n.Name(), err) + } + + c.cleanupServiceBindings(n.ID()) + // deleteFromStore performs an atomic delete operation and the // network.epCnt will help prevent any possible // race between endpoint join and network delete @@ -770,12 +783,6 @@ func (n *network) delete(force bool) error { return fmt.Errorf("error deleting network from store: %v", err) } - n.cancelDriverWatches() - - if err = n.leaveCluster(); err != nil { - log.Errorf("Failed leaving network %s from the agent cluster: %v", n.Name(), err) - } - return nil } diff --git a/service.go b/service.go index 30a17c5056..a957026b2f 100644 --- a/service.go +++ b/service.go @@ -45,6 +45,9 @@ type service struct { // List of ingress ports exposed by the service ingressPorts portConfigs + // Service aliases + aliases []string + sync.Mutex } diff --git a/service_linux.go b/service_linux.go index 9dc27f5578..ec47a51f0f 100644 --- a/service_linux.go +++ b/service_linux.go @@ -28,15 +28,52 @@ func init() { reexec.Register("fwmarker", fwMarker) } -func newService(name string, id string, ingressPorts []*PortConfig) *service { +func newService(name string, id string, ingressPorts []*PortConfig, aliases []string) *service { return &service{ name: name, id: id, ingressPorts: ingressPorts, loadBalancers: make(map[string]*loadBalancer), + aliases: aliases, } } +func (c *controller) cleanupServiceBindings(cleanupNID string) { + var cleanupFuncs []func() + c.Lock() + for _, s := range c.serviceBindings { + s.Lock() + for nid, lb := range s.loadBalancers { + if cleanupNID != "" && nid != cleanupNID { + continue + } + + for eid, ip := range lb.backEnds { + service := s + loadBalancer := lb + networkID := nid + epID := eid + epIP := ip + + cleanupFuncs = append(cleanupFuncs, func() { + if err := c.rmServiceBinding(service.name, service.id, networkID, epID, loadBalancer.vip, + service.ingressPorts, service.aliases, epIP); err != nil { + logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v", + service.id, networkID, epID, err) + } + }) + } + } + s.Unlock() + } + c.Unlock() + + for _, f := range cleanupFuncs { + f() + } + +} + func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error { var ( s *service @@ -58,7 +95,7 @@ func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, i if !ok { // Create a new service if we are seeing this service // for the first time. - s = newService(name, sid, ingressPorts) + s = newService(name, sid, ingressPorts, aliases) c.serviceBindings[skey] = s } c.Unlock() diff --git a/service_unsupported.go b/service_unsupported.go index 9668dcc07e..9f91b4e4f5 100644 --- a/service_unsupported.go +++ b/service_unsupported.go @@ -7,6 +7,9 @@ import ( "net" ) +func (c *controller) cleanupServiceBindings(nid string) { +} + func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error { return fmt.Errorf("not supported") } From bb736c4c7851711a30c80454d90062a02d806b66 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Sun, 21 Aug 2016 15:52:40 -0700 Subject: [PATCH 042/799] Propage the vxlan device creation error in driver to libnetwork Signed-off-by: Santhosh Manohar --- drivers/overlay/ov_network.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/overlay/ov_network.go b/drivers/overlay/ov_network.go index 4b4c0c417f..b5af0f4b04 100644 --- a/drivers/overlay/ov_network.go +++ b/drivers/overlay/ov_network.go @@ -500,9 +500,13 @@ func (n *network) initSubnetSandbox(s *subnet, restore bool) error { vxlanName := n.generateVxlanName(s) if restore { - n.restoreSubnetSandbox(s, brName, vxlanName) + if err := n.restoreSubnetSandbox(s, brName, vxlanName); err != nil { + return err + } } else { - n.setupSubnetSandbox(s, brName, vxlanName) + if err := n.setupSubnetSandbox(s, brName, vxlanName); err != nil { + return err + } } n.Lock() From 9c78843130f09dc8f7193ab84f7ec64b12d7950a Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 22 Aug 2016 18:35:53 -0700 Subject: [PATCH 043/799] Updated godeps Signed-off-by: Jana Radhakrishnan --- Godeps/Godeps.json | 26 +- .../docker/docker/pkg/proxy/proxy.go | 37 --- .../docker/docker/pkg/proxy/stub_proxy.go | 31 -- .../docker/docker/pkg/proxy/tcp_proxy.go | 99 ------ .../docker/docker/pkg/proxy/udp_proxy.go | 169 ---------- .../src/github.com/docker/engine-api/LICENSE | 191 +++++++++++ .../docker/engine-api/types/filters/parse.go | 307 ++++++++++++++++++ .../engine-api/types/network/network.go | 53 +++ .../engine-api/types/versions/README.md | 14 + .../engine-api/types/versions/compare.go | 62 ++++ .../mattn/go-shellwords/.travis.yml | 8 + .../github.com/mattn/go-shellwords/README.md | 47 +++ .../mattn/go-shellwords/shellwords.go | 134 ++++++++ .../mattn/go-shellwords/util_posix.go | 19 ++ .../mattn/go-shellwords/util_windows.go | 17 + 15 files changed, 872 insertions(+), 342 deletions(-) delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/proxy.go delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/stub_proxy.go delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/tcp_proxy.go delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/udp_proxy.go create mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/LICENSE create mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go create mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/types/network/network.go create mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/types/versions/README.md create mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/types/versions/compare.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 892b3a2a26..10bca97a7c 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,7 +1,6 @@ { "ImportPath": "github.com/docker/libnetwork", "GoVersion": "go1.5", - "GodepVersion": "v74", "Packages": [ "./..." ], @@ -136,11 +135,6 @@ "Comment": "v1.4.1-11716-g24076ed", "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" }, - { - "ImportPath": "github.com/docker/docker/pkg/proxy", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" - }, { "ImportPath": "github.com/docker/docker/pkg/random", "Comment": "v1.4.1-11716-g24076ed", @@ -186,6 +180,21 @@ "Comment": "v1.4.1-11716-g24076ed", "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" }, + { + "ImportPath": "github.com/docker/engine-api/types/filters", + "Comment": "v0.3.1-210-g25941ec", + "Rev": "25941ecf6e8351810e8530c60de8dda7d5e1baba" + }, + { + "ImportPath": "github.com/docker/engine-api/types/network", + "Comment": "v0.3.1-210-g25941ec", + "Rev": "25941ecf6e8351810e8530c60de8dda7d5e1baba" + }, + { + "ImportPath": "github.com/docker/engine-api/types/versions", + "Comment": "v0.3.1-210-g25941ec", + "Rev": "25941ecf6e8351810e8530c60de8dda7d5e1baba" + }, { "ImportPath": "github.com/docker/go-connections/sockets", "Comment": "v0.2.0", @@ -294,6 +303,11 @@ "Comment": "v0.7.0-47-g598c548", "Rev": "598c54895cc5a7b1a24a398d635e8c0ea0959870" }, + { + "ImportPath": "github.com/mattn/go-shellwords", + "Comment": "v1.0.0-1-g525bede", + "Rev": "525bedee691b5a8df547cb5cf9f86b7fb1883e24" + }, { "ImportPath": "github.com/miekg/dns", "Rev": "d27455715200c7d3e321a1e5cadb27c9ee0b0f02" diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/proxy.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/proxy.go deleted file mode 100644 index 4e24e5f6a8..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/proxy.go +++ /dev/null @@ -1,37 +0,0 @@ -// Package proxy provides a network Proxy interface and implementations for TCP -// and UDP. -package proxy - -import ( - "fmt" - "net" -) - -// Proxy defines the behavior of a proxy. It forwards traffic back and forth -// between two endpoints : the frontend and the backend. -// It can be used to do software port-mapping between two addresses. -// e.g. forward all traffic between the frontend (host) 127.0.0.1:3000 -// to the backend (container) at 172.17.42.108:4000. -type Proxy interface { - // Run starts forwarding traffic back and forth between the front - // and back-end addresses. - Run() - // Close stops forwarding traffic and close both ends of the Proxy. - Close() - // FrontendAddr returns the address on which the proxy is listening. - FrontendAddr() net.Addr - // BackendAddr returns the proxied address. - BackendAddr() net.Addr -} - -// NewProxy creates a Proxy according to the specified frontendAddr and backendAddr. -func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) { - switch frontendAddr.(type) { - case *net.UDPAddr: - return NewUDPProxy(frontendAddr.(*net.UDPAddr), backendAddr.(*net.UDPAddr)) - case *net.TCPAddr: - return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr)) - default: - panic(fmt.Errorf("Unsupported protocol")) - } -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/stub_proxy.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/stub_proxy.go deleted file mode 100644 index 571749e467..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/stub_proxy.go +++ /dev/null @@ -1,31 +0,0 @@ -package proxy - -import ( - "net" -) - -// StubProxy is a proxy that is a stub (does nothing). -type StubProxy struct { - frontendAddr net.Addr - backendAddr net.Addr -} - -// Run does nothing. -func (p *StubProxy) Run() {} - -// Close does nothing. -func (p *StubProxy) Close() {} - -// FrontendAddr returns the frontend address. -func (p *StubProxy) FrontendAddr() net.Addr { return p.frontendAddr } - -// BackendAddr returns the backend address. -func (p *StubProxy) BackendAddr() net.Addr { return p.backendAddr } - -// NewStubProxy creates a new StubProxy -func NewStubProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) { - return &StubProxy{ - frontendAddr: frontendAddr, - backendAddr: backendAddr, - }, nil -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/tcp_proxy.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/tcp_proxy.go deleted file mode 100644 index 3cd742af76..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/tcp_proxy.go +++ /dev/null @@ -1,99 +0,0 @@ -package proxy - -import ( - "io" - "net" - "syscall" - - "github.com/Sirupsen/logrus" -) - -// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to -// handle TCP traffic forwarding between the frontend and backend addresses. -type TCPProxy struct { - listener *net.TCPListener - frontendAddr *net.TCPAddr - backendAddr *net.TCPAddr -} - -// NewTCPProxy creates a new TCPProxy. -func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) { - listener, err := net.ListenTCP("tcp", frontendAddr) - if err != nil { - return nil, err - } - // If the port in frontendAddr was 0 then ListenTCP will have a picked - // a port to listen on, hence the call to Addr to get that actual port: - return &TCPProxy{ - listener: listener, - frontendAddr: listener.Addr().(*net.TCPAddr), - backendAddr: backendAddr, - }, nil -} - -func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) { - backend, err := net.DialTCP("tcp", nil, proxy.backendAddr) - if err != nil { - logrus.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err) - client.Close() - return - } - - event := make(chan int64) - var broker = func(to, from *net.TCPConn) { - written, err := io.Copy(to, from) - if err != nil { - // If the socket we are writing to is shutdown with - // SHUT_WR, forward it to the other end of the pipe: - if err, ok := err.(*net.OpError); ok && err.Err == syscall.EPIPE { - from.CloseWrite() - } - } - to.CloseRead() - event <- written - } - - go broker(client, backend) - go broker(backend, client) - - var transferred int64 - for i := 0; i < 2; i++ { - select { - case written := <-event: - transferred += written - case <-quit: - // Interrupt the two brokers and "join" them. - client.Close() - backend.Close() - for ; i < 2; i++ { - transferred += <-event - } - return - } - } - client.Close() - backend.Close() -} - -// Run starts forwarding the traffic using TCP. -func (proxy *TCPProxy) Run() { - quit := make(chan bool) - defer close(quit) - for { - client, err := proxy.listener.Accept() - if err != nil { - logrus.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) - return - } - go proxy.clientLoop(client.(*net.TCPConn), quit) - } -} - -// Close stops forwarding the traffic. -func (proxy *TCPProxy) Close() { proxy.listener.Close() } - -// FrontendAddr returns the TCP address on which the proxy is listening. -func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr } - -// BackendAddr returns the TCP proxied address. -func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/udp_proxy.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/udp_proxy.go deleted file mode 100644 index b8375c374f..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/udp_proxy.go +++ /dev/null @@ -1,169 +0,0 @@ -package proxy - -import ( - "encoding/binary" - "net" - "strings" - "sync" - "syscall" - "time" - - "github.com/Sirupsen/logrus" -) - -const ( - // UDPConnTrackTimeout is the timeout used for UDP connection tracking - UDPConnTrackTimeout = 90 * time.Second - // UDPBufSize is the buffer size for the UDP proxy - UDPBufSize = 65507 -) - -// A net.Addr where the IP is split into two fields so you can use it as a key -// in a map: -type connTrackKey struct { - IPHigh uint64 - IPLow uint64 - Port int -} - -func newConnTrackKey(addr *net.UDPAddr) *connTrackKey { - if len(addr.IP) == net.IPv4len { - return &connTrackKey{ - IPHigh: 0, - IPLow: uint64(binary.BigEndian.Uint32(addr.IP)), - Port: addr.Port, - } - } - return &connTrackKey{ - IPHigh: binary.BigEndian.Uint64(addr.IP[:8]), - IPLow: binary.BigEndian.Uint64(addr.IP[8:]), - Port: addr.Port, - } -} - -type connTrackMap map[connTrackKey]*net.UDPConn - -// UDPProxy is proxy for which handles UDP datagrams. It implements the Proxy -// interface to handle UDP traffic forwarding between the frontend and backend -// addresses. -type UDPProxy struct { - listener *net.UDPConn - frontendAddr *net.UDPAddr - backendAddr *net.UDPAddr - connTrackTable connTrackMap - connTrackLock sync.Mutex -} - -// NewUDPProxy creates a new UDPProxy. -func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) { - listener, err := net.ListenUDP("udp", frontendAddr) - if err != nil { - return nil, err - } - return &UDPProxy{ - listener: listener, - frontendAddr: listener.LocalAddr().(*net.UDPAddr), - backendAddr: backendAddr, - connTrackTable: make(connTrackMap), - }, nil -} - -func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) { - defer func() { - proxy.connTrackLock.Lock() - delete(proxy.connTrackTable, *clientKey) - proxy.connTrackLock.Unlock() - proxyConn.Close() - }() - - readBuf := make([]byte, UDPBufSize) - for { - proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout)) - again: - read, err := proxyConn.Read(readBuf) - if err != nil { - if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED { - // This will happen if the last write failed - // (e.g: nothing is actually listening on the - // proxied port on the container), ignore it - // and continue until UDPConnTrackTimeout - // expires: - goto again - } - return - } - for i := 0; i != read; { - written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr) - if err != nil { - return - } - i += written - } - } -} - -// Run starts forwarding the traffic using UDP. -func (proxy *UDPProxy) Run() { - readBuf := make([]byte, UDPBufSize) - for { - read, from, err := proxy.listener.ReadFromUDP(readBuf) - if err != nil { - // NOTE: Apparently ReadFrom doesn't return - // ECONNREFUSED like Read do (see comment in - // UDPProxy.replyLoop) - if !isClosedError(err) { - logrus.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) - } - break - } - - fromKey := newConnTrackKey(from) - proxy.connTrackLock.Lock() - proxyConn, hit := proxy.connTrackTable[*fromKey] - if !hit { - proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr) - if err != nil { - logrus.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) - proxy.connTrackLock.Unlock() - continue - } - proxy.connTrackTable[*fromKey] = proxyConn - go proxy.replyLoop(proxyConn, from, fromKey) - } - proxy.connTrackLock.Unlock() - for i := 0; i != read; { - written, err := proxyConn.Write(readBuf[i:read]) - if err != nil { - logrus.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) - break - } - i += written - } - } -} - -// Close stops forwarding the traffic. -func (proxy *UDPProxy) Close() { - proxy.listener.Close() - proxy.connTrackLock.Lock() - defer proxy.connTrackLock.Unlock() - for _, conn := range proxy.connTrackTable { - conn.Close() - } -} - -// FrontendAddr returns the UDP address on which the proxy is listening. -func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr } - -// BackendAddr returns the proxied UDP address. -func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr } - -func isClosedError(err error) bool { - /* This comparison is ugly, but unfortunately, net.go doesn't export errClosing. - * See: - * http://golang.org/src/pkg/net/net.go - * https://code.google.com/p/go/issues/detail?id=4337 - * https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ - */ - return strings.HasSuffix(err.Error(), "use of closed network connection") -} diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/LICENSE b/Godeps/_workspace/src/github.com/docker/engine-api/LICENSE new file mode 100644 index 0000000000..c157bff96a --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/engine-api/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 2015-2016 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/Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go b/Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go new file mode 100644 index 0000000000..dc2c48b894 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go @@ -0,0 +1,307 @@ +// Package filters provides helper function to parse and handle command line +// filter, used for example in docker ps or docker images commands. +package filters + +import ( + "encoding/json" + "errors" + "fmt" + "regexp" + "strings" + + "github.com/docker/engine-api/types/versions" +) + +// Args stores filter arguments as map key:{map key: bool}. +// It contains an aggregation of the map of arguments (which are in the form +// of -f 'key=value') based on the key, and stores values for the same key +// in a map with string keys and boolean values. +// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu' +// the args will be {"image.name":{"ubuntu":true},"label":{"label1=1":true,"label2=2":true}} +type Args struct { + fields map[string]map[string]bool +} + +// NewArgs initializes a new Args struct. +func NewArgs() Args { + return Args{fields: map[string]map[string]bool{}} +} + +// ParseFlag parses the argument to the filter flag. Like +// +// `docker ps -f 'created=today' -f 'image.name=ubuntu*'` +// +// If prev map is provided, then it is appended to, and returned. By default a new +// map is created. +func ParseFlag(arg string, prev Args) (Args, error) { + filters := prev + if len(arg) == 0 { + return filters, nil + } + + if !strings.Contains(arg, "=") { + return filters, ErrBadFormat + } + + f := strings.SplitN(arg, "=", 2) + + name := strings.ToLower(strings.TrimSpace(f[0])) + value := strings.TrimSpace(f[1]) + + filters.Add(name, value) + + return filters, nil +} + +// ErrBadFormat is an error returned in case of bad format for a filter. +var ErrBadFormat = errors.New("bad format of filter (expected name=value)") + +// ToParam packs the Args into a string for easy transport from client to server. +func ToParam(a Args) (string, error) { + // this way we don't URL encode {}, just empty space + if a.Len() == 0 { + return "", nil + } + + buf, err := json.Marshal(a.fields) + if err != nil { + return "", err + } + return string(buf), nil +} + +// ToParamWithVersion packs the Args into a string for easy transport from client to server. +// The generated string will depend on the specified version (corresponding to the API version). +func ToParamWithVersion(version string, a Args) (string, error) { + // this way we don't URL encode {}, just empty space + if a.Len() == 0 { + return "", nil + } + + // for daemons older than v1.10, filter must be of the form map[string][]string + buf := []byte{} + err := errors.New("") + if version != "" && versions.LessThan(version, "1.22") { + buf, err = json.Marshal(convertArgsToSlice(a.fields)) + } else { + buf, err = json.Marshal(a.fields) + } + if err != nil { + return "", err + } + return string(buf), nil +} + +// FromParam unpacks the filter Args. +func FromParam(p string) (Args, error) { + if len(p) == 0 { + return NewArgs(), nil + } + + r := strings.NewReader(p) + d := json.NewDecoder(r) + + m := map[string]map[string]bool{} + if err := d.Decode(&m); err != nil { + r.Seek(0, 0) + + // Allow parsing old arguments in slice format. + // Because other libraries might be sending them in this format. + deprecated := map[string][]string{} + if deprecatedErr := d.Decode(&deprecated); deprecatedErr == nil { + m = deprecatedArgs(deprecated) + } else { + return NewArgs(), err + } + } + return Args{m}, nil +} + +// Get returns the list of values associates with a field. +// It returns a slice of strings to keep backwards compatibility with old code. +func (filters Args) Get(field string) []string { + values := filters.fields[field] + if values == nil { + return make([]string, 0) + } + slice := make([]string, 0, len(values)) + for key := range values { + slice = append(slice, key) + } + return slice +} + +// Add adds a new value to a filter field. +func (filters Args) Add(name, value string) { + if _, ok := filters.fields[name]; ok { + filters.fields[name][value] = true + } else { + filters.fields[name] = map[string]bool{value: true} + } +} + +// Del removes a value from a filter field. +func (filters Args) Del(name, value string) { + if _, ok := filters.fields[name]; ok { + delete(filters.fields[name], value) + } +} + +// Len returns the number of fields in the arguments. +func (filters Args) Len() int { + return len(filters.fields) +} + +// MatchKVList returns true if the values for the specified field matches the ones +// from the sources. +// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, +// field is 'label' and sources are {'label1': '1', 'label2': '2'} +// it returns true. +func (filters Args) MatchKVList(field string, sources map[string]string) bool { + fieldValues := filters.fields[field] + + //do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + + if sources == nil || len(sources) == 0 { + return false + } + + for name2match := range fieldValues { + testKV := strings.SplitN(name2match, "=", 2) + + v, ok := sources[testKV[0]] + if !ok { + return false + } + if len(testKV) == 2 && testKV[1] != v { + return false + } + } + + return true +} + +// Match returns true if the values for the specified field matches the source string +// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, +// field is 'image.name' and source is 'ubuntu' +// it returns true. +func (filters Args) Match(field, source string) bool { + if filters.ExactMatch(field, source) { + return true + } + + fieldValues := filters.fields[field] + for name2match := range fieldValues { + match, err := regexp.MatchString(name2match, source) + if err != nil { + continue + } + if match { + return true + } + } + return false +} + +// ExactMatch returns true if the source matches exactly one of the filters. +func (filters Args) ExactMatch(field, source string) bool { + fieldValues, ok := filters.fields[field] + //do not filter if there is no filter set or cannot determine filter + if !ok || len(fieldValues) == 0 { + return true + } + + // try to match full name value to avoid O(N) regular expression matching + return fieldValues[source] +} + +// UniqueExactMatch returns true if there is only one filter and the source matches exactly this one. +func (filters Args) UniqueExactMatch(field, source string) bool { + fieldValues := filters.fields[field] + //do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + if len(filters.fields[field]) != 1 { + return false + } + + // try to match full name value to avoid O(N) regular expression matching + return fieldValues[source] +} + +// FuzzyMatch returns true if the source matches exactly one of the filters, +// or the source has one of the filters as a prefix. +func (filters Args) FuzzyMatch(field, source string) bool { + if filters.ExactMatch(field, source) { + return true + } + + fieldValues := filters.fields[field] + for prefix := range fieldValues { + if strings.HasPrefix(source, prefix) { + return true + } + } + return false +} + +// Include returns true if the name of the field to filter is in the filters. +func (filters Args) Include(field string) bool { + _, ok := filters.fields[field] + return ok +} + +// Validate ensures that all the fields in the filter are valid. +// It returns an error as soon as it finds an invalid field. +func (filters Args) Validate(accepted map[string]bool) error { + for name := range filters.fields { + if !accepted[name] { + return fmt.Errorf("Invalid filter '%s'", name) + } + } + return nil +} + +// WalkValues iterates over the list of filtered values for a field. +// It stops the iteration if it finds an error and it returns that error. +func (filters Args) WalkValues(field string, op func(value string) error) error { + if _, ok := filters.fields[field]; !ok { + return nil + } + for v := range filters.fields[field] { + if err := op(v); err != nil { + return err + } + } + return nil +} + +func deprecatedArgs(d map[string][]string) map[string]map[string]bool { + m := map[string]map[string]bool{} + for k, v := range d { + values := map[string]bool{} + for _, vv := range v { + values[vv] = true + } + m[k] = values + } + return m +} + +func convertArgsToSlice(f map[string]map[string]bool) map[string][]string { + m := map[string][]string{} + for k, v := range f { + values := []string{} + for kk := range v { + if v[kk] { + values = append(values, kk) + } + } + m[k] = values + } + return m +} diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/types/network/network.go b/Godeps/_workspace/src/github.com/docker/engine-api/types/network/network.go new file mode 100644 index 0000000000..47080b652e --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/engine-api/types/network/network.go @@ -0,0 +1,53 @@ +package network + +// Address represents an IP address +type Address struct { + Addr string + PrefixLen int +} + +// IPAM represents IP Address Management +type IPAM struct { + Driver string + Options map[string]string //Per network IPAM driver options + Config []IPAMConfig +} + +// IPAMConfig represents IPAM configurations +type IPAMConfig struct { + Subnet string `json:",omitempty"` + IPRange string `json:",omitempty"` + Gateway string `json:",omitempty"` + AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"` +} + +// EndpointIPAMConfig represents IPAM configurations for the endpoint +type EndpointIPAMConfig struct { + IPv4Address string `json:",omitempty"` + IPv6Address string `json:",omitempty"` + LinkLocalIPs []string `json:",omitempty"` +} + +// EndpointSettings stores the network endpoint details +type EndpointSettings struct { + // Configurations + IPAMConfig *EndpointIPAMConfig + Links []string + Aliases []string + // Operational data + NetworkID string + EndpointID string + Gateway string + IPAddress string + IPPrefixLen int + IPv6Gateway string + GlobalIPv6Address string + GlobalIPv6PrefixLen int + MacAddress string +} + +// NetworkingConfig represents the container's networking configuration for each of its interfaces +// Carries the networking configs specified in the `docker run` and `docker network connect` commands +type NetworkingConfig struct { + EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network +} diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/README.md b/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/README.md new file mode 100644 index 0000000000..cdac50a53c --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/README.md @@ -0,0 +1,14 @@ +## Legacy API type versions + +This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`. + +Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`. + +### Package name conventions + +The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention: + +1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`. +2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`. + +For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`. diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/compare.go b/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/compare.go new file mode 100644 index 0000000000..611d4fed66 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/compare.go @@ -0,0 +1,62 @@ +package versions + +import ( + "strconv" + "strings" +) + +// compare compares two version strings +// returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise. +func compare(v1, v2 string) int { + var ( + currTab = strings.Split(v1, ".") + otherTab = strings.Split(v2, ".") + ) + + max := len(currTab) + if len(otherTab) > max { + max = len(otherTab) + } + for i := 0; i < max; i++ { + var currInt, otherInt int + + if len(currTab) > i { + currInt, _ = strconv.Atoi(currTab[i]) + } + if len(otherTab) > i { + otherInt, _ = strconv.Atoi(otherTab[i]) + } + if currInt > otherInt { + return 1 + } + if otherInt > currInt { + return -1 + } + } + return 0 +} + +// LessThan checks if a version is less than another +func LessThan(v, other string) bool { + return compare(v, other) == -1 +} + +// LessThanOrEqualTo checks if a version is less than or equal to another +func LessThanOrEqualTo(v, other string) bool { + return compare(v, other) <= 0 +} + +// GreaterThan checks if a version is greater than another +func GreaterThan(v, other string) bool { + return compare(v, other) == 1 +} + +// GreaterThanOrEqualTo checks if a version is greater than or equal to another +func GreaterThanOrEqualTo(v, other string) bool { + return compare(v, other) >= 0 +} + +// Equal checks if a version is equal to another +func Equal(v, other string) bool { + return compare(v, other) == 0 +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml b/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml new file mode 100644 index 0000000000..16d1430aa2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml @@ -0,0 +1,8 @@ +language: go +go: + - tip +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -repotoken 2FMhp57u8LcstKL9B190fLTcEnBtAAiEL diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md b/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md new file mode 100644 index 0000000000..56f357fad7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md @@ -0,0 +1,47 @@ +# go-shellwords + +[![Coverage Status](https://coveralls.io/repos/mattn/go-shellwords/badge.png?branch=master)](https://coveralls.io/r/mattn/go-shellwords?branch=master) +[![Build Status](https://travis-ci.org/mattn/go-shellwords.svg?branch=master)](https://travis-ci.org/mattn/go-shellwords) + +Parse line as shell words. + +## Usage + +```go +args, err := shellwords.Parse("./foo --bar=baz") +// args should be ["./foo", "--bar=baz"] +``` + +```go +os.Setenv("FOO", "bar") +p := shellwords.NewParser() +p.ParseEnv = true +args, err := p.Parse("./foo $FOO") +// args should be ["./foo", "bar"] +``` + +```go +p := shellwords.NewParser() +p.ParseBacktick = true +args, err := p.Parse("./foo `echo $SHELL`") +// args should be ["./foo", "/bin/bash"] +``` + +```go +shellwords.ParseBacktick = true +p := shellwords.NewParser() +args, err := p.Parse("./foo `echo $SHELL`") +// args should be ["./foo", "/bin/bash"] +``` + +# Thanks + +This is based on cpan module [Parse::CommandLine](https://metacpan.org/pod/Parse::CommandLine). + +# License + +under the MIT License: http://mattn.mit-license.org/2014 + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go new file mode 100644 index 0000000000..1abaa6c9df --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go @@ -0,0 +1,134 @@ +package shellwords + +import ( + "errors" + "os" + "regexp" + "strings" +) + +var ( + ParseEnv bool = false + ParseBacktick bool = false +) + +var envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`) + +func isSpace(r rune) bool { + switch r { + case ' ', '\t', '\r', '\n': + return true + } + return false +} + +func replaceEnv(s string) string { + return envRe.ReplaceAllStringFunc(s, func(s string) string { + s = s[1:] + if s[0] == '{' { + s = s[1 : len(s)-1] + } + return os.Getenv(s) + }) +} + +type Parser struct { + ParseEnv bool + ParseBacktick bool +} + +func NewParser() *Parser { + return &Parser{ParseEnv, ParseBacktick} +} + +func (p *Parser) Parse(line string) ([]string, error) { + line = strings.TrimSpace(line) + + args := []string{} + buf := "" + var escaped, doubleQuoted, singleQuoted, backQuote bool + backtick := "" + + for _, r := range line { + if escaped { + buf += string(r) + escaped = false + continue + } + + if r == '\\' { + if singleQuoted { + buf += string(r) + } else { + escaped = true + } + continue + } + + if isSpace(r) { + if singleQuoted || doubleQuoted || backQuote { + buf += string(r) + backtick += string(r) + } else if buf != "" { + if p.ParseEnv { + buf = replaceEnv(buf) + } + args = append(args, buf) + buf = "" + } + continue + } + + switch r { + case '`': + if !singleQuoted && !doubleQuoted { + if p.ParseBacktick { + if backQuote { + out, err := shellRun(backtick) + if err != nil { + return nil, err + } + buf = out + } + backtick = "" + backQuote = !backQuote + continue + } + backtick = "" + backQuote = !backQuote + } + case '"': + if !singleQuoted { + doubleQuoted = !doubleQuoted + continue + } + case '\'': + if !doubleQuoted { + singleQuoted = !singleQuoted + continue + } + } + + buf += string(r) + if backQuote { + backtick += string(r) + } + } + + if buf != "" { + if p.ParseEnv { + buf = replaceEnv(buf) + } + args = append(args, buf) + } + + if escaped || singleQuoted || doubleQuoted || backQuote { + return nil, errors.New("invalid command line string") + } + + return args, nil +} + +func Parse(line string) ([]string, error) { + return NewParser().Parse(line) +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go new file mode 100644 index 0000000000..4f8ac55e47 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go @@ -0,0 +1,19 @@ +// +build !windows + +package shellwords + +import ( + "errors" + "os" + "os/exec" + "strings" +) + +func shellRun(line string) (string, error) { + shell := os.Getenv("SHELL") + b, err := exec.Command(shell, "-c", line).Output() + if err != nil { + return "", errors.New(err.Error() + ":" + string(b)) + } + return strings.TrimSpace(string(b)), nil +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go new file mode 100644 index 0000000000..7cad4cf06f --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go @@ -0,0 +1,17 @@ +package shellwords + +import ( + "errors" + "os" + "os/exec" + "strings" +) + +func shellRun(line string) (string, error) { + shell := os.Getenv("COMSPEC") + b, err := exec.Command(shell, "/c", line).Output() + if err != nil { + return "", errors.New(err.Error() + ":" + string(b)) + } + return strings.TrimSpace(string(b)), nil +} From d98be36f7af8e6e6836d442db369f84e1124bbe9 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 22 Aug 2016 18:36:12 -0700 Subject: [PATCH 044/799] Add network attachment methods to cluster provider Signed-off-by: Jana Radhakrishnan --- cluster/provider.go | 9 +++++++++ cmd/dnet/dnet.go | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/cluster/provider.go b/cluster/provider.go index f8dc6f09b8..e2c34dce6a 100644 --- a/cluster/provider.go +++ b/cluster/provider.go @@ -1,5 +1,10 @@ package cluster +import ( + "github.com/docker/engine-api/types/network" + "golang.org/x/net/context" +) + // Provider provides clustering config details type Provider interface { IsManager() bool @@ -8,4 +13,8 @@ type Provider interface { GetAdvertiseAddress() string GetRemoteAddress() string ListenClusterEvents() <-chan struct{} + AttachNetwork(string, string, []string) (*network.NetworkingConfig, error) + DetachNetwork(string, string) error + UpdateAttachment(string, string, *network.NetworkingConfig) error + WaitForDetachment(context.Context, string, string, string) error } diff --git a/cmd/dnet/dnet.go b/cmd/dnet/dnet.go index a38d128886..044e066317 100644 --- a/cmd/dnet/dnet.go +++ b/cmd/dnet/dnet.go @@ -24,6 +24,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/term" + "github.com/docker/engine-api/types/network" "github.com/docker/libnetwork" "github.com/docker/libnetwork/api" "github.com/docker/libnetwork/config" @@ -34,6 +35,7 @@ import ( "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/types" "github.com/gorilla/mux" + "golang.org/x/net/context" ) const ( @@ -329,6 +331,22 @@ func (d *dnetConnection) ListenClusterEvents() <-chan struct{} { return d.configEvent } +func (d *dnetConnection) AttachNetwork(string, string, []string) (*network.NetworkingConfig, error) { + return nil, nil +} + +func (d *dnetConnection) DetachNetwork(string, string) error { + return nil +} + +func (d *dnetConnection) UpdateAttachment(string, string, *network.NetworkingConfig) error { + return nil +} + +func (d *dnetConnection) WaitForDetachment(context.Context, string, string, string) error { + return nil +} + func handleSignals(controller libnetwork.NetworkController) { c := make(chan os.Signal, 1) signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT} From deec490224c0b0a47a5a5881c5ba8df319079a21 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Tue, 23 Aug 2016 14:03:52 -0700 Subject: [PATCH 045/799] Avoid k/v store endpoint update in swarm mode Avoid the whole store endpoint update logic when running in swarm mode and the endpoint is part of a global scope network. Currently there is no store update that is happening for global scope networks in swarm mode, but this code path will delete the svcRecords database when the last endpoint on the network is removed which is something that is not required. Signed-off-by: Jana Radhakrishnan --- store.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/store.go b/store.go index b622836498..9830a22d47 100644 --- a/store.go +++ b/store.go @@ -346,6 +346,10 @@ func (c *controller) networkWatchLoop(nw *netWatch, ep *endpoint, ecCh <-chan da } func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoint) { + if !c.isDistributedControl() && ep.getNetwork().driverScope() == datastore.GlobalScope { + return + } + c.Lock() nw, ok := nmap[ep.getNetwork().ID()] c.Unlock() @@ -400,6 +404,10 @@ func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoi } func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoint) { + if !c.isDistributedControl() && ep.getNetwork().driverScope() == datastore.GlobalScope { + return + } + c.Lock() nw, ok := nmap[ep.getNetwork().ID()] From d3ce2488d9a25d447124ea13c9a08aa37a973809 Mon Sep 17 00:00:00 2001 From: Daniel Hiltgen Date: Tue, 23 Aug 2016 14:12:43 -0700 Subject: [PATCH 046/799] Simple support script to gather libnetwork info This script gathers some basic information from a system that might be useful to help troubleshoot problems. If added into an image including the proper binaries, running looks something like this: docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker/netns:/var/run/docker/netns \ --privileged --net=host nwsupport /bin/support Signed-off-by: Daniel Hiltgen --- support.sh | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 support.sh diff --git a/support.sh b/support.sh new file mode 100755 index 0000000000..e913bf33dd --- /dev/null +++ b/support.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# Required tools +DOCKER="${DOCKER:-docker}" +NSENTER="${NSENTER:-nsenter}" +BRIDGE="${BRIDGE:-bridge}" +BRCTL="${BRCTL:-brctl}" +IPTABLES="${IPTABLES:-iptables}" + +NSDIR=/var/run/docker/netns +BRIDGEIF=br0 + +function die { + echo $* + exit 1 +} + +type -P ${DOCKER} > /dev/null || die "This tool requires the docker binary" +type -P ${NSENTER} > /dev/null || die "This tool requires nsenter" +type -P ${BRIDGE} > /dev/null || die "This tool requires bridge" +type -P ${BRCTL} > /dev/null || die "This tool requires brctl" +type -P ${IPTABLES} > /dev/null || die "This tool requires iptables" + +echo "iptables configuration" +${IPTABLES} -n -v -L -t filter +${IPTABLES} -n -v -L -t nat +echo "" + +echo "Overlay network configuration" +for networkID in $(${DOCKER} network ls --filter driver=overlay -q) ; do + echo "Network ${networkID}" + nspath=(${NSDIR}/*-$(echo ${networkID}| cut -c1-10)) + ${NSENTER} --net=${nspath[0]} ${BRIDGE} fdb show ${BRIDGEIF} + ${NSENTER} --net=${nspath[0]} ${BRCTL} showmacs ${BRIDGEIF} + echo "" +done From 37c0b6e5174f4a890dfa6d57fe4b48dfc51b1bb8 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 24 Aug 2016 09:51:02 -0700 Subject: [PATCH 047/799] Avoid double close of agentInitDone Avoid by reinitializing the channel immediately after closing the channel within a lock. Also change the wait code to cache the channel in stack be retrieving it from controller and wait on the stack copy of the channel. Signed-off-by: Jana Radhakrishnan --- agent.go | 5 ++++- controller.go | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/agent.go b/agent.go index 499e2d5221..2b2ecf4324 100644 --- a/agent.go +++ b/agent.go @@ -193,9 +193,12 @@ func (c *controller) agentSetup() error { } } - if c.agent != nil { + c.Lock() + if c.agent != nil && c.agentInitDone != nil { close(c.agentInitDone) + c.agentInitDone = nil } + c.Unlock() return nil } diff --git a/controller.go b/controller.go index b1094a3b95..ff22d79d98 100644 --- a/controller.go +++ b/controller.go @@ -347,7 +347,13 @@ func (c *controller) clusterAgentInit() { // AgentInitWait waits for agent initialization to be completed in the // controller. func (c *controller) AgentInitWait() { - <-c.agentInitDone + c.Lock() + agentInitDone := c.agentInitDone + c.Unlock() + + if agentInitDone != nil { + <-agentInitDone + } } func (c *controller) makeDriverConfig(ntype string) map[string]interface{} { From 60da5f959b63fea3a898a639178ca21b58a23df6 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Thu, 25 Aug 2016 22:25:16 -0700 Subject: [PATCH 048/799] Nil check ingressSandbox before deleting Signed-off-by: Jana Radhakrishnan --- controller.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/controller.go b/controller.go index ff22d79d98..4474cdc93a 100644 --- a/controller.go +++ b/controller.go @@ -320,14 +320,17 @@ func (c *controller) clusterAgentInit() { c.agentClose() c.cleanupServiceBindings("") - if err := c.ingressSandbox.Delete(); err != nil { - log.Warnf("Could not delete ingress sandbox while leaving: %v", err) - } - c.Lock() + ingressSandbox := c.ingressSandbox c.ingressSandbox = nil c.Unlock() + if ingressSandbox != nil { + if err := ingressSandbox.Delete(); err != nil { + log.Warnf("Could not delete ingress sandbox while leaving: %v", err) + } + } + n, err := c.NetworkByName("ingress") if err != nil { log.Warnf("Could not find ingress network while leaving: %v", err) From 9dfce0b6e8ea9448e8af2ce8678df9415fcdf6c4 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Mon, 15 Aug 2016 10:54:18 -0700 Subject: [PATCH 049/799] Allow reachability across services on different networks in the same host This also allows pubslied services to be accessible from containers on bridge networks on the host Signed-off-by: Santhosh Manohar --- controller.go | 3 ++ service_linux.go | 72 +++++++++++++++++++++++++++++++++++++++--- service_unsupported.go | 3 ++ 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/controller.go b/controller.go index 382e64cdfb..0b3b004ade 100644 --- a/controller.go +++ b/controller.go @@ -660,6 +660,9 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... } joinCluster(network) + if !c.isDistributedControl() { + arrangeIngressFilterRule() + } return network, nil } diff --git a/service_linux.go b/service_linux.go index 9dc27f5578..6b2f29b572 100644 --- a/service_linux.go +++ b/service_linux.go @@ -479,14 +479,19 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro } chainExists := iptables.ExistChain(ingressChain, iptables.Nat) + filterChainExists := iptables.ExistChain(ingressChain, iptables.Filter) ingressOnce.Do(func() { + // Flush nat table and filter table ingress chain rules during init if it + // exists. It might contain stale rules from previous life. if chainExists { - // Flush ingress chain rules during init if it - // exists. It might contain stale rules from - // previous life. if err := iptables.RawCombinedOutput("-t", "nat", "-F", ingressChain); err != nil { - logrus.Errorf("Could not flush ingress chain rules during init: %v", err) + logrus.Errorf("Could not flush nat table ingress chain rules during init: %v", err) + } + } + if filterChainExists { + if err := iptables.RawCombinedOutput("-F", ingressChain); err != nil { + logrus.Errorf("Could not flush filter table ingress chain rules during init: %v", err) } } }) @@ -497,10 +502,21 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro return fmt.Errorf("failed to create ingress chain: %v", err) } } + if !filterChainExists { + if err := iptables.RawCombinedOutput("-N", ingressChain); err != nil { + return fmt.Errorf("failed to create filter table ingress chain: %v", err) + } + } if !iptables.Exists(iptables.Nat, ingressChain, "-j", "RETURN") { if err := iptables.RawCombinedOutput("-t", "nat", "-A", ingressChain, "-j", "RETURN"); err != nil { - return fmt.Errorf("failed to add return rule in ingress chain: %v", err) + return fmt.Errorf("failed to add return rule in nat table ingress chain: %v", err) + } + } + + if !iptables.Exists(iptables.Filter, ingressChain, "-j", "RETURN") { + if err := iptables.RawCombinedOutput("-A", ingressChain, "-j", "RETURN"); err != nil { + return fmt.Errorf("failed to add return rule to filter table ingress chain: %v", err) } } @@ -512,6 +528,12 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro } } + if !iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) { + if err := iptables.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil { + return fmt.Errorf("failed to add jump rule to %s in filter table forward chain: %v", ingressChain, err) + } + } + oifName, err := findOIFName(gwIP) if err != nil { return fmt.Errorf("failed to find gateway bridge interface name for %s: %v", gwIP, err) @@ -544,6 +566,30 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro } } + // Filter table rules to allow a published service to be accessible in the local node from.. + // 1) service tasks attached to other networks + // 2) unmanaged containers on bridge networks + rule := strings.Fields(fmt.Sprintf("%s %s -m state -p %s --sport %d --state ESTABLISHED,RELATED -j ACCEPT", + addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort)) + if err := iptables.RawCombinedOutput(rule...); err != nil { + errStr := fmt.Sprintf("setting up rule failed, %v: %v", rule, err) + if !isDelete { + return fmt.Errorf("%s", errStr) + } + logrus.Warnf("%s", errStr) + } + + rule = strings.Fields(fmt.Sprintf("%s %s -p %s --dport %d -j ACCEPT", + addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort)) + if err := iptables.RawCombinedOutput(rule...); err != nil { + errStr := fmt.Sprintf("setting up rule failed, %v: %v", rule, err) + if !isDelete { + return fmt.Errorf("%s", errStr) + } + + logrus.Warnf("%s", errStr) + } + if err := plumbProxy(iPort, isDelete); err != nil { logrus.Warnf("failed to create proxy for port %d: %v", iPort.PublishedPort, err) } @@ -552,6 +598,22 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro return nil } +// In the filter table FORWARD chain first rule should be to jump to INGRESS-CHAIN +// This chain has the rules to allow access to the published ports for swarm tasks +// from local bridge networks and docker_gwbridge (ie:taks on other swarm netwroks) +func arrangeIngressFilterRule() { + if iptables.ExistChain(ingressChain, iptables.Filter) { + if iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) { + if err := iptables.RawCombinedOutput("-D", "FORWARD", "-j", ingressChain); err != nil { + logrus.Warnf("failed to delete jump rule to ingressChain in filter table: %v", err) + } + } + if err := iptables.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil { + logrus.Warnf("failed to add jump rule to ingressChain in filter table: %v", err) + } + } +} + func findOIFName(ip net.IP) (string, error) { nlh := ns.NlHandle() diff --git a/service_unsupported.go b/service_unsupported.go index 9668dcc07e..a6ca5025d4 100644 --- a/service_unsupported.go +++ b/service_unsupported.go @@ -17,3 +17,6 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in func (sb *sandbox) populateLoadbalancers(ep *endpoint) { } + +func arrangeIngressFilterRule() { +} From 18b93cb943f26e90aa4763f6e6f39fabf7f0945c Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Tue, 30 Aug 2016 09:41:16 -0700 Subject: [PATCH 050/799] Do not try LB populate on interface-less endpoint Signed-off-by: Jana Radhakrishnan --- service_linux.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/service_linux.go b/service_linux.go index ec47a51f0f..c881300e6c 100644 --- a/service_linux.go +++ b/service_linux.go @@ -267,6 +267,11 @@ func (n *network) connectedLoadbalancers() []*loadBalancer { func (sb *sandbox) populateLoadbalancers(ep *endpoint) { var gwIP net.IP + // This is an interface less endpoint. Nothing to do. + if ep.Iface() == nil { + return + } + n := ep.getNetwork() eIP := ep.Iface().Address() From fda4c19b7a5348b2f2cc13e500c045076472e006 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Tue, 30 Aug 2016 11:46:09 -0700 Subject: [PATCH 051/799] Fix CircleCI Signed-off-by: Jana Radhakrishnan --- netutils/utils_test.go | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/netutils/utils_test.go b/netutils/utils_test.go index a81effde0d..c051d6e0b1 100644 --- a/netutils/utils_test.go +++ b/netutils/utils_test.go @@ -213,35 +213,44 @@ func TestNetworkRequest(t *testing.T) { defer testutils.SetupTestOSContext(t)() ipamutils.InitNetworks() - _, exp, err := net.ParseCIDR("172.17.0.0/16") - if err != nil { - t.Fatal(err) - } - nw, err := FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) if err != nil { t.Fatal(err) } - if !types.CompareIPNet(exp, nw) { - t.Fatalf("exected %s. got %s", exp, nw) + + var found bool + for _, exp := range ipamutils.PredefinedBroadNetworks { + if types.CompareIPNet(exp, nw) { + found = true + break + } } - _, exp, err = net.ParseCIDR("10.0.0.0/24") - if err != nil { - t.Fatal(err) + if !found { + t.Fatalf("Found unexpected broad network %s", nw) } + nw, err = FindAvailableNetwork(ipamutils.PredefinedGranularNetworks) if err != nil { t.Fatal(err) } - if !types.CompareIPNet(exp, nw) { - t.Fatalf("exected %s. got %s", exp, nw) + + found = false + for _, exp := range ipamutils.PredefinedGranularNetworks { + if types.CompareIPNet(exp, nw) { + found = true + break + } + } + + if !found { + t.Fatalf("Found unexpected granular network %s", nw) } // Add iface and ssert returned address on request createInterface(t, "test", "172.17.42.1/16") - _, exp, err = net.ParseCIDR("172.18.0.0/16") + _, exp, err := net.ParseCIDR("172.18.0.0/16") if err != nil { t.Fatal(err) } From b4bb1b6626e7c6baa9cc74af3afe9aac5c4cc365 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 30 Aug 2016 12:31:28 -0700 Subject: [PATCH 052/799] Fix potential deadlock in getSvcRecords() Signed-off-by: Alessandro Boch --- network.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network.go b/network.go index 8c5cdf1d3f..2cd857a462 100644 --- a/network.go +++ b/network.go @@ -1125,7 +1125,7 @@ func (n *network) getSvcRecords(ep *endpoint) []etchosts.Record { continue } if len(ip) == 0 { - log.Warnf("Found empty list of IP addresses for service %s on network %s (%s)", h, n.Name(), n.ID()) + log.Warnf("Found empty list of IP addresses for service %s on network %s (%s)", h, n.name, n.id) continue } recs = append(recs, etchosts.Record{ From a5f8723c30c6dd40502f0afcde5af48d32cba3c9 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 31 Aug 2016 12:22:36 -0700 Subject: [PATCH 053/799] Adjust WaitForDetachment to also accept networkID Signed-off-by: Jana Radhakrishnan --- cluster/provider.go | 2 +- cmd/dnet/dnet.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cluster/provider.go b/cluster/provider.go index e2c34dce6a..5e6b560946 100644 --- a/cluster/provider.go +++ b/cluster/provider.go @@ -16,5 +16,5 @@ type Provider interface { AttachNetwork(string, string, []string) (*network.NetworkingConfig, error) DetachNetwork(string, string) error UpdateAttachment(string, string, *network.NetworkingConfig) error - WaitForDetachment(context.Context, string, string, string) error + WaitForDetachment(context.Context, string, string, string, string) error } diff --git a/cmd/dnet/dnet.go b/cmd/dnet/dnet.go index 044e066317..757e9666f8 100644 --- a/cmd/dnet/dnet.go +++ b/cmd/dnet/dnet.go @@ -343,7 +343,7 @@ func (d *dnetConnection) UpdateAttachment(string, string, *network.NetworkingCon return nil } -func (d *dnetConnection) WaitForDetachment(context.Context, string, string, string) error { +func (d *dnetConnection) WaitForDetachment(context.Context, string, string, string, string) error { return nil } From 03460125a724681a57a7f37947ec72346abf8eae Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Thu, 1 Sep 2016 14:27:36 -0700 Subject: [PATCH 054/799] Do not hold sandbox if not in distributed control When the libnetwork controller is not in distributed control mode avoid retaining stale sandboxes when the network cannot be retrieved from store. This ratining logic is only applicable for an independent k/v store which manages libnetwork state. In such case the k/v store may be temporarily unavailable so there is a need to retain the sandbox so that the resource cleanup happens properly. Signed-off-by: Jana Radhakrishnan --- sandbox.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sandbox.go b/sandbox.go index 52e9bb6783..775b92ab31 100644 --- a/sandbox.go +++ b/sandbox.go @@ -202,12 +202,14 @@ func (sb *sandbox) delete(force bool) error { retain := false for _, ep := range sb.getConnectedEndpoints() { // gw network endpoint detach and removal are automatic - if ep.endpointInGWNetwork() { + if ep.endpointInGWNetwork() && !force { continue } // Retain the sanbdox if we can't obtain the network from store. if _, err := c.getNetworkFromStore(ep.getNetwork().ID()); err != nil { - retain = true + if c.isDistributedControl() { + retain = true + } log.Warnf("Failed getting network for ep %s during sandbox %s delete: %v", ep.ID(), sb.ID(), err) continue } From afaf385f5c3ce642a5435fd35bfb0538b290dbd9 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Fri, 2 Sep 2016 10:08:09 -0700 Subject: [PATCH 055/799] Cleanup on error in ProgramExternalConnectivity Signed-off-by: Alessandro Boch --- drivers/bridge/bridge.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index 8410eb037a..e276bc7b96 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -1243,8 +1243,17 @@ func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string return err } + defer func() { + if err != nil { + if e := network.releasePorts(endpoint); e != nil { + logrus.Errorf("Failed to release ports allocated for the bridge endpoint %s on failure %v because of %v", + eid, err, e) + } + endpoint.portMapping = nil + } + }() + if err = d.storeUpdate(endpoint); err != nil { - endpoint.portMapping = nil return fmt.Errorf("failed to update bridge endpoint %s to store: %v", endpoint.id[0:7], err) } From 550913c2fd9939db1935a03de8319933a8b6b9c2 Mon Sep 17 00:00:00 2001 From: Puneet Pruthi Date: Fri, 8 Jul 2016 17:49:32 -0700 Subject: [PATCH 056/799] uprev docker/docker/pkg/reexec for libnetwork Signed-off-by: Puneet Pruthi --- Godeps/Godeps.json | 101 +++--- .../github.com/Azure/go-ansiterm/constants.go | 22 +- .../github.com/Azure/go-ansiterm/context.go | 2 +- .../Azure/go-ansiterm/csi_entry_state.go | 32 +- .../Azure/go-ansiterm/csi_param_state.go | 22 +- .../go-ansiterm/escape_intermediate_state.go | 26 +- .../Azure/go-ansiterm/escape_state.go | 34 +- .../Azure/go-ansiterm/ground_state.go | 12 +- .../Azure/go-ansiterm/osc_string_state.go | 10 +- .../github.com/Azure/go-ansiterm/parser.go | 67 ++-- .../go-ansiterm/parser_action_helpers.go | 2 +- .../Azure/go-ansiterm/parser_actions.go | 2 +- .../Azure/go-ansiterm/parser_test_helpers.go | 114 ------- .../go-ansiterm/parser_test_utilities.go | 66 ---- .../github.com/Azure/go-ansiterm/states.go | 42 +-- .../Azure/go-ansiterm/test_event_handler.go | 173 ---------- .../Azure/go-ansiterm/winterm/ansi.go | 22 +- .../Azure/go-ansiterm/winterm/api.go | 89 +++-- .../go-ansiterm/winterm/attr_translation.go | 56 ++-- .../go-ansiterm/winterm/cursor_helpers.go | 34 +- .../go-ansiterm/winterm/erase_helpers.go | 10 +- .../go-ansiterm/winterm/scroll_helper.go | 26 +- .../Azure/go-ansiterm/winterm/utilities.go | 2 +- .../go-ansiterm/winterm/win_event_handler.go | 157 ++++----- .../github.com/armon/go-metrics/.gitignore | 0 .../github.com/armon/go-metrics/metrics.go | 0 .../src/github.com/armon/go-metrics/sink.go | 0 .../src/github.com/armon/go-metrics/start.go | 0 .../github.com/armon/go-metrics/statsite.go | 0 .../docker/docker/pkg/ioutils/bytespipe.go | 7 +- .../docker/docker/pkg/ioutils/fswriters.go | 75 +++++ .../docker/pkg/mount/flags_unsupported.go | 2 +- .../docker/docker/pkg/mount/mount.go | 4 +- .../docker/pkg/mount/mounter_solaris.go | 33 ++ .../docker/pkg/mount/mounter_unsupported.go | 2 +- .../docker/pkg/mount/mountinfo_solaris.go | 37 +++ .../docker/pkg/mount/mountinfo_unsupported.go | 2 +- .../pkg/parsers/kernel/uname_solaris.go | 14 + .../pkg/parsers/kernel/uname_unsupported.go | 2 +- .../{command_freebsd.go => command_unix.go} | 2 +- .../docker/pkg/reexec/command_unsupported.go | 2 +- .../docker/pkg/signal/signal_solaris.go | 42 +++ .../docker/pkg/signal/signal_unsupported.go | 2 +- .../docker/pkg/system/meminfo_solaris.go | 128 ++++++++ .../docker/pkg/system/meminfo_unsupported.go | 2 +- .../docker/docker/pkg/system/path_unix.go | 6 + .../docker/docker/pkg/system/path_windows.go | 30 ++ .../docker/docker/pkg/system/stat_solaris.go | 17 + .../docker/pkg/system/syscall_windows.go | 32 +- .../docker/docker/pkg/term/term_windows.go | 12 +- .../docker/pkg/term/windows/ansi_reader.go | 8 +- .../docker/engine-api/types/filters/parse.go | 307 ------------------ .../engine-api/types/versions/README.md | 14 - .../engine-api/types/versions/compare.go | 62 ---- .../go-msgpack/codec/msgpack_test.py | 0 .../mattn/go-shellwords/.travis.yml | 8 - .../github.com/mattn/go-shellwords/README.md | 47 --- .../mattn/go-shellwords/shellwords.go | 134 -------- .../mattn/go-shellwords/util_posix.go | 19 -- .../mattn/go-shellwords/util_windows.go | 17 - .../github.com/ugorji/go/codec/prebuild.sh | 0 .../src/github.com/ugorji/go/codec/test.py | 0 .../src/golang.org/x/sys/unix/mkall.sh | 0 .../src/golang.org/x/sys/unix/mkerrors.sh | 0 .../src/golang.org/x/sys/unix/mksyscall.pl | 0 .../x/sys/unix/mksyscall_solaris.pl | 0 .../golang.org/x/sys/unix/mksysctl_openbsd.pl | 0 .../golang.org/x/sys/unix/mksysnum_darwin.pl | 0 .../x/sys/unix/mksysnum_dragonfly.pl | 0 .../golang.org/x/sys/unix/mksysnum_freebsd.pl | 0 .../golang.org/x/sys/unix/mksysnum_linux.pl | 0 .../golang.org/x/sys/unix/mksysnum_netbsd.pl | 0 .../golang.org/x/sys/unix/mksysnum_openbsd.pl | 0 73 files changed, 812 insertions(+), 1380 deletions(-) delete mode 100644 Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_helpers.go delete mode 100644 Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_utilities.go delete mode 100644 Godeps/_workspace/src/github.com/Azure/go-ansiterm/test_event_handler.go mode change 100644 => 100755 Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore mode change 100644 => 100755 Godeps/_workspace/src/github.com/armon/go-metrics/metrics.go mode change 100644 => 100755 Godeps/_workspace/src/github.com/armon/go-metrics/sink.go mode change 100644 => 100755 Godeps/_workspace/src/github.com/armon/go-metrics/start.go mode change 100644 => 100755 Godeps/_workspace/src/github.com/armon/go-metrics/statsite.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_solaris.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_solaris.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_solaris.go rename Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/{command_freebsd.go => command_unix.go} (94%) create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_solaris.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/system/meminfo_solaris.go delete mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go delete mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/types/versions/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/types/versions/compare.go mode change 100644 => 100755 Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/msgpack_test.py delete mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md delete mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go delete mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go delete mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go mode change 100644 => 100755 Godeps/_workspace/src/github.com/ugorji/go/codec/prebuild.sh mode change 100644 => 100755 Godeps/_workspace/src/github.com/ugorji/go/codec/test.py mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mkall.sh mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mkerrors.sh mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksyscall.pl mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksyscall_solaris.pl mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysctl_openbsd.pl mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_darwin.pl mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_dragonfly.pl mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_freebsd.pl mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_linux.pl mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_netbsd.pl mode change 100644 => 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_openbsd.pl diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 10bca97a7c..b1f35ffc04 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -7,11 +7,11 @@ "Deps": [ { "ImportPath": "github.com/Azure/go-ansiterm", - "Rev": "70b2c90b260171e829f1ebd7c17f600c11858dbe" + "Rev": "04b7f292a41fcb5da32dda536c0807fc13e8351c" }, { "ImportPath": "github.com/Azure/go-ansiterm/winterm", - "Rev": "70b2c90b260171e829f1ebd7c17f600c11858dbe" + "Rev": "04b7f292a41fcb5da32dda536c0807fc13e8351c" }, { "ImportPath": "github.com/BurntSushi/toml", @@ -47,7 +47,7 @@ }, { "ImportPath": "github.com/codegangsta/cli", - "Comment": "1.2.0-143-ga65b733", + "Comment": "v1.9.0", "Rev": "a65b733b303f0055f8d324d805f393cd3e7a7904" }, { @@ -82,119 +82,109 @@ }, { "ImportPath": "github.com/docker/docker/opts", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/discovery", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/discovery/kv", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/homedir", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/ioutils", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/longpath", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/mflag", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/mount", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/parsers/kernel", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/plugins", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/plugins/transport", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/random", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/reexec", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/signal", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/stringid", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/symlink", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/system", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/term", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/term/windows", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/docker/pkg/tlsconfig", - "Comment": "v1.4.1-11716-g24076ed", - "Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a" - }, - { - "ImportPath": "github.com/docker/engine-api/types/filters", - "Comment": "v0.3.1-210-g25941ec", - "Rev": "25941ecf6e8351810e8530c60de8dda7d5e1baba" + "Comment": "v1.4.1-12227-g86a7632", + "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, { "ImportPath": "github.com/docker/engine-api/types/network", "Comment": "v0.3.1-210-g25941ec", "Rev": "25941ecf6e8351810e8530c60de8dda7d5e1baba" }, - { - "ImportPath": "github.com/docker/engine-api/types/versions", - "Comment": "v0.3.1-210-g25941ec", - "Rev": "25941ecf6e8351810e8530c60de8dda7d5e1baba" - }, { "ImportPath": "github.com/docker/go-connections/sockets", "Comment": "v0.2.0", @@ -303,11 +293,6 @@ "Comment": "v0.7.0-47-g598c548", "Rev": "598c54895cc5a7b1a24a398d635e8c0ea0959870" }, - { - "ImportPath": "github.com/mattn/go-shellwords", - "Comment": "v1.0.0-1-g525bede", - "Rev": "525bedee691b5a8df547cb5cf9f86b7fb1883e24" - }, { "ImportPath": "github.com/miekg/dns", "Rev": "d27455715200c7d3e321a1e5cadb27c9ee0b0f02" diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/constants.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/constants.go index ebfce8a8d3..96504a33bc 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/constants.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/constants.go @@ -124,32 +124,32 @@ func getByteRange(start byte, end byte) []byte { return bytes } -var ToGroundBytes = getToGroundBytes() -var Executors = getExecuteBytes() +var toGroundBytes = getToGroundBytes() +var executors = getExecuteBytes() // SPACE 20+A0 hex Always and everywhere a blank space // Intermediate 20-2F hex !"#$%&'()*+,-./ -var Intermeds = getByteRange(0x20, 0x2F) +var intermeds = getByteRange(0x20, 0x2F) // Parameters 30-3F hex 0123456789:;<=>? // CSI Parameters 30-39, 3B hex 0123456789; -var CsiParams = getByteRange(0x30, 0x3F) +var csiParams = getByteRange(0x30, 0x3F) -var CsiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...) +var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...) // Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ -var UpperCase = getByteRange(0x40, 0x5F) +var upperCase = getByteRange(0x40, 0x5F) // Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~ -var LowerCase = getByteRange(0x60, 0x7E) +var lowerCase = getByteRange(0x60, 0x7E) // Alphabetics 40-7E hex (all of upper and lower case) -var Alphabetics = append(UpperCase, LowerCase...) +var alphabetics = append(upperCase, lowerCase...) -var Printables = getByteRange(0x20, 0x7F) +var printables = getByteRange(0x20, 0x7F) -var EscapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E) -var EscapeToGroundBytes = getEscapeToGroundBytes() +var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E) +var escapeToGroundBytes = getEscapeToGroundBytes() // See http://www.vt100.net/emu/vt500_parser.png for description of the complex // byte ranges below diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/context.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/context.go index d55cc2aec7..8d66e777c0 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/context.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/context.go @@ -1,6 +1,6 @@ package ansiterm -type AnsiContext struct { +type ansiContext struct { currentChar byte paramBuffer []byte interBuffer []byte diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_entry_state.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_entry_state.go index 9fd4bd28e2..1bd6057da8 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_entry_state.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_entry_state.go @@ -1,41 +1,41 @@ package ansiterm -type CsiEntryState struct { - BaseState +type csiEntryState struct { + baseState } -func (csiState CsiEntryState) Handle(b byte) (s State, e error) { +func (csiState csiEntryState) Handle(b byte) (s state, e error) { logger.Infof("CsiEntry::Handle %#x", b) - nextState, err := csiState.BaseState.Handle(b) + nextState, err := csiState.baseState.Handle(b) if nextState != nil || err != nil { return nextState, err } switch { - case sliceContains(Alphabetics, b): - return csiState.parser.Ground, nil - case sliceContains(CsiCollectables, b): - return csiState.parser.CsiParam, nil - case sliceContains(Executors, b): + case sliceContains(alphabetics, b): + return csiState.parser.ground, nil + case sliceContains(csiCollectables, b): + return csiState.parser.csiParam, nil + case sliceContains(executors, b): return csiState, csiState.parser.execute() } return csiState, nil } -func (csiState CsiEntryState) Transition(s State) error { +func (csiState csiEntryState) Transition(s state) error { logger.Infof("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name()) - csiState.BaseState.Transition(s) + csiState.baseState.Transition(s) switch s { - case csiState.parser.Ground: + case csiState.parser.ground: return csiState.parser.csiDispatch() - case csiState.parser.CsiParam: + case csiState.parser.csiParam: switch { - case sliceContains(CsiParams, csiState.parser.context.currentChar): + case sliceContains(csiParams, csiState.parser.context.currentChar): csiState.parser.collectParam() - case sliceContains(Intermeds, csiState.parser.context.currentChar): + case sliceContains(intermeds, csiState.parser.context.currentChar): csiState.parser.collectInter() } } @@ -43,7 +43,7 @@ func (csiState CsiEntryState) Transition(s State) error { return nil } -func (csiState CsiEntryState) Enter() error { +func (csiState csiEntryState) Enter() error { csiState.parser.clear() return nil } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_param_state.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_param_state.go index 27807dd35b..4be35c5fd2 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_param_state.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_param_state.go @@ -1,36 +1,36 @@ package ansiterm -type CsiParamState struct { - BaseState +type csiParamState struct { + baseState } -func (csiState CsiParamState) Handle(b byte) (s State, e error) { +func (csiState csiParamState) Handle(b byte) (s state, e error) { logger.Infof("CsiParam::Handle %#x", b) - nextState, err := csiState.BaseState.Handle(b) + nextState, err := csiState.baseState.Handle(b) if nextState != nil || err != nil { return nextState, err } switch { - case sliceContains(Alphabetics, b): - return csiState.parser.Ground, nil - case sliceContains(CsiCollectables, b): + case sliceContains(alphabetics, b): + return csiState.parser.ground, nil + case sliceContains(csiCollectables, b): csiState.parser.collectParam() return csiState, nil - case sliceContains(Executors, b): + case sliceContains(executors, b): return csiState, csiState.parser.execute() } return csiState, nil } -func (csiState CsiParamState) Transition(s State) error { +func (csiState csiParamState) Transition(s state) error { logger.Infof("CsiParam::Transition %s --> %s", csiState.Name(), s.Name()) - csiState.BaseState.Transition(s) + csiState.baseState.Transition(s) switch s { - case csiState.parser.Ground: + case csiState.parser.ground: return csiState.parser.csiDispatch() } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_intermediate_state.go index b14e0ce977..2189eb6b6b 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_intermediate_state.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_intermediate_state.go @@ -1,34 +1,34 @@ package ansiterm -type EscapeIntermediateState struct { - BaseState +type escapeIntermediateState struct { + baseState } -func (escState EscapeIntermediateState) Handle(b byte) (s State, e error) { - logger.Infof("EscapeIntermediateState::Handle %#x", b) - nextState, err := escState.BaseState.Handle(b) +func (escState escapeIntermediateState) Handle(b byte) (s state, e error) { + logger.Infof("escapeIntermediateState::Handle %#x", b) + nextState, err := escState.baseState.Handle(b) if nextState != nil || err != nil { return nextState, err } switch { - case sliceContains(Intermeds, b): + case sliceContains(intermeds, b): return escState, escState.parser.collectInter() - case sliceContains(Executors, b): + case sliceContains(executors, b): return escState, escState.parser.execute() - case sliceContains(EscapeIntermediateToGroundBytes, b): - return escState.parser.Ground, nil + case sliceContains(escapeIntermediateToGroundBytes, b): + return escState.parser.ground, nil } return escState, nil } -func (escState EscapeIntermediateState) Transition(s State) error { - logger.Infof("EscapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) - escState.BaseState.Transition(s) +func (escState escapeIntermediateState) Transition(s state) error { + logger.Infof("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) + escState.baseState.Transition(s) switch s { - case escState.parser.Ground: + case escState.parser.ground: return escState.parser.escDispatch() } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_state.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_state.go index 232dd8e0d1..7b1b9ad3f1 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_state.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_state.go @@ -1,47 +1,47 @@ package ansiterm -type EscapeState struct { - BaseState +type escapeState struct { + baseState } -func (escState EscapeState) Handle(b byte) (s State, e error) { - logger.Infof("EscapeState::Handle %#x", b) - nextState, err := escState.BaseState.Handle(b) +func (escState escapeState) Handle(b byte) (s state, e error) { + logger.Infof("escapeState::Handle %#x", b) + nextState, err := escState.baseState.Handle(b) if nextState != nil || err != nil { return nextState, err } switch { case b == ANSI_ESCAPE_SECONDARY: - return escState.parser.CsiEntry, nil + return escState.parser.csiEntry, nil case b == ANSI_OSC_STRING_ENTRY: - return escState.parser.OscString, nil - case sliceContains(Executors, b): + return escState.parser.oscString, nil + case sliceContains(executors, b): return escState, escState.parser.execute() - case sliceContains(EscapeToGroundBytes, b): - return escState.parser.Ground, nil - case sliceContains(Intermeds, b): - return escState.parser.EscapeIntermediate, nil + case sliceContains(escapeToGroundBytes, b): + return escState.parser.ground, nil + case sliceContains(intermeds, b): + return escState.parser.escapeIntermediate, nil } return escState, nil } -func (escState EscapeState) Transition(s State) error { +func (escState escapeState) Transition(s state) error { logger.Infof("Escape::Transition %s --> %s", escState.Name(), s.Name()) - escState.BaseState.Transition(s) + escState.baseState.Transition(s) switch s { - case escState.parser.Ground: + case escState.parser.ground: return escState.parser.escDispatch() - case escState.parser.EscapeIntermediate: + case escState.parser.escapeIntermediate: return escState.parser.collectInter() } return nil } -func (escState EscapeState) Enter() error { +func (escState escapeState) Enter() error { escState.parser.clear() return nil } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/ground_state.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/ground_state.go index d600e3e4ae..52451e9469 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/ground_state.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/ground_state.go @@ -1,22 +1,22 @@ package ansiterm -type GroundState struct { - BaseState +type groundState struct { + baseState } -func (gs GroundState) Handle(b byte) (s State, e error) { +func (gs groundState) Handle(b byte) (s state, e error) { gs.parser.context.currentChar = b - nextState, err := gs.BaseState.Handle(b) + nextState, err := gs.baseState.Handle(b) if nextState != nil || err != nil { return nextState, err } switch { - case sliceContains(Printables, b): + case sliceContains(printables, b): return gs, gs.parser.print() - case sliceContains(Executors, b): + case sliceContains(executors, b): return gs, gs.parser.execute() } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/osc_string_state.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/osc_string_state.go index 4490e3cdf6..24062d420e 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/osc_string_state.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/osc_string_state.go @@ -1,19 +1,19 @@ package ansiterm -type OscStringState struct { - BaseState +type oscStringState struct { + baseState } -func (oscState OscStringState) Handle(b byte) (s State, e error) { +func (oscState oscStringState) Handle(b byte) (s state, e error) { logger.Infof("OscString::Handle %#x", b) - nextState, err := oscState.BaseState.Handle(b) + nextState, err := oscState.baseState.Handle(b) if nextState != nil || err != nil { return nextState, err } switch { case isOscStringTerminator(b): - return oscState.parser.Ground, nil + return oscState.parser.ground, nil } return oscState, nil diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser.go index ef5e0ad199..169f68dbef 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser.go @@ -2,7 +2,6 @@ package ansiterm import ( "errors" - "fmt" "io/ioutil" "os" @@ -12,18 +11,18 @@ import ( var logger *logrus.Logger type AnsiParser struct { - currState State + currState state eventHandler AnsiEventHandler - context *AnsiContext - CsiEntry State - CsiParam State - DcsEntry State - Escape State - EscapeIntermediate State - Error State - Ground State - OscString State - stateMap []State + context *ansiContext + csiEntry state + csiParam state + dcsEntry state + escape state + escapeIntermediate state + error state + ground state + oscString state + stateMap []state } func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser { @@ -41,27 +40,27 @@ func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser parser := &AnsiParser{ eventHandler: evtHandler, - context: &AnsiContext{}, + context: &ansiContext{}, } - parser.CsiEntry = CsiEntryState{BaseState{name: "CsiEntry", parser: parser}} - parser.CsiParam = CsiParamState{BaseState{name: "CsiParam", parser: parser}} - parser.DcsEntry = DcsEntryState{BaseState{name: "DcsEntry", parser: parser}} - parser.Escape = EscapeState{BaseState{name: "Escape", parser: parser}} - parser.EscapeIntermediate = EscapeIntermediateState{BaseState{name: "EscapeIntermediate", parser: parser}} - parser.Error = ErrorState{BaseState{name: "Error", parser: parser}} - parser.Ground = GroundState{BaseState{name: "Ground", parser: parser}} - parser.OscString = OscStringState{BaseState{name: "OscString", parser: parser}} - - parser.stateMap = []State{ - parser.CsiEntry, - parser.CsiParam, - parser.DcsEntry, - parser.Escape, - parser.EscapeIntermediate, - parser.Error, - parser.Ground, - parser.OscString, + parser.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: parser}} + parser.csiParam = csiParamState{baseState{name: "CsiParam", parser: parser}} + parser.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: parser}} + parser.escape = escapeState{baseState{name: "Escape", parser: parser}} + parser.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: parser}} + parser.error = errorState{baseState{name: "Error", parser: parser}} + parser.ground = groundState{baseState{name: "Ground", parser: parser}} + parser.oscString = oscStringState{baseState{name: "OscString", parser: parser}} + + parser.stateMap = []state{ + parser.csiEntry, + parser.csiParam, + parser.dcsEntry, + parser.escape, + parser.escapeIntermediate, + parser.error, + parser.ground, + parser.oscString, } parser.currState = getState(initialState, parser.stateMap) @@ -70,7 +69,7 @@ func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser return parser } -func getState(name string, states []State) State { +func getState(name string, states []state) state { for _, el := range states { if el.Name() == name { return el @@ -99,7 +98,7 @@ func (ap *AnsiParser) handle(b byte) error { if newState == nil { logger.Warning("newState is nil") - return errors.New(fmt.Sprintf("New state of 'nil' is invalid.")) + return errors.New("New state of 'nil' is invalid.") } if newState != ap.currState { @@ -111,7 +110,7 @@ func (ap *AnsiParser) handle(b byte) error { return nil } -func (ap *AnsiParser) changeState(newState State) error { +func (ap *AnsiParser) changeState(newState state) error { logger.Infof("ChangeState %s --> %s", ap.currState.Name(), newState.Name()) // Exit old state diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_action_helpers.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_action_helpers.go index 438802097d..8b69a67a5a 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_action_helpers.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_action_helpers.go @@ -31,7 +31,7 @@ func parseParams(bytes []byte) ([]string, error) { return params, nil } -func parseCmd(context AnsiContext) (string, error) { +func parseCmd(context ansiContext) (string, error) { return string(context.currentChar), nil } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_actions.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_actions.go index 260e6aae3c..58750a2d2b 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_actions.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_actions.go @@ -113,7 +113,7 @@ func (ap *AnsiParser) print() error { } func (ap *AnsiParser) clear() error { - ap.context = &AnsiContext{} + ap.context = &ansiContext{} return nil } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_helpers.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_helpers.go deleted file mode 100644 index 562f215d34..0000000000 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_helpers.go +++ /dev/null @@ -1,114 +0,0 @@ -package ansiterm - -import ( - "fmt" - "testing" -) - -func getStateNames() []string { - parser, _ := createTestParser("Ground") - - stateNames := []string{} - for _, state := range parser.stateMap { - stateNames = append(stateNames, state.Name()) - } - - return stateNames -} - -func stateTransitionHelper(t *testing.T, start string, end string, bytes []byte) { - for _, b := range bytes { - bytes := []byte{byte(b)} - parser, _ := createTestParser(start) - parser.Parse(bytes) - validateState(t, parser.currState, end) - } -} - -func anyToXHelper(t *testing.T, bytes []byte, expectedState string) { - for _, s := range getStateNames() { - stateTransitionHelper(t, s, expectedState, bytes) - } -} - -func funcCallParamHelper(t *testing.T, bytes []byte, start string, expected string, expectedCalls []string) { - parser, evtHandler := createTestParser(start) - parser.Parse(bytes) - validateState(t, parser.currState, expected) - validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls) -} - -func parseParamsHelper(t *testing.T, bytes []byte, expectedParams []string) { - params, err := parseParams(bytes) - - if err != nil { - t.Errorf("Parameter parse error: %v", err) - return - } - - if len(params) != len(expectedParams) { - t.Errorf("Parsed parameters: %v", params) - t.Errorf("Expected parameters: %v", expectedParams) - t.Errorf("Parameter length failure: %d != %d", len(params), len(expectedParams)) - return - } - - for i, v := range expectedParams { - if v != params[i] { - t.Errorf("Parsed parameters: %v", params) - t.Errorf("Expected parameters: %v", expectedParams) - t.Errorf("Parameter parse failure: %s != %s at position %d", v, params[i], i) - } - } -} - -func cursorSingleParamHelper(t *testing.T, command byte, funcName string) { - funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) - funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) - funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)}) - funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23])", funcName)}) - funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)}) - funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)}) -} - -func cursorTwoParamHelper(t *testing.T, command byte, funcName string) { - funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)}) - funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)}) - funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 1])", funcName)}) - funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23 1])", funcName)}) - funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)}) - funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)}) -} - -func eraseHelper(t *testing.T, command byte, funcName string) { - funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)}) - funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)}) - funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) - funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)}) - funcCallParamHelper(t, []byte{'3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([3])", funcName)}) - funcCallParamHelper(t, []byte{'4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)}) - funcCallParamHelper(t, []byte{'1', ';', '2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) -} - -func scrollHelper(t *testing.T, command byte, funcName string) { - funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) - funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) - funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) - funcCallParamHelper(t, []byte{'5', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([5])", funcName)}) - funcCallParamHelper(t, []byte{'4', ';', '6', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([4])", funcName)}) -} - -func clearOnStateChangeHelper(t *testing.T, start string, end string, bytes []byte) { - p, _ := createTestParser(start) - fillContext(p.context) - p.Parse(bytes) - validateState(t, p.currState, end) - validateEmptyContext(t, p.context) -} - -func c0Helper(t *testing.T, bytes []byte, expectedState string, expectedCalls []string) { - parser, evtHandler := createTestParser("Ground") - parser.Parse(bytes) - validateState(t, parser.currState, expectedState) - validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls) -} diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_utilities.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_utilities.go deleted file mode 100644 index 51d1d49bf0..0000000000 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_utilities.go +++ /dev/null @@ -1,66 +0,0 @@ -package ansiterm - -import ( - "testing" -) - -func createTestParser(s string) (*AnsiParser, *TestAnsiEventHandler) { - evtHandler := CreateTestAnsiEventHandler() - parser := CreateParser(s, evtHandler) - - return parser, evtHandler -} - -func validateState(t *testing.T, actualState State, expectedStateName string) { - actualName := "Nil" - - if actualState != nil { - actualName = actualState.Name() - } - - if actualName != expectedStateName { - t.Errorf("Invalid State: '%s' != '%s'", actualName, expectedStateName) - } -} - -func validateFuncCalls(t *testing.T, actualCalls []string, expectedCalls []string) { - actualCount := len(actualCalls) - expectedCount := len(expectedCalls) - - if actualCount != expectedCount { - t.Errorf("Actual calls: %v", actualCalls) - t.Errorf("Expected calls: %v", expectedCalls) - t.Errorf("Call count error: %d != %d", actualCount, expectedCount) - return - } - - for i, v := range actualCalls { - if v != expectedCalls[i] { - t.Errorf("Actual calls: %v", actualCalls) - t.Errorf("Expected calls: %v", expectedCalls) - t.Errorf("Mismatched calls: %s != %s with lengths %d and %d", v, expectedCalls[i], len(v), len(expectedCalls[i])) - } - } -} - -func fillContext(context *AnsiContext) { - context.currentChar = 'A' - context.paramBuffer = []byte{'C', 'D', 'E'} - context.interBuffer = []byte{'F', 'G', 'H'} -} - -func validateEmptyContext(t *testing.T, context *AnsiContext) { - var expectedCurrChar byte = 0x0 - if context.currentChar != expectedCurrChar { - t.Errorf("Currentchar mismatch '%#x' != '%#x'", context.currentChar, expectedCurrChar) - } - - if len(context.paramBuffer) != 0 { - t.Errorf("Non-empty parameter buffer: %v", context.paramBuffer) - } - - if len(context.paramBuffer) != 0 { - t.Errorf("Non-empty intermediate buffer: %v", context.interBuffer) - } - -} diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/states.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/states.go index 0cbdcb3c83..f2ea1fcd12 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/states.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/states.go @@ -1,52 +1,52 @@ package ansiterm -type StateId int +type stateID int -type State interface { +type state interface { Enter() error Exit() error - Handle(byte) (State, error) + Handle(byte) (state, error) Name() string - Transition(State) error + Transition(state) error } -type BaseState struct { +type baseState struct { name string parser *AnsiParser } -func (base BaseState) Enter() error { +func (base baseState) Enter() error { return nil } -func (base BaseState) Exit() error { +func (base baseState) Exit() error { return nil } -func (base BaseState) Handle(b byte) (s State, e error) { +func (base baseState) Handle(b byte) (s state, e error) { switch { case b == CSI_ENTRY: - return base.parser.CsiEntry, nil + return base.parser.csiEntry, nil case b == DCS_ENTRY: - return base.parser.DcsEntry, nil + return base.parser.dcsEntry, nil case b == ANSI_ESCAPE_PRIMARY: - return base.parser.Escape, nil + return base.parser.escape, nil case b == OSC_STRING: - return base.parser.OscString, nil - case sliceContains(ToGroundBytes, b): - return base.parser.Ground, nil + return base.parser.oscString, nil + case sliceContains(toGroundBytes, b): + return base.parser.ground, nil } return nil, nil } -func (base BaseState) Name() string { +func (base baseState) Name() string { return base.name } -func (base BaseState) Transition(s State) error { - if s == base.parser.Ground { +func (base baseState) Transition(s state) error { + if s == base.parser.ground { execBytes := []byte{0x18} execBytes = append(execBytes, 0x1A) execBytes = append(execBytes, getByteRange(0x80, 0x8F)...) @@ -62,10 +62,10 @@ func (base BaseState) Transition(s State) error { return nil } -type DcsEntryState struct { - BaseState +type dcsEntryState struct { + baseState } -type ErrorState struct { - BaseState +type errorState struct { + baseState } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/test_event_handler.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/test_event_handler.go deleted file mode 100644 index 60f9f30b98..0000000000 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/test_event_handler.go +++ /dev/null @@ -1,173 +0,0 @@ -package ansiterm - -import ( - "fmt" - "strconv" -) - -type TestAnsiEventHandler struct { - FunctionCalls []string -} - -func CreateTestAnsiEventHandler() *TestAnsiEventHandler { - evtHandler := TestAnsiEventHandler{} - evtHandler.FunctionCalls = make([]string, 0) - return &evtHandler -} - -func (h *TestAnsiEventHandler) recordCall(call string, params []string) { - s := fmt.Sprintf("%s(%v)", call, params) - h.FunctionCalls = append(h.FunctionCalls, s) -} - -func (h *TestAnsiEventHandler) Print(b byte) error { - h.recordCall("Print", []string{string(b)}) - return nil -} - -func (h *TestAnsiEventHandler) Execute(b byte) error { - h.recordCall("Execute", []string{string(b)}) - return nil -} - -func (h *TestAnsiEventHandler) CUU(param int) error { - h.recordCall("CUU", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) CUD(param int) error { - h.recordCall("CUD", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) CUF(param int) error { - h.recordCall("CUF", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) CUB(param int) error { - h.recordCall("CUB", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) CNL(param int) error { - h.recordCall("CNL", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) CPL(param int) error { - h.recordCall("CPL", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) CHA(param int) error { - h.recordCall("CHA", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) VPA(param int) error { - h.recordCall("VPA", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) CUP(x int, y int) error { - xS, yS := strconv.Itoa(x), strconv.Itoa(y) - h.recordCall("CUP", []string{xS, yS}) - return nil -} - -func (h *TestAnsiEventHandler) HVP(x int, y int) error { - xS, yS := strconv.Itoa(x), strconv.Itoa(y) - h.recordCall("HVP", []string{xS, yS}) - return nil -} - -func (h *TestAnsiEventHandler) DECTCEM(visible bool) error { - h.recordCall("DECTCEM", []string{strconv.FormatBool(visible)}) - return nil -} - -func (h *TestAnsiEventHandler) DECOM(visible bool) error { - h.recordCall("DECOM", []string{strconv.FormatBool(visible)}) - return nil -} - -func (h *TestAnsiEventHandler) DECCOLM(use132 bool) error { - h.recordCall("DECOLM", []string{strconv.FormatBool(use132)}) - return nil -} - -func (h *TestAnsiEventHandler) ED(param int) error { - h.recordCall("ED", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) EL(param int) error { - h.recordCall("EL", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) IL(param int) error { - h.recordCall("IL", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) DL(param int) error { - h.recordCall("DL", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) ICH(param int) error { - h.recordCall("ICH", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) DCH(param int) error { - h.recordCall("DCH", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) SGR(params []int) error { - strings := []string{} - for _, v := range params { - strings = append(strings, strconv.Itoa(v)) - } - - h.recordCall("SGR", strings) - return nil -} - -func (h *TestAnsiEventHandler) SU(param int) error { - h.recordCall("SU", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) SD(param int) error { - h.recordCall("SD", []string{strconv.Itoa(param)}) - return nil -} - -func (h *TestAnsiEventHandler) DA(params []string) error { - h.recordCall("DA", params) - return nil -} - -func (h *TestAnsiEventHandler) DECSTBM(top int, bottom int) error { - topS, bottomS := strconv.Itoa(top), strconv.Itoa(bottom) - h.recordCall("DECSTBM", []string{topS, bottomS}) - return nil -} - -func (h *TestAnsiEventHandler) RI() error { - h.recordCall("RI", nil) - return nil -} - -func (h *TestAnsiEventHandler) IND() error { - h.recordCall("IND", nil) - return nil -} - -func (h *TestAnsiEventHandler) Flush() error { - return nil -} diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/ansi.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/ansi.go index 78fe92fe65..daf2f06961 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/ansi.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/ansi.go @@ -9,7 +9,7 @@ import ( "strings" "syscall" - . "github.com/Azure/go-ansiterm" + "github.com/Azure/go-ansiterm" ) // Windows keyboard constants @@ -85,17 +85,17 @@ func newAnsiCommand(command []byte) *ansiCommand { if lastCharIndex != 0 { start := 1 // skip if double char escape sequence - if command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_ESCAPE_SECONDARY { + if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY { start++ } // convert this to GetNextParam method - ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ANSI_PARAMETER_SEP) + ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP) } return ac } -func (ac *ansiCommand) paramAsSHORT(index int, defaultValue SHORT) SHORT { +func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 { if index < 0 || index >= len(ac.Parameters) { return defaultValue } @@ -105,7 +105,7 @@ func (ac *ansiCommand) paramAsSHORT(index int, defaultValue SHORT) SHORT { return defaultValue } - return SHORT(param) + return int16(param) } func (ac *ansiCommand) String() string { @@ -119,12 +119,12 @@ func (ac *ansiCommand) String() string { // See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html. func isAnsiCommandChar(b byte) bool { switch { - case ANSI_COMMAND_FIRST <= b && b <= ANSI_COMMAND_LAST && b != ANSI_ESCAPE_SECONDARY: + case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY: return true - case b == ANSI_CMD_G1 || b == ANSI_CMD_OSC || b == ANSI_CMD_DECPAM || b == ANSI_CMD_DECPNM: + case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM: // non-CSI escape sequence terminator return true - case b == ANSI_CMD_STR_TERM || b == ANSI_BEL: + case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL: // String escape sequence terminator return true } @@ -132,11 +132,11 @@ func isAnsiCommandChar(b byte) bool { } func isXtermOscSequence(command []byte, current byte) bool { - return (len(command) >= 2 && command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_CMD_OSC && current != ANSI_BEL) + return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL) } func isCharacterSelectionCmdChar(b byte) bool { - return (b == ANSI_CMD_G0 || b == ANSI_CMD_G1 || b == ANSI_CMD_G2 || b == ANSI_CMD_G3) + return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3) } // bytesToHex converts a slice of bytes to a human-readable string. @@ -150,7 +150,7 @@ func bytesToHex(b []byte) string { // ensureInRange adjusts the passed value, if necessary, to ensure it is within // the passed min / max range. -func ensureInRange(n SHORT, min SHORT, max SHORT) SHORT { +func ensureInRange(n int16, min int16, max int16) int16 { if n < min { return min } else if n > max { diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/api.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/api.go index 1f2f3853cc..462d92f8ef 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/api.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/api.go @@ -66,21 +66,21 @@ const ( // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan). // Clearing all foreground or background colors results in black; setting all creates white. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes. - FOREGROUND_BLUE WORD = 0x0001 - FOREGROUND_GREEN WORD = 0x0002 - FOREGROUND_RED WORD = 0x0004 - FOREGROUND_INTENSITY WORD = 0x0008 - FOREGROUND_MASK WORD = 0x000F - - BACKGROUND_BLUE WORD = 0x0010 - BACKGROUND_GREEN WORD = 0x0020 - BACKGROUND_RED WORD = 0x0040 - BACKGROUND_INTENSITY WORD = 0x0080 - BACKGROUND_MASK WORD = 0x00F0 - - COMMON_LVB_MASK WORD = 0xFF00 - COMMON_LVB_REVERSE_VIDEO WORD = 0x4000 - COMMON_LVB_UNDERSCORE WORD = 0x8000 + FOREGROUND_BLUE uint16 = 0x0001 + FOREGROUND_GREEN uint16 = 0x0002 + FOREGROUND_RED uint16 = 0x0004 + FOREGROUND_INTENSITY uint16 = 0x0008 + FOREGROUND_MASK uint16 = 0x000F + + BACKGROUND_BLUE uint16 = 0x0010 + BACKGROUND_GREEN uint16 = 0x0020 + BACKGROUND_RED uint16 = 0x0040 + BACKGROUND_INTENSITY uint16 = 0x0080 + BACKGROUND_MASK uint16 = 0x00F0 + + COMMON_LVB_MASK uint16 = 0xFF00 + COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000 + COMMON_LVB_UNDERSCORE uint16 = 0x8000 // Input event types // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. @@ -104,60 +104,53 @@ const ( ) // Windows API Console types -// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx for core types (e.g., SHORT) // -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD) // -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment type ( - SHORT int16 - BOOL int32 - WORD uint16 - WCHAR uint16 - DWORD uint32 - CHAR_INFO struct { - UnicodeChar WCHAR - Attributes WORD + UnicodeChar uint16 + Attributes uint16 } CONSOLE_CURSOR_INFO struct { - Size DWORD - Visible BOOL + Size uint32 + Visible int32 } CONSOLE_SCREEN_BUFFER_INFO struct { Size COORD CursorPosition COORD - Attributes WORD + Attributes uint16 Window SMALL_RECT MaximumWindowSize COORD } COORD struct { - X SHORT - Y SHORT + X int16 + Y int16 } SMALL_RECT struct { - Left SHORT - Top SHORT - Right SHORT - Bottom SHORT + Left int16 + Top int16 + Right int16 + Bottom int16 } // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. INPUT_RECORD struct { - EventType WORD + EventType uint16 KeyEvent KEY_EVENT_RECORD } KEY_EVENT_RECORD struct { - KeyDown BOOL - RepeatCount WORD - VirtualKeyCode WORD - VirtualScanCode WORD - UnicodeChar WCHAR - ControlKeyState DWORD + KeyDown int32 + RepeatCount uint16 + VirtualKeyCode uint16 + VirtualScanCode uint16 + UnicodeChar uint16 + ControlKeyState uint32 } WINDOW_BUFFER_SIZE struct { @@ -165,12 +158,12 @@ type ( } ) -// boolToBOOL converts a Go bool into a Windows BOOL. -func boolToBOOL(f bool) BOOL { +// boolToBOOL converts a Go bool into a Windows int32. +func boolToBOOL(f bool) int32 { if f { - return BOOL(1) + return int32(1) } else { - return BOOL(0) + return int32(0) } } @@ -242,7 +235,7 @@ func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error { // SetConsoleTextAttribute sets the attributes of characters written to the // console screen buffer by the WriteFile or WriteConsole function. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx. -func SetConsoleTextAttribute(handle uintptr, attribute WORD) error { +func SetConsoleTextAttribute(handle uintptr, attribute uint16) error { r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0) use(attribute) return checkError(r1, r2, err) @@ -280,7 +273,7 @@ func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) erro // It returns true if the handle was signaled; false otherwise. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx. func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) { - r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(DWORD(msWait))) + r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait))) switch r1 { case WAIT_ABANDONED, WAIT_TIMEOUT: return false, nil @@ -320,8 +313,8 @@ func checkError(r1, r2 uintptr, err error) error { // coordToPointer converts a COORD into a uintptr (by fooling the type system). func coordToPointer(c COORD) uintptr { - // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to DWORD is just to get a pointer to pass. - return uintptr(*((*DWORD)(unsafe.Pointer(&c)))) + // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass. + return uintptr(*((*uint32)(unsafe.Pointer(&c)))) } // use is a no-op, but the compiler cannot see that it is. diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/attr_translation.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/attr_translation.go index 94665db6fb..cbec8f728f 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/attr_translation.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/attr_translation.go @@ -2,9 +2,7 @@ package winterm -import ( - . "github.com/Azure/go-ansiterm" -) +import "github.com/Azure/go-ansiterm" const ( FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE @@ -13,83 +11,83 @@ const ( // collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the // request represented by the passed ANSI mode. -func collectAnsiIntoWindowsAttributes(windowsMode WORD, inverted bool, baseMode WORD, ansiMode SHORT) (WORD, bool) { +func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) { switch ansiMode { // Mode styles - case ANSI_SGR_BOLD: + case ansiterm.ANSI_SGR_BOLD: windowsMode = windowsMode | FOREGROUND_INTENSITY - case ANSI_SGR_DIM, ANSI_SGR_BOLD_DIM_OFF: + case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF: windowsMode &^= FOREGROUND_INTENSITY - case ANSI_SGR_UNDERLINE: + case ansiterm.ANSI_SGR_UNDERLINE: windowsMode = windowsMode | COMMON_LVB_UNDERSCORE - case ANSI_SGR_REVERSE: + case ansiterm.ANSI_SGR_REVERSE: inverted = true - case ANSI_SGR_REVERSE_OFF: + case ansiterm.ANSI_SGR_REVERSE_OFF: inverted = false - case ANSI_SGR_UNDERLINE_OFF: + case ansiterm.ANSI_SGR_UNDERLINE_OFF: windowsMode &^= COMMON_LVB_UNDERSCORE // Foreground colors - case ANSI_SGR_FOREGROUND_DEFAULT: + case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT: windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK) - case ANSI_SGR_FOREGROUND_BLACK: + case ansiterm.ANSI_SGR_FOREGROUND_BLACK: windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) - case ANSI_SGR_FOREGROUND_RED: + case ansiterm.ANSI_SGR_FOREGROUND_RED: windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED - case ANSI_SGR_FOREGROUND_GREEN: + case ansiterm.ANSI_SGR_FOREGROUND_GREEN: windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN - case ANSI_SGR_FOREGROUND_YELLOW: + case ansiterm.ANSI_SGR_FOREGROUND_YELLOW: windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN - case ANSI_SGR_FOREGROUND_BLUE: + case ansiterm.ANSI_SGR_FOREGROUND_BLUE: windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE - case ANSI_SGR_FOREGROUND_MAGENTA: + case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA: windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE - case ANSI_SGR_FOREGROUND_CYAN: + case ansiterm.ANSI_SGR_FOREGROUND_CYAN: windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE - case ANSI_SGR_FOREGROUND_WHITE: + case ansiterm.ANSI_SGR_FOREGROUND_WHITE: windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE // Background colors - case ANSI_SGR_BACKGROUND_DEFAULT: + case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT: // Black with no intensity windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK) - case ANSI_SGR_BACKGROUND_BLACK: + case ansiterm.ANSI_SGR_BACKGROUND_BLACK: windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) - case ANSI_SGR_BACKGROUND_RED: + case ansiterm.ANSI_SGR_BACKGROUND_RED: windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED - case ANSI_SGR_BACKGROUND_GREEN: + case ansiterm.ANSI_SGR_BACKGROUND_GREEN: windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN - case ANSI_SGR_BACKGROUND_YELLOW: + case ansiterm.ANSI_SGR_BACKGROUND_YELLOW: windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN - case ANSI_SGR_BACKGROUND_BLUE: + case ansiterm.ANSI_SGR_BACKGROUND_BLUE: windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE - case ANSI_SGR_BACKGROUND_MAGENTA: + case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA: windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE - case ANSI_SGR_BACKGROUND_CYAN: + case ansiterm.ANSI_SGR_BACKGROUND_CYAN: windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE - case ANSI_SGR_BACKGROUND_WHITE: + case ansiterm.ANSI_SGR_BACKGROUND_WHITE: windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE } @@ -97,6 +95,6 @@ func collectAnsiIntoWindowsAttributes(windowsMode WORD, inverted bool, baseMode } // invertAttributes inverts the foreground and background colors of a Windows attributes value -func invertAttributes(windowsMode WORD) WORD { +func invertAttributes(windowsMode uint16) uint16 { return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4) } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go index e4b1c255a4..f015723ade 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go @@ -3,11 +3,11 @@ package winterm const ( - Horizontal = iota - Vertical + horizontal = iota + vertical ) -func (h *WindowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT { +func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT { if h.originMode { sr := h.effectiveSr(info.Window) return SMALL_RECT{ @@ -27,7 +27,7 @@ func (h *WindowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_IN } // setCursorPosition sets the cursor to the specified position, bounded to the screen size -func (h *WindowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error { +func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error { position.X = ensureInRange(position.X, window.Left, window.Right) position.Y = ensureInRange(position.Y, window.Top, window.Bottom) err := SetConsoleCursorPosition(h.fd, position) @@ -38,15 +38,15 @@ func (h *WindowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL return err } -func (h *WindowsAnsiEventHandler) moveCursorVertical(param int) error { - return h.moveCursor(Vertical, param) +func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error { + return h.moveCursor(vertical, param) } -func (h *WindowsAnsiEventHandler) moveCursorHorizontal(param int) error { - return h.moveCursor(Horizontal, param) +func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error { + return h.moveCursor(horizontal, param) } -func (h *WindowsAnsiEventHandler) moveCursor(moveMode int, param int) error { +func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error { info, err := GetConsoleScreenBufferInfo(h.fd) if err != nil { return err @@ -54,10 +54,10 @@ func (h *WindowsAnsiEventHandler) moveCursor(moveMode int, param int) error { position := info.CursorPosition switch moveMode { - case Horizontal: - position.X += SHORT(param) - case Vertical: - position.Y += SHORT(param) + case horizontal: + position.X += int16(param) + case vertical: + position.Y += int16(param) } if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { @@ -67,7 +67,7 @@ func (h *WindowsAnsiEventHandler) moveCursor(moveMode int, param int) error { return nil } -func (h *WindowsAnsiEventHandler) moveCursorLine(param int) error { +func (h *windowsAnsiEventHandler) moveCursorLine(param int) error { info, err := GetConsoleScreenBufferInfo(h.fd) if err != nil { return err @@ -75,7 +75,7 @@ func (h *WindowsAnsiEventHandler) moveCursorLine(param int) error { position := info.CursorPosition position.X = 0 - position.Y += SHORT(param) + position.Y += int16(param) if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { return err @@ -84,14 +84,14 @@ func (h *WindowsAnsiEventHandler) moveCursorLine(param int) error { return nil } -func (h *WindowsAnsiEventHandler) moveCursorColumn(param int) error { +func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error { info, err := GetConsoleScreenBufferInfo(h.fd) if err != nil { return err } position := info.CursorPosition - position.X = SHORT(param) - 1 + position.X = int16(param) - 1 if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { return err diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/erase_helpers.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/erase_helpers.go index f02a5b261b..244b5fa25e 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/erase_helpers.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/erase_helpers.go @@ -2,11 +2,9 @@ package winterm -import ( - . "github.com/Azure/go-ansiterm" -) +import "github.com/Azure/go-ansiterm" -func (h *WindowsAnsiEventHandler) clearRange(attributes WORD, fromCoord COORD, toCoord COORD) error { +func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error { // Ignore an invalid (negative area) request if toCoord.Y < fromCoord.Y { return nil @@ -60,7 +58,7 @@ func (h *WindowsAnsiEventHandler) clearRange(attributes WORD, fromCoord COORD, t return nil } -func (h *WindowsAnsiEventHandler) clearRect(attributes WORD, fromCoord COORD, toCoord COORD) error { +func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error { region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X} width := toCoord.X - fromCoord.X + 1 height := toCoord.Y - fromCoord.Y + 1 @@ -72,7 +70,7 @@ func (h *WindowsAnsiEventHandler) clearRect(attributes WORD, fromCoord COORD, to buffer := make([]CHAR_INFO, size) - char := CHAR_INFO{WCHAR(FILL_CHARACTER), attributes} + char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes} for i := 0; i < int(size); i++ { buffer[i] = char } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/scroll_helper.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/scroll_helper.go index ed1998245c..706d270577 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/scroll_helper.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/scroll_helper.go @@ -3,9 +3,9 @@ package winterm // effectiveSr gets the current effective scroll region in buffer coordinates -func (h *WindowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion { - top := AddInRange(window.Top, h.sr.top, window.Top, window.Bottom) - bottom := AddInRange(window.Top, h.sr.bottom, window.Top, window.Bottom) +func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion { + top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom) + bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom) if top >= bottom { top = window.Top bottom = window.Bottom @@ -13,7 +13,7 @@ func (h *WindowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion { return scrollRegion{top: top, bottom: bottom} } -func (h *WindowsAnsiEventHandler) scrollUp(param int) error { +func (h *windowsAnsiEventHandler) scrollUp(param int) error { info, err := GetConsoleScreenBufferInfo(h.fd) if err != nil { return err @@ -23,11 +23,11 @@ func (h *WindowsAnsiEventHandler) scrollUp(param int) error { return h.scroll(param, sr, info) } -func (h *WindowsAnsiEventHandler) scrollDown(param int) error { +func (h *windowsAnsiEventHandler) scrollDown(param int) error { return h.scrollUp(-param) } -func (h *WindowsAnsiEventHandler) deleteLines(param int) error { +func (h *windowsAnsiEventHandler) deleteLines(param int) error { info, err := GetConsoleScreenBufferInfo(h.fd) if err != nil { return err @@ -44,12 +44,12 @@ func (h *WindowsAnsiEventHandler) deleteLines(param int) error { } } -func (h *WindowsAnsiEventHandler) insertLines(param int) error { +func (h *windowsAnsiEventHandler) insertLines(param int) error { return h.deleteLines(-param) } // scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates. -func (h *WindowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error { +func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error { logger.Infof("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom) logger.Infof("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom) @@ -64,7 +64,7 @@ func (h *WindowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSO // Origin to which area should be copied destOrigin := COORD{ X: 0, - Y: sr.top - SHORT(param), + Y: sr.top - int16(param), } char := CHAR_INFO{ @@ -78,7 +78,7 @@ func (h *WindowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSO return nil } -func (h *WindowsAnsiEventHandler) deleteCharacters(param int) error { +func (h *windowsAnsiEventHandler) deleteCharacters(param int) error { info, err := GetConsoleScreenBufferInfo(h.fd) if err != nil { return err @@ -86,12 +86,12 @@ func (h *WindowsAnsiEventHandler) deleteCharacters(param int) error { return h.scrollLine(param, info.CursorPosition, info) } -func (h *WindowsAnsiEventHandler) insertCharacters(param int) error { +func (h *windowsAnsiEventHandler) insertCharacters(param int) error { return h.deleteCharacters(-param) } // scrollLine scrolls a line horizontally starting at the provided position by a number of columns. -func (h *WindowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error { +func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error { // Copy from and clip to the scroll region (full buffer width) scrollRect := SMALL_RECT{ Top: position.Y, @@ -102,7 +102,7 @@ func (h *WindowsAnsiEventHandler) scrollLine(columns int, position COORD, info * // Origin to which area should be copied destOrigin := COORD{ - X: position.X - SHORT(columns), + X: position.X - int16(columns), Y: position.Y, } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/utilities.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/utilities.go index 2f963ff132..afa7635d77 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/utilities.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/utilities.go @@ -4,6 +4,6 @@ package winterm // AddInRange increments a value by the passed quantity while ensuring the values // always remain within the supplied min / max range. -func AddInRange(n SHORT, increment SHORT, min SHORT, max SHORT) SHORT { +func addInRange(n int16, increment int16, min int16, max int16) int16 { return ensureInRange(n+increment, min, max) } diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/win_event_handler.go b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/win_event_handler.go index 2d492b32e4..4d858ed611 100644 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/win_event_handler.go +++ b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/win_event_handler.go @@ -8,19 +8,19 @@ import ( "os" "strconv" - . "github.com/Azure/go-ansiterm" + "github.com/Azure/go-ansiterm" "github.com/Sirupsen/logrus" ) var logger *logrus.Logger -type WindowsAnsiEventHandler struct { +type windowsAnsiEventHandler struct { fd uintptr file *os.File infoReset *CONSOLE_SCREEN_BUFFER_INFO sr scrollRegion buffer bytes.Buffer - attributes WORD + attributes uint16 inverted bool wrapNext bool drewMarginByte bool @@ -30,10 +30,10 @@ type WindowsAnsiEventHandler struct { curPos COORD } -func CreateWinEventHandler(fd uintptr, file *os.File) AnsiEventHandler { +func CreateWinEventHandler(fd uintptr, file *os.File) ansiterm.AnsiEventHandler { logFile := ioutil.Discard - if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" { + if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { logFile, _ = os.Create("winEventHandler.log") } @@ -48,7 +48,7 @@ func CreateWinEventHandler(fd uintptr, file *os.File) AnsiEventHandler { return nil } - return &WindowsAnsiEventHandler{ + return &windowsAnsiEventHandler{ fd: fd, file: file, infoReset: infoReset, @@ -57,8 +57,8 @@ func CreateWinEventHandler(fd uintptr, file *os.File) AnsiEventHandler { } type scrollRegion struct { - top SHORT - bottom SHORT + top int16 + bottom int16 } // simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the @@ -68,7 +68,7 @@ type scrollRegion struct { // // In the false case, the caller should ensure that a carriage return // and line feed are inserted or that the text is otherwise wrapped. -func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { +func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { if h.wrapNext { if err := h.Flush(); err != nil { return false, err @@ -89,24 +89,25 @@ func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { h.updatePos(pos) } return false, nil - } else { - // A custom scroll region is active. Scroll the window manually to simulate - // the LF. - if err := h.Flush(); err != nil { - return false, err - } - logger.Info("Simulating LF inside scroll region") - if err := h.scrollUp(1); err != nil { + } + + // A custom scroll region is active. Scroll the window manually to simulate + // the LF. + if err := h.Flush(); err != nil { + return false, err + } + logger.Info("Simulating LF inside scroll region") + if err := h.scrollUp(1); err != nil { + return false, err + } + if includeCR { + pos.X = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { return false, err } - if includeCR { - pos.X = 0 - if err := SetConsoleCursorPosition(h.fd, pos); err != nil { - return false, err - } - } - return true, nil } + return true, nil + } else if pos.Y < info.Window.Bottom { // Let Windows handle the LF. pos.Y++ @@ -133,7 +134,7 @@ func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { } // executeLF executes a LF without a CR. -func (h *WindowsAnsiEventHandler) executeLF() error { +func (h *windowsAnsiEventHandler) executeLF() error { handled, err := h.simulateLF(false) if err != nil { return err @@ -145,7 +146,7 @@ func (h *WindowsAnsiEventHandler) executeLF() error { if err != nil { return err } - h.buffer.WriteByte(ANSI_LINE_FEED) + h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) if pos.X != 0 { if err := h.Flush(); err != nil { return err @@ -159,7 +160,7 @@ func (h *WindowsAnsiEventHandler) executeLF() error { return nil } -func (h *WindowsAnsiEventHandler) Print(b byte) error { +func (h *windowsAnsiEventHandler) Print(b byte) error { if h.wrapNext { h.buffer.WriteByte(h.marginByte) h.clearWrap() @@ -182,9 +183,9 @@ func (h *WindowsAnsiEventHandler) Print(b byte) error { return nil } -func (h *WindowsAnsiEventHandler) Execute(b byte) error { +func (h *windowsAnsiEventHandler) Execute(b byte) error { switch b { - case ANSI_TAB: + case ansiterm.ANSI_TAB: logger.Info("Execute(TAB)") // Move to the next tab stop, but preserve auto-wrap if already set. if !h.wrapNext { @@ -205,11 +206,11 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error { } return nil - case ANSI_BEL: - h.buffer.WriteByte(ANSI_BEL) + case ansiterm.ANSI_BEL: + h.buffer.WriteByte(ansiterm.ANSI_BEL) return nil - case ANSI_BACKSPACE: + case ansiterm.ANSI_BACKSPACE: if h.wrapNext { if err := h.Flush(); err != nil { return err @@ -223,15 +224,15 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error { if pos.X > 0 { pos.X-- h.updatePos(pos) - h.buffer.WriteByte(ANSI_BACKSPACE) + h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE) } return nil - case ANSI_VERTICAL_TAB, ANSI_FORM_FEED: + case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED: // Treat as true LF. return h.executeLF() - case ANSI_LINE_FEED: + case ansiterm.ANSI_LINE_FEED: // Simulate a CR and LF for now since there is no way in go-ansiterm // to tell if the LF should include CR (and more things break when it's // missing than when it's incorrectly added). @@ -239,9 +240,9 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error { if handled || err != nil { return err } - return h.buffer.WriteByte(ANSI_LINE_FEED) + return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) - case ANSI_CARRIAGE_RETURN: + case ansiterm.ANSI_CARRIAGE_RETURN: if h.wrapNext { if err := h.Flush(); err != nil { return err @@ -255,7 +256,7 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error { if pos.X != 0 { pos.X = 0 h.updatePos(pos) - h.buffer.WriteByte(ANSI_CARRIAGE_RETURN) + h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN) } return nil @@ -264,7 +265,7 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error { } } -func (h *WindowsAnsiEventHandler) CUU(param int) error { +func (h *windowsAnsiEventHandler) CUU(param int) error { if err := h.Flush(); err != nil { return err } @@ -273,7 +274,7 @@ func (h *WindowsAnsiEventHandler) CUU(param int) error { return h.moveCursorVertical(-param) } -func (h *WindowsAnsiEventHandler) CUD(param int) error { +func (h *windowsAnsiEventHandler) CUD(param int) error { if err := h.Flush(); err != nil { return err } @@ -282,7 +283,7 @@ func (h *WindowsAnsiEventHandler) CUD(param int) error { return h.moveCursorVertical(param) } -func (h *WindowsAnsiEventHandler) CUF(param int) error { +func (h *windowsAnsiEventHandler) CUF(param int) error { if err := h.Flush(); err != nil { return err } @@ -291,7 +292,7 @@ func (h *WindowsAnsiEventHandler) CUF(param int) error { return h.moveCursorHorizontal(param) } -func (h *WindowsAnsiEventHandler) CUB(param int) error { +func (h *windowsAnsiEventHandler) CUB(param int) error { if err := h.Flush(); err != nil { return err } @@ -300,7 +301,7 @@ func (h *WindowsAnsiEventHandler) CUB(param int) error { return h.moveCursorHorizontal(-param) } -func (h *WindowsAnsiEventHandler) CNL(param int) error { +func (h *windowsAnsiEventHandler) CNL(param int) error { if err := h.Flush(); err != nil { return err } @@ -309,7 +310,7 @@ func (h *WindowsAnsiEventHandler) CNL(param int) error { return h.moveCursorLine(param) } -func (h *WindowsAnsiEventHandler) CPL(param int) error { +func (h *windowsAnsiEventHandler) CPL(param int) error { if err := h.Flush(); err != nil { return err } @@ -318,7 +319,7 @@ func (h *WindowsAnsiEventHandler) CPL(param int) error { return h.moveCursorLine(-param) } -func (h *WindowsAnsiEventHandler) CHA(param int) error { +func (h *windowsAnsiEventHandler) CHA(param int) error { if err := h.Flush(); err != nil { return err } @@ -327,7 +328,7 @@ func (h *WindowsAnsiEventHandler) CHA(param int) error { return h.moveCursorColumn(param) } -func (h *WindowsAnsiEventHandler) VPA(param int) error { +func (h *windowsAnsiEventHandler) VPA(param int) error { if err := h.Flush(); err != nil { return err } @@ -339,11 +340,11 @@ func (h *WindowsAnsiEventHandler) VPA(param int) error { } window := h.getCursorWindow(info) position := info.CursorPosition - position.Y = window.Top + SHORT(param) - 1 + position.Y = window.Top + int16(param) - 1 return h.setCursorPosition(position, window) } -func (h *WindowsAnsiEventHandler) CUP(row int, col int) error { +func (h *windowsAnsiEventHandler) CUP(row int, col int) error { if err := h.Flush(); err != nil { return err } @@ -355,11 +356,11 @@ func (h *WindowsAnsiEventHandler) CUP(row int, col int) error { } window := h.getCursorWindow(info) - position := COORD{window.Left + SHORT(col) - 1, window.Top + SHORT(row) - 1} + position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1} return h.setCursorPosition(position, window) } -func (h *WindowsAnsiEventHandler) HVP(row int, col int) error { +func (h *windowsAnsiEventHandler) HVP(row int, col int) error { if err := h.Flush(); err != nil { return err } @@ -368,7 +369,7 @@ func (h *WindowsAnsiEventHandler) HVP(row int, col int) error { return h.CUP(row, col) } -func (h *WindowsAnsiEventHandler) DECTCEM(visible bool) error { +func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error { if err := h.Flush(); err != nil { return err } @@ -377,7 +378,7 @@ func (h *WindowsAnsiEventHandler) DECTCEM(visible bool) error { return nil } -func (h *WindowsAnsiEventHandler) DECOM(enable bool) error { +func (h *windowsAnsiEventHandler) DECOM(enable bool) error { if err := h.Flush(); err != nil { return err } @@ -387,7 +388,7 @@ func (h *WindowsAnsiEventHandler) DECOM(enable bool) error { return h.CUP(1, 1) } -func (h *WindowsAnsiEventHandler) DECCOLM(use132 bool) error { +func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error { if err := h.Flush(); err != nil { return err } @@ -400,7 +401,7 @@ func (h *WindowsAnsiEventHandler) DECCOLM(use132 bool) error { if err != nil { return err } - targetWidth := SHORT(80) + targetWidth := int16(80) if use132 { targetWidth = 132 } @@ -426,7 +427,7 @@ func (h *WindowsAnsiEventHandler) DECCOLM(use132 bool) error { return SetConsoleCursorPosition(h.fd, COORD{0, 0}) } -func (h *WindowsAnsiEventHandler) ED(param int) error { +func (h *windowsAnsiEventHandler) ED(param int) error { if err := h.Flush(); err != nil { return err } @@ -485,7 +486,7 @@ func (h *WindowsAnsiEventHandler) ED(param int) error { return nil } -func (h *WindowsAnsiEventHandler) EL(param int) error { +func (h *windowsAnsiEventHandler) EL(param int) error { if err := h.Flush(); err != nil { return err } @@ -526,7 +527,7 @@ func (h *WindowsAnsiEventHandler) EL(param int) error { return nil } -func (h *WindowsAnsiEventHandler) IL(param int) error { +func (h *windowsAnsiEventHandler) IL(param int) error { if err := h.Flush(); err != nil { return err } @@ -535,7 +536,7 @@ func (h *WindowsAnsiEventHandler) IL(param int) error { return h.insertLines(param) } -func (h *WindowsAnsiEventHandler) DL(param int) error { +func (h *windowsAnsiEventHandler) DL(param int) error { if err := h.Flush(); err != nil { return err } @@ -544,7 +545,7 @@ func (h *WindowsAnsiEventHandler) DL(param int) error { return h.deleteLines(param) } -func (h *WindowsAnsiEventHandler) ICH(param int) error { +func (h *windowsAnsiEventHandler) ICH(param int) error { if err := h.Flush(); err != nil { return err } @@ -553,7 +554,7 @@ func (h *WindowsAnsiEventHandler) ICH(param int) error { return h.insertCharacters(param) } -func (h *WindowsAnsiEventHandler) DCH(param int) error { +func (h *windowsAnsiEventHandler) DCH(param int) error { if err := h.Flush(); err != nil { return err } @@ -562,7 +563,7 @@ func (h *WindowsAnsiEventHandler) DCH(param int) error { return h.deleteCharacters(param) } -func (h *WindowsAnsiEventHandler) SGR(params []int) error { +func (h *windowsAnsiEventHandler) SGR(params []int) error { if err := h.Flush(); err != nil { return err } @@ -579,13 +580,13 @@ func (h *WindowsAnsiEventHandler) SGR(params []int) error { } else { for _, attr := range params { - if attr == ANSI_SGR_RESET { + if attr == ansiterm.ANSI_SGR_RESET { h.attributes = h.infoReset.Attributes h.inverted = false continue } - h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, SHORT(attr)) + h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr)) } } @@ -601,7 +602,7 @@ func (h *WindowsAnsiEventHandler) SGR(params []int) error { return nil } -func (h *WindowsAnsiEventHandler) SU(param int) error { +func (h *windowsAnsiEventHandler) SU(param int) error { if err := h.Flush(); err != nil { return err } @@ -610,7 +611,7 @@ func (h *WindowsAnsiEventHandler) SU(param int) error { return h.scrollUp(param) } -func (h *WindowsAnsiEventHandler) SD(param int) error { +func (h *windowsAnsiEventHandler) SD(param int) error { if err := h.Flush(); err != nil { return err } @@ -619,29 +620,29 @@ func (h *WindowsAnsiEventHandler) SD(param int) error { return h.scrollDown(param) } -func (h *WindowsAnsiEventHandler) DA(params []string) error { +func (h *windowsAnsiEventHandler) DA(params []string) error { logger.Infof("DA: [%v]", params) // DA cannot be implemented because it must send data on the VT100 input stream, // which is not available to go-ansiterm. return nil } -func (h *WindowsAnsiEventHandler) DECSTBM(top int, bottom int) error { +func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error { if err := h.Flush(); err != nil { return err } logger.Infof("DECSTBM: [%d, %d]", top, bottom) // Windows is 0 indexed, Linux is 1 indexed - h.sr.top = SHORT(top - 1) - h.sr.bottom = SHORT(bottom - 1) + h.sr.top = int16(top - 1) + h.sr.bottom = int16(bottom - 1) // This command also moves the cursor to the origin. h.clearWrap() return h.CUP(1, 1) } -func (h *WindowsAnsiEventHandler) RI() error { +func (h *windowsAnsiEventHandler) RI() error { if err := h.Flush(); err != nil { return err } @@ -656,17 +657,17 @@ func (h *WindowsAnsiEventHandler) RI() error { sr := h.effectiveSr(info.Window) if info.CursorPosition.Y == sr.top { return h.scrollDown(1) - } else { - return h.moveCursorVertical(-1) } + + return h.moveCursorVertical(-1) } -func (h *WindowsAnsiEventHandler) IND() error { +func (h *windowsAnsiEventHandler) IND() error { logger.Info("IND: []") return h.executeLF() } -func (h *WindowsAnsiEventHandler) Flush() error { +func (h *windowsAnsiEventHandler) Flush() error { h.curInfo = nil if h.buffer.Len() > 0 { logger.Infof("Flush: [%s]", h.buffer.Bytes()) @@ -683,7 +684,7 @@ func (h *WindowsAnsiEventHandler) Flush() error { return err } - charInfo := []CHAR_INFO{{UnicodeChar: WCHAR(h.marginByte), Attributes: info.Attributes}} + charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}} size := COORD{1, 1} position := COORD{0, 0} region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y} @@ -697,7 +698,7 @@ func (h *WindowsAnsiEventHandler) Flush() error { // cacheConsoleInfo ensures that the current console screen information has been queried // since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos. -func (h *WindowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) { +func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) { if h.curInfo == nil { info, err := GetConsoleScreenBufferInfo(h.fd) if err != nil { @@ -709,7 +710,7 @@ func (h *WindowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFE return h.curPos, h.curInfo, nil } -func (h *WindowsAnsiEventHandler) updatePos(pos COORD) { +func (h *windowsAnsiEventHandler) updatePos(pos COORD) { if h.curInfo == nil { panic("failed to call getCurrentInfo before calling updatePos") } @@ -719,7 +720,7 @@ func (h *WindowsAnsiEventHandler) updatePos(pos COORD) { // clearWrap clears the state where the cursor is in the margin // waiting for the next character before wrapping the line. This must // be done before most operations that act on the cursor. -func (h *WindowsAnsiEventHandler) clearWrap() { +func (h *windowsAnsiEventHandler) clearWrap() { h.wrapNext = false h.drewMarginByte = false } diff --git a/Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore b/Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/github.com/armon/go-metrics/metrics.go b/Godeps/_workspace/src/github.com/armon/go-metrics/metrics.go old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/github.com/armon/go-metrics/sink.go b/Godeps/_workspace/src/github.com/armon/go-metrics/sink.go old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/github.com/armon/go-metrics/start.go b/Godeps/_workspace/src/github.com/armon/go-metrics/start.go old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/github.com/armon/go-metrics/statsite.go b/Godeps/_workspace/src/github.com/armon/go-metrics/statsite.go old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go index 59bba96265..eca129be39 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go @@ -20,7 +20,8 @@ var ( // ErrClosed is returned when Write is called on a closed BytesPipe. ErrClosed = errors.New("write to closed BytesPipe") - bufPools = make(map[int]*sync.Pool) + bufPools = make(map[int]*sync.Pool) + bufPoolsLock sync.Mutex ) // BytesPipe is io.ReadWriteCloser which works similarly to pipe(queue). @@ -164,17 +165,21 @@ func (bp *BytesPipe) Read(p []byte) (n int, err error) { func returnBuffer(b *fixedBuffer) { b.Reset() + bufPoolsLock.Lock() pool := bufPools[b.Cap()] + bufPoolsLock.Unlock() if pool != nil { pool.Put(b) } } func getBuffer(size int) *fixedBuffer { + bufPoolsLock.Lock() pool, ok := bufPools[size] if !ok { pool = &sync.Pool{New: func() interface{} { return &fixedBuffer{buf: make([]byte, 0, size)} }} bufPools[size] = pool } + bufPoolsLock.Unlock() return pool.Get().(*fixedBuffer) } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go new file mode 100644 index 0000000000..ca97670724 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go @@ -0,0 +1,75 @@ +package ioutils + +import ( + "io" + "io/ioutil" + "os" + "path/filepath" +) + +// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a +// temporary file and closing it atomically changes the temporary file to +// destination path. Writing and closing concurrently is not allowed. +func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) { + f, err := ioutil.TempFile(filepath.Dir(filename), ".tmp-"+filepath.Base(filename)) + if err != nil { + return nil, err + } + abspath, err := filepath.Abs(filename) + if err != nil { + return nil, err + } + return &atomicFileWriter{ + f: f, + fn: abspath, + }, nil +} + +// AtomicWriteFile atomically writes data to a file named by filename. +func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { + f, err := NewAtomicFileWriter(filename, perm) + if err != nil { + return err + } + n, err := f.Write(data) + if err == nil && n < len(data) { + err = io.ErrShortWrite + } + if err1 := f.Close(); err == nil { + err = err1 + } + return err +} + +type atomicFileWriter struct { + f *os.File + fn string + writeErr error +} + +func (w *atomicFileWriter) Write(dt []byte) (int, error) { + n, err := w.f.Write(dt) + if err != nil { + w.writeErr = err + } + return n, err +} + +func (w *atomicFileWriter) Close() (retErr error) { + defer func() { + if retErr != nil { + os.Remove(w.f.Name()) + } + }() + if err := w.f.Sync(); err != nil { + w.f.Close() + return err + } + if err := w.f.Close(); err != nil { + return err + } + if w.writeErr == nil { + return os.Rename(w.f.Name(), w.fn) + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_unsupported.go index a90d3d1151..5564f7b3cd 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd freebsd,!cgo +// +build !linux,!freebsd freebsd,!cgo solaris,!cgo package mount diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mount.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mount.go index ed7216e5c0..66ac4bf472 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mount.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mount.go @@ -9,8 +9,8 @@ func GetMounts() ([]*Info, error) { return parseMountTable() } -// Mounted looks at /proc/self/mountinfo to determine of the specified -// mountpoint has been mounted +// Mounted determines if a specified mountpoint has been mounted. +// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab. func Mounted(mountpoint string) (bool, error) { entries, err := parseMountTable() if err != nil { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_solaris.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_solaris.go new file mode 100644 index 0000000000..c684aa81fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_solaris.go @@ -0,0 +1,33 @@ +// +build solaris,cgo + +package mount + +import ( + "golang.org/x/sys/unix" + "unsafe" +) + +// #include +// #include +// #include +// int Mount(const char *spec, const char *dir, int mflag, +// char *fstype, char *dataptr, int datalen, char *optptr, int optlen) { +// return mount(spec, dir, mflag, fstype, dataptr, datalen, optptr, optlen); +// } +import "C" + +func mount(device, target, mType string, flag uintptr, data string) error { + spec := C.CString(device) + dir := C.CString(target) + fstype := C.CString(mType) + _, err := C.Mount(spec, dir, C.int(flag), fstype, nil, 0, nil, 0) + C.free(unsafe.Pointer(spec)) + C.free(unsafe.Pointer(dir)) + C.free(unsafe.Pointer(fstype)) + return err +} + +func unmount(target string, flag int) error { + err := unix.Unmount(target, flag) + return err +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go index eb93365eb7..a2a3bb457f 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd freebsd,!cgo +// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo package mount diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_solaris.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_solaris.go new file mode 100644 index 0000000000..ad9ab57f8b --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_solaris.go @@ -0,0 +1,37 @@ +// +build solaris,cgo + +package mount + +/* +#include +#include +*/ +import "C" + +import ( + "fmt" +) + +func parseMountTable() ([]*Info, error) { + mnttab := C.fopen(C.CString(C.MNTTAB), C.CString("r")) + if mnttab == nil { + return nil, fmt.Errorf("Failed to open %s", C.MNTTAB) + } + + var out []*Info + var mp C.struct_mnttab + + ret := C.getmntent(mnttab, &mp) + for ret == 0 { + var mountinfo Info + mountinfo.Mountpoint = C.GoString(mp.mnt_mountp) + mountinfo.Source = C.GoString(mp.mnt_special) + mountinfo.Fstype = C.GoString(mp.mnt_fstype) + mountinfo.Opts = C.GoString(mp.mnt_mntopts) + out = append(out, &mountinfo) + ret = C.getmntent(mnttab, &mp) + } + + C.fclose(mnttab) + return out, nil +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go index b8d9aa5c73..7fbcf19214 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go @@ -1,4 +1,4 @@ -// +build !windows,!linux,!freebsd freebsd,!cgo +// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo package mount diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_solaris.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_solaris.go new file mode 100644 index 0000000000..49370bd3dd --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_solaris.go @@ -0,0 +1,14 @@ +package kernel + +import ( + "golang.org/x/sys/unix" +) + +func uname() (*unix.Utsname, error) { + uts := &unix.Utsname{} + + if err := unix.Uname(uts); err != nil { + return nil, err + } + return uts, nil +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go index 79c66b3228..1da3f239fa 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux,!solaris package kernel diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_freebsd.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unix.go similarity index 94% rename from Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_freebsd.go rename to Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unix.go index c7f797a5fa..b70edcb316 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_freebsd.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unix.go @@ -1,4 +1,4 @@ -// +build freebsd +// +build freebsd solaris package reexec diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go index ad4ea38ebb..9aed004e86 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!freebsd +// +build !linux,!windows,!freebsd,!solaris package reexec diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_solaris.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_solaris.go new file mode 100644 index 0000000000..89576b9e3b --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_solaris.go @@ -0,0 +1,42 @@ +package signal + +import ( + "syscall" +) + +// SignalMap is a map of Solaris signals. +// SIGINFO and SIGTHR not defined for Solaris +var SignalMap = map[string]syscall.Signal{ + "ABRT": syscall.SIGABRT, + "ALRM": syscall.SIGALRM, + "BUF": syscall.SIGBUS, + "CHLD": syscall.SIGCHLD, + "CONT": syscall.SIGCONT, + "EMT": syscall.SIGEMT, + "FPE": syscall.SIGFPE, + "HUP": syscall.SIGHUP, + "ILL": syscall.SIGILL, + "INT": syscall.SIGINT, + "IO": syscall.SIGIO, + "IOT": syscall.SIGIOT, + "KILL": syscall.SIGKILL, + "LWP": syscall.SIGLWP, + "PIPE": syscall.SIGPIPE, + "PROF": syscall.SIGPROF, + "QUIT": syscall.SIGQUIT, + "SEGV": syscall.SIGSEGV, + "STOP": syscall.SIGSTOP, + "SYS": syscall.SIGSYS, + "TERM": syscall.SIGTERM, + "TRAP": syscall.SIGTRAP, + "TSTP": syscall.SIGTSTP, + "TTIN": syscall.SIGTTIN, + "TTOU": syscall.SIGTTOU, + "URG": syscall.SIGURG, + "USR1": syscall.SIGUSR1, + "USR2": syscall.SIGUSR2, + "VTALRM": syscall.SIGVTALRM, + "WINCH": syscall.SIGWINCH, + "XCPU": syscall.SIGXCPU, + "XFSZ": syscall.SIGXFSZ, +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_unsupported.go index 161ba27397..c592d37dfe 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!darwin,!freebsd,!windows +// +build !linux,!darwin,!freebsd,!windows,!solaris package signal diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/meminfo_solaris.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/meminfo_solaris.go new file mode 100644 index 0000000000..313c601b12 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/meminfo_solaris.go @@ -0,0 +1,128 @@ +// +build solaris,cgo + +package system + +import ( + "fmt" + "unsafe" +) + +// #cgo LDFLAGS: -lkstat +// #include +// #include +// #include +// #include +// #include +// #include +// struct swaptable *allocSwaptable(int num) { +// struct swaptable *st; +// struct swapent *swapent; +// st = (struct swaptable *)malloc(num * sizeof(swapent_t) + sizeof (int)); +// swapent = st->swt_ent; +// for (int i = 0; i < num; i++,swapent++) { +// swapent->ste_path = (char *)malloc(MAXPATHLEN * sizeof (char)); +// } +// st->swt_n = num; +// return st; +//} +// void freeSwaptable (struct swaptable *st) { +// struct swapent *swapent = st->swt_ent; +// for (int i = 0; i < st->swt_n; i++,swapent++) { +// free(swapent->ste_path); +// } +// free(st); +// } +// swapent_t getSwapEnt(swapent_t *ent, int i) { +// return ent[i]; +// } +// int64_t getPpKernel() { +// int64_t pp_kernel = 0; +// kstat_ctl_t *ksc; +// kstat_t *ks; +// kstat_named_t *knp; +// kid_t kid; +// +// if ((ksc = kstat_open()) == NULL) { +// return -1; +// } +// if ((ks = kstat_lookup(ksc, "unix", 0, "system_pages")) == NULL) { +// return -1; +// } +// if (((kid = kstat_read(ksc, ks, NULL)) == -1) || +// ((knp = kstat_data_lookup(ks, "pp_kernel")) == NULL)) { +// return -1; +// } +// switch (knp->data_type) { +// case KSTAT_DATA_UINT64: +// pp_kernel = knp->value.ui64; +// break; +// case KSTAT_DATA_UINT32: +// pp_kernel = knp->value.ui32; +// break; +// } +// pp_kernel *= sysconf(_SC_PAGESIZE); +// return (pp_kernel > 0 ? pp_kernel : -1); +// } +import "C" + +// Get the system memory info using sysconf same as prtconf +func getTotalMem() int64 { + pagesize := C.sysconf(C._SC_PAGESIZE) + npages := C.sysconf(C._SC_PHYS_PAGES) + return int64(pagesize * npages) +} + +func getFreeMem() int64 { + pagesize := C.sysconf(C._SC_PAGESIZE) + npages := C.sysconf(C._SC_AVPHYS_PAGES) + return int64(pagesize * npages) +} + +// ReadMemInfo retrieves memory statistics of the host system and returns a +// MemInfo type. +func ReadMemInfo() (*MemInfo, error) { + + ppKernel := C.getPpKernel() + MemTotal := getTotalMem() + MemFree := getFreeMem() + SwapTotal, SwapFree, err := getSysSwap() + + if ppKernel < 0 || MemTotal < 0 || MemFree < 0 || SwapTotal < 0 || + SwapFree < 0 { + return nil, fmt.Errorf("Error getting system memory info %v\n", err) + } + + meminfo := &MemInfo{} + // Total memory is total physical memory less than memory locked by kernel + meminfo.MemTotal = MemTotal - int64(ppKernel) + meminfo.MemFree = MemFree + meminfo.SwapTotal = SwapTotal + meminfo.SwapFree = SwapFree + + return meminfo, nil +} + +func getSysSwap() (int64, int64, error) { + var tSwap int64 + var fSwap int64 + var diskblksPerPage int64 + num, err := C.swapctl(C.SC_GETNSWP, nil) + if err != nil { + return -1, -1, err + } + st := C.allocSwaptable(num) + _, err = C.swapctl(C.SC_LIST, unsafe.Pointer(st)) + if err != nil { + C.freeSwaptable(st) + return -1, -1, err + } + + diskblksPerPage = int64(C.sysconf(C._SC_PAGESIZE) >> C.DEV_BSHIFT) + for i := 0; i < int(num); i++ { + swapent := C.getSwapEnt(&st.swt_ent[0], C.int(i)) + tSwap += int64(swapent.ste_pages) * diskblksPerPage + fSwap += int64(swapent.ste_free) * diskblksPerPage + } + C.freeSwaptable(st) + return tSwap, fSwap, nil +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/meminfo_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/meminfo_unsupported.go index 82ddd30c1b..3ce019dffd 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/meminfo_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/meminfo_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows +// +build !linux,!windows,!solaris package system diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/path_unix.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/path_unix.go index 1b6cc9cbd9..c607c4db09 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/path_unix.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/path_unix.go @@ -6,3 +6,9 @@ package system // executables. Each directory is separated from the next by a colon // ':' character . const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter, +// is the system drive. This is a no-op on Linux. +func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) { + return path, nil +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/path_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/path_windows.go index 09e7f89fed..cbfe2c1576 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/path_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/path_windows.go @@ -2,6 +2,36 @@ package system +import ( + "fmt" + "path/filepath" + "strings" +) + // DefaultPathEnv is deliberately empty on Windows as the default path will be set by // the container. Docker has no context of what the default path should be. const DefaultPathEnv = "" + +// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path. +// This is used, for example, when validating a user provided path in docker cp. +// If a drive letter is supplied, it must be the system drive. The drive letter +// is always removed. Also, it translates it to OS semantics (IOW / to \). We +// need the path in this syntax so that it can ultimately be contatenated with +// a Windows long-path which doesn't support drive-letters. Examples: +// C: --> Fail +// C:\ --> \ +// a --> a +// /a --> \a +// d:\ --> Fail +func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) { + if len(path) == 2 && string(path[1]) == ":" { + return "", fmt.Errorf("No relative path specified in %q", path) + } + if !filepath.IsAbs(path) || len(path) < 2 { + return filepath.FromSlash(path), nil + } + if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") { + return "", fmt.Errorf("The specified path is not on the system drive (C:)") + } + return filepath.FromSlash(path[2:]), nil +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_solaris.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_solaris.go index b01d08acfe..0216985a25 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_solaris.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_solaris.go @@ -15,3 +15,20 @@ func fromStatT(s *syscall.Stat_t) (*StatT, error) { rdev: uint64(s.Rdev), mtim: s.Mtim}, nil } + +// FromStatT loads a system.StatT from a syscal.Stat_t. +func FromStatT(s *syscall.Stat_t) (*StatT, error) { + return fromStatT(s) +} + +// Stat takes a path to a file and returns +// a system.StatT type pertaining to that file. +// +// Throws an error if the file does not exist +func Stat(path string) (*StatT, error) { + s := &syscall.Stat_t{} + if err := syscall.Stat(path, s); err != nil { + return nil, err + } + return fromStatT(s) +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/syscall_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/syscall_windows.go index ef596f343f..f5f2d56941 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/syscall_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/syscall_windows.go @@ -3,10 +3,13 @@ package system import ( "syscall" "unsafe" + + "github.com/Sirupsen/logrus" ) var ( - ntuserApiset = syscall.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") + ntuserApiset = syscall.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") + procGetVersionExW = modkernel32.NewProc("GetVersionExW") ) // OSVersion is a wrapper for Windows version information @@ -18,6 +21,21 @@ type OSVersion struct { Build uint16 } +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx +type osVersionInfoEx struct { + OSVersionInfoSize uint32 + MajorVersion uint32 + MinorVersion uint32 + BuildNumber uint32 + PlatformID uint32 + CSDVersion [128]uint16 + ServicePackMajor uint16 + ServicePackMinor uint16 + SuiteMask uint16 + ProductType byte + Reserve byte +} + // GetOSVersion gets the operating system version on Windows. Note that // docker.exe must be manifested to get the correct version information. func GetOSVersion() OSVersion { @@ -34,6 +52,18 @@ func GetOSVersion() OSVersion { return osv } +// IsWindowsClient returns true if the SKU is client +func IsWindowsClient() bool { + osviex := &osVersionInfoEx{OSVersionInfoSize: 284} + r1, _, err := procGetVersionExW.Call(uintptr(unsafe.Pointer(osviex))) + if r1 == 0 { + logrus.Warnf("GetVersionExW failed - assuming server SKU: %v", err) + return false + } + const verNTWorkstation = 0x00000001 + return osviex.ProductType == verNTWorkstation +} + // Unmount is a platform-specific helper function to call // the unmount syscall. Not supported on Windows func Unmount(dest string) error { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go index cd21b5fc2b..9bc52a8c65 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go @@ -83,11 +83,13 @@ func useNativeConsole() bool { return false } - // TODO Windows. The native emulator still has issues which - // mean it shouldn't be enabled for everyone. Change this next line to true - // to change the default to "enable if available". In the meantime, users - // can still try it out by using USE_NATIVE_CONSOLE env variable. - return false + // Must have a post-TP5 RS1 build of Windows Server 2016/Windows 10 for + // the native console to be usable. + if osv.Build < 14350 { + return false + } + + return true } // getNativeConsole returns the console modes ('state') for the native Windows console diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_reader.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_reader.go index 3bf2b2b6b4..5b91b78342 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_reader.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_reader.go @@ -136,14 +136,14 @@ func readInputEvents(fd uintptr, maxBytes int) ([]winterm.INPUT_RECORD, error) { // KeyEvent Translation Helpers -var arrowKeyMapPrefix = map[winterm.WORD]string{ +var arrowKeyMapPrefix = map[uint16]string{ winterm.VK_UP: "%s%sA", winterm.VK_DOWN: "%s%sB", winterm.VK_RIGHT: "%s%sC", winterm.VK_LEFT: "%s%sD", } -var keyMapPrefix = map[winterm.WORD]string{ +var keyMapPrefix = map[uint16]string{ winterm.VK_UP: "\x1B[%sA", winterm.VK_DOWN: "\x1B[%sB", winterm.VK_RIGHT: "\x1B[%sC", @@ -207,7 +207,7 @@ func keyToString(keyEvent *winterm.KEY_EVENT_RECORD, escapeSequence []byte) stri } // formatVirtualKey converts a virtual key (e.g., up arrow) into the appropriate ANSI string. -func formatVirtualKey(key winterm.WORD, controlState winterm.DWORD, escapeSequence []byte) string { +func formatVirtualKey(key uint16, controlState uint32, escapeSequence []byte) string { shift, alt, control := getControlKeys(controlState) modifier := getControlKeysModifier(shift, alt, control) @@ -223,7 +223,7 @@ func formatVirtualKey(key winterm.WORD, controlState winterm.DWORD, escapeSequen } // getControlKeys extracts the shift, alt, and ctrl key states. -func getControlKeys(controlState winterm.DWORD) (shift, alt, control bool) { +func getControlKeys(controlState uint32) (shift, alt, control bool) { shift = 0 != (controlState & winterm.SHIFT_PRESSED) alt = 0 != (controlState & (winterm.LEFT_ALT_PRESSED | winterm.RIGHT_ALT_PRESSED)) control = 0 != (controlState & (winterm.LEFT_CTRL_PRESSED | winterm.RIGHT_CTRL_PRESSED)) diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go b/Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go deleted file mode 100644 index dc2c48b894..0000000000 --- a/Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go +++ /dev/null @@ -1,307 +0,0 @@ -// Package filters provides helper function to parse and handle command line -// filter, used for example in docker ps or docker images commands. -package filters - -import ( - "encoding/json" - "errors" - "fmt" - "regexp" - "strings" - - "github.com/docker/engine-api/types/versions" -) - -// Args stores filter arguments as map key:{map key: bool}. -// It contains an aggregation of the map of arguments (which are in the form -// of -f 'key=value') based on the key, and stores values for the same key -// in a map with string keys and boolean values. -// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu' -// the args will be {"image.name":{"ubuntu":true},"label":{"label1=1":true,"label2=2":true}} -type Args struct { - fields map[string]map[string]bool -} - -// NewArgs initializes a new Args struct. -func NewArgs() Args { - return Args{fields: map[string]map[string]bool{}} -} - -// ParseFlag parses the argument to the filter flag. Like -// -// `docker ps -f 'created=today' -f 'image.name=ubuntu*'` -// -// If prev map is provided, then it is appended to, and returned. By default a new -// map is created. -func ParseFlag(arg string, prev Args) (Args, error) { - filters := prev - if len(arg) == 0 { - return filters, nil - } - - if !strings.Contains(arg, "=") { - return filters, ErrBadFormat - } - - f := strings.SplitN(arg, "=", 2) - - name := strings.ToLower(strings.TrimSpace(f[0])) - value := strings.TrimSpace(f[1]) - - filters.Add(name, value) - - return filters, nil -} - -// ErrBadFormat is an error returned in case of bad format for a filter. -var ErrBadFormat = errors.New("bad format of filter (expected name=value)") - -// ToParam packs the Args into a string for easy transport from client to server. -func ToParam(a Args) (string, error) { - // this way we don't URL encode {}, just empty space - if a.Len() == 0 { - return "", nil - } - - buf, err := json.Marshal(a.fields) - if err != nil { - return "", err - } - return string(buf), nil -} - -// ToParamWithVersion packs the Args into a string for easy transport from client to server. -// The generated string will depend on the specified version (corresponding to the API version). -func ToParamWithVersion(version string, a Args) (string, error) { - // this way we don't URL encode {}, just empty space - if a.Len() == 0 { - return "", nil - } - - // for daemons older than v1.10, filter must be of the form map[string][]string - buf := []byte{} - err := errors.New("") - if version != "" && versions.LessThan(version, "1.22") { - buf, err = json.Marshal(convertArgsToSlice(a.fields)) - } else { - buf, err = json.Marshal(a.fields) - } - if err != nil { - return "", err - } - return string(buf), nil -} - -// FromParam unpacks the filter Args. -func FromParam(p string) (Args, error) { - if len(p) == 0 { - return NewArgs(), nil - } - - r := strings.NewReader(p) - d := json.NewDecoder(r) - - m := map[string]map[string]bool{} - if err := d.Decode(&m); err != nil { - r.Seek(0, 0) - - // Allow parsing old arguments in slice format. - // Because other libraries might be sending them in this format. - deprecated := map[string][]string{} - if deprecatedErr := d.Decode(&deprecated); deprecatedErr == nil { - m = deprecatedArgs(deprecated) - } else { - return NewArgs(), err - } - } - return Args{m}, nil -} - -// Get returns the list of values associates with a field. -// It returns a slice of strings to keep backwards compatibility with old code. -func (filters Args) Get(field string) []string { - values := filters.fields[field] - if values == nil { - return make([]string, 0) - } - slice := make([]string, 0, len(values)) - for key := range values { - slice = append(slice, key) - } - return slice -} - -// Add adds a new value to a filter field. -func (filters Args) Add(name, value string) { - if _, ok := filters.fields[name]; ok { - filters.fields[name][value] = true - } else { - filters.fields[name] = map[string]bool{value: true} - } -} - -// Del removes a value from a filter field. -func (filters Args) Del(name, value string) { - if _, ok := filters.fields[name]; ok { - delete(filters.fields[name], value) - } -} - -// Len returns the number of fields in the arguments. -func (filters Args) Len() int { - return len(filters.fields) -} - -// MatchKVList returns true if the values for the specified field matches the ones -// from the sources. -// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, -// field is 'label' and sources are {'label1': '1', 'label2': '2'} -// it returns true. -func (filters Args) MatchKVList(field string, sources map[string]string) bool { - fieldValues := filters.fields[field] - - //do not filter if there is no filter set or cannot determine filter - if len(fieldValues) == 0 { - return true - } - - if sources == nil || len(sources) == 0 { - return false - } - - for name2match := range fieldValues { - testKV := strings.SplitN(name2match, "=", 2) - - v, ok := sources[testKV[0]] - if !ok { - return false - } - if len(testKV) == 2 && testKV[1] != v { - return false - } - } - - return true -} - -// Match returns true if the values for the specified field matches the source string -// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, -// field is 'image.name' and source is 'ubuntu' -// it returns true. -func (filters Args) Match(field, source string) bool { - if filters.ExactMatch(field, source) { - return true - } - - fieldValues := filters.fields[field] - for name2match := range fieldValues { - match, err := regexp.MatchString(name2match, source) - if err != nil { - continue - } - if match { - return true - } - } - return false -} - -// ExactMatch returns true if the source matches exactly one of the filters. -func (filters Args) ExactMatch(field, source string) bool { - fieldValues, ok := filters.fields[field] - //do not filter if there is no filter set or cannot determine filter - if !ok || len(fieldValues) == 0 { - return true - } - - // try to match full name value to avoid O(N) regular expression matching - return fieldValues[source] -} - -// UniqueExactMatch returns true if there is only one filter and the source matches exactly this one. -func (filters Args) UniqueExactMatch(field, source string) bool { - fieldValues := filters.fields[field] - //do not filter if there is no filter set or cannot determine filter - if len(fieldValues) == 0 { - return true - } - if len(filters.fields[field]) != 1 { - return false - } - - // try to match full name value to avoid O(N) regular expression matching - return fieldValues[source] -} - -// FuzzyMatch returns true if the source matches exactly one of the filters, -// or the source has one of the filters as a prefix. -func (filters Args) FuzzyMatch(field, source string) bool { - if filters.ExactMatch(field, source) { - return true - } - - fieldValues := filters.fields[field] - for prefix := range fieldValues { - if strings.HasPrefix(source, prefix) { - return true - } - } - return false -} - -// Include returns true if the name of the field to filter is in the filters. -func (filters Args) Include(field string) bool { - _, ok := filters.fields[field] - return ok -} - -// Validate ensures that all the fields in the filter are valid. -// It returns an error as soon as it finds an invalid field. -func (filters Args) Validate(accepted map[string]bool) error { - for name := range filters.fields { - if !accepted[name] { - return fmt.Errorf("Invalid filter '%s'", name) - } - } - return nil -} - -// WalkValues iterates over the list of filtered values for a field. -// It stops the iteration if it finds an error and it returns that error. -func (filters Args) WalkValues(field string, op func(value string) error) error { - if _, ok := filters.fields[field]; !ok { - return nil - } - for v := range filters.fields[field] { - if err := op(v); err != nil { - return err - } - } - return nil -} - -func deprecatedArgs(d map[string][]string) map[string]map[string]bool { - m := map[string]map[string]bool{} - for k, v := range d { - values := map[string]bool{} - for _, vv := range v { - values[vv] = true - } - m[k] = values - } - return m -} - -func convertArgsToSlice(f map[string]map[string]bool) map[string][]string { - m := map[string][]string{} - for k, v := range f { - values := []string{} - for kk := range v { - if v[kk] { - values = append(values, kk) - } - } - m[k] = values - } - return m -} diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/README.md b/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/README.md deleted file mode 100644 index cdac50a53c..0000000000 --- a/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/README.md +++ /dev/null @@ -1,14 +0,0 @@ -## Legacy API type versions - -This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`. - -Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`. - -### Package name conventions - -The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention: - -1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`. -2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`. - -For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`. diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/compare.go b/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/compare.go deleted file mode 100644 index 611d4fed66..0000000000 --- a/Godeps/_workspace/src/github.com/docker/engine-api/types/versions/compare.go +++ /dev/null @@ -1,62 +0,0 @@ -package versions - -import ( - "strconv" - "strings" -) - -// compare compares two version strings -// returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise. -func compare(v1, v2 string) int { - var ( - currTab = strings.Split(v1, ".") - otherTab = strings.Split(v2, ".") - ) - - max := len(currTab) - if len(otherTab) > max { - max = len(otherTab) - } - for i := 0; i < max; i++ { - var currInt, otherInt int - - if len(currTab) > i { - currInt, _ = strconv.Atoi(currTab[i]) - } - if len(otherTab) > i { - otherInt, _ = strconv.Atoi(otherTab[i]) - } - if currInt > otherInt { - return 1 - } - if otherInt > currInt { - return -1 - } - } - return 0 -} - -// LessThan checks if a version is less than another -func LessThan(v, other string) bool { - return compare(v, other) == -1 -} - -// LessThanOrEqualTo checks if a version is less than or equal to another -func LessThanOrEqualTo(v, other string) bool { - return compare(v, other) <= 0 -} - -// GreaterThan checks if a version is greater than another -func GreaterThan(v, other string) bool { - return compare(v, other) == 1 -} - -// GreaterThanOrEqualTo checks if a version is greater than or equal to another -func GreaterThanOrEqualTo(v, other string) bool { - return compare(v, other) >= 0 -} - -// Equal checks if a version is equal to another -func Equal(v, other string) bool { - return compare(v, other) == 0 -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/msgpack_test.py b/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/msgpack_test.py old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml b/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml deleted file mode 100644 index 16d1430aa2..0000000000 --- a/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: go -go: - - tip -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover -script: - - $HOME/gopath/bin/goveralls -repotoken 2FMhp57u8LcstKL9B190fLTcEnBtAAiEL diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md b/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md deleted file mode 100644 index 56f357fad7..0000000000 --- a/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# go-shellwords - -[![Coverage Status](https://coveralls.io/repos/mattn/go-shellwords/badge.png?branch=master)](https://coveralls.io/r/mattn/go-shellwords?branch=master) -[![Build Status](https://travis-ci.org/mattn/go-shellwords.svg?branch=master)](https://travis-ci.org/mattn/go-shellwords) - -Parse line as shell words. - -## Usage - -```go -args, err := shellwords.Parse("./foo --bar=baz") -// args should be ["./foo", "--bar=baz"] -``` - -```go -os.Setenv("FOO", "bar") -p := shellwords.NewParser() -p.ParseEnv = true -args, err := p.Parse("./foo $FOO") -// args should be ["./foo", "bar"] -``` - -```go -p := shellwords.NewParser() -p.ParseBacktick = true -args, err := p.Parse("./foo `echo $SHELL`") -// args should be ["./foo", "/bin/bash"] -``` - -```go -shellwords.ParseBacktick = true -p := shellwords.NewParser() -args, err := p.Parse("./foo `echo $SHELL`") -// args should be ["./foo", "/bin/bash"] -``` - -# Thanks - -This is based on cpan module [Parse::CommandLine](https://metacpan.org/pod/Parse::CommandLine). - -# License - -under the MIT License: http://mattn.mit-license.org/2014 - -# Author - -Yasuhiro Matsumoto (a.k.a mattn) diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go deleted file mode 100644 index 1abaa6c9df..0000000000 --- a/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go +++ /dev/null @@ -1,134 +0,0 @@ -package shellwords - -import ( - "errors" - "os" - "regexp" - "strings" -) - -var ( - ParseEnv bool = false - ParseBacktick bool = false -) - -var envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`) - -func isSpace(r rune) bool { - switch r { - case ' ', '\t', '\r', '\n': - return true - } - return false -} - -func replaceEnv(s string) string { - return envRe.ReplaceAllStringFunc(s, func(s string) string { - s = s[1:] - if s[0] == '{' { - s = s[1 : len(s)-1] - } - return os.Getenv(s) - }) -} - -type Parser struct { - ParseEnv bool - ParseBacktick bool -} - -func NewParser() *Parser { - return &Parser{ParseEnv, ParseBacktick} -} - -func (p *Parser) Parse(line string) ([]string, error) { - line = strings.TrimSpace(line) - - args := []string{} - buf := "" - var escaped, doubleQuoted, singleQuoted, backQuote bool - backtick := "" - - for _, r := range line { - if escaped { - buf += string(r) - escaped = false - continue - } - - if r == '\\' { - if singleQuoted { - buf += string(r) - } else { - escaped = true - } - continue - } - - if isSpace(r) { - if singleQuoted || doubleQuoted || backQuote { - buf += string(r) - backtick += string(r) - } else if buf != "" { - if p.ParseEnv { - buf = replaceEnv(buf) - } - args = append(args, buf) - buf = "" - } - continue - } - - switch r { - case '`': - if !singleQuoted && !doubleQuoted { - if p.ParseBacktick { - if backQuote { - out, err := shellRun(backtick) - if err != nil { - return nil, err - } - buf = out - } - backtick = "" - backQuote = !backQuote - continue - } - backtick = "" - backQuote = !backQuote - } - case '"': - if !singleQuoted { - doubleQuoted = !doubleQuoted - continue - } - case '\'': - if !doubleQuoted { - singleQuoted = !singleQuoted - continue - } - } - - buf += string(r) - if backQuote { - backtick += string(r) - } - } - - if buf != "" { - if p.ParseEnv { - buf = replaceEnv(buf) - } - args = append(args, buf) - } - - if escaped || singleQuoted || doubleQuoted || backQuote { - return nil, errors.New("invalid command line string") - } - - return args, nil -} - -func Parse(line string) ([]string, error) { - return NewParser().Parse(line) -} diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go deleted file mode 100644 index 4f8ac55e47..0000000000 --- a/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build !windows - -package shellwords - -import ( - "errors" - "os" - "os/exec" - "strings" -) - -func shellRun(line string) (string, error) { - shell := os.Getenv("SHELL") - b, err := exec.Command(shell, "-c", line).Output() - if err != nil { - return "", errors.New(err.Error() + ":" + string(b)) - } - return strings.TrimSpace(string(b)), nil -} diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go deleted file mode 100644 index 7cad4cf06f..0000000000 --- a/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go +++ /dev/null @@ -1,17 +0,0 @@ -package shellwords - -import ( - "errors" - "os" - "os/exec" - "strings" -) - -func shellRun(line string) (string, error) { - shell := os.Getenv("COMSPEC") - b, err := exec.Command(shell, "/c", line).Output() - if err != nil { - return "", errors.New(err.Error() + ":" + string(b)) - } - return strings.TrimSpace(string(b)), nil -} diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/prebuild.sh b/Godeps/_workspace/src/github.com/ugorji/go/codec/prebuild.sh old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/test.py b/Godeps/_workspace/src/github.com/ugorji/go/codec/test.py old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mkall.sh b/Godeps/_workspace/src/golang.org/x/sys/unix/mkall.sh old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mkerrors.sh b/Godeps/_workspace/src/golang.org/x/sys/unix/mkerrors.sh old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksyscall.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksyscall.pl old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksyscall_solaris.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksyscall_solaris.pl old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksysctl_openbsd.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksysctl_openbsd.pl old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_darwin.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_darwin.pl old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_dragonfly.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_dragonfly.pl old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_freebsd.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_freebsd.pl old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_linux.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_linux.pl old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_netbsd.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_netbsd.pl old mode 100644 new mode 100755 diff --git a/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_openbsd.pl b/Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_openbsd.pl old mode 100644 new mode 100755 From 0048e5578df4b8868da054c5846dc7bcf2318044 Mon Sep 17 00:00:00 2001 From: Shijiang Wei Date: Mon, 5 Sep 2016 19:36:59 +0800 Subject: [PATCH 057/799] make sure the user-provided bridge interface is a bridge Signed-off-by: Shijiang Wei --- drivers/bridge/bridge.go | 5 ++++- drivers/bridge/interface.go | 6 ++++-- drivers/bridge/interface_test.go | 13 +++++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index e276bc7b96..6c6256a947 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -641,7 +641,10 @@ func (d *driver) createNetwork(config *networkConfiguration) error { d.Unlock() // Create or retrieve the bridge L3 interface - bridgeIface := newInterface(d.nlh, config) + bridgeIface, err := newInterface(d.nlh, config) + if err != nil { + return err + } network.bridge = bridgeIface // Verify the network configuration does not conflict with previously installed diff --git a/drivers/bridge/interface.go b/drivers/bridge/interface.go index 4a5dbfcbe5..16a8c7722d 100644 --- a/drivers/bridge/interface.go +++ b/drivers/bridge/interface.go @@ -28,7 +28,7 @@ type bridgeInterface struct { // an already existing device identified by the configuration BridgeName field, // or the default bridge name when unspecified, but doesn't attempt to create // one when missing -func newInterface(nlh *netlink.Handle, config *networkConfiguration) *bridgeInterface { +func newInterface(nlh *netlink.Handle, config *networkConfiguration) (*bridgeInterface, error) { var err error i := &bridgeInterface{nlh: nlh} @@ -41,8 +41,10 @@ func newInterface(nlh *netlink.Handle, config *networkConfiguration) *bridgeInte i.Link, err = nlh.LinkByName(config.BridgeName) if err != nil { logrus.Debugf("Did not find any interface with name %s: %v", config.BridgeName, err) + } else if _, ok := i.Link.(*netlink.Bridge); !ok { + return nil, fmt.Errorf("existing interface %s is not a bridge", i.Link.Attrs().Name) } - return i + return i, nil } // exists indicates if the existing bridge interface exists on the system. diff --git a/drivers/bridge/interface_test.go b/drivers/bridge/interface_test.go index 48b479ca49..0e7dec3b5a 100644 --- a/drivers/bridge/interface_test.go +++ b/drivers/bridge/interface_test.go @@ -15,7 +15,12 @@ func TestInterfaceDefaultName(t *testing.T) { t.Fatal(err) } config := &networkConfiguration{} - if _ = newInterface(nh, config); config.BridgeName != DefaultBridgeName { + _, err = newInterface(nh, config) + if err != nil { + t.Fatalf("newInterface() failed: %v", err) + } + + if config.BridgeName != DefaultBridgeName { t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName) } } @@ -27,7 +32,11 @@ func TestAddressesEmptyInterface(t *testing.T) { if err != nil { t.Fatal(err) } - inf := newInterface(nh, &networkConfiguration{}) + inf, err := newInterface(nh, &networkConfiguration{}) + if err != nil { + t.Fatalf("newInterface() failed: %v", err) + } + addrv4, addrsv6, err := inf.addresses() if err != nil { t.Fatalf("Failed to get addresses of default interface: %v", err) From 780253d924efececa46712348a6ec730bf3d755f Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 6 Sep 2016 14:10:58 -0700 Subject: [PATCH 058/799] Remove pkg/tlsconfig dependency Signed-off-by: Tonis Tiigi --- Godeps/Godeps.json | 6 +- .../docker/docker/pkg/tlsconfig/config.go | 133 ------------------ config/config.go | 2 +- 3 files changed, 2 insertions(+), 139 deletions(-) delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/tlsconfig/config.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index b1f35ffc04..6ef8ba03ec 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,7 @@ { "ImportPath": "github.com/docker/libnetwork", "GoVersion": "go1.5", + "GodepVersion": "v74", "Packages": [ "./..." ], @@ -175,11 +176,6 @@ "Comment": "v1.4.1-12227-g86a7632", "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" }, - { - "ImportPath": "github.com/docker/docker/pkg/tlsconfig", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" - }, { "ImportPath": "github.com/docker/engine-api/types/network", "Comment": "v0.3.1-210-g25941ec", diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/tlsconfig/config.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/tlsconfig/config.go deleted file mode 100644 index e3dfad1f0e..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/tlsconfig/config.go +++ /dev/null @@ -1,133 +0,0 @@ -// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. -// -// As a reminder from https://golang.org/pkg/crypto/tls/#Config: -// A Config structure is used to configure a TLS client or server. After one has been passed to a TLS function it must not be modified. -// A Config may be reused; the tls package will also not modify it. -package tlsconfig - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" - "os" - - "github.com/Sirupsen/logrus" -) - -// Options represents the information needed to create client and server TLS configurations. -type Options struct { - CAFile string - - // If either CertFile or KeyFile is empty, Client() will not load them - // preventing the client from authenticating to the server. - // However, Server() requires them and will error out if they are empty. - CertFile string - KeyFile string - - // client-only option - InsecureSkipVerify bool - // server-only option - ClientAuth tls.ClientAuthType -} - -// Extra (server-side) accepted CBC cipher suites - will phase out in the future -var acceptedCBCCiphers = []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - tls.TLS_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_RSA_WITH_AES_128_CBC_SHA, -} - -// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) -var clientCipherSuites = []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, -} - -// DefaultServerAcceptedCiphers should be uses by code which already has a crypto/tls -// options struct but wants to use a commonly accepted set of TLS cipher suites, with -// known weak algorithms removed. -var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...) - -// ServerDefault is a secure-enough TLS configuration for the server TLS configuration. -var ServerDefault = tls.Config{ - // Avoid fallback to SSL protocols < TLS1.0 - MinVersion: tls.VersionTLS10, - PreferServerCipherSuites: true, - CipherSuites: DefaultServerAcceptedCiphers, -} - -// ClientDefault is a secure-enough TLS configuration for the client TLS configuration. -var ClientDefault = tls.Config{ - // Prefer TLS1.2 as the client minimum - MinVersion: tls.VersionTLS12, - CipherSuites: clientCipherSuites, -} - -// certPool returns an X.509 certificate pool from `caFile`, the certificate file. -func certPool(caFile string) (*x509.CertPool, error) { - // If we should verify the server, we need to load a trusted ca - certPool := x509.NewCertPool() - pem, err := ioutil.ReadFile(caFile) - if err != nil { - return nil, fmt.Errorf("Could not read CA certificate %q: %v", caFile, err) - } - if !certPool.AppendCertsFromPEM(pem) { - return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile) - } - s := certPool.Subjects() - subjects := make([]string, len(s)) - for i, subject := range s { - subjects[i] = string(subject) - } - logrus.Debugf("Trusting certs with subjects: %v", subjects) - return certPool, nil -} - -// Client returns a TLS configuration meant to be used by a client. -func Client(options Options) (*tls.Config, error) { - tlsConfig := ClientDefault - tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify - if !options.InsecureSkipVerify { - CAs, err := certPool(options.CAFile) - if err != nil { - return nil, err - } - tlsConfig.RootCAs = CAs - } - - if options.CertFile != "" && options.KeyFile != "" { - tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) - if err != nil { - return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err) - } - tlsConfig.Certificates = []tls.Certificate{tlsCert} - } - - return &tlsConfig, nil -} - -// Server returns a TLS configuration meant to be used by a server. -func Server(options Options) (*tls.Config, error) { - tlsConfig := ServerDefault - tlsConfig.ClientAuth = options.ClientAuth - tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) - if err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("Could not load X509 key pair (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err) - } - return nil, fmt.Errorf("Error reading X509 key pair (cert: %q, key: %q): %v. Make sure the key is not encrypted.", options.CertFile, options.KeyFile, err) - } - tlsConfig.Certificates = []tls.Certificate{tlsCert} - if options.ClientAuth >= tls.VerifyClientCertIfGiven { - CAs, err := certPool(options.CAFile) - if err != nil { - return nil, err - } - tlsConfig.ClientCAs = CAs - } - return &tlsConfig, nil -} diff --git a/config/config.go b/config/config.go index eb8afea8b4..832412ec74 100644 --- a/config/config.go +++ b/config/config.go @@ -6,7 +6,7 @@ import ( "github.com/BurntSushi/toml" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" - "github.com/docker/docker/pkg/tlsconfig" + "github.com/docker/go-connections/tlsconfig" "github.com/docker/libkv/store" "github.com/docker/libnetwork/cluster" "github.com/docker/libnetwork/datastore" From 34628de7d0d05c2c561fdb875ee3274970034c3f Mon Sep 17 00:00:00 2001 From: Shijiang Wei Date: Tue, 28 Jun 2016 11:42:50 +0800 Subject: [PATCH 059/799] don't delete the bridge interface if it was not created by libnetwork Signed-off-by: Shijiang Wei --- drivers/bridge/bridge.go | 36 ++++++++++-- drivers/bridge/bridge_store.go | 5 ++ drivers/bridge/bridge_test.go | 91 ++++++++++++++++++++++++----- drivers/bridge/network_test.go | 8 +-- drivers/bridge/port_mapping_test.go | 2 +- drivers/bridge/setup_verify.go | 18 ++++++ 6 files changed, 137 insertions(+), 23 deletions(-) diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index e276bc7b96..289b3c10c1 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -70,8 +70,19 @@ type networkConfiguration struct { dbIndex uint64 dbExists bool Internal bool + + BridgeIfaceCreator ifaceCreator } +// ifaceCreator represents how the bridge interface was created +type ifaceCreator int8 + +const ( + ifaceCreatorUnknown ifaceCreator = iota + ifaceCreatedByLibnetwork + ifaceCreatedByUser +) + // endpointConfiguration represents the user specified configuration for the sandbox endpoint type endpointConfiguration struct { MacAddress net.HardwareAddr @@ -512,6 +523,17 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati config.BridgeName = "br-" + id[:12] } + exists, err := bridgeInterfaceExists(config.BridgeName) + if err != nil { + return nil, err + } + + if !exists { + config.BridgeIfaceCreator = ifaceCreatedByLibnetwork + } else { + config.BridgeIfaceCreator = ifaceCreatedByUser + } + config.ID = id return config, nil } @@ -775,11 +797,17 @@ func (d *driver) DeleteNetwork(nid string) error { return err } - // We only delete the bridge when it's not the default bridge. This is keep the backward compatible behavior. - if !config.DefaultBridge { - if err := d.nlh.LinkDel(n.bridge.Link); err != nil { - logrus.Warnf("Failed to remove bridge interface %s on network %s delete: %v", config.BridgeName, nid, err) + switch config.BridgeIfaceCreator { + case ifaceCreatedByLibnetwork, ifaceCreatorUnknown: + // We only delete the bridge if it was created by the bridge driver and + // it is not the default one (to keep the backward compatible behavior.) + if !config.DefaultBridge { + if err := d.nlh.LinkDel(n.bridge.Link); err != nil { + logrus.Warnf("Failed to remove bridge interface %s on network %s delete: %v", config.BridgeName, nid, err) + } } + case ifaceCreatedByUser: + // Don't delete the bridge interface if it was not created by libnetwork. } // clean all relevant iptables rules diff --git a/drivers/bridge/bridge_store.go b/drivers/bridge/bridge_store.go index 41c54b00f1..2ed60c7510 100644 --- a/drivers/bridge/bridge_store.go +++ b/drivers/bridge/bridge_store.go @@ -143,6 +143,7 @@ func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) { nMap["DefaultBindingIP"] = ncfg.DefaultBindingIP.String() nMap["DefaultGatewayIPv4"] = ncfg.DefaultGatewayIPv4.String() nMap["DefaultGatewayIPv6"] = ncfg.DefaultGatewayIPv6.String() + nMap["BridgeIfaceCreator"] = ncfg.BridgeIfaceCreator if ncfg.AddressIPv4 != nil { nMap["AddressIPv4"] = ncfg.AddressIPv4.String() @@ -191,6 +192,10 @@ func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error { ncfg.Internal = v.(bool) } + if v, ok := nMap["BridgeIfaceCreator"]; ok { + ncfg.BridgeIfaceCreator = ifaceCreator(v.(float64)) + } + return nil } diff --git a/drivers/bridge/bridge_test.go b/drivers/bridge/bridge_test.go index 6c53b162c9..403bdcb286 100644 --- a/drivers/bridge/bridge_test.go +++ b/drivers/bridge/bridge_test.go @@ -16,6 +16,7 @@ import ( "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/testutils" "github.com/docker/libnetwork/types" + "github.com/vishvananda/netlink" ) func init() { @@ -166,9 +167,9 @@ func compareBindings(a, b []types.PortBinding) bool { return true } -func getIPv4Data(t *testing.T) []driverapi.IPAMData { +func getIPv4Data(t *testing.T, iface string) []driverapi.IPAMData { ipd := driverapi.IPAMData{AddressSpace: "full"} - nw, _, err := netutils.ElectInterfaceAddresses("") + nw, _, err := netutils.ElectInterfaceAddresses(iface) if err != nil { t.Fatal(err) } @@ -243,7 +244,7 @@ func TestCreateNoConfig(t *testing.T) { genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = netconfig - if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil { + if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err != nil { t.Fatalf("Failed to create bridge: %v", err) } } @@ -282,7 +283,7 @@ func TestCreateFullOptionsLabels(t *testing.T) { netOption[netlabel.EnableIPv6] = true netOption[netlabel.GenericData] = labels - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") ipd6List := []driverapi.IPAMData{ { Pool: nwV6, @@ -364,11 +365,11 @@ func TestCreate(t *testing.T) { genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = netconfig - if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil { + if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err != nil { t.Fatalf("Failed to create bridge: %v", err) } - err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil) + err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil) if err == nil { t.Fatalf("Expected bridge driver to refuse creation of second network with default name") } @@ -392,7 +393,7 @@ func TestCreateFail(t *testing.T) { genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = netconfig - if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err == nil { + if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err == nil { t.Fatal("Bridge creation was expected to fail") } } @@ -417,13 +418,13 @@ func TestCreateMultipleNetworks(t *testing.T) { config1 := &networkConfiguration{BridgeName: "net_test_1"} genericOption = make(map[string]interface{}) genericOption[netlabel.GenericData] = config1 - if err := d.CreateNetwork("1", genericOption, nil, getIPv4Data(t), nil); err != nil { + if err := d.CreateNetwork("1", genericOption, nil, getIPv4Data(t, ""), nil); err != nil { t.Fatalf("Failed to create bridge: %v", err) } config2 := &networkConfiguration{BridgeName: "net_test_2"} genericOption[netlabel.GenericData] = config2 - if err := d.CreateNetwork("2", genericOption, nil, getIPv4Data(t), nil); err != nil { + if err := d.CreateNetwork("2", genericOption, nil, getIPv4Data(t, ""), nil); err != nil { t.Fatalf("Failed to create bridge: %v", err) } @@ -432,7 +433,7 @@ func TestCreateMultipleNetworks(t *testing.T) { config3 := &networkConfiguration{BridgeName: "net_test_3"} genericOption[netlabel.GenericData] = config3 - if err := d.CreateNetwork("3", genericOption, nil, getIPv4Data(t), nil); err != nil { + if err := d.CreateNetwork("3", genericOption, nil, getIPv4Data(t, ""), nil); err != nil { t.Fatalf("Failed to create bridge: %v", err) } @@ -441,7 +442,7 @@ func TestCreateMultipleNetworks(t *testing.T) { config4 := &networkConfiguration{BridgeName: "net_test_4"} genericOption[netlabel.GenericData] = config4 - if err := d.CreateNetwork("4", genericOption, nil, getIPv4Data(t), nil); err != nil { + if err := d.CreateNetwork("4", genericOption, nil, getIPv4Data(t, ""), nil); err != nil { t.Fatalf("Failed to create bridge: %v", err) } @@ -625,7 +626,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) { genericOption = make(map[string]interface{}) genericOption[netlabel.GenericData] = netconfig - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil) if err != nil { t.Fatalf("Failed to create bridge: %v", err) @@ -728,7 +729,7 @@ func TestLinkContainers(t *testing.T) { genericOption = make(map[string]interface{}) genericOption[netlabel.GenericData] = netconfig - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil) if err != nil { t.Fatalf("Failed to create bridge: %v", err) @@ -945,7 +946,7 @@ func TestSetDefaultGw(t *testing.T) { _, subnetv6, _ := net.ParseCIDR("2001:db8:ea9:9abc:b0c4::/80") - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") gw4 := types.GetIPCopy(ipdList[0].Pool.IP).To4() gw4[3] = 254 gw6 := net.ParseIP("2001:db8:ea9:9abc:b0c4::254") @@ -1008,3 +1009,65 @@ func TestCleanupIptableRules(t *testing.T) { } } } + +func TestCreateWithExistingBridge(t *testing.T) { + defer testutils.SetupTestOSContext(t)() + d := newDriver() + + if err := d.configure(nil); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + brName := "br111" + br := &netlink.Bridge{ + LinkAttrs: netlink.LinkAttrs{ + Name: brName, + }, + } + if err := netlink.LinkAdd(br); err != nil { + t.Fatalf("Failed to create bridge interface: %v", err) + } + defer netlink.LinkDel(br) + if err := netlink.LinkSetUp(br); err != nil { + t.Fatalf("Failed to set bridge interface up: %v", err) + } + + ip := net.IP{192, 168, 122, 1} + addr := &netlink.Addr{IPNet: &net.IPNet{ + IP: ip, + Mask: net.IPv4Mask(255, 255, 255, 0), + }} + if err := netlink.AddrAdd(br, addr); err != nil { + t.Fatalf("Failed to add IP address to bridge: %v", err) + } + + netconfig := &networkConfiguration{BridgeName: brName} + genericOption := make(map[string]interface{}) + genericOption[netlabel.GenericData] = netconfig + + if err := d.CreateNetwork(brName, genericOption, nil, getIPv4Data(t, brName), nil); err != nil { + t.Fatalf("Failed to create bridge network: %v", err) + } + + nw, err := d.getNetwork(brName) + if err != nil { + t.Fatalf("Failed to getNetwork(%s): %v", brName, err) + } + + addr4, _, err := nw.bridge.addresses() + if err != nil { + t.Fatalf("Failed to get the bridge network's address: %v", err) + } + + if !addr4.IP.Equal(ip) { + t.Fatal("Creating bridge network with existing bridge interface unexpectedly modified the IP address of the bridge") + } + + if err := d.DeleteNetwork(brName); err != nil { + t.Fatalf("Failed to delete network %s: %v", brName, err) + } + + if _, err := netlink.LinkByName(brName); err != nil { + t.Fatalf("Deleting bridge network that using existing bridge interface unexpectedly deleted the bridge interface") + } +} diff --git a/drivers/bridge/network_test.go b/drivers/bridge/network_test.go index 6b9a5898c5..ca632e4c31 100644 --- a/drivers/bridge/network_test.go +++ b/drivers/bridge/network_test.go @@ -26,7 +26,7 @@ func TestLinkCreate(t *testing.T) { genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = config - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil) if err != nil { t.Fatalf("Failed to create bridge: %v", err) @@ -118,7 +118,7 @@ func TestLinkCreateTwo(t *testing.T) { genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = config - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil) if err != nil { t.Fatalf("Failed to create bridge: %v", err) @@ -154,7 +154,7 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) { genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = config - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil) if err != nil { t.Fatalf("Failed to create bridge: %v", err) @@ -189,7 +189,7 @@ func TestLinkDelete(t *testing.T) { genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = config - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil) if err != nil { t.Fatalf("Failed to create bridge: %v", err) diff --git a/drivers/bridge/port_mapping_test.go b/drivers/bridge/port_mapping_test.go index 4c99caa9cf..e4d342dd95 100644 --- a/drivers/bridge/port_mapping_test.go +++ b/drivers/bridge/port_mapping_test.go @@ -44,7 +44,7 @@ func TestPortMappingConfig(t *testing.T) { netOptions := make(map[string]interface{}) netOptions[netlabel.GenericData] = netConfig - ipdList := getIPv4Data(t) + ipdList := getIPv4Data(t, "") err := d.CreateNetwork("dummy", netOptions, nil, ipdList, nil) if err != nil { t.Fatalf("Failed to create bridge: %v", err) diff --git a/drivers/bridge/setup_verify.go b/drivers/bridge/setup_verify.go index f6ef7ae552..0bafed6011 100644 --- a/drivers/bridge/setup_verify.go +++ b/drivers/bridge/setup_verify.go @@ -2,8 +2,10 @@ package bridge import ( "fmt" + "strings" log "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/ns" "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" ) @@ -51,3 +53,19 @@ func findIPv6Address(addr netlink.Addr, addresses []netlink.Addr) bool { } return false } + +func bridgeInterfaceExists(name string) (bool, error) { + nlh := ns.NlHandle() + link, err := nlh.LinkByName(name) + if err != nil { + if strings.Contains(err.Error(), "Link not found") { + return false, nil + } + return false, fmt.Errorf("failed to check bridge interface existence: %v", err) + } + + if link.Type() == "bridge" { + return true, nil + } + return false, fmt.Errorf("existing interface %s is not a bridge", name) +} From 03f440667f79f33ef3cb1faeb13c0bca1a0f8737 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 7 Sep 2016 10:45:40 -0700 Subject: [PATCH 060/799] Ensure purging neighbor cache for stale deletes When stale delete notifications are received, we still need to make sure to purge sandbox neighbor cache because these stale deletes are most typically out of order delete notifications and if an add for the peermac was received before the delete of the old peermac,vtep pair then we process that and replace the kernel state but the old neighbor state in the sandbox cache remains. That needs to be purged when we finally get the out of order delete notification. Signed-off-by: Jana Radhakrishnan --- drivers/overlay/peerdb.go | 36 +++++++++++++++++---------- osl/neigh_linux.go | 52 +++++++++++++++++++++------------------ osl/sandbox.go | 2 +- 3 files changed, 52 insertions(+), 38 deletions(-) diff --git a/drivers/overlay/peerdb.go b/drivers/overlay/peerdb.go index c9808f692a..517909a816 100644 --- a/drivers/overlay/peerdb.go +++ b/drivers/overlay/peerdb.go @@ -168,14 +168,14 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask } func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, - peerMac net.HardwareAddr, vtep net.IP) bool { + peerMac net.HardwareAddr, vtep net.IP) peerEntry { peerDbWg.Wait() d.peerDb.Lock() pMap, ok := d.peerDb.mp[nid] if !ok { d.peerDb.Unlock() - return false + return peerEntry{} } d.peerDb.Unlock() @@ -186,19 +186,20 @@ func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPM pMap.Lock() - if pEntry, ok := pMap.mp[pKey.String()]; ok { + pEntry, ok := pMap.mp[pKey.String()] + if ok { // Mismatched endpoint ID(possibly outdated). Do not // delete peerdb if pEntry.eid != eid { pMap.Unlock() - return false + return pEntry } } delete(pMap.mp, pKey.String()) pMap.Unlock() - return true + return pEntry } func (d *driver) peerDbUpdateSandbox(nid string) { @@ -312,10 +313,9 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMas return err } + var pEntry peerEntry if updateDb { - if !d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep) { - return nil - } + pEntry = d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep) } n := d.network(nid) @@ -328,14 +328,24 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMas return nil } - // Delete fdb entry to the bridge for the peer mac - if err := sbox.DeleteNeighbor(vtep, peerMac); err != nil { - return fmt.Errorf("could not delete fdb entry into the sandbox: %v", err) + // Delete fdb entry to the bridge for the peer mac only if the + // entry existed in local peerdb. If it is a stale delete + // request, still call DeleteNeighbor but only to cleanup any + // leftover sandbox neighbor cache and not actually delete the + // kernel state. + if (eid == pEntry.eid && vtep.Equal(pEntry.vtep)) || + (eid != pEntry.eid && !vtep.Equal(pEntry.vtep)) { + if err := sbox.DeleteNeighbor(vtep, peerMac, + eid == pEntry.eid && vtep.Equal(pEntry.vtep)); err != nil { + return fmt.Errorf("could not delete fdb entry into the sandbox: %v", err) + } } // Delete neighbor entry for the peer IP - if err := sbox.DeleteNeighbor(peerIP, peerMac); err != nil { - return fmt.Errorf("could not delete neighbor entry into the sandbox: %v", err) + if eid == pEntry.eid { + if err := sbox.DeleteNeighbor(peerIP, peerMac, true); err != nil { + return fmt.Errorf("could not delete neighbor entry into the sandbox: %v", err) + } } if err := d.checkEncryption(nid, vtep, 0, false, false); err != nil { diff --git a/osl/neigh_linux.go b/osl/neigh_linux.go index c5c6c103d0..a7669a111b 100644 --- a/osl/neigh_linux.go +++ b/osl/neigh_linux.go @@ -32,7 +32,7 @@ func (n *networkNamespace) findNeighbor(dstIP net.IP, dstMac net.HardwareAddr) * return nil } -func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr) error { +func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr, osDelete bool) error { var ( iface netlink.Link err error @@ -43,42 +43,46 @@ func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr) return fmt.Errorf("could not find the neighbor entry to delete") } - n.Lock() - nlh := n.nlHandle - n.Unlock() + if osDelete { + n.Lock() + nlh := n.nlHandle + n.Unlock() - if nh.linkDst != "" { - iface, err = nlh.LinkByName(nh.linkDst) - if err != nil { - return fmt.Errorf("could not find interface with destination name %s: %v", - nh.linkDst, err) + if nh.linkDst != "" { + iface, err = nlh.LinkByName(nh.linkDst) + if err != nil { + return fmt.Errorf("could not find interface with destination name %s: %v", + nh.linkDst, err) + } } - } - nlnh := &netlink.Neigh{ - IP: dstIP, - State: netlink.NUD_PERMANENT, - Family: nh.family, - } + nlnh := &netlink.Neigh{ + IP: dstIP, + State: netlink.NUD_PERMANENT, + Family: nh.family, + } - if nlnh.Family > 0 { - nlnh.HardwareAddr = dstMac - nlnh.Flags = netlink.NTF_SELF - } + if nlnh.Family > 0 { + nlnh.HardwareAddr = dstMac + nlnh.Flags = netlink.NTF_SELF + } - if nh.linkDst != "" { - nlnh.LinkIndex = iface.Attrs().Index - } + if nh.linkDst != "" { + nlnh.LinkIndex = iface.Attrs().Index + } - if err := nlh.NeighDel(nlnh); err != nil { - return fmt.Errorf("could not delete neighbor entry: %v", err) + if err := nlh.NeighDel(nlnh); err != nil { + return fmt.Errorf("could not delete neighbor entry: %v", err) + } } + n.Lock() for i, nh := range n.neighbors { if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) { n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...) } } + n.Unlock() return nil } diff --git a/osl/sandbox.go b/osl/sandbox.go index 75968a0f87..18085c9082 100644 --- a/osl/sandbox.go +++ b/osl/sandbox.go @@ -42,7 +42,7 @@ type Sandbox interface { AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, option ...NeighOption) error // DeleteNeighbor deletes neighbor entry from the sandbox. - DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr) error + DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr, osDelete bool) error // Returns an interface with methods to set neighbor options. NeighborOptions() NeighborOptionSetter From b47fdaef7958c39214ca7181ada4d55271e2de96 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Thu, 1 Sep 2016 19:09:34 -0700 Subject: [PATCH 061/799] Decrement epCnt only after all cleanup Currently the endpoint count is being decremented before the driver cleanup and more importantly before releasing the ip address. This is racy as it creates a time window where we already have decremented the endpoint count and so the network can be deleted now. But we haven't released the IP address yet and the pool is already gone. Although there is no harm done since the pool is already gone. it generates unnecessary error message about not able to release the address. Also if the driver cleanup fails we really should not decrement endpoint count. Signed-off-by: Jana Radhakrishnan --- endpoint.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/endpoint.go b/endpoint.go index d211dafc53..44893573ff 100644 --- a/endpoint.go +++ b/endpoint.go @@ -757,17 +757,6 @@ func (ep *endpoint) Delete(force bool) error { } }() - if err = n.getEpCnt().DecEndpointCnt(); err != nil && !force { - return err - } - defer func() { - if err != nil && !force { - if e := n.getEpCnt().IncEndpointCnt(); e != nil { - log.Warnf("failed to update network %s : %v", n.name, e) - } - } - }() - // unwatch for service records n.getController().unWatchSvcRecord(ep) @@ -777,6 +766,10 @@ func (ep *endpoint) Delete(force bool) error { ep.releaseAddress() + if err := n.getEpCnt().DecEndpointCnt(); err != nil { + log.Warnf("failed to decrement endpoint coint for ep %s: %v", ep.ID(), err) + } + return nil } From 34a52b799c7a2b3b36537e434bd4840ae8755108 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 7 Sep 2016 12:30:02 -0700 Subject: [PATCH 062/799] Add mflag package locally to libnetwork Since docker/docker removed mflag package and libnetwork relies on it create a copy of mflag package in libnetwork project. Signed-off-by: Jana Radhakrishnan --- client/client.go | 2 +- client/mflag/LICENSE | 27 + client/mflag/README.md | 40 + client/mflag/example/example.go | 36 + client/mflag/flag.go | 1280 +++++++++++++++++++++++++++++++ client/mflag/flag_test.go | 529 +++++++++++++ client/network.go | 2 +- client/service.go | 2 +- 8 files changed, 1915 insertions(+), 3 deletions(-) create mode 100644 client/mflag/LICENSE create mode 100644 client/mflag/README.md create mode 100644 client/mflag/example/example.go create mode 100644 client/mflag/flag.go create mode 100644 client/mflag/flag_test.go diff --git a/client/client.go b/client/client.go index c5713b01b3..f2bcca5329 100644 --- a/client/client.go +++ b/client/client.go @@ -8,7 +8,7 @@ import ( "reflect" "strings" - flag "github.com/docker/docker/pkg/mflag" + flag "github.com/docker/libnetwork/client/mflag" ) // CallFunc provides environment specific call utility to invoke backend functions from UI diff --git a/client/mflag/LICENSE b/client/mflag/LICENSE new file mode 100644 index 0000000000..9b4f4a294e --- /dev/null +++ b/client/mflag/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014-2016 The Docker & Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/client/mflag/README.md b/client/mflag/README.md new file mode 100644 index 0000000000..da00efa336 --- /dev/null +++ b/client/mflag/README.md @@ -0,0 +1,40 @@ +Package mflag (aka multiple-flag) implements command-line flag parsing. +It's an **hacky** fork of the [official golang package](http://golang.org/pkg/flag/) + +It adds: + +* both short and long flag version +`./example -s red` `./example --string blue` + +* multiple names for the same option +``` +$>./example -h +Usage of example: + -s, --string="": a simple string +``` + +___ +It is very flexible on purpose, so you can do things like: +``` +$>./example -h +Usage of example: + -s, -string, --string="": a simple string +``` + +Or: +``` +$>./example -h +Usage of example: + -oldflag, --newflag="": a simple string +``` + +You can also hide some flags from the usage, so if we want only `--newflag`: +``` +$>./example -h +Usage of example: + --newflag="": a simple string +$>./example -oldflag str +str +``` + +See [example.go](example/example.go) for more details. diff --git a/client/mflag/example/example.go b/client/mflag/example/example.go new file mode 100644 index 0000000000..b93a37c1d8 --- /dev/null +++ b/client/mflag/example/example.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + + flag "github.com/docker/libnetwork/client/mflag" +) + +var ( + i int + str string + b, b2, h bool +) + +func init() { + flag.Bool([]string{"#hp", "#-halp"}, false, "display the halp") + flag.BoolVar(&b, []string{"b", "#bal", "#bol", "-bal"}, false, "a simple bool") + flag.BoolVar(&b, []string{"g", "#gil"}, false, "a simple bool") + flag.BoolVar(&b2, []string{"#-bool"}, false, "a simple bool") + flag.IntVar(&i, []string{"-integer", "-number"}, -1, "a simple integer") + flag.StringVar(&str, []string{"s", "#hidden", "-string"}, "", "a simple string") //-s -hidden and --string will work, but -hidden won't be in the usage + flag.BoolVar(&h, []string{"h", "#help", "-help"}, false, "display the help") + flag.StringVar(&str, []string{"mode"}, "mode1", "set the mode\nmode1: use the mode1\nmode2: use the mode2\nmode3: use the mode3") + flag.Parse() +} +func main() { + if h { + flag.PrintDefaults() + } else { + fmt.Printf("s/#hidden/-string: %s\n", str) + fmt.Printf("b: %t\n", b) + fmt.Printf("-bool: %t\n", b2) + fmt.Printf("s/#hidden/-string(via lookup): %s\n", flag.Lookup("s").Value.String()) + fmt.Printf("ARGS: %v\n", flag.Args()) + } +} diff --git a/client/mflag/flag.go b/client/mflag/flag.go new file mode 100644 index 0000000000..dd0dafe396 --- /dev/null +++ b/client/mflag/flag.go @@ -0,0 +1,1280 @@ +// Copyright 2014-2016 The Docker & Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package mflag implements command-line flag parsing. +// +// Usage: +// +// Define flags using flag.String(), Bool(), Int(), etc. +// +// This declares an integer flag, -f or --flagname, stored in the pointer ip, with type *int. +// import "flag /github.com/docker/libnetwork/client/mflag" +// var ip = flag.Int([]string{"f", "-flagname"}, 1234, "help message for flagname") +// If you like, you can bind the flag to a variable using the Var() functions. +// var flagvar int +// func init() { +// // -flaghidden will work, but will be hidden from the usage +// flag.IntVar(&flagvar, []string{"f", "#flaghidden", "-flagname"}, 1234, "help message for flagname") +// } +// Or you can create custom flags that satisfy the Value interface (with +// pointer receivers) and couple them to flag parsing by +// flag.Var(&flagVal, []string{"name"}, "help message for flagname") +// For such flags, the default value is just the initial value of the variable. +// +// You can also add "deprecated" flags, they are still usable, but are not shown +// in the usage and will display a warning when you try to use them. `#` before +// an option means this option is deprecated, if there is an following option +// without `#` ahead, then that's the replacement, if not, it will just be removed: +// var ip = flag.Int([]string{"#f", "#flagname", "-flagname"}, 1234, "help message for flagname") +// this will display: `Warning: '-f' is deprecated, it will be replaced by '--flagname' soon. See usage.` or +// this will display: `Warning: '-flagname' is deprecated, it will be replaced by '--flagname' soon. See usage.` +// var ip = flag.Int([]string{"f", "#flagname"}, 1234, "help message for flagname") +// will display: `Warning: '-flagname' is deprecated, it will be removed soon. See usage.` +// so you can only use `-f`. +// +// You can also group one letter flags, bif you declare +// var v = flag.Bool([]string{"v", "-verbose"}, false, "help message for verbose") +// var s = flag.Bool([]string{"s", "-slow"}, false, "help message for slow") +// you will be able to use the -vs or -sv +// +// After all flags are defined, call +// flag.Parse() +// to parse the command line into the defined flags. +// +// Flags may then be used directly. If you're using the flags themselves, +// they are all pointers; if you bind to variables, they're values. +// fmt.Println("ip has value ", *ip) +// fmt.Println("flagvar has value ", flagvar) +// +// After parsing, the arguments after the flag are available as the +// slice flag.Args() or individually as flag.Arg(i). +// The arguments are indexed from 0 through flag.NArg()-1. +// +// Command line flag syntax: +// -flag +// -flag=x +// -flag="x" +// -flag='x' +// -flag x // non-boolean flags only +// One or two minus signs may be used; they are equivalent. +// The last form is not permitted for boolean flags because the +// meaning of the command +// cmd -x * +// will change if there is a file called 0, false, etc. You must +// use the -flag=false form to turn off a boolean flag. +// +// Flag parsing stops just before the first non-flag argument +// ("-" is a non-flag argument) or after the terminator "--". +// +// Integer flags accept 1234, 0664, 0x1234 and may be negative. +// Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False. +// Duration flags accept any input valid for time.ParseDuration. +// +// The default set of command-line flags is controlled by +// top-level functions. The FlagSet type allows one to define +// independent sets of flags, such as to implement subcommands +// in a command-line interface. The methods of FlagSet are +// analogous to the top-level functions for the command-line +// flag set. + +package mflag + +import ( + "errors" + "fmt" + "io" + "os" + "runtime" + "sort" + "strconv" + "strings" + "text/tabwriter" + "time" + + "github.com/docker/docker/pkg/homedir" +) + +// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. +var ErrHelp = errors.New("flag: help requested") + +// ErrRetry is the error returned if you need to try letter by letter +var ErrRetry = errors.New("flag: retry") + +// -- bool Value +type boolValue bool + +func newBoolValue(val bool, p *bool) *boolValue { + *p = val + return (*boolValue)(p) +} + +func (b *boolValue) Set(s string) error { + v, err := strconv.ParseBool(s) + *b = boolValue(v) + return err +} + +func (b *boolValue) Get() interface{} { return bool(*b) } + +func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) } + +func (b *boolValue) IsBoolFlag() bool { return true } + +// optional interface to indicate boolean flags that can be +// supplied without "=value" text +type boolFlag interface { + Value + IsBoolFlag() bool +} + +// -- int Value +type intValue int + +func newIntValue(val int, p *int) *intValue { + *p = val + return (*intValue)(p) +} + +func (i *intValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = intValue(v) + return err +} + +func (i *intValue) Get() interface{} { return int(*i) } + +func (i *intValue) String() string { return fmt.Sprintf("%v", *i) } + +// -- int64 Value +type int64Value int64 + +func newInt64Value(val int64, p *int64) *int64Value { + *p = val + return (*int64Value)(p) +} + +func (i *int64Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = int64Value(v) + return err +} + +func (i *int64Value) Get() interface{} { return int64(*i) } + +func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) } + +// -- uint Value +type uintValue uint + +func newUintValue(val uint, p *uint) *uintValue { + *p = val + return (*uintValue)(p) +} + +func (i *uintValue) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + *i = uintValue(v) + return err +} + +func (i *uintValue) Get() interface{} { return uint(*i) } + +func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) } + +// -- uint64 Value +type uint64Value uint64 + +func newUint64Value(val uint64, p *uint64) *uint64Value { + *p = val + return (*uint64Value)(p) +} + +func (i *uint64Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + *i = uint64Value(v) + return err +} + +func (i *uint64Value) Get() interface{} { return uint64(*i) } + +func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) } + +// -- uint16 Value +type uint16Value uint16 + +func newUint16Value(val uint16, p *uint16) *uint16Value { + *p = val + return (*uint16Value)(p) +} + +func (i *uint16Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 16) + *i = uint16Value(v) + return err +} + +func (i *uint16Value) Get() interface{} { return uint16(*i) } + +func (i *uint16Value) String() string { return fmt.Sprintf("%v", *i) } + +// -- string Value +type stringValue string + +func newStringValue(val string, p *string) *stringValue { + *p = val + return (*stringValue)(p) +} + +func (s *stringValue) Set(val string) error { + *s = stringValue(val) + return nil +} + +func (s *stringValue) Get() interface{} { return string(*s) } + +func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) } + +// -- float64 Value +type float64Value float64 + +func newFloat64Value(val float64, p *float64) *float64Value { + *p = val + return (*float64Value)(p) +} + +func (f *float64Value) Set(s string) error { + v, err := strconv.ParseFloat(s, 64) + *f = float64Value(v) + return err +} + +func (f *float64Value) Get() interface{} { return float64(*f) } + +func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) } + +// -- time.Duration Value +type durationValue time.Duration + +func newDurationValue(val time.Duration, p *time.Duration) *durationValue { + *p = val + return (*durationValue)(p) +} + +func (d *durationValue) Set(s string) error { + v, err := time.ParseDuration(s) + *d = durationValue(v) + return err +} + +func (d *durationValue) Get() interface{} { return time.Duration(*d) } + +func (d *durationValue) String() string { return (*time.Duration)(d).String() } + +// Value is the interface to the dynamic value stored in a flag. +// (The default value is represented as a string.) +// +// If a Value has an IsBoolFlag() bool method returning true, +// the command-line parser makes -name equivalent to -name=true +// rather than using the next command-line argument. +type Value interface { + String() string + Set(string) error +} + +// Getter is an interface that allows the contents of a Value to be retrieved. +// It wraps the Value interface, rather than being part of it, because it +// appeared after Go 1 and its compatibility rules. All Value types provided +// by this package satisfy the Getter interface. +type Getter interface { + Value + Get() interface{} +} + +// ErrorHandling defines how to handle flag parsing errors. +type ErrorHandling int + +// ErrorHandling strategies available when a flag parsing error occurs +const ( + ContinueOnError ErrorHandling = iota + ExitOnError + PanicOnError +) + +// A FlagSet represents a set of defined flags. The zero value of a FlagSet +// has no name and has ContinueOnError error handling. +type FlagSet struct { + // Usage is the function called when an error occurs while parsing flags. + // The field is a function (not a method) that may be changed to point to + // a custom error handler. + Usage func() + ShortUsage func() + + name string + parsed bool + actual map[string]*Flag + formal map[string]*Flag + args []string // arguments after flags + errorHandling ErrorHandling + output io.Writer // nil means stderr; use Out() accessor + nArgRequirements []nArgRequirement +} + +// A Flag represents the state of a flag. +type Flag struct { + Names []string // name as it appears on command line + Usage string // help message + Value Value // value as set + DefValue string // default value (as text); for usage message +} + +type flagSlice []string + +func (p flagSlice) Len() int { return len(p) } +func (p flagSlice) Less(i, j int) bool { + pi, pj := strings.TrimPrefix(p[i], "-"), strings.TrimPrefix(p[j], "-") + lpi, lpj := strings.ToLower(pi), strings.ToLower(pj) + if lpi != lpj { + return lpi < lpj + } + return pi < pj +} +func (p flagSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// sortFlags returns the flags as a slice in lexicographical sorted order. +func sortFlags(flags map[string]*Flag) []*Flag { + var list flagSlice + + // The sorted list is based on the first name, when flag map might use the other names. + nameMap := make(map[string]string) + + for n, f := range flags { + fName := strings.TrimPrefix(f.Names[0], "#") + nameMap[fName] = n + if len(f.Names) == 1 { + list = append(list, fName) + continue + } + + found := false + for _, name := range list { + if name == fName { + found = true + break + } + } + if !found { + list = append(list, fName) + } + } + sort.Sort(list) + result := make([]*Flag, len(list)) + for i, name := range list { + result[i] = flags[nameMap[name]] + } + return result +} + +// Name returns the name of the FlagSet. +func (fs *FlagSet) Name() string { + return fs.name +} + +// Out returns the destination for usage and error messages. +func (fs *FlagSet) Out() io.Writer { + if fs.output == nil { + return os.Stderr + } + return fs.output +} + +// SetOutput sets the destination for usage and error messages. +// If output is nil, os.Stderr is used. +func (fs *FlagSet) SetOutput(output io.Writer) { + fs.output = output +} + +// VisitAll visits the flags in lexicographical order, calling fn for each. +// It visits all flags, even those not set. +func (fs *FlagSet) VisitAll(fn func(*Flag)) { + for _, flag := range sortFlags(fs.formal) { + fn(flag) + } +} + +// VisitAll visits the command-line flags in lexicographical order, calling +// fn for each. It visits all flags, even those not set. +func VisitAll(fn func(*Flag)) { + CommandLine.VisitAll(fn) +} + +// Visit visits the flags in lexicographical order, calling fn for each. +// It visits only those flags that have been set. +func (fs *FlagSet) Visit(fn func(*Flag)) { + for _, flag := range sortFlags(fs.actual) { + fn(flag) + } +} + +// Visit visits the command-line flags in lexicographical order, calling fn +// for each. It visits only those flags that have been set. +func Visit(fn func(*Flag)) { + CommandLine.Visit(fn) +} + +// Lookup returns the Flag structure of the named flag, returning nil if none exists. +func (fs *FlagSet) Lookup(name string) *Flag { + return fs.formal[name] +} + +// IsSet indicates whether the specified flag is set in the given FlagSet +func (fs *FlagSet) IsSet(name string) bool { + return fs.actual[name] != nil +} + +// Lookup returns the Flag structure of the named command-line flag, +// returning nil if none exists. +func Lookup(name string) *Flag { + return CommandLine.formal[name] +} + +// IsSet indicates whether the specified flag was specified at all on the cmd line. +func IsSet(name string) bool { + return CommandLine.IsSet(name) +} + +type nArgRequirementType int + +// Indicator used to pass to BadArgs function +const ( + Exact nArgRequirementType = iota + Max + Min +) + +type nArgRequirement struct { + Type nArgRequirementType + N int +} + +// Require adds a requirement about the number of arguments for the FlagSet. +// The first parameter can be Exact, Max, or Min to respectively specify the exact, +// the maximum, or the minimal number of arguments required. +// The actual check is done in FlagSet.CheckArgs(). +func (fs *FlagSet) Require(nArgRequirementType nArgRequirementType, nArg int) { + fs.nArgRequirements = append(fs.nArgRequirements, nArgRequirement{nArgRequirementType, nArg}) +} + +// CheckArgs uses the requirements set by FlagSet.Require() to validate +// the number of arguments. If the requirements are not met, +// an error message string is returned. +func (fs *FlagSet) CheckArgs() (message string) { + for _, req := range fs.nArgRequirements { + var arguments string + if req.N == 1 { + arguments = "1 argument" + } else { + arguments = fmt.Sprintf("%d arguments", req.N) + } + + str := func(kind string) string { + return fmt.Sprintf("%q requires %s%s", fs.name, kind, arguments) + } + + switch req.Type { + case Exact: + if fs.NArg() != req.N { + return str("") + } + case Max: + if fs.NArg() > req.N { + return str("a maximum of ") + } + case Min: + if fs.NArg() < req.N { + return str("a minimum of ") + } + } + } + return "" +} + +// Set sets the value of the named flag. +func (fs *FlagSet) Set(name, value string) error { + flag, ok := fs.formal[name] + if !ok { + return fmt.Errorf("no such flag -%v", name) + } + if err := flag.Value.Set(value); err != nil { + return err + } + if fs.actual == nil { + fs.actual = make(map[string]*Flag) + } + fs.actual[name] = flag + return nil +} + +// Set sets the value of the named command-line flag. +func Set(name, value string) error { + return CommandLine.Set(name, value) +} + +// isZeroValue guesses whether the string represents the zero +// value for a flag. It is not accurate but in practice works OK. +func isZeroValue(value string) bool { + switch value { + case "false": + return true + case "": + return true + case "0": + return true + } + return false +} + +// PrintDefaults prints, to standard error unless configured +// otherwise, the default values of all defined flags in the set. +func (fs *FlagSet) PrintDefaults() { + writer := tabwriter.NewWriter(fs.Out(), 20, 1, 3, ' ', 0) + home := homedir.Get() + + // Don't substitute when HOME is / + if runtime.GOOS != "windows" && home == "/" { + home = "" + } + + // Add a blank line between cmd description and list of options + if fs.FlagCount() > 0 { + fmt.Fprintln(writer, "") + } + + fs.VisitAll(func(flag *Flag) { + names := []string{} + for _, name := range flag.Names { + if name[0] != '#' { + names = append(names, name) + } + } + if len(names) > 0 && len(flag.Usage) > 0 { + val := flag.DefValue + + if home != "" && strings.HasPrefix(val, home) { + val = homedir.GetShortcutString() + val[len(home):] + } + + if isZeroValue(val) { + format := " -%s" + fmt.Fprintf(writer, format, strings.Join(names, ", -")) + } else { + format := " -%s=%s" + fmt.Fprintf(writer, format, strings.Join(names, ", -"), val) + } + for _, line := range strings.Split(flag.Usage, "\n") { + fmt.Fprintln(writer, "\t", line) + } + } + }) + writer.Flush() +} + +// PrintDefaults prints to standard error the default values of all defined command-line flags. +func PrintDefaults() { + CommandLine.PrintDefaults() +} + +// defaultUsage is the default function to print a usage message. +func defaultUsage(fs *FlagSet) { + if fs.name == "" { + fmt.Fprintf(fs.Out(), "Usage:\n") + } else { + fmt.Fprintf(fs.Out(), "Usage of %s:\n", fs.name) + } + fs.PrintDefaults() +} + +// NOTE: Usage is not just defaultUsage(CommandLine) +// because it serves (via godoc flag Usage) as the example +// for how to write your own usage function. + +// Usage prints to standard error a usage message documenting all defined command-line flags. +// The function is a variable that may be changed to point to a custom function. +var Usage = func() { + fmt.Fprintf(CommandLine.Out(), "Usage of %s:\n", os.Args[0]) + PrintDefaults() +} + +// ShortUsage prints to standard error a usage message documenting the standard command layout +// The function is a variable that may be changed to point to a custom function. +var ShortUsage = func() { + fmt.Fprintf(CommandLine.output, "Usage of %s:\n", os.Args[0]) +} + +// FlagCount returns the number of flags that have been defined. +func (fs *FlagSet) FlagCount() int { return len(sortFlags(fs.formal)) } + +// FlagCountUndeprecated returns the number of undeprecated flags that have been defined. +func (fs *FlagSet) FlagCountUndeprecated() int { + count := 0 + for _, flag := range sortFlags(fs.formal) { + for _, name := range flag.Names { + if name[0] != '#' { + count++ + break + } + } + } + return count +} + +// NFlag returns the number of flags that have been set. +func (fs *FlagSet) NFlag() int { return len(fs.actual) } + +// NFlag returns the number of command-line flags that have been set. +func NFlag() int { return len(CommandLine.actual) } + +// Arg returns the i'th argument. Arg(0) is the first remaining argument +// after flags have been processed. +func (fs *FlagSet) Arg(i int) string { + if i < 0 || i >= len(fs.args) { + return "" + } + return fs.args[i] +} + +// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument +// after flags have been processed. +func Arg(i int) string { + return CommandLine.Arg(i) +} + +// NArg is the number of arguments remaining after flags have been processed. +func (fs *FlagSet) NArg() int { return len(fs.args) } + +// NArg is the number of arguments remaining after flags have been processed. +func NArg() int { return len(CommandLine.args) } + +// Args returns the non-flag arguments. +func (fs *FlagSet) Args() []string { return fs.args } + +// Args returns the non-flag command-line arguments. +func Args() []string { return CommandLine.args } + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func (fs *FlagSet) BoolVar(p *bool, names []string, value bool, usage string) { + fs.Var(newBoolValue(value, p), names, usage) +} + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func BoolVar(p *bool, names []string, value bool, usage string) { + CommandLine.Var(newBoolValue(value, p), names, usage) +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func (fs *FlagSet) Bool(names []string, value bool, usage string) *bool { + p := new(bool) + fs.BoolVar(p, names, value, usage) + return p +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func Bool(names []string, value bool, usage string) *bool { + return CommandLine.Bool(names, value, usage) +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func (fs *FlagSet) IntVar(p *int, names []string, value int, usage string) { + fs.Var(newIntValue(value, p), names, usage) +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func IntVar(p *int, names []string, value int, usage string) { + CommandLine.Var(newIntValue(value, p), names, usage) +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func (fs *FlagSet) Int(names []string, value int, usage string) *int { + p := new(int) + fs.IntVar(p, names, value, usage) + return p +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func Int(names []string, value int, usage string) *int { + return CommandLine.Int(names, value, usage) +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func (fs *FlagSet) Int64Var(p *int64, names []string, value int64, usage string) { + fs.Var(newInt64Value(value, p), names, usage) +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func Int64Var(p *int64, names []string, value int64, usage string) { + CommandLine.Var(newInt64Value(value, p), names, usage) +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func (fs *FlagSet) Int64(names []string, value int64, usage string) *int64 { + p := new(int64) + fs.Int64Var(p, names, value, usage) + return p +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func Int64(names []string, value int64, usage string) *int64 { + return CommandLine.Int64(names, value, usage) +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func (fs *FlagSet) UintVar(p *uint, names []string, value uint, usage string) { + fs.Var(newUintValue(value, p), names, usage) +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func UintVar(p *uint, names []string, value uint, usage string) { + CommandLine.Var(newUintValue(value, p), names, usage) +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func (fs *FlagSet) Uint(names []string, value uint, usage string) *uint { + p := new(uint) + fs.UintVar(p, names, value, usage) + return p +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func Uint(names []string, value uint, usage string) *uint { + return CommandLine.Uint(names, value, usage) +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func (fs *FlagSet) Uint64Var(p *uint64, names []string, value uint64, usage string) { + fs.Var(newUint64Value(value, p), names, usage) +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func Uint64Var(p *uint64, names []string, value uint64, usage string) { + CommandLine.Var(newUint64Value(value, p), names, usage) +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func (fs *FlagSet) Uint64(names []string, value uint64, usage string) *uint64 { + p := new(uint64) + fs.Uint64Var(p, names, value, usage) + return p +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func Uint64(names []string, value uint64, usage string) *uint64 { + return CommandLine.Uint64(names, value, usage) +} + +// Uint16Var defines a uint16 flag with specified name, default value, and usage string. +// The argument p points to a uint16 variable in which to store the value of the flag. +func (fs *FlagSet) Uint16Var(p *uint16, names []string, value uint16, usage string) { + fs.Var(newUint16Value(value, p), names, usage) +} + +// Uint16Var defines a uint16 flag with specified name, default value, and usage string. +// The argument p points to a uint16 variable in which to store the value of the flag. +func Uint16Var(p *uint16, names []string, value uint16, usage string) { + CommandLine.Var(newUint16Value(value, p), names, usage) +} + +// Uint16 defines a uint16 flag with specified name, default value, and usage string. +// The return value is the address of a uint16 variable that stores the value of the flag. +func (fs *FlagSet) Uint16(names []string, value uint16, usage string) *uint16 { + p := new(uint16) + fs.Uint16Var(p, names, value, usage) + return p +} + +// Uint16 defines a uint16 flag with specified name, default value, and usage string. +// The return value is the address of a uint16 variable that stores the value of the flag. +func Uint16(names []string, value uint16, usage string) *uint16 { + return CommandLine.Uint16(names, value, usage) +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func (fs *FlagSet) StringVar(p *string, names []string, value string, usage string) { + fs.Var(newStringValue(value, p), names, usage) +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func StringVar(p *string, names []string, value string, usage string) { + CommandLine.Var(newStringValue(value, p), names, usage) +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func (fs *FlagSet) String(names []string, value string, usage string) *string { + p := new(string) + fs.StringVar(p, names, value, usage) + return p +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func String(names []string, value string, usage string) *string { + return CommandLine.String(names, value, usage) +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func (fs *FlagSet) Float64Var(p *float64, names []string, value float64, usage string) { + fs.Var(newFloat64Value(value, p), names, usage) +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func Float64Var(p *float64, names []string, value float64, usage string) { + CommandLine.Var(newFloat64Value(value, p), names, usage) +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func (fs *FlagSet) Float64(names []string, value float64, usage string) *float64 { + p := new(float64) + fs.Float64Var(p, names, value, usage) + return p +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func Float64(names []string, value float64, usage string) *float64 { + return CommandLine.Float64(names, value, usage) +} + +// DurationVar defines a time.Duration flag with specified name, default value, and usage string. +// The argument p points to a time.Duration variable in which to store the value of the flag. +func (fs *FlagSet) DurationVar(p *time.Duration, names []string, value time.Duration, usage string) { + fs.Var(newDurationValue(value, p), names, usage) +} + +// DurationVar defines a time.Duration flag with specified name, default value, and usage string. +// The argument p points to a time.Duration variable in which to store the value of the flag. +func DurationVar(p *time.Duration, names []string, value time.Duration, usage string) { + CommandLine.Var(newDurationValue(value, p), names, usage) +} + +// Duration defines a time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a time.Duration variable that stores the value of the flag. +func (fs *FlagSet) Duration(names []string, value time.Duration, usage string) *time.Duration { + p := new(time.Duration) + fs.DurationVar(p, names, value, usage) + return p +} + +// Duration defines a time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a time.Duration variable that stores the value of the flag. +func Duration(names []string, value time.Duration, usage string) *time.Duration { + return CommandLine.Duration(names, value, usage) +} + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func (fs *FlagSet) Var(value Value, names []string, usage string) { + // Remember the default value as a string; it won't change. + flag := &Flag{names, usage, value, value.String()} + for _, name := range names { + name = strings.TrimPrefix(name, "#") + _, alreadythere := fs.formal[name] + if alreadythere { + var msg string + if fs.name == "" { + msg = fmt.Sprintf("flag redefined: %s", name) + } else { + msg = fmt.Sprintf("%s flag redefined: %s", fs.name, name) + } + fmt.Fprintln(fs.Out(), msg) + panic(msg) // Happens only if flags are declared with identical names + } + if fs.formal == nil { + fs.formal = make(map[string]*Flag) + } + fs.formal[name] = flag + } +} + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func Var(value Value, names []string, usage string) { + CommandLine.Var(value, names, usage) +} + +// failf prints to standard error a formatted error and usage message and +// returns the error. +func (fs *FlagSet) failf(format string, a ...interface{}) error { + err := fmt.Errorf(format, a...) + fmt.Fprintln(fs.Out(), err) + if os.Args[0] == fs.name { + fmt.Fprintf(fs.Out(), "See '%s --help'.\n", os.Args[0]) + } else { + fmt.Fprintf(fs.Out(), "See '%s %s --help'.\n", os.Args[0], fs.name) + } + return err +} + +// usage calls the Usage method for the flag set, or the usage function if +// the flag set is CommandLine. +func (fs *FlagSet) usage() { + if fs == CommandLine { + Usage() + } else if fs.Usage == nil { + defaultUsage(fs) + } else { + fs.Usage() + } +} + +func trimQuotes(str string) string { + if len(str) == 0 { + return str + } + type quote struct { + start, end byte + } + + // All valid quote types. + quotes := []quote{ + // Double quotes + { + start: '"', + end: '"', + }, + + // Single quotes + { + start: '\'', + end: '\'', + }, + } + + for _, quote := range quotes { + // Only strip if outermost match. + if str[0] == quote.start && str[len(str)-1] == quote.end { + str = str[1 : len(str)-1] + break + } + } + + return str +} + +// parseOne parses one flag. It reports whether a flag was seen. +func (fs *FlagSet) parseOne() (bool, string, error) { + if len(fs.args) == 0 { + return false, "", nil + } + s := fs.args[0] + if len(s) == 0 || s[0] != '-' || len(s) == 1 { + return false, "", nil + } + if s[1] == '-' && len(s) == 2 { // "--" terminates the flags + fs.args = fs.args[1:] + return false, "", nil + } + name := s[1:] + if len(name) == 0 || name[0] == '=' { + return false, "", fs.failf("bad flag syntax: %s", s) + } + + // it's a flag. does it have an argument? + fs.args = fs.args[1:] + hasValue := false + value := "" + if i := strings.Index(name, "="); i != -1 { + value = trimQuotes(name[i+1:]) + hasValue = true + name = name[:i] + } + + m := fs.formal + flag, alreadythere := m[name] // BUG + if !alreadythere { + if name == "-help" || name == "help" || name == "h" { // special case for nice help message. + fs.usage() + return false, "", ErrHelp + } + if len(name) > 0 && name[0] == '-' { + return false, "", fs.failf("flag provided but not defined: -%s", name) + } + return false, name, ErrRetry + } + if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg + if hasValue { + if err := fv.Set(value); err != nil { + return false, "", fs.failf("invalid boolean value %q for -%s: %v", value, name, err) + } + } else { + fv.Set("true") + } + } else { + // It must have a value, which might be the next argument. + if !hasValue && len(fs.args) > 0 { + // value is the next arg + hasValue = true + value, fs.args = fs.args[0], fs.args[1:] + } + if !hasValue { + return false, "", fs.failf("flag needs an argument: -%s", name) + } + if err := flag.Value.Set(value); err != nil { + return false, "", fs.failf("invalid value %q for flag -%s: %v", value, name, err) + } + } + if fs.actual == nil { + fs.actual = make(map[string]*Flag) + } + fs.actual[name] = flag + for i, n := range flag.Names { + if n == fmt.Sprintf("#%s", name) { + replacement := "" + for j := i; j < len(flag.Names); j++ { + if flag.Names[j][0] != '#' { + replacement = flag.Names[j] + break + } + } + if replacement != "" { + fmt.Fprintf(fs.Out(), "Warning: '-%s' is deprecated, it will be replaced by '-%s' soon. See usage.\n", name, replacement) + } else { + fmt.Fprintf(fs.Out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name) + } + } + } + return true, "", nil +} + +// Parse parses flag definitions from the argument list, which should not +// include the command name. Must be called after all flags in the FlagSet +// are defined and before flags are accessed by the program. +// The return value will be ErrHelp if -help was set but not defined. +func (fs *FlagSet) Parse(arguments []string) error { + fs.parsed = true + fs.args = arguments + for { + seen, name, err := fs.parseOne() + if seen { + continue + } + if err == nil { + break + } + if err == ErrRetry { + if len(name) > 1 { + err = nil + for _, letter := range strings.Split(name, "") { + fs.args = append([]string{"-" + letter}, fs.args...) + seen2, _, err2 := fs.parseOne() + if seen2 { + continue + } + if err2 != nil { + err = fs.failf("flag provided but not defined: -%s", name) + break + } + } + if err == nil { + continue + } + } else { + err = fs.failf("flag provided but not defined: -%s", name) + } + } + switch fs.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(125) + case PanicOnError: + panic(err) + } + } + return nil +} + +// ParseFlags is a utility function that adds a help flag if withHelp is true, +// calls fs.Parse(args) and prints a relevant error message if there are +// incorrect number of arguments. It returns error only if error handling is +// set to ContinueOnError and parsing fails. If error handling is set to +// ExitOnError, it's safe to ignore the return value. +func (fs *FlagSet) ParseFlags(args []string, withHelp bool) error { + var help *bool + if withHelp { + help = fs.Bool([]string{"#help", "-help"}, false, "Print usage") + } + if err := fs.Parse(args); err != nil { + return err + } + if help != nil && *help { + fs.SetOutput(os.Stdout) + fs.Usage() + os.Exit(0) + } + if str := fs.CheckArgs(); str != "" { + fs.SetOutput(os.Stderr) + fs.ReportError(str, withHelp) + fs.ShortUsage() + os.Exit(1) + } + return nil +} + +// ReportError is a utility method that prints a user-friendly message +// containing the error that occurred during parsing and a suggestion to get help +func (fs *FlagSet) ReportError(str string, withHelp bool) { + if withHelp { + if os.Args[0] == fs.Name() { + str += ".\nSee '" + os.Args[0] + " --help'" + } else { + str += ".\nSee '" + os.Args[0] + " " + fs.Name() + " --help'" + } + } + fmt.Fprintf(fs.Out(), "%s: %s.\n", os.Args[0], str) +} + +// Parsed reports whether fs.Parse has been called. +func (fs *FlagSet) Parsed() bool { + return fs.parsed +} + +// Parse parses the command-line flags from os.Args[1:]. Must be called +// after all flags are defined and before flags are accessed by the program. +func Parse() { + // Ignore errors; CommandLine is set for ExitOnError. + CommandLine.Parse(os.Args[1:]) +} + +// Parsed returns true if the command-line flags have been parsed. +func Parsed() bool { + return CommandLine.Parsed() +} + +// CommandLine is the default set of command-line flags, parsed from os.Args. +// The top-level functions such as BoolVar, Arg, and on are wrappers for the +// methods of CommandLine. +var CommandLine = NewFlagSet(os.Args[0], ExitOnError) + +// NewFlagSet returns a new, empty flag set with the specified name and +// error handling property. +func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { + f := &FlagSet{ + name: name, + errorHandling: errorHandling, + } + return f +} + +// Init sets the name and error handling property for a flag set. +// By default, the zero FlagSet uses an empty name and the +// ContinueOnError error handling policy. +func (fs *FlagSet) Init(name string, errorHandling ErrorHandling) { + fs.name = name + fs.errorHandling = errorHandling +} + +type mergeVal struct { + Value + key string + fset *FlagSet +} + +func (v mergeVal) Set(s string) error { + return v.fset.Set(v.key, s) +} + +func (v mergeVal) IsBoolFlag() bool { + if b, ok := v.Value.(boolFlag); ok { + return b.IsBoolFlag() + } + return false +} + +// Name returns the name of a mergeVal. +// If the original value had a name, return the original name, +// otherwise, return the key asinged to this mergeVal. +func (v mergeVal) Name() string { + type namedValue interface { + Name() string + } + if nVal, ok := v.Value.(namedValue); ok { + return nVal.Name() + } + return v.key +} + +// Merge is an helper function that merges n FlagSets into a single dest FlagSet +// In case of name collision between the flagsets it will apply +// the destination FlagSet's errorHandling behavior. +func Merge(dest *FlagSet, flagsets ...*FlagSet) error { + for _, fset := range flagsets { + if fset.formal == nil { + continue + } + for k, f := range fset.formal { + if _, ok := dest.formal[k]; ok { + var err error + if fset.name == "" { + err = fmt.Errorf("flag redefined: %s", k) + } else { + err = fmt.Errorf("%s flag redefined: %s", fset.name, k) + } + fmt.Fprintln(fset.Out(), err.Error()) + // Happens only if flags are declared with identical names + switch dest.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(2) + case PanicOnError: + panic(err) + } + } + newF := *f + newF.Value = mergeVal{f.Value, k, fset} + if dest.formal == nil { + dest.formal = make(map[string]*Flag) + } + dest.formal[k] = &newF + } + } + return nil +} + +// IsEmpty reports if the FlagSet is actually empty. +func (fs *FlagSet) IsEmpty() bool { + return len(fs.actual) == 0 +} diff --git a/client/mflag/flag_test.go b/client/mflag/flag_test.go new file mode 100644 index 0000000000..a09d49cd60 --- /dev/null +++ b/client/mflag/flag_test.go @@ -0,0 +1,529 @@ +// Copyright 2014-2016 The Docker & Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mflag + +import ( + "bytes" + "fmt" + "os" + "sort" + "strings" + "testing" + "time" + + _ "github.com/docker/libnetwork/testutils" +) + +// ResetForTesting clears all flag state and sets the usage function as directed. +// After calling ResetForTesting, parse errors in flag handling will not +// exit the program. +func ResetForTesting(usage func()) { + CommandLine = NewFlagSet(os.Args[0], ContinueOnError) + Usage = usage +} +func boolString(s string) string { + if s == "0" { + return "false" + } + return "true" +} + +func TestEverything(t *testing.T) { + ResetForTesting(nil) + Bool([]string{"test_bool"}, false, "bool value") + Int([]string{"test_int"}, 0, "int value") + Int64([]string{"test_int64"}, 0, "int64 value") + Uint([]string{"test_uint"}, 0, "uint value") + Uint64([]string{"test_uint64"}, 0, "uint64 value") + String([]string{"test_string"}, "0", "string value") + Float64([]string{"test_float64"}, 0, "float64 value") + Duration([]string{"test_duration"}, 0, "time.Duration value") + + m := make(map[string]*Flag) + desired := "0" + visitor := func(f *Flag) { + for _, name := range f.Names { + if len(name) > 5 && name[0:5] == "test_" { + m[name] = f + ok := false + switch { + case f.Value.String() == desired: + ok = true + case name == "test_bool" && f.Value.String() == boolString(desired): + ok = true + case name == "test_duration" && f.Value.String() == desired+"s": + ok = true + } + if !ok { + t.Error("Visit: bad value", f.Value.String(), "for", name) + } + } + } + } + VisitAll(visitor) + if len(m) != 8 { + t.Error("VisitAll misses some flags") + for k, v := range m { + t.Log(k, *v) + } + } + m = make(map[string]*Flag) + Visit(visitor) + if len(m) != 0 { + t.Errorf("Visit sees unset flags") + for k, v := range m { + t.Log(k, *v) + } + } + // Now set all flags + Set("test_bool", "true") + Set("test_int", "1") + Set("test_int64", "1") + Set("test_uint", "1") + Set("test_uint64", "1") + Set("test_string", "1") + Set("test_float64", "1") + Set("test_duration", "1s") + desired = "1" + Visit(visitor) + if len(m) != 8 { + t.Error("Visit fails after set") + for k, v := range m { + t.Log(k, *v) + } + } + // Now test they're visited in sort order. + var flagNames []string + Visit(func(f *Flag) { + for _, name := range f.Names { + flagNames = append(flagNames, name) + } + }) + if !sort.StringsAreSorted(flagNames) { + t.Errorf("flag names not sorted: %v", flagNames) + } +} + +func TestGet(t *testing.T) { + ResetForTesting(nil) + Bool([]string{"test_bool"}, true, "bool value") + Int([]string{"test_int"}, 1, "int value") + Int64([]string{"test_int64"}, 2, "int64 value") + Uint([]string{"test_uint"}, 3, "uint value") + Uint64([]string{"test_uint64"}, 4, "uint64 value") + String([]string{"test_string"}, "5", "string value") + Float64([]string{"test_float64"}, 6, "float64 value") + Duration([]string{"test_duration"}, 7, "time.Duration value") + + visitor := func(f *Flag) { + for _, name := range f.Names { + if len(name) > 5 && name[0:5] == "test_" { + g, ok := f.Value.(Getter) + if !ok { + t.Errorf("Visit: value does not satisfy Getter: %T", f.Value) + return + } + switch name { + case "test_bool": + ok = g.Get() == true + case "test_int": + ok = g.Get() == int(1) + case "test_int64": + ok = g.Get() == int64(2) + case "test_uint": + ok = g.Get() == uint(3) + case "test_uint64": + ok = g.Get() == uint64(4) + case "test_string": + ok = g.Get() == "5" + case "test_float64": + ok = g.Get() == float64(6) + case "test_duration": + ok = g.Get() == time.Duration(7) + } + if !ok { + t.Errorf("Visit: bad value %T(%v) for %s", g.Get(), g.Get(), name) + } + } + } + } + VisitAll(visitor) +} + +func testParse(f *FlagSet, t *testing.T) { + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + boolFlag := f.Bool([]string{"bool"}, false, "bool value") + bool2Flag := f.Bool([]string{"bool2"}, false, "bool2 value") + f.Bool([]string{"bool3"}, false, "bool3 value") + bool4Flag := f.Bool([]string{"bool4"}, false, "bool4 value") + intFlag := f.Int([]string{"-int"}, 0, "int value") + int64Flag := f.Int64([]string{"-int64"}, 0, "int64 value") + uintFlag := f.Uint([]string{"uint"}, 0, "uint value") + uint64Flag := f.Uint64([]string{"-uint64"}, 0, "uint64 value") + stringFlag := f.String([]string{"string"}, "0", "string value") + f.String([]string{"string2"}, "0", "string2 value") + singleQuoteFlag := f.String([]string{"squote"}, "", "single quoted value") + doubleQuoteFlag := f.String([]string{"dquote"}, "", "double quoted value") + mixedQuoteFlag := f.String([]string{"mquote"}, "", "mixed quoted value") + mixed2QuoteFlag := f.String([]string{"mquote2"}, "", "mixed2 quoted value") + nestedQuoteFlag := f.String([]string{"nquote"}, "", "nested quoted value") + nested2QuoteFlag := f.String([]string{"nquote2"}, "", "nested2 quoted value") + float64Flag := f.Float64([]string{"float64"}, 0, "float64 value") + durationFlag := f.Duration([]string{"duration"}, 5*time.Second, "time.Duration value") + extra := "one-extra-argument" + args := []string{ + "-bool", + "-bool2=true", + "-bool4=false", + "--int", "22", + "--int64", "0x23", + "-uint", "24", + "--uint64", "25", + "-string", "hello", + "-squote='single'", + `-dquote="double"`, + `-mquote='mixed"`, + `-mquote2="mixed2'`, + `-nquote="'single nested'"`, + `-nquote2='"double nested"'`, + "-float64", "2718e28", + "-duration", "2m", + extra, + } + if err := f.Parse(args); err != nil { + t.Fatal(err) + } + if !f.Parsed() { + t.Error("f.Parse() = false after Parse") + } + if *boolFlag != true { + t.Error("bool flag should be true, is ", *boolFlag) + } + if *bool2Flag != true { + t.Error("bool2 flag should be true, is ", *bool2Flag) + } + if !f.IsSet("bool2") { + t.Error("bool2 should be marked as set") + } + if f.IsSet("bool3") { + t.Error("bool3 should not be marked as set") + } + if !f.IsSet("bool4") { + t.Error("bool4 should be marked as set") + } + if *bool4Flag != false { + t.Error("bool4 flag should be false, is ", *bool4Flag) + } + if *intFlag != 22 { + t.Error("int flag should be 22, is ", *intFlag) + } + if *int64Flag != 0x23 { + t.Error("int64 flag should be 0x23, is ", *int64Flag) + } + if *uintFlag != 24 { + t.Error("uint flag should be 24, is ", *uintFlag) + } + if *uint64Flag != 25 { + t.Error("uint64 flag should be 25, is ", *uint64Flag) + } + if *stringFlag != "hello" { + t.Error("string flag should be `hello`, is ", *stringFlag) + } + if !f.IsSet("string") { + t.Error("string flag should be marked as set") + } + if f.IsSet("string2") { + t.Error("string2 flag should not be marked as set") + } + if *singleQuoteFlag != "single" { + t.Error("single quote string flag should be `single`, is ", *singleQuoteFlag) + } + if *doubleQuoteFlag != "double" { + t.Error("double quote string flag should be `double`, is ", *doubleQuoteFlag) + } + if *mixedQuoteFlag != `'mixed"` { + t.Error("mixed quote string flag should be `'mixed\"`, is ", *mixedQuoteFlag) + } + if *mixed2QuoteFlag != `"mixed2'` { + t.Error("mixed2 quote string flag should be `\"mixed2'`, is ", *mixed2QuoteFlag) + } + if *nestedQuoteFlag != "'single nested'" { + t.Error("nested quote string flag should be `'single nested'`, is ", *nestedQuoteFlag) + } + if *nested2QuoteFlag != `"double nested"` { + t.Error("double quote string flag should be `\"double nested\"`, is ", *nested2QuoteFlag) + } + if *float64Flag != 2718e28 { + t.Error("float64 flag should be 2718e28, is ", *float64Flag) + } + if *durationFlag != 2*time.Minute { + t.Error("duration flag should be 2m, is ", *durationFlag) + } + if len(f.Args()) != 1 { + t.Error("expected one argument, got", len(f.Args())) + } else if f.Args()[0] != extra { + t.Errorf("expected argument %q got %q", extra, f.Args()[0]) + } +} + +func testPanic(f *FlagSet, t *testing.T) { + f.Int([]string{"-int"}, 0, "int value") + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + args := []string{ + "-int", "21", + } + f.Parse(args) +} + +func TestParsePanic(t *testing.T) { + ResetForTesting(func() {}) + testPanic(CommandLine, t) +} + +func TestParse(t *testing.T) { + ResetForTesting(func() { t.Error("bad parse") }) + testParse(CommandLine, t) +} + +func TestFlagSetParse(t *testing.T) { + testParse(NewFlagSet("test", ContinueOnError), t) +} + +// Declare a user-defined flag type. +type flagVar []string + +func (f *flagVar) String() string { + return fmt.Sprint([]string(*f)) +} + +func (f *flagVar) Set(value string) error { + *f = append(*f, value) + return nil +} + +func TestUserDefined(t *testing.T) { + var flags FlagSet + flags.Init("test", ContinueOnError) + var v flagVar + flags.Var(&v, []string{"v"}, "usage") + if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil { + t.Error(err) + } + if len(v) != 3 { + t.Fatal("expected 3 args; got ", len(v)) + } + expect := "[1 2 3]" + if v.String() != expect { + t.Errorf("expected value %q got %q", expect, v.String()) + } +} + +// Declare a user-defined boolean flag type. +type boolFlagVar struct { + count int +} + +func (b *boolFlagVar) String() string { + return fmt.Sprintf("%d", b.count) +} + +func (b *boolFlagVar) Set(value string) error { + if value == "true" { + b.count++ + } + return nil +} + +func (b *boolFlagVar) IsBoolFlag() bool { + return b.count < 4 +} + +func TestUserDefinedBool(t *testing.T) { + var flags FlagSet + flags.Init("test", ContinueOnError) + var b boolFlagVar + var err error + flags.Var(&b, []string{"b"}, "usage") + if err = flags.Parse([]string{"-b", "-b", "-b", "-b=true", "-b=false", "-b", "barg", "-b"}); err != nil { + if b.count < 4 { + t.Error(err) + } + } + + if b.count != 4 { + t.Errorf("want: %d; got: %d", 4, b.count) + } + + if err == nil { + t.Error("expected error; got none") + } +} + +func TestSetOutput(t *testing.T) { + var flags FlagSet + var buf bytes.Buffer + flags.SetOutput(&buf) + flags.Init("test", ContinueOnError) + flags.Parse([]string{"-unknown"}) + if out := buf.String(); !strings.Contains(out, "-unknown") { + t.Logf("expected output mentioning unknown; got %q", out) + } +} + +// This tests that one can reset the flags. This still works but not well, and is +// superseded by FlagSet. +func TestChangingArgs(t *testing.T) { + ResetForTesting(func() { t.Fatal("bad parse") }) + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"} + before := Bool([]string{"before"}, false, "") + if err := CommandLine.Parse(os.Args[1:]); err != nil { + t.Fatal(err) + } + cmd := Arg(0) + os.Args = Args() + after := Bool([]string{"after"}, false, "") + Parse() + args := Args() + + if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" { + t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args) + } +} + +// Test that -help invokes the usage message and returns ErrHelp. +func TestHelp(t *testing.T) { + var helpCalled = false + fs := NewFlagSet("help test", ContinueOnError) + fs.Usage = func() { helpCalled = true } + var flag bool + fs.BoolVar(&flag, []string{"flag"}, false, "regular flag") + // Regular flag invocation should work + err := fs.Parse([]string{"-flag=true"}) + if err != nil { + t.Fatal("expected no error; got ", err) + } + if !flag { + t.Error("flag was not set by -flag") + } + if helpCalled { + t.Error("help called for regular flag") + helpCalled = false // reset for next test + } + // Help flag should work as expected. + err = fs.Parse([]string{"-help"}) + if err == nil { + t.Fatal("error expected") + } + if err != ErrHelp { + t.Fatal("expected ErrHelp; got ", err) + } + if !helpCalled { + t.Fatal("help was not called") + } + // If we define a help flag, that should override. + var help bool + fs.BoolVar(&help, []string{"help"}, false, "help flag") + helpCalled = false + err = fs.Parse([]string{"-help"}) + if err != nil { + t.Fatal("expected no error for defined -help; got ", err) + } + if helpCalled { + t.Fatal("help was called; should not have been for defined help flag") + } +} + +// Test the flag count functions. +func TestFlagCounts(t *testing.T) { + fs := NewFlagSet("help test", ContinueOnError) + var flag bool + fs.BoolVar(&flag, []string{"flag1"}, false, "regular flag") + fs.BoolVar(&flag, []string{"#deprecated1"}, false, "regular flag") + fs.BoolVar(&flag, []string{"f", "flag2"}, false, "regular flag") + fs.BoolVar(&flag, []string{"#d", "#deprecated2"}, false, "regular flag") + fs.BoolVar(&flag, []string{"flag3"}, false, "regular flag") + fs.BoolVar(&flag, []string{"g", "#flag4", "-flag4"}, false, "regular flag") + + if fs.FlagCount() != 6 { + t.Fatal("FlagCount wrong. ", fs.FlagCount()) + } + if fs.FlagCountUndeprecated() != 4 { + t.Fatal("FlagCountUndeprecated wrong. ", fs.FlagCountUndeprecated()) + } + if fs.NFlag() != 0 { + t.Fatal("NFlag wrong. ", fs.NFlag()) + } + err := fs.Parse([]string{"-fd", "-g", "-flag4"}) + if err != nil { + t.Fatal("expected no error for defined -help; got ", err) + } + if fs.NFlag() != 4 { + t.Fatal("NFlag wrong. ", fs.NFlag()) + } +} + +// Show up bug in sortFlags +func TestSortFlags(t *testing.T) { + fs := NewFlagSet("help TestSortFlags", ContinueOnError) + + var err error + + var b bool + fs.BoolVar(&b, []string{"b", "-banana"}, false, "usage") + + err = fs.Parse([]string{"--banana=true"}) + if err != nil { + t.Fatal("expected no error; got ", err) + } + + count := 0 + + fs.VisitAll(func(flag *Flag) { + count++ + if flag == nil { + t.Fatal("VisitAll should not return a nil flag") + } + }) + flagcount := fs.FlagCount() + if flagcount != count { + t.Fatalf("FlagCount (%d) != number (%d) of elements visited", flagcount, count) + } + // Make sure its idempotent + if flagcount != fs.FlagCount() { + t.Fatalf("FlagCount (%d) != fs.FlagCount() (%d) of elements visited", flagcount, fs.FlagCount()) + } + + count = 0 + fs.Visit(func(flag *Flag) { + count++ + if flag == nil { + t.Fatal("Visit should not return a nil flag") + } + }) + nflag := fs.NFlag() + if nflag != count { + t.Fatalf("NFlag (%d) != number (%d) of elements visited", nflag, count) + } + if nflag != fs.NFlag() { + t.Fatalf("NFlag (%d) != fs.NFlag() (%d) of elements visited", nflag, fs.NFlag()) + } +} + +func TestMergeFlags(t *testing.T) { + base := NewFlagSet("base", ContinueOnError) + base.String([]string{"f"}, "", "") + + fs := NewFlagSet("test", ContinueOnError) + Merge(fs, base) + if len(fs.formal) != 1 { + t.Fatalf("FlagCount (%d) != number (1) of elements merged", len(fs.formal)) + } +} diff --git a/client/network.go b/client/network.go index 1edc43086e..f080f62fe7 100644 --- a/client/network.go +++ b/client/network.go @@ -8,8 +8,8 @@ import ( "strings" "text/tabwriter" - flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/stringid" + flag "github.com/docker/libnetwork/client/mflag" "github.com/docker/libnetwork/netlabel" ) diff --git a/client/service.go b/client/service.go index 77b0e63609..da69af3a1f 100644 --- a/client/service.go +++ b/client/service.go @@ -9,8 +9,8 @@ import ( "text/tabwriter" "github.com/docker/docker/opts" - flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/stringid" + flag "github.com/docker/libnetwork/client/mflag" "github.com/docker/libnetwork/netutils" ) From 6d4e3ab5d03679a0c05854a69c3117573192c25b Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 7 Sep 2016 13:46:57 -0700 Subject: [PATCH 063/799] Update Godeps Signed-off-by: Jana Radhakrishnan --- Godeps/Godeps.json | 103 +++--- .../docker/docker/api/types/filters/parse.go | 307 ++++++++++++++++++ .../api}/types/network/network.go | 0 .../docker/api/types/versions/README.md | 14 + .../docker/api/types/versions/compare.go | 62 ++++ .../github.com/docker/docker/opts/hosts.go | 13 +- .../src/github.com/docker/docker/opts/ip.go | 5 + .../src/github.com/docker/docker/opts/opts.go | 51 ++- .../docker/docker/pkg/discovery/backends.go | 8 +- .../docker/docker/pkg/discovery/kv/kv.go | 8 +- .../docker/docker/pkg/ioutils/bytespipe.go | 3 +- .../docker/docker/pkg/ioutils/fswriters.go | 13 +- .../docker/docker/pkg/ioutils/multireader.go | 21 +- .../docker/docker/pkg/ioutils/readers.go | 2 +- .../docker/docker/pkg/mount/flags.go | 155 ++++++--- .../docker/pkg/parsers/kernel/kernel.go | 26 -- .../pkg/parsers/kernel/kernel_darwin.go | 56 ++++ .../docker/pkg/parsers/kernel/kernel_unix.go | 45 +++ .../pkg/parsers/kernel/kernel_windows.go | 2 + .../docker/docker/pkg/plugins/client.go | 14 +- .../docker/docker/pkg/plugins/discovery.go | 9 +- .../docker/pkg/plugins/discovery_unix.go | 5 + .../docker/pkg/plugins/discovery_windows.go | 8 + .../docker/docker/pkg/plugins/plugins.go | 37 ++- .../docker/docker/pkg/reexec/command_linux.go | 2 +- .../docker/docker/pkg/reexec/command_unix.go | 4 +- .../docker/pkg/reexec/command_unsupported.go | 4 +- .../docker/pkg/reexec/command_windows.go | 2 +- .../docker/docker/pkg/signal/trap.go | 48 ++- .../docker/docker/pkg/stringid/stringid.go | 8 +- .../docker/docker/pkg/system/stat_darwin.go | 32 ++ .../docker/pkg/system/stat_unsupported.go | 2 +- .../docker/docker/pkg/system/utimes_darwin.go | 8 - .../docker/pkg/system/utimes_unsupported.go | 4 +- .../github.com/docker/docker/pkg/term/term.go | 24 +- .../docker/docker/pkg/term/term_windows.go | 221 +++++-------- .../docker/pkg/term/windows/ansi_reader.go | 6 +- .../docker/pkg/term/windows/ansi_writer.go | 22 +- .../docker/docker/pkg/term/windows/console.go | 62 ---- .../docker/docker/pkg/term/windows/windows.go | 28 ++ .../mattn/go-shellwords/.travis.yml | 8 + .../github.com/mattn/go-shellwords/README.md | 47 +++ .../mattn/go-shellwords/shellwords.go | 134 ++++++++ .../mattn/go-shellwords/util_posix.go | 19 ++ .../mattn/go-shellwords/util_windows.go | 17 + 45 files changed, 1234 insertions(+), 435 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/docker/docker/api/types/filters/parse.go rename Godeps/_workspace/src/github.com/docker/{engine-api => docker/api}/types/network/network.go (100%) create mode 100644 Godeps/_workspace/src/github.com/docker/docker/api/types/versions/README.md create mode 100644 Godeps/_workspace/src/github.com/docker/docker/api/types/versions/compare.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_darwin.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_unix.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_unix.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_windows.go create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_darwin.go delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/system/utimes_darwin.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 6ef8ba03ec..476e88db76 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,7 +1,6 @@ { "ImportPath": "github.com/docker/libnetwork", "GoVersion": "go1.5", - "GodepVersion": "v74", "Packages": [ "./..." ], @@ -81,105 +80,110 @@ "Comment": "v1-26-gef32fa3", "Rev": "ef32fa3046d9f249d399f98ebaf9be944430fd1d" }, + { + "ImportPath": "github.com/docker/docker/api/types/filters", + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + }, + { + "ImportPath": "github.com/docker/docker/api/types/network", + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + }, + { + "ImportPath": "github.com/docker/docker/api/types/versions", + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + }, { "ImportPath": "github.com/docker/docker/opts", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/discovery", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/discovery/kv", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/homedir", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/ioutils", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/longpath", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" - }, - { - "ImportPath": "github.com/docker/docker/pkg/mflag", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/mount", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/parsers/kernel", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/plugins", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/plugins/transport", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/random", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/reexec", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/signal", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/stringid", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/symlink", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/system", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/term", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/docker/pkg/term/windows", - "Comment": "v1.4.1-12227-g86a7632", - "Rev": "86a7632d63bdddb95aaf1472648056a4fb737d38" - }, - { - "ImportPath": "github.com/docker/engine-api/types/network", - "Comment": "v0.3.1-210-g25941ec", - "Rev": "25941ecf6e8351810e8530c60de8dda7d5e1baba" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, { "ImportPath": "github.com/docker/go-connections/sockets", @@ -289,6 +293,11 @@ "Comment": "v0.7.0-47-g598c548", "Rev": "598c54895cc5a7b1a24a398d635e8c0ea0959870" }, + { + "ImportPath": "github.com/mattn/go-shellwords", + "Comment": "v1.0.0-1-g525bede", + "Rev": "525bedee691b5a8df547cb5cf9f86b7fb1883e24" + }, { "ImportPath": "github.com/miekg/dns", "Rev": "d27455715200c7d3e321a1e5cadb27c9ee0b0f02" diff --git a/Godeps/_workspace/src/github.com/docker/docker/api/types/filters/parse.go b/Godeps/_workspace/src/github.com/docker/docker/api/types/filters/parse.go new file mode 100644 index 0000000000..12e5a3b0d5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/api/types/filters/parse.go @@ -0,0 +1,307 @@ +// Package filters provides helper function to parse and handle command line +// filter, used for example in docker ps or docker images commands. +package filters + +import ( + "encoding/json" + "errors" + "fmt" + "regexp" + "strings" + + "github.com/docker/docker/api/types/versions" +) + +// Args stores filter arguments as map key:{map key: bool}. +// It contains an aggregation of the map of arguments (which are in the form +// of -f 'key=value') based on the key, and stores values for the same key +// in a map with string keys and boolean values. +// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu' +// the args will be {"image.name":{"ubuntu":true},"label":{"label1=1":true,"label2=2":true}} +type Args struct { + fields map[string]map[string]bool +} + +// NewArgs initializes a new Args struct. +func NewArgs() Args { + return Args{fields: map[string]map[string]bool{}} +} + +// ParseFlag parses the argument to the filter flag. Like +// +// `docker ps -f 'created=today' -f 'image.name=ubuntu*'` +// +// If prev map is provided, then it is appended to, and returned. By default a new +// map is created. +func ParseFlag(arg string, prev Args) (Args, error) { + filters := prev + if len(arg) == 0 { + return filters, nil + } + + if !strings.Contains(arg, "=") { + return filters, ErrBadFormat + } + + f := strings.SplitN(arg, "=", 2) + + name := strings.ToLower(strings.TrimSpace(f[0])) + value := strings.TrimSpace(f[1]) + + filters.Add(name, value) + + return filters, nil +} + +// ErrBadFormat is an error returned in case of bad format for a filter. +var ErrBadFormat = errors.New("bad format of filter (expected name=value)") + +// ToParam packs the Args into a string for easy transport from client to server. +func ToParam(a Args) (string, error) { + // this way we don't URL encode {}, just empty space + if a.Len() == 0 { + return "", nil + } + + buf, err := json.Marshal(a.fields) + if err != nil { + return "", err + } + return string(buf), nil +} + +// ToParamWithVersion packs the Args into a string for easy transport from client to server. +// The generated string will depend on the specified version (corresponding to the API version). +func ToParamWithVersion(version string, a Args) (string, error) { + // this way we don't URL encode {}, just empty space + if a.Len() == 0 { + return "", nil + } + + // for daemons older than v1.10, filter must be of the form map[string][]string + buf := []byte{} + err := errors.New("") + if version != "" && versions.LessThan(version, "1.22") { + buf, err = json.Marshal(convertArgsToSlice(a.fields)) + } else { + buf, err = json.Marshal(a.fields) + } + if err != nil { + return "", err + } + return string(buf), nil +} + +// FromParam unpacks the filter Args. +func FromParam(p string) (Args, error) { + if len(p) == 0 { + return NewArgs(), nil + } + + r := strings.NewReader(p) + d := json.NewDecoder(r) + + m := map[string]map[string]bool{} + if err := d.Decode(&m); err != nil { + r.Seek(0, 0) + + // Allow parsing old arguments in slice format. + // Because other libraries might be sending them in this format. + deprecated := map[string][]string{} + if deprecatedErr := d.Decode(&deprecated); deprecatedErr == nil { + m = deprecatedArgs(deprecated) + } else { + return NewArgs(), err + } + } + return Args{m}, nil +} + +// Get returns the list of values associates with a field. +// It returns a slice of strings to keep backwards compatibility with old code. +func (filters Args) Get(field string) []string { + values := filters.fields[field] + if values == nil { + return make([]string, 0) + } + slice := make([]string, 0, len(values)) + for key := range values { + slice = append(slice, key) + } + return slice +} + +// Add adds a new value to a filter field. +func (filters Args) Add(name, value string) { + if _, ok := filters.fields[name]; ok { + filters.fields[name][value] = true + } else { + filters.fields[name] = map[string]bool{value: true} + } +} + +// Del removes a value from a filter field. +func (filters Args) Del(name, value string) { + if _, ok := filters.fields[name]; ok { + delete(filters.fields[name], value) + } +} + +// Len returns the number of fields in the arguments. +func (filters Args) Len() int { + return len(filters.fields) +} + +// MatchKVList returns true if the values for the specified field matches the ones +// from the sources. +// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, +// field is 'label' and sources are {'label1': '1', 'label2': '2'} +// it returns true. +func (filters Args) MatchKVList(field string, sources map[string]string) bool { + fieldValues := filters.fields[field] + + //do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + + if sources == nil || len(sources) == 0 { + return false + } + + for name2match := range fieldValues { + testKV := strings.SplitN(name2match, "=", 2) + + v, ok := sources[testKV[0]] + if !ok { + return false + } + if len(testKV) == 2 && testKV[1] != v { + return false + } + } + + return true +} + +// Match returns true if the values for the specified field matches the source string +// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, +// field is 'image.name' and source is 'ubuntu' +// it returns true. +func (filters Args) Match(field, source string) bool { + if filters.ExactMatch(field, source) { + return true + } + + fieldValues := filters.fields[field] + for name2match := range fieldValues { + match, err := regexp.MatchString(name2match, source) + if err != nil { + continue + } + if match { + return true + } + } + return false +} + +// ExactMatch returns true if the source matches exactly one of the filters. +func (filters Args) ExactMatch(field, source string) bool { + fieldValues, ok := filters.fields[field] + //do not filter if there is no filter set or cannot determine filter + if !ok || len(fieldValues) == 0 { + return true + } + + // try to match full name value to avoid O(N) regular expression matching + return fieldValues[source] +} + +// UniqueExactMatch returns true if there is only one filter and the source matches exactly this one. +func (filters Args) UniqueExactMatch(field, source string) bool { + fieldValues := filters.fields[field] + //do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + if len(filters.fields[field]) != 1 { + return false + } + + // try to match full name value to avoid O(N) regular expression matching + return fieldValues[source] +} + +// FuzzyMatch returns true if the source matches exactly one of the filters, +// or the source has one of the filters as a prefix. +func (filters Args) FuzzyMatch(field, source string) bool { + if filters.ExactMatch(field, source) { + return true + } + + fieldValues := filters.fields[field] + for prefix := range fieldValues { + if strings.HasPrefix(source, prefix) { + return true + } + } + return false +} + +// Include returns true if the name of the field to filter is in the filters. +func (filters Args) Include(field string) bool { + _, ok := filters.fields[field] + return ok +} + +// Validate ensures that all the fields in the filter are valid. +// It returns an error as soon as it finds an invalid field. +func (filters Args) Validate(accepted map[string]bool) error { + for name := range filters.fields { + if !accepted[name] { + return fmt.Errorf("Invalid filter '%s'", name) + } + } + return nil +} + +// WalkValues iterates over the list of filtered values for a field. +// It stops the iteration if it finds an error and it returns that error. +func (filters Args) WalkValues(field string, op func(value string) error) error { + if _, ok := filters.fields[field]; !ok { + return nil + } + for v := range filters.fields[field] { + if err := op(v); err != nil { + return err + } + } + return nil +} + +func deprecatedArgs(d map[string][]string) map[string]map[string]bool { + m := map[string]map[string]bool{} + for k, v := range d { + values := map[string]bool{} + for _, vv := range v { + values[vv] = true + } + m[k] = values + } + return m +} + +func convertArgsToSlice(f map[string]map[string]bool) map[string][]string { + m := map[string][]string{} + for k, v := range f { + values := []string{} + for kk := range v { + if v[kk] { + values = append(values, kk) + } + } + m[k] = values + } + return m +} diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/types/network/network.go b/Godeps/_workspace/src/github.com/docker/docker/api/types/network/network.go similarity index 100% rename from Godeps/_workspace/src/github.com/docker/engine-api/types/network/network.go rename to Godeps/_workspace/src/github.com/docker/docker/api/types/network/network.go diff --git a/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/README.md b/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/README.md new file mode 100644 index 0000000000..cdac50a53c --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/README.md @@ -0,0 +1,14 @@ +## Legacy API type versions + +This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`. + +Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`. + +### Package name conventions + +The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention: + +1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`. +2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`. + +For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`. diff --git a/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/compare.go b/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/compare.go new file mode 100644 index 0000000000..611d4fed66 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/compare.go @@ -0,0 +1,62 @@ +package versions + +import ( + "strconv" + "strings" +) + +// compare compares two version strings +// returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise. +func compare(v1, v2 string) int { + var ( + currTab = strings.Split(v1, ".") + otherTab = strings.Split(v2, ".") + ) + + max := len(currTab) + if len(otherTab) > max { + max = len(otherTab) + } + for i := 0; i < max; i++ { + var currInt, otherInt int + + if len(currTab) > i { + currInt, _ = strconv.Atoi(currTab[i]) + } + if len(otherTab) > i { + otherInt, _ = strconv.Atoi(otherTab[i]) + } + if currInt > otherInt { + return 1 + } + if otherInt > currInt { + return -1 + } + } + return 0 +} + +// LessThan checks if a version is less than another +func LessThan(v, other string) bool { + return compare(v, other) == -1 +} + +// LessThanOrEqualTo checks if a version is less than or equal to another +func LessThanOrEqualTo(v, other string) bool { + return compare(v, other) <= 0 +} + +// GreaterThan checks if a version is greater than another +func GreaterThan(v, other string) bool { + return compare(v, other) == 1 +} + +// GreaterThanOrEqualTo checks if a version is greater than or equal to another +func GreaterThanOrEqualTo(v, other string) bool { + return compare(v, other) >= 0 +} + +// Equal checks if a version is equal to another +func Equal(v, other string) bool { + return compare(v, other) == 0 +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/opts/hosts.go b/Godeps/_workspace/src/github.com/docker/docker/opts/hosts.go index ad16759236..266df1e537 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/opts/hosts.go +++ b/Godeps/_workspace/src/github.com/docker/docker/opts/hosts.go @@ -63,14 +63,14 @@ func ParseHost(defaultToTLS bool, val string) (string, error) { // parseDockerDaemonHost parses the specified address and returns an address that will be used as the host. // Depending of the address specified, this may return one of the global Default* strings defined in hosts.go. func parseDockerDaemonHost(addr string) (string, error) { - addrParts := strings.Split(addr, "://") + addrParts := strings.SplitN(addr, "://", 2) if len(addrParts) == 1 && addrParts[0] != "" { addrParts = []string{"tcp", addrParts[0]} } switch addrParts[0] { case "tcp": - return parseTCPAddr(addrParts[1], DefaultTCPHost) + return ParseTCPAddr(addrParts[1], DefaultTCPHost) case "unix": return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket) case "npipe": @@ -97,12 +97,12 @@ func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) { return fmt.Sprintf("%s://%s", proto, addr), nil } -// parseTCPAddr parses and validates that the specified address is a valid TCP +// ParseTCPAddr parses and validates that the specified address is a valid TCP // address. It returns a formatted TCP address, either using the address parsed // from tryAddr, or the contents of defaultAddr if tryAddr is a blank string. // tryAddr is expected to have already been Trim()'d // defaultAddr must be in the full `tcp://host:port` form -func parseTCPAddr(tryAddr string, defaultAddr string) (string, error) { +func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) { if tryAddr == "" || tryAddr == "tcp://" { return defaultAddr, nil } @@ -127,8 +127,11 @@ func parseTCPAddr(tryAddr string, defaultAddr string) (string, error) { if err != nil { return "", err } - host, port, err := net.SplitHostPort(u.Host) + if err != nil { + // try port addition once + host, port, err = net.SplitHostPort(net.JoinHostPort(u.Host, defaultPort)) + } if err != nil { return "", fmt.Errorf("Invalid bind address format: %s", tryAddr) } diff --git a/Godeps/_workspace/src/github.com/docker/docker/opts/ip.go b/Godeps/_workspace/src/github.com/docker/docker/opts/ip.go index c7b0dc9947..fb03b50111 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/opts/ip.go +++ b/Godeps/_workspace/src/github.com/docker/docker/opts/ip.go @@ -40,3 +40,8 @@ func (o *IPOpt) String() string { } return o.IP.String() } + +// Type returns the type of the option +func (o *IPOpt) Type() string { + return "ip" +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/opts/opts.go b/Godeps/_workspace/src/github.com/docker/docker/opts/opts.go index 0b09981778..f8bb3ba745 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/opts/opts.go +++ b/Godeps/_workspace/src/github.com/docker/docker/opts/opts.go @@ -5,6 +5,8 @@ import ( "net" "regexp" "strings" + + "github.com/docker/docker/api/types/filters" ) var ( @@ -100,6 +102,11 @@ func (opts *ListOpts) Len() int { return len((*opts.values)) } +// Type returns a string name for this Option type +func (opts *ListOpts) Type() string { + return "list" +} + // NamedOption is an interface that list and map options // with names implement. type NamedOption interface { @@ -129,7 +136,7 @@ func (o *NamedListOpts) Name() string { return o.name } -//MapOpts holds a map of values and a validation function. +// MapOpts holds a map of values and a validation function. type MapOpts struct { values map[string]string validator ValidatorFctType @@ -163,6 +170,11 @@ func (opts *MapOpts) String() string { return fmt.Sprintf("%v", map[string]string((opts.values))) } +// Type returns a string name for this Option type +func (opts *MapOpts) Type() string { + return "map" +} + // NewMapOpts creates a new MapOpts with the specified map of values and a validator. func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts { if values == nil { @@ -241,7 +253,7 @@ func ValidateLabel(val string) (string, error) { return val, nil } -// ValidateSysctl validates an sysctl and returns it. +// ValidateSysctl validates a sysctl and returns it. func ValidateSysctl(val string) (string, error) { validSysctlMap := map[string]bool{ "kernel.msgmax": true, @@ -272,3 +284,38 @@ func ValidateSysctl(val string) (string, error) { } return "", fmt.Errorf("sysctl '%s' is not whitelisted", val) } + +// FilterOpt is a flag type for validating filters +type FilterOpt struct { + filter filters.Args +} + +// NewFilterOpt returns a new FilterOpt +func NewFilterOpt() FilterOpt { + return FilterOpt{filter: filters.NewArgs()} +} + +func (o *FilterOpt) String() string { + repr, err := filters.ToParam(o.filter) + if err != nil { + return "invalid filters" + } + return repr +} + +// Set sets the value of the opt by parsing the command line value +func (o *FilterOpt) Set(value string) error { + var err error + o.filter, err = filters.ParseFlag(value, o.filter) + return err +} + +// Type returns the option type +func (o *FilterOpt) Type() string { + return "filter" +} + +// Value returns the value of this option +func (o *FilterOpt) Value() filters.Args { + return o.filter +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go index 65364c9ae8..10febb5442 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go @@ -6,7 +6,7 @@ import ( "strings" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" ) var ( @@ -21,7 +21,7 @@ func Register(scheme string, d Backend) error { if _, exists := backends[scheme]; exists { return fmt.Errorf("scheme already registered %s", scheme) } - log.WithField("name", scheme).Debug("Registering discovery service") + logrus.WithField("name", scheme).Debugf("Registering discovery service") backends[scheme] = d return nil } @@ -57,7 +57,7 @@ func ParseAdvertise(advertise string) (string, error) { return advertise, nil } - // If advertise is a valid interface name, get the valid ipv4 address and use it to advertise + // If advertise is a valid interface name, get the valid IPv4 address and use it to advertise ifaceName := addr iface, err = net.InterfaceByName(ifaceName) if err != nil { @@ -98,7 +98,7 @@ func ParseAdvertise(advertise string) (string, error) { func New(rawurl string, heartbeat time.Duration, ttl time.Duration, clusterOpts map[string]string) (Backend, error) { scheme, uri := parse(rawurl) if backend, exists := backends[scheme]; exists { - log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service") + logrus.WithFields(logrus.Fields{"name": scheme, "uri": uri}).Debugf("Initializing discovery service") err := backend.Initialize(uri, heartbeat, ttl, clusterOpts) return backend, err } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/kv/kv.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/kv/kv.go index f371c0cba0..2e0f69dcea 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/kv/kv.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/kv/kv.go @@ -6,7 +6,7 @@ import ( "strings" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" "github.com/docker/go-connections/tlsconfig" "github.com/docker/libkv" @@ -73,7 +73,7 @@ func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Du var config *store.Config if clusterOpts["kv.cacertfile"] != "" && clusterOpts["kv.certfile"] != "" && clusterOpts["kv.keyfile"] != "" { - log.Info("Initializing discovery with TLS") + logrus.Infof("Initializing discovery with TLS") tlsConfig, err := tlsconfig.Client(tlsconfig.Options{ CAFile: clusterOpts["kv.cacertfile"], CertFile: clusterOpts["kv.certfile"], @@ -93,7 +93,7 @@ func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Du TLS: tlsConfig, } } else { - log.Info("Initializing discovery without TLS") + logrus.Infof("Initializing discovery without TLS") } // Creates a new store, will ignore options given @@ -112,7 +112,7 @@ func (s *Discovery) watchOnce(stopCh <-chan struct{}, watchCh <-chan []*store.KV return true } - log.WithField("discovery", s.backend).Debugf("Watch triggered with %d nodes", len(pairs)) + logrus.WithField("discovery", s.backend).Debugf("Watch triggered with %d nodes", len(pairs)) // Convert `KVPair` into `discovery.Entry`. addrs := make([]string, len(pairs)) diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go index eca129be39..72a04f3491 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go @@ -133,8 +133,9 @@ func (bp *BytesPipe) Read(p []byte) (n int, err error) { } bp.wait.Wait() if bp.bufLen == 0 && bp.closeErr != nil { + err := bp.closeErr bp.mu.Unlock() - return 0, bp.closeErr + return 0, err } } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go index ca97670724..6dc50a03dc 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go @@ -15,13 +15,15 @@ func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, err if err != nil { return nil, err } + abspath, err := filepath.Abs(filename) if err != nil { return nil, err } return &atomicFileWriter{ - f: f, - fn: abspath, + f: f, + fn: abspath, + perm: perm, }, nil } @@ -34,6 +36,7 @@ func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { n, err := f.Write(data) if err == nil && n < len(data) { err = io.ErrShortWrite + f.(*atomicFileWriter).writeErr = err } if err1 := f.Close(); err == nil { err = err1 @@ -45,6 +48,7 @@ type atomicFileWriter struct { f *os.File fn string writeErr error + perm os.FileMode } func (w *atomicFileWriter) Write(dt []byte) (int, error) { @@ -57,7 +61,7 @@ func (w *atomicFileWriter) Write(dt []byte) (int, error) { func (w *atomicFileWriter) Close() (retErr error) { defer func() { - if retErr != nil { + if retErr != nil || w.writeErr != nil { os.Remove(w.f.Name()) } }() @@ -68,6 +72,9 @@ func (w *atomicFileWriter) Close() (retErr error) { if err := w.f.Close(); err != nil { return err } + if err := os.Chmod(w.f.Name(), w.perm); err != nil { + return err + } if w.writeErr == nil { return os.Rename(w.f.Name(), w.fn) } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/multireader.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/multireader.go index 0d2d76b479..234999bc92 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/multireader.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/multireader.go @@ -97,27 +97,24 @@ func (r *multiReadSeeker) Seek(offset int64, whence int) (int64, error) { } func (r *multiReadSeeker) getReaderForOffset(offset int64) (io.ReadSeeker, int64, error) { - var rdr io.ReadSeeker - var rdrOffset int64 - for i, rdr := range r.readers { - offsetTo, err := r.getOffsetToReader(rdr) + var offsetTo int64 + + for _, rdr := range r.readers { + size, err := getReadSeekerSize(rdr) if err != nil { return nil, -1, err } - if offsetTo > offset { - rdr = r.readers[i-1] - rdrOffset = offsetTo - offset - break + if offsetTo+size > offset { + return rdr, offset - offsetTo, nil } - if rdr == r.readers[len(r.readers)-1] { - rdrOffset = offsetTo + offset - break + return rdr, offsetTo + offset, nil } + offsetTo += size } - return rdr, rdrOffset, nil + return nil, 0, nil } func (r *multiReadSeeker) getCurOffset() (int64, error) { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/readers.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/readers.go index e73b02bbf1..63f3c07f46 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/readers.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/readers.go @@ -55,7 +55,7 @@ func HashData(src io.Reader) (string, error) { return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil } -// OnEOFReader wraps a io.ReadCloser and a function +// OnEOFReader wraps an io.ReadCloser and a function // the function will run at the end of file or close the file. type OnEOFReader struct { Rc io.ReadCloser diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags.go index d2fb1fb4d0..607dbed43a 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags.go @@ -5,6 +5,112 @@ import ( "strings" ) +var flags = map[string]struct { + clear bool + flag int +}{ + "defaults": {false, 0}, + "ro": {false, RDONLY}, + "rw": {true, RDONLY}, + "suid": {true, NOSUID}, + "nosuid": {false, NOSUID}, + "dev": {true, NODEV}, + "nodev": {false, NODEV}, + "exec": {true, NOEXEC}, + "noexec": {false, NOEXEC}, + "sync": {false, SYNCHRONOUS}, + "async": {true, SYNCHRONOUS}, + "dirsync": {false, DIRSYNC}, + "remount": {false, REMOUNT}, + "mand": {false, MANDLOCK}, + "nomand": {true, MANDLOCK}, + "atime": {true, NOATIME}, + "noatime": {false, NOATIME}, + "diratime": {true, NODIRATIME}, + "nodiratime": {false, NODIRATIME}, + "bind": {false, BIND}, + "rbind": {false, RBIND}, + "unbindable": {false, UNBINDABLE}, + "runbindable": {false, RUNBINDABLE}, + "private": {false, PRIVATE}, + "rprivate": {false, RPRIVATE}, + "shared": {false, SHARED}, + "rshared": {false, RSHARED}, + "slave": {false, SLAVE}, + "rslave": {false, RSLAVE}, + "relatime": {false, RELATIME}, + "norelatime": {true, RELATIME}, + "strictatime": {false, STRICTATIME}, + "nostrictatime": {true, STRICTATIME}, +} + +var validFlags = map[string]bool{ + "": true, + "size": true, + "mode": true, + "uid": true, + "gid": true, + "nr_inodes": true, + "nr_blocks": true, + "mpol": true, +} + +var propagationFlags = map[string]bool{ + "bind": true, + "rbind": true, + "unbindable": true, + "runbindable": true, + "private": true, + "rprivate": true, + "shared": true, + "rshared": true, + "slave": true, + "rslave": true, +} + +// MergeTmpfsOptions merge mount options to make sure there is no duplicate. +func MergeTmpfsOptions(options []string) ([]string, error) { + // We use collisions maps to remove duplicates. + // For flag, the key is the flag value (the key for propagation flag is -1) + // For data=value, the key is the data + flagCollisions := map[int]bool{} + dataCollisions := map[string]bool{} + + var newOptions []string + // We process in reverse order + for i := len(options) - 1; i >= 0; i-- { + option := options[i] + if option == "defaults" { + continue + } + if f, ok := flags[option]; ok && f.flag != 0 { + // There is only one propagation mode + key := f.flag + if propagationFlags[option] { + key = -1 + } + // Check to see if there is collision for flag + if !flagCollisions[key] { + // We prepend the option and add to collision map + newOptions = append([]string{option}, newOptions...) + flagCollisions[key] = true + } + continue + } + opt := strings.SplitN(option, "=", 2) + if len(opt) != 2 || !validFlags[opt[0]] { + return nil, fmt.Errorf("Invalid tmpfs option %q", opt) + } + if !dataCollisions[opt[0]] { + // We prepend the option and add to collision map + newOptions = append([]string{option}, newOptions...) + dataCollisions[opt[0]] = true + } + } + + return newOptions, nil +} + // Parse fstab type mount options into mount() flags // and device specific data func parseOptions(options string) (int, string) { @@ -13,45 +119,6 @@ func parseOptions(options string) (int, string) { data []string ) - flags := map[string]struct { - clear bool - flag int - }{ - "defaults": {false, 0}, - "ro": {false, RDONLY}, - "rw": {true, RDONLY}, - "suid": {true, NOSUID}, - "nosuid": {false, NOSUID}, - "dev": {true, NODEV}, - "nodev": {false, NODEV}, - "exec": {true, NOEXEC}, - "noexec": {false, NOEXEC}, - "sync": {false, SYNCHRONOUS}, - "async": {true, SYNCHRONOUS}, - "dirsync": {false, DIRSYNC}, - "remount": {false, REMOUNT}, - "mand": {false, MANDLOCK}, - "nomand": {true, MANDLOCK}, - "atime": {true, NOATIME}, - "noatime": {false, NOATIME}, - "diratime": {true, NODIRATIME}, - "nodiratime": {false, NODIRATIME}, - "bind": {false, BIND}, - "rbind": {false, RBIND}, - "unbindable": {false, UNBINDABLE}, - "runbindable": {false, RUNBINDABLE}, - "private": {false, PRIVATE}, - "rprivate": {false, RPRIVATE}, - "shared": {false, SHARED}, - "rshared": {false, RSHARED}, - "slave": {false, SLAVE}, - "rslave": {false, RSLAVE}, - "relatime": {false, RELATIME}, - "norelatime": {true, RELATIME}, - "strictatime": {false, STRICTATIME}, - "nostrictatime": {true, STRICTATIME}, - } - for _, o := range strings.Split(options, ",") { // If the option does not exist in the flags table or the flag // is not supported on the platform, @@ -72,16 +139,6 @@ func parseOptions(options string) (int, string) { // ParseTmpfsOptions parse fstab type mount options into flags and data func ParseTmpfsOptions(options string) (int, string, error) { flags, data := parseOptions(options) - validFlags := map[string]bool{ - "": true, - "size": true, - "mode": true, - "uid": true, - "gid": true, - "nr_inodes": true, - "nr_blocks": true, - "mpol": true, - } for _, o := range strings.Split(data, ",") { opt := strings.SplitN(o, "=", 2) if !validFlags[opt[0]] { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go index a21ba137e3..7738fc7411 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go @@ -5,7 +5,6 @@ package kernel import ( - "bytes" "errors" "fmt" ) @@ -46,31 +45,6 @@ func CompareKernelVersion(a, b VersionInfo) int { return 0 } -// GetKernelVersion gets the current kernel version. -func GetKernelVersion() (*VersionInfo, error) { - var ( - err error - ) - - uts, err := uname() - if err != nil { - return nil, err - } - - release := make([]byte, len(uts.Release)) - - i := 0 - for _, c := range uts.Release { - release[i] = byte(c) - i++ - } - - // Remove the \x00 from the release for Atoi to parse correctly - release = release[:bytes.IndexByte(release, 0)] - - return ParseRelease(string(release)) -} - // ParseRelease parses a string and creates a VersionInfo based on it. func ParseRelease(release string) (*VersionInfo, error) { var ( diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_darwin.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_darwin.go new file mode 100644 index 0000000000..71f205b285 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_darwin.go @@ -0,0 +1,56 @@ +// +build darwin + +// Package kernel provides helper function to get, parse and compare kernel +// versions for different platforms. +package kernel + +import ( + "fmt" + "os/exec" + "strings" + + "github.com/mattn/go-shellwords" +) + +// GetKernelVersion gets the current kernel version. +func GetKernelVersion() (*VersionInfo, error) { + release, err := getRelease() + if err != nil { + return nil, err + } + + return ParseRelease(release) +} + +// getRelease uses `system_profiler SPSoftwareDataType` to get OSX kernel version +func getRelease() (string, error) { + cmd := exec.Command("system_profiler", "SPSoftwareDataType") + osName, err := cmd.Output() + if err != nil { + return "", err + } + + var release string + data := strings.Split(string(osName), "\n") + for _, line := range data { + if strings.Contains(line, "Kernel Version") { + // It has the format like ' Kernel Version: Darwin 14.5.0' + content := strings.SplitN(line, ":", 2) + if len(content) != 2 { + return "", fmt.Errorf("Kernel Version is invalid") + } + + prettyNames, err := shellwords.Parse(content[1]) + if err != nil { + return "", fmt.Errorf("Kernel Version is invalid: %s", err.Error()) + } + + if len(prettyNames) != 2 { + return "", fmt.Errorf("Kernel Version needs to be 'Darwin x.x.x' ") + } + release = prettyNames[1] + } + } + + return release, nil +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_unix.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_unix.go new file mode 100644 index 0000000000..744d5e1f83 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_unix.go @@ -0,0 +1,45 @@ +// +build linux freebsd solaris + +// Package kernel provides helper function to get, parse and compare kernel +// versions for different platforms. +package kernel + +import ( + "bytes" + + "github.com/Sirupsen/logrus" +) + +// GetKernelVersion gets the current kernel version. +func GetKernelVersion() (*VersionInfo, error) { + uts, err := uname() + if err != nil { + return nil, err + } + + release := make([]byte, len(uts.Release)) + + i := 0 + for _, c := range uts.Release { + release[i] = byte(c) + i++ + } + + // Remove the \x00 from the release for Atoi to parse correctly + release = release[:bytes.IndexByte(release, 0)] + + return ParseRelease(string(release)) +} + +// CheckKernelVersion checks if current kernel is newer than (or equal to) +// the given version. +func CheckKernelVersion(k, major, minor int) bool { + if v, err := GetKernelVersion(); err != nil { + logrus.Warnf("error getting kernel version: %s", err) + } else { + if CompareKernelVersion(*v, VersionInfo{Kernel: k, Major: major, Minor: minor}) < 0 { + return false + } + } + return true +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_windows.go index 85ca250c9f..80fab8ff64 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_windows.go @@ -1,3 +1,5 @@ +// +build windows + package kernel import ( diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/client.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/client.go index e3fd326ed5..a778677f7c 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/client.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/client.go @@ -20,14 +20,16 @@ const ( ) // NewClient creates a new plugin client (http). -func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) { +func NewClient(addr string, tlsConfig *tlsconfig.Options) (*Client, error) { tr := &http.Transport{} - c, err := tlsconfig.Client(tlsConfig) - if err != nil { - return nil, err + if tlsConfig != nil { + c, err := tlsconfig.Client(*tlsConfig) + if err != nil { + return nil, err + } + tr.TLSClientConfig = c } - tr.TLSClientConfig = c u, err := url.Parse(addr) if err != nil { @@ -130,7 +132,7 @@ func (c *Client) callWithRetry(serviceMethod string, data io.Reader, retry bool) return nil, err } retries++ - logrus.Warnf("Unable to connect to plugin: %s:%s, retrying in %v", req.URL.Host, req.URL.Path, timeOff) + logrus.Warnf("Unable to connect to plugin: %s%s: %v, retrying in %v", req.URL.Host, req.URL.Path, err, timeOff) time.Sleep(timeOff) continue } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery.go index 9dc64194f2..e99581c573 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery.go @@ -16,7 +16,6 @@ var ( // ErrNotFound plugin not found ErrNotFound = errors.New("plugin not found") socketsPath = "/run/docker/plugins" - specsPaths = []string{"/etc/docker/plugins", "/usr/lib/docker/plugins"} ) // localRegistry defines a registry that is local (using unix socket). @@ -64,7 +63,7 @@ func (l *localRegistry) Plugin(name string) (*Plugin, error) { for _, p := range socketpaths { if fi, err := os.Stat(p); err == nil && fi.Mode()&os.ModeSocket != 0 { - return newLocalPlugin(name, "unix://"+p), nil + return NewLocalPlugin(name, "unix://"+p), nil } } @@ -101,7 +100,7 @@ func readPluginInfo(name, path string) (*Plugin, error) { return nil, fmt.Errorf("Unknown protocol") } - return newLocalPlugin(name, addr), nil + return NewLocalPlugin(name, addr), nil } func readPluginJSONInfo(name, path string) (*Plugin, error) { @@ -115,8 +114,8 @@ func readPluginJSONInfo(name, path string) (*Plugin, error) { if err := json.NewDecoder(f).Decode(&p); err != nil { return nil, err } - p.Name = name - if len(p.TLSConfig.CAFile) == 0 { + p.name = name + if p.TLSConfig != nil && len(p.TLSConfig.CAFile) == 0 { p.TLSConfig.InsecureSkipVerify = true } p.activateWait = sync.NewCond(&sync.Mutex{}) diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_unix.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_unix.go new file mode 100644 index 0000000000..693a47e394 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_unix.go @@ -0,0 +1,5 @@ +// +build !windows + +package plugins + +var specsPaths = []string{"/etc/docker/plugins", "/usr/lib/docker/plugins"} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_windows.go new file mode 100644 index 0000000000..d7c1fe4942 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_windows.go @@ -0,0 +1,8 @@ +package plugins + +import ( + "os" + "path/filepath" +) + +var specsPaths = []string{filepath.Join(os.Getenv("programdata"), "docker", "plugins")} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go index b83b5ae61d..debcd087c9 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go @@ -55,13 +55,13 @@ type Manifest struct { // Plugin is the definition of a docker plugin. type Plugin struct { // Name of the plugin - Name string `json:"-"` + name string // Address of the plugin Addr string // TLS configuration of the plugin - TLSConfig tlsconfig.Options + TLSConfig *tlsconfig.Options // Client attached to the plugin - Client *Client `json:"-"` + client *Client // Manifest of the plugin (see above) Manifest *Manifest `json:"-"` @@ -73,11 +73,28 @@ type Plugin struct { activateWait *sync.Cond } -func newLocalPlugin(name, addr string) *Plugin { +// Name returns the name of the plugin. +func (p *Plugin) Name() string { + return p.name +} + +// Client returns a ready-to-use plugin client that can be used to communicate with the plugin. +func (p *Plugin) Client() *Client { + return p.client +} + +// IsLegacy returns true for legacy plugins and false otherwise. +func (p *Plugin) IsLegacy() bool { + return true +} + +// NewLocalPlugin creates a new local plugin. +func NewLocalPlugin(name, addr string) *Plugin { return &Plugin{ - Name: name, - Addr: addr, - TLSConfig: tlsconfig.Options{InsecureSkipVerify: true}, + name: name, + Addr: addr, + // TODO: change to nil + TLSConfig: &tlsconfig.Options{InsecureSkipVerify: true}, activateWait: sync.NewCond(&sync.Mutex{}), } } @@ -102,10 +119,10 @@ func (p *Plugin) activateWithLock() error { if err != nil { return err } - p.Client = c + p.client = c m := new(Manifest) - if err = p.Client.Call("Plugin.Activate", nil, m); err != nil { + if err = p.client.Call("Plugin.Activate", nil, m); err != nil { return err } @@ -116,7 +133,7 @@ func (p *Plugin) activateWithLock() error { if !handled { continue } - handler(p.Name, p.Client) + handler(p.name, p.client) } return nil } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_linux.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_linux.go index 3c3a73a9d5..34ae2a9dcd 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_linux.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_linux.go @@ -13,7 +13,7 @@ func Self() string { return "/proc/self/exe" } -// Command returns *exec.Cmd which have Path as current binary. Also it setting +// 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]). diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unix.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unix.go index b70edcb316..778a720e3b 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unix.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unix.go @@ -1,4 +1,4 @@ -// +build freebsd solaris +// +build freebsd solaris darwin package reexec @@ -12,7 +12,7 @@ func Self() string { return naiveSelf() } -// Command returns *exec.Cmd which have Path as current binary. +// 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 { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go index 9aed004e86..76edd82427 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!freebsd,!solaris +// +build !linux,!windows,!freebsd,!solaris,!darwin package reexec @@ -6,7 +6,7 @@ import ( "os/exec" ) -// Command is unsupported on operating systems apart from Linux and Windows. +// Command is unsupported on operating systems apart from Linux, Windows, Solaris and Darwin. func Command(args ...string) *exec.Cmd { return nil } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_windows.go index 8d65e0ae1a..ca871c4227 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_windows.go @@ -12,7 +12,7 @@ func Self() string { return naiveSelf() } -// Command returns *exec.Cmd which have Path as current binary. +// 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 { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/trap.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/trap.go index 2cf5ccf0d2..bd8675c9aa 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/trap.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/trap.go @@ -3,9 +3,11 @@ package signal import ( "os" gosignal "os/signal" + "path/filepath" "runtime" "sync/atomic" "syscall" + "time" "github.com/Sirupsen/logrus" ) @@ -18,15 +20,22 @@ import ( // * If SIGINT or SIGTERM are received 3 times before cleanup is complete, then cleanup is // skipped and the process is terminated immediately (allows force quit of stuck daemon) // * A SIGQUIT always causes an exit without cleanup, with a goroutine dump preceding exit. +// * Ignore SIGPIPE events. These are generated by systemd when journald is restarted while +// the docker daemon is not restarted and also running under systemd. +// Fixes https://github.com/docker/docker/issues/19728 // func Trap(cleanup func()) { c := make(chan os.Signal, 1) - // we will handle INT, TERM, QUIT here - signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT} + // we will handle INT, TERM, QUIT, SIGPIPE here + signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE} gosignal.Notify(c, signals...) go func() { interruptCount := uint32(0) for sig := range c { + if sig == syscall.SIGPIPE { + continue + } + go func(sig os.Signal) { logrus.Infof("Processing signal '%v'", sig) switch sig { @@ -42,11 +51,11 @@ func Trap(cleanup func()) { } } else { // 3 SIGTERM/INT signals received; force exit without cleanup - logrus.Infof("Forcing docker daemon shutdown without cleanup; 3 interrupts received") + logrus.Info("Forcing docker daemon shutdown without cleanup; 3 interrupts received") } case syscall.SIGQUIT: - DumpStacks() - logrus.Infof("Forcing docker daemon shutdown without cleanup on SIGQUIT") + DumpStacks("") + logrus.Info("Forcing docker daemon shutdown without cleanup on SIGQUIT") } //for the SIGINT/TERM, and SIGQUIT non-clean shutdown case, exit with 128 + signal # os.Exit(128 + int(sig.(syscall.Signal))) @@ -56,7 +65,7 @@ func Trap(cleanup func()) { } // DumpStacks dumps the runtime stack. -func DumpStacks() { +func DumpStacks(root string) { var ( buf []byte stackSize int @@ -70,5 +79,30 @@ func DumpStacks() { buf = buf[:stackSize] // Note that if the daemon is started with a less-verbose log-level than "info" (the default), the goroutine // traces won't show up in the log. - logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf) + if root == "" { + logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf) + } else { + // Dumps the stacks to a file in the root directory of the daemon + // On Windows, this overcomes two issues - one being that if the stack is too big, it doesn't + // get written to the event log when the Windows daemon is running as a service. + // Second, using logrus, the tabs and new-lines end up getting written as literal + // \t and \n's, meaning you need to use something like notepad++ to convert the + // output into something readable using 'type' from a command line or notepad/notepad++ etc. + path := filepath.Join(root, "goroutine-stacks.log") + f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) + if err != nil { + logrus.Warnf("Could not open %s to write the goroutine stacks: %v", path, err) + return + } + defer f.Close() + f.WriteString("=== BEGIN goroutine stack dump ===\n") + f.WriteString(time.Now().String() + "\n") + if _, err := f.Write(buf); err != nil { + logrus.Warnf("Could not write goroutine stacks to %s: %v", path, err) + return + } + f.WriteString("=== END goroutine stack dump ===\n") + f.Sync() + logrus.Infof("goroutine stacks written to %s", path) + } } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/stringid/stringid.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/stringid/stringid.go index 161184ff8a..fa35d8bad5 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/stringid/stringid.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/stringid/stringid.go @@ -29,11 +29,10 @@ func TruncateID(id string) string { if i := strings.IndexRune(id, ':'); i >= 0 { id = id[i+1:] } - trimTo := shortLen - if len(id) < shortLen { - trimTo = len(id) + if len(id) > shortLen { + id = id[:shortLen] } - return id[:trimTo] + return id } func generateID(crypto bool) string { @@ -60,7 +59,6 @@ func generateID(crypto bool) string { // GenerateRandomID returns a unique id. func GenerateRandomID() string { return generateID(true) - } // GenerateNonCryptoID generates unique id without using cryptographically diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_darwin.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_darwin.go new file mode 100644 index 0000000000..f0742f59e5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_darwin.go @@ -0,0 +1,32 @@ +package system + +import ( + "syscall" +) + +// fromStatT creates a system.StatT type from a syscall.Stat_t type +func fromStatT(s *syscall.Stat_t) (*StatT, error) { + return &StatT{size: s.Size, + mode: uint32(s.Mode), + uid: s.Uid, + gid: s.Gid, + rdev: uint64(s.Rdev), + mtim: s.Mtimespec}, nil +} + +// FromStatT loads a system.StatT from a syscall.Stat_t. +func FromStatT(s *syscall.Stat_t) (*StatT, error) { + return fromStatT(s) +} + +// Stat takes a path to a file and returns +// a system.StatT type pertaining to that file. +// +// Throws an error if the file does not exist +func Stat(path string) (*StatT, error) { + s := &syscall.Stat_t{} + if err := syscall.Stat(path, s); err != nil { + return nil, err + } + return fromStatT(s) +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_unsupported.go index f53e9de4d1..5d85f523cf 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/stat_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!freebsd,!solaris,!openbsd +// +build !linux,!windows,!freebsd,!solaris,!openbsd,!darwin package system diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/utimes_darwin.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/utimes_darwin.go deleted file mode 100644 index 0a16197544..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/utimes_darwin.go +++ /dev/null @@ -1,8 +0,0 @@ -package system - -import "syscall" - -// LUtimesNano is not supported by darwin platform. -func LUtimesNano(path string, ts []syscall.Timespec) error { - return ErrNotSupportedPlatform -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/utimes_unsupported.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/utimes_unsupported.go index 50c3a04364..139714544d 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/utimes_unsupported.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/utimes_unsupported.go @@ -1,10 +1,10 @@ -// +build !linux,!freebsd,!darwin +// +build !linux,!freebsd package system import "syscall" -// LUtimesNano is not supported on platforms other than linux, freebsd and darwin. +// LUtimesNano is only supported on linux and freebsd. func LUtimesNano(path string, ts []syscall.Timespec) error { return ErrNotSupportedPlatform } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term.go index 8f554847f0..fe59faa949 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term.go @@ -1,11 +1,12 @@ // +build !windows -// Package term provides provides structures and helper functions to work with +// Package term provides structures and helper functions to work with // terminal (state, sizes). package term import ( "errors" + "fmt" "io" "os" "os/signal" @@ -88,7 +89,8 @@ func DisableEcho(fd uintptr, state *State) error { } // SetRawTerminal puts the terminal connected to the given file descriptor into -// raw mode and returns the previous state. +// raw mode and returns the previous state. On UNIX, this puts both the input +// and output into raw mode. On Windows, it only puts the input into raw mode. func SetRawTerminal(fd uintptr) (*State, error) { oldState, err := MakeRaw(fd) if err != nil { @@ -98,12 +100,24 @@ func SetRawTerminal(fd uintptr) (*State, error) { return oldState, err } +// SetRawTerminalOutput puts the output of terminal connected to the given file +// descriptor into raw mode. On UNIX, this does nothing and returns nil for the +// state. On Windows, it disables LF -> CRLF translation. +func SetRawTerminalOutput(fd uintptr) (*State, error) { + return nil, nil +} + func handleInterrupt(fd uintptr, state *State) { sigchan := make(chan os.Signal, 1) signal.Notify(sigchan, os.Interrupt) - go func() { - _ = <-sigchan - RestoreTerminal(fd, state) + for range sigchan { + // quit cleanly and the new terminal item is on a new line + fmt.Println() + signal.Stop(sigchan) + close(sigchan) + RestoreTerminal(fd, state) + os.Exit(1) + } }() } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go index 9bc52a8c65..dc50da4577 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go @@ -9,14 +9,12 @@ import ( "syscall" "github.com/Azure/go-ansiterm/winterm" - "github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/term/windows" ) // State holds the console mode for the terminal. type State struct { - inMode, outMode uint32 - inHandle, outHandle syscall.Handle + mode uint32 } // Winsize is used for window size. @@ -32,143 +30,72 @@ const ( disableNewlineAutoReturn = 0x0008 ) -// usingNativeConsole is true if we are using the Windows native console -var usingNativeConsole bool +// vtInputSupported is true if enableVirtualTerminalInput is supported by the console +var vtInputSupported bool // StdStreams returns the standard streams (stdin, stdout, stedrr). func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { - switch { - case os.Getenv("ConEmuANSI") == "ON": - // The ConEmu terminal emulates ANSI on output streams well. - return windows.ConEmuStreams() - case os.Getenv("MSYSTEM") != "": - // MSYS (mingw) does not emulate ANSI well. - return windows.ConsoleStreams() - default: - if useNativeConsole() { - usingNativeConsole = true - return os.Stdin, os.Stdout, os.Stderr + // Turn on VT handling on all std handles, if possible. This might + // fail, in which case we will fall back to terminal emulation. + var emulateStdin, emulateStdout, emulateStderr bool + fd := os.Stdin.Fd() + if mode, err := winterm.GetConsoleMode(fd); err == nil { + // Validate that enableVirtualTerminalInput is supported, but do not set it. + if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalInput); err != nil { + emulateStdin = true + } else { + vtInputSupported = true } - return windows.ConsoleStreams() - } -} - -// useNativeConsole determines if the docker client should use the built-in -// console which supports ANSI emulation, or fall-back to the golang emulator -// (github.com/azure/go-ansiterm). -func useNativeConsole() bool { - osv := system.GetOSVersion() - - // Native console is not available before major version 10 - if osv.MajorVersion < 10 { - return false - } - - // Get the console modes. If this fails, we can't use the native console - state, err := getNativeConsole() - if err != nil { - return false - } - - // Probe the console to see if it can be enabled. - if nil != probeNativeConsole(state) { - return false - } - - // Environment variable override - if e := os.Getenv("USE_NATIVE_CONSOLE"); e != "" { - if e == "1" { - return true + // Unconditionally set the console mode back even on failure because SetConsoleMode + // remembers invalid bits on input handles. + winterm.SetConsoleMode(fd, mode) + } + + fd = os.Stdout.Fd() + if mode, err := winterm.GetConsoleMode(fd); err == nil { + // Validate disableNewlineAutoReturn is supported, but do not set it. + if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing|disableNewlineAutoReturn); err != nil { + emulateStdout = true + } else { + winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing) } - return false - } - - // Must have a post-TP5 RS1 build of Windows Server 2016/Windows 10 for - // the native console to be usable. - if osv.Build < 14350 { - return false - } - - return true -} - -// getNativeConsole returns the console modes ('state') for the native Windows console -func getNativeConsole() (State, error) { - var ( - err error - state State - ) - - // Get the handle to stdout - if state.outHandle, err = syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE); err != nil { - return state, err } - // Get the console mode from the consoles stdout handle - if err = syscall.GetConsoleMode(state.outHandle, &state.outMode); err != nil { - return state, err + fd = os.Stderr.Fd() + if mode, err := winterm.GetConsoleMode(fd); err == nil { + // Validate disableNewlineAutoReturn is supported, but do not set it. + if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing|disableNewlineAutoReturn); err != nil { + emulateStderr = true + } else { + winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing) + } } - // Get the handle to stdin - if state.inHandle, err = syscall.GetStdHandle(syscall.STD_INPUT_HANDLE); err != nil { - return state, err + if os.Getenv("ConEmuANSI") == "ON" { + // The ConEmu terminal emulates ANSI on output streams well. + emulateStdout = false + emulateStderr = false } - // Get the console mode from the consoles stdin handle - if err = syscall.GetConsoleMode(state.inHandle, &state.inMode); err != nil { - return state, err + if emulateStdin { + stdIn = windows.NewAnsiReader(syscall.STD_INPUT_HANDLE) + } else { + stdIn = os.Stdin } - return state, nil -} - -// probeNativeConsole probes the console to determine if native can be supported, -func probeNativeConsole(state State) error { - if err := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode|enableVirtualTerminalProcessing); err != nil { - return err + if emulateStdout { + stdOut = windows.NewAnsiWriter(syscall.STD_OUTPUT_HANDLE) + } else { + stdOut = os.Stdout } - defer winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode) - if err := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode|enableVirtualTerminalInput); err != nil { - return err + if emulateStderr { + stdErr = windows.NewAnsiWriter(syscall.STD_ERROR_HANDLE) + } else { + stdErr = os.Stderr } - defer winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode) - return nil -} - -// enableNativeConsole turns on native console mode -func enableNativeConsole(state State) error { - // First attempt both enableVirtualTerminalProcessing and disableNewlineAutoReturn - if err := winterm.SetConsoleMode(uintptr(state.outHandle), - state.outMode|(enableVirtualTerminalProcessing|disableNewlineAutoReturn)); err != nil { - - // That may fail, so fallback to trying just enableVirtualTerminalProcessing - if err := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode|enableVirtualTerminalProcessing); err != nil { - return err - } - } - - if err := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode|enableVirtualTerminalInput); err != nil { - winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode) // restore out if we can - return err - } - - return nil -} - -// disableNativeConsole turns off native console mode -func disableNativeConsole(state *State) error { - // Try and restore both in an out before error checking. - errout := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode) - errin := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode) - if errout != nil { - return errout - } - if errin != nil { - return errin - } - return nil + return } // GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal. @@ -199,34 +126,23 @@ func IsTerminal(fd uintptr) bool { // RestoreTerminal restores the terminal connected to the given file descriptor // to a previous state. func RestoreTerminal(fd uintptr, state *State) error { - if usingNativeConsole { - return disableNativeConsole(state) - } - return winterm.SetConsoleMode(fd, state.outMode) + return winterm.SetConsoleMode(fd, state.mode) } // SaveState saves the state of the terminal connected to the given file descriptor. func SaveState(fd uintptr) (*State, error) { - if usingNativeConsole { - state, err := getNativeConsole() - if err != nil { - return nil, err - } - return &state, nil - } - mode, e := winterm.GetConsoleMode(fd) if e != nil { return nil, e } - return &State{outMode: mode}, nil + return &State{mode: mode}, nil } // DisableEcho disables echo for the terminal connected to the given file descriptor. // -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx func DisableEcho(fd uintptr, state *State) error { - mode := state.inMode + mode := state.mode mode &^= winterm.ENABLE_ECHO_INPUT mode |= winterm.ENABLE_PROCESSED_INPUT | winterm.ENABLE_LINE_INPUT err := winterm.SetConsoleMode(fd, mode) @@ -239,8 +155,9 @@ func DisableEcho(fd uintptr, state *State) error { return nil } -// SetRawTerminal puts the terminal connected to the given file descriptor into raw -// mode and returns the previous state. +// SetRawTerminal puts the terminal connected to the given file descriptor into +// raw mode and returns the previous state. On UNIX, this puts both the input +// and output into raw mode. On Windows, it only puts the input into raw mode. func SetRawTerminal(fd uintptr) (*State, error) { state, err := MakeRaw(fd) if err != nil { @@ -252,6 +169,21 @@ func SetRawTerminal(fd uintptr) (*State, error) { return state, err } +// SetRawTerminalOutput puts the output of terminal connected to the given file +// descriptor into raw mode. On UNIX, this does nothing and returns nil for the +// state. On Windows, it disables LF -> CRLF translation. +func SetRawTerminalOutput(fd uintptr) (*State, error) { + state, err := SaveState(fd) + if err != nil { + return nil, err + } + + // Ignore failures, since disableNewlineAutoReturn might not be supported on this + // version of Windows. + winterm.SetConsoleMode(fd, state.mode|disableNewlineAutoReturn) + return state, err +} + // MakeRaw puts the terminal (Windows Console) connected to the given file descriptor into raw // mode and returns the previous state of the terminal so that it can be restored. func MakeRaw(fd uintptr) (*State, error) { @@ -260,13 +192,7 @@ func MakeRaw(fd uintptr) (*State, error) { return nil, err } - mode := state.inMode - if usingNativeConsole { - if err := enableNativeConsole(*state); err != nil { - return nil, err - } - mode |= enableVirtualTerminalInput - } + mode := state.mode // See // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx @@ -283,6 +209,9 @@ func MakeRaw(fd uintptr) (*State, error) { mode |= winterm.ENABLE_EXTENDED_FLAGS mode |= winterm.ENABLE_INSERT_MODE mode |= winterm.ENABLE_QUICK_EDIT_MODE + if vtInputSupported { + mode |= enableVirtualTerminalInput + } err = winterm.SetConsoleMode(fd, mode) if err != nil { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_reader.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_reader.go index 5b91b78342..58452ad786 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_reader.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_reader.go @@ -6,6 +6,7 @@ import ( "bytes" "errors" "fmt" + "io" "os" "strings" "unsafe" @@ -27,7 +28,10 @@ type ansiReader struct { command []byte } -func newAnsiReader(nFile int) *ansiReader { +// NewAnsiReader returns an io.ReadCloser that provides VT100 terminal emulation on top of a +// Windows console input handle. +func NewAnsiReader(nFile int) io.ReadCloser { + initLogger() file, fd := winterm.GetStdFile(nFile) return &ansiReader{ file: file, diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_writer.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_writer.go index 9f3232c093..a3ce5697d9 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_writer.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/ansi_writer.go @@ -3,16 +3,13 @@ package windows import ( - "io/ioutil" + "io" "os" ansiterm "github.com/Azure/go-ansiterm" "github.com/Azure/go-ansiterm/winterm" - "github.com/Sirupsen/logrus" ) -var logger *logrus.Logger - // ansiWriter wraps a standard output file (e.g., os.Stdout) providing ANSI sequence translation. type ansiWriter struct { file *os.File @@ -24,19 +21,10 @@ type ansiWriter struct { parser *ansiterm.AnsiParser } -func newAnsiWriter(nFile int) *ansiWriter { - logFile := ioutil.Discard - - if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { - logFile, _ = os.Create("ansiReaderWriter.log") - } - - logger = &logrus.Logger{ - Out: logFile, - Formatter: new(logrus.TextFormatter), - Level: logrus.DebugLevel, - } - +// NewAnsiWriter returns an io.Writer that provides VT100 terminal emulation on top of a +// Windows console output handle. +func NewAnsiWriter(nFile int) io.Writer { + initLogger() file, fd := winterm.GetStdFile(nFile) info, err := winterm.GetConsoleScreenBufferInfo(fd) if err != nil { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/console.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/console.go index 3036a04605..ca5c3b2e53 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/console.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/console.go @@ -3,73 +3,11 @@ package windows import ( - "io" "os" - "syscall" "github.com/Azure/go-ansiterm/winterm" - - ansiterm "github.com/Azure/go-ansiterm" - "github.com/Sirupsen/logrus" - "io/ioutil" ) -// ConEmuStreams returns prepared versions of console streams, -// for proper use in ConEmu terminal. -// The ConEmu terminal emulates ANSI on output streams well by default. -func ConEmuStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { - if IsConsole(os.Stdin.Fd()) { - stdIn = newAnsiReader(syscall.STD_INPUT_HANDLE) - } else { - stdIn = os.Stdin - } - - stdOut = os.Stdout - stdErr = os.Stderr - - // WARNING (BEGIN): sourced from newAnsiWriter - - logFile := ioutil.Discard - - if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { - logFile, _ = os.Create("ansiReaderWriter.log") - } - - logger = &logrus.Logger{ - Out: logFile, - Formatter: new(logrus.TextFormatter), - Level: logrus.DebugLevel, - } - - // WARNING (END): sourced from newAnsiWriter - - return stdIn, stdOut, stdErr -} - -// ConsoleStreams returns a wrapped version for each standard stream referencing a console, -// that handles ANSI character sequences. -func ConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { - if IsConsole(os.Stdin.Fd()) { - stdIn = newAnsiReader(syscall.STD_INPUT_HANDLE) - } else { - stdIn = os.Stdin - } - - if IsConsole(os.Stdout.Fd()) { - stdOut = newAnsiWriter(syscall.STD_OUTPUT_HANDLE) - } else { - stdOut = os.Stdout - } - - if IsConsole(os.Stderr.Fd()) { - stdErr = newAnsiWriter(syscall.STD_ERROR_HANDLE) - } else { - stdErr = os.Stderr - } - - return stdIn, stdOut, stdErr -} - // GetHandleInfo returns file descriptor and bool indicating whether the file is a console. func GetHandleInfo(in interface{}) (uintptr, bool) { switch t := in.(type) { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/windows.go index bf4c7b5025..ce4cb5990e 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/windows/windows.go @@ -3,3 +3,31 @@ // and return pseudo-streams that convert ANSI sequences to / from Windows Console API calls. package windows + +import ( + "io/ioutil" + "os" + "sync" + + ansiterm "github.com/Azure/go-ansiterm" + "github.com/Sirupsen/logrus" +) + +var logger *logrus.Logger +var initOnce sync.Once + +func initLogger() { + initOnce.Do(func() { + logFile := ioutil.Discard + + if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { + logFile, _ = os.Create("ansiReaderWriter.log") + } + + logger = &logrus.Logger{ + Out: logFile, + Formatter: new(logrus.TextFormatter), + Level: logrus.DebugLevel, + } + }) +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml b/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml new file mode 100644 index 0000000000..16d1430aa2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml @@ -0,0 +1,8 @@ +language: go +go: + - tip +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -repotoken 2FMhp57u8LcstKL9B190fLTcEnBtAAiEL diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md b/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md new file mode 100644 index 0000000000..56f357fad7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md @@ -0,0 +1,47 @@ +# go-shellwords + +[![Coverage Status](https://coveralls.io/repos/mattn/go-shellwords/badge.png?branch=master)](https://coveralls.io/r/mattn/go-shellwords?branch=master) +[![Build Status](https://travis-ci.org/mattn/go-shellwords.svg?branch=master)](https://travis-ci.org/mattn/go-shellwords) + +Parse line as shell words. + +## Usage + +```go +args, err := shellwords.Parse("./foo --bar=baz") +// args should be ["./foo", "--bar=baz"] +``` + +```go +os.Setenv("FOO", "bar") +p := shellwords.NewParser() +p.ParseEnv = true +args, err := p.Parse("./foo $FOO") +// args should be ["./foo", "bar"] +``` + +```go +p := shellwords.NewParser() +p.ParseBacktick = true +args, err := p.Parse("./foo `echo $SHELL`") +// args should be ["./foo", "/bin/bash"] +``` + +```go +shellwords.ParseBacktick = true +p := shellwords.NewParser() +args, err := p.Parse("./foo `echo $SHELL`") +// args should be ["./foo", "/bin/bash"] +``` + +# Thanks + +This is based on cpan module [Parse::CommandLine](https://metacpan.org/pod/Parse::CommandLine). + +# License + +under the MIT License: http://mattn.mit-license.org/2014 + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go new file mode 100644 index 0000000000..1abaa6c9df --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/shellwords.go @@ -0,0 +1,134 @@ +package shellwords + +import ( + "errors" + "os" + "regexp" + "strings" +) + +var ( + ParseEnv bool = false + ParseBacktick bool = false +) + +var envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`) + +func isSpace(r rune) bool { + switch r { + case ' ', '\t', '\r', '\n': + return true + } + return false +} + +func replaceEnv(s string) string { + return envRe.ReplaceAllStringFunc(s, func(s string) string { + s = s[1:] + if s[0] == '{' { + s = s[1 : len(s)-1] + } + return os.Getenv(s) + }) +} + +type Parser struct { + ParseEnv bool + ParseBacktick bool +} + +func NewParser() *Parser { + return &Parser{ParseEnv, ParseBacktick} +} + +func (p *Parser) Parse(line string) ([]string, error) { + line = strings.TrimSpace(line) + + args := []string{} + buf := "" + var escaped, doubleQuoted, singleQuoted, backQuote bool + backtick := "" + + for _, r := range line { + if escaped { + buf += string(r) + escaped = false + continue + } + + if r == '\\' { + if singleQuoted { + buf += string(r) + } else { + escaped = true + } + continue + } + + if isSpace(r) { + if singleQuoted || doubleQuoted || backQuote { + buf += string(r) + backtick += string(r) + } else if buf != "" { + if p.ParseEnv { + buf = replaceEnv(buf) + } + args = append(args, buf) + buf = "" + } + continue + } + + switch r { + case '`': + if !singleQuoted && !doubleQuoted { + if p.ParseBacktick { + if backQuote { + out, err := shellRun(backtick) + if err != nil { + return nil, err + } + buf = out + } + backtick = "" + backQuote = !backQuote + continue + } + backtick = "" + backQuote = !backQuote + } + case '"': + if !singleQuoted { + doubleQuoted = !doubleQuoted + continue + } + case '\'': + if !doubleQuoted { + singleQuoted = !singleQuoted + continue + } + } + + buf += string(r) + if backQuote { + backtick += string(r) + } + } + + if buf != "" { + if p.ParseEnv { + buf = replaceEnv(buf) + } + args = append(args, buf) + } + + if escaped || singleQuoted || doubleQuoted || backQuote { + return nil, errors.New("invalid command line string") + } + + return args, nil +} + +func Parse(line string) ([]string, error) { + return NewParser().Parse(line) +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go new file mode 100644 index 0000000000..4f8ac55e47 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_posix.go @@ -0,0 +1,19 @@ +// +build !windows + +package shellwords + +import ( + "errors" + "os" + "os/exec" + "strings" +) + +func shellRun(line string) (string, error) { + shell := os.Getenv("SHELL") + b, err := exec.Command(shell, "-c", line).Output() + if err != nil { + return "", errors.New(err.Error() + ":" + string(b)) + } + return strings.TrimSpace(string(b)), nil +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go new file mode 100644 index 0000000000..7cad4cf06f --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-shellwords/util_windows.go @@ -0,0 +1,17 @@ +package shellwords + +import ( + "errors" + "os" + "os/exec" + "strings" +) + +func shellRun(line string) (string, error) { + shell := os.Getenv("COMSPEC") + b, err := exec.Command(shell, "/c", line).Output() + if err != nil { + return "", errors.New(err.Error() + ":" + string(b)) + } + return strings.TrimSpace(string(b)), nil +} From 734d6261410d8d5d968fc8824924798efff5dd40 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 7 Sep 2016 13:32:35 -0700 Subject: [PATCH 064/799] Move engine-api to docker/docker/api Remove all dependencies to engine-api and start using docker/docker/api. Signed-off-by: Jana Radhakrishnan --- cluster/provider.go | 2 +- cmd/dnet/dnet.go | 2 +- cmd/dnet/dnet_linux.go | 2 +- cmd/dnet/dnet_windows.go | 2 +- drivers/remote/driver_test.go | 14 +++++++------- ipams/remote/remote_test.go | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cluster/provider.go b/cluster/provider.go index 5e6b560946..7bbf5d3557 100644 --- a/cluster/provider.go +++ b/cluster/provider.go @@ -1,7 +1,7 @@ package cluster import ( - "github.com/docker/engine-api/types/network" + "github.com/docker/docker/api/types/network" "golang.org/x/net/context" ) diff --git a/cmd/dnet/dnet.go b/cmd/dnet/dnet.go index 757e9666f8..8d88eecc94 100644 --- a/cmd/dnet/dnet.go +++ b/cmd/dnet/dnet.go @@ -23,8 +23,8 @@ import ( "github.com/docker/docker/pkg/reexec" "github.com/Sirupsen/logrus" + "github.com/docker/docker/api/types/network" "github.com/docker/docker/pkg/term" - "github.com/docker/engine-api/types/network" "github.com/docker/libnetwork" "github.com/docker/libnetwork/api" "github.com/docker/libnetwork/config" diff --git a/cmd/dnet/dnet_linux.go b/cmd/dnet/dnet_linux.go index f0f4702b61..44b9ab9e7b 100644 --- a/cmd/dnet/dnet_linux.go +++ b/cmd/dnet/dnet_linux.go @@ -13,7 +13,7 @@ func setupDumpStackTrap() { signal.Notify(c, syscall.SIGUSR1) go func() { for range c { - psignal.DumpStacks() + psignal.DumpStacks("") } }() } diff --git a/cmd/dnet/dnet_windows.go b/cmd/dnet/dnet_windows.go index 338ae6dceb..54788e923b 100644 --- a/cmd/dnet/dnet_windows.go +++ b/cmd/dnet/dnet_windows.go @@ -21,7 +21,7 @@ func setupDumpStackTrap() { logrus.Debugf("Stackdump - waiting signal at %s", ev) for { syscall.WaitForSingleObject(h, syscall.INFINITE) - signal.DumpStacks() + signal.DumpStacks("") } } }() diff --git a/drivers/remote/driver_test.go b/drivers/remote/driver_test.go index efc82e439f..6440de77e5 100644 --- a/drivers/remote/driver_test.go +++ b/drivers/remote/driver_test.go @@ -218,7 +218,7 @@ func TestGetEmptyCapabilities(t *testing.T) { t.Fatal(err) } - d := newDriver(plugin, p.Client) + d := newDriver(plugin, p.Client()) if d.Type() != plugin { t.Fatal("Driver type does not match that given") } @@ -247,7 +247,7 @@ func TestGetExtraCapabilities(t *testing.T) { t.Fatal(err) } - d := newDriver(plugin, p.Client) + d := newDriver(plugin, p.Client()) if d.Type() != plugin { t.Fatal("Driver type does not match that given") } @@ -277,7 +277,7 @@ func TestGetInvalidCapabilities(t *testing.T) { t.Fatal(err) } - d := newDriver(plugin, p.Client) + d := newDriver(plugin, p.Client()) if d.Type() != plugin { t.Fatal("Driver type does not match that given") } @@ -391,7 +391,7 @@ func TestRemoteDriver(t *testing.T) { t.Fatal(err) } - d := newDriver(plugin, p.Client) + d := newDriver(plugin, p.Client()) if d.Type() != plugin { t.Fatal("Driver type does not match that given") } @@ -469,7 +469,7 @@ func TestDriverError(t *testing.T) { t.Fatal(err) } - driver := newDriver(plugin, p.Client) + driver := newDriver(plugin, p.Client()) if err := driver.CreateEndpoint("dummy", "dummy", &testEndpoint{t: t}, map[string]interface{}{}); err == nil { t.Fatalf("Expected error from driver") @@ -501,7 +501,7 @@ func TestMissingValues(t *testing.T) { if err != nil { t.Fatal(err) } - driver := newDriver(plugin, p.Client) + driver := newDriver(plugin, p.Client()) if err := driver.CreateEndpoint("dummy", "dummy", ep, map[string]interface{}{}); err != nil { t.Fatal(err) @@ -562,7 +562,7 @@ func TestRollback(t *testing.T) { if err != nil { t.Fatal(err) } - driver := newDriver(plugin, p.Client) + driver := newDriver(plugin, p.Client()) ep := &rollbackEndpoint{} diff --git a/ipams/remote/remote_test.go b/ipams/remote/remote_test.go index 14c732768e..ed393735ac 100644 --- a/ipams/remote/remote_test.go +++ b/ipams/remote/remote_test.go @@ -79,7 +79,7 @@ func TestGetCapabilities(t *testing.T) { t.Fatal(err) } - d := newAllocator(plugin, p.Client) + d := newAllocator(plugin, p.Client()) caps, err := d.(*allocator).getCapabilities() if err != nil { @@ -102,7 +102,7 @@ func TestGetCapabilitiesFromLegacyDriver(t *testing.T) { t.Fatal(err) } - d := newAllocator(plugin, p.Client) + d := newAllocator(plugin, p.Client()) if _, err := d.(*allocator).getCapabilities(); err == nil { t.Fatalf("Expected error, but got Success %v", err) @@ -127,7 +127,7 @@ func TestGetDefaultAddressSpaces(t *testing.T) { t.Fatal(err) } - d := newAllocator(plugin, p.Client) + d := newAllocator(plugin, p.Client()) l, g, err := d.(*allocator).GetDefaultAddressSpaces() if err != nil { @@ -217,7 +217,7 @@ func TestRemoteDriver(t *testing.T) { t.Fatal(err) } - d := newAllocator(plugin, p.Client) + d := newAllocator(plugin, p.Client()) l, g, err := d.(*allocator).GetDefaultAddressSpaces() if err != nil { From 7ec221476330ace5c5bd1471936eb33cfa5be28c Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Thu, 8 Sep 2016 12:22:20 -0700 Subject: [PATCH 065/799] add missed defer to unlock Signed-off-by: Alexander Morozov --- sandbox.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sandbox.go b/sandbox.go index 775b92ab31..4367518d70 100644 --- a/sandbox.go +++ b/sandbox.go @@ -147,7 +147,7 @@ func (sb *sandbox) Key() string { func (sb *sandbox) Labels() map[string]interface{} { sb.Lock() - sb.Unlock() + defer sb.Unlock() opts := make(map[string]interface{}, len(sb.config.generic)) for k, v := range sb.config.generic { opts[k] = v From 2fb2fd20c7aea931a388d61c4994fc76c581957a Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Sat, 20 Aug 2016 22:55:00 -0700 Subject: [PATCH 066/799] Add sandbox API for task insertion to service LB and service discovery Signed-off-by: Santhosh Manohar --- endpoint.go | 23 +++++++++++++++++++---- libnetwork_test.go | 8 ++++++++ networkdb/networkdb.go | 5 +++-- sandbox.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 6 deletions(-) diff --git a/endpoint.go b/endpoint.go index 44893573ff..70b2daf77e 100644 --- a/endpoint.go +++ b/endpoint.go @@ -74,6 +74,7 @@ type endpoint struct { ingressPorts []*PortConfig dbIndex uint64 dbExists bool + serviceEnabled bool sync.Mutex } @@ -303,6 +304,24 @@ func (ep *endpoint) isAnonymous() bool { return ep.anonymous } +// CompareAndSwap ep's serviceEnabled. If its in oldState, set it to newState +// and return true. If its not in oldState return false +func (ep *endpoint) casServiceEnabled(oldState, newState bool) bool { + ep.Lock() + defer ep.Unlock() + if ep.serviceEnabled == oldState { + ep.serviceEnabled = newState + return true + } + return false +} + +func (ep *endpoint) setServiceEnabled(state bool) { + ep.Lock() + defer ep.Unlock() + ep.serviceEnabled = state +} + func (ep *endpoint) needResolver() bool { ep.Lock() defer ep.Unlock() @@ -500,10 +519,6 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { return err } - if e := ep.addToCluster(); e != nil { - log.Errorf("Could not update state for endpoint %s into cluster: %v", ep.Name(), e) - } - if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil { return sb.setupDefaultGW() } diff --git a/libnetwork_test.go b/libnetwork_test.go index eb09a1673f..a981649fa2 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -1216,6 +1216,14 @@ func (f *fakeSandbox) Endpoints() []libnetwork.Endpoint { return nil } +func (f *fakeSandbox) EnableService() error { + return nil +} + +func (f *fakeSandbox) DisableService() error { + return nil +} + func TestExternalKey(t *testing.T) { externalKeyTest(t, false) } diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 2f35be6ffa..ffb2d4690c 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -203,9 +203,10 @@ func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) { // table, key) tuple and if the NetworkDB is part of the cluster // propogates this event to the cluster. It is an error to create an // entry for the same tuple for which there is already an existing -// entry. +// entry unless the current entry is deleting state. func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error { - if _, err := nDB.GetEntry(tname, nid, key); err == nil { + e, _ := nDB.getEntry(tname, nid, key) + if e != nil && !e.deleting { return fmt.Errorf("cannot create entry as the entry in table %s with network id %s and key %s already exists", tname, nid, key) } diff --git a/sandbox.go b/sandbox.go index 775b92ab31..11884a84e4 100644 --- a/sandbox.go +++ b/sandbox.go @@ -50,6 +50,12 @@ type Sandbox interface { ResolveService(name string) ([]*net.SRV, []net.IP, error) // Endpoints returns all the endpoints connected to the sandbox Endpoints() []Endpoint + // EnableService makes a managed container's service available by adding the + // endpoint to the service load balancer and service discovery + EnableService() error + // DisableService removes a managed contianer's endpoints from the load balancer + // and service discovery + DisableService() error } // SandboxOption is an option setter function type used to pass various options to @@ -721,6 +727,30 @@ func (sb *sandbox) SetKey(basePath string) error { return nil } +func (sb *sandbox) EnableService() error { + for _, ep := range sb.getConnectedEndpoints() { + if ep.casServiceEnabled(false, true) { + if e := ep.addToCluster(); e != nil { + ep.setServiceEnabled(false) + return fmt.Errorf("could not update state for endpoint %s into cluster: %v", ep.Name(), e) + } + } + } + return nil +} + +func (sb *sandbox) DisableService() error { + for _, ep := range sb.getConnectedEndpoints() { + if ep.casServiceEnabled(true, false) { + if e := ep.deleteFromCluster(); e != nil { + ep.setServiceEnabled(true) + return fmt.Errorf("could not delete state for endpoint %s from cluster: %v", ep.Name(), e) + } + } + } + return nil +} + func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) { for _, i := range osSbox.Info().Interfaces() { // Only remove the interfaces owned by this endpoint from the sandbox. From 757ea83c41bfbe30d2a710620315db758f2f5fd6 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 9 Sep 2016 17:51:30 +0200 Subject: [PATCH 067/799] Revert "add s390x arch build info at the netlink_deprecated_linux bridge driver" This reverts commit 8c72dab7167dc934e9dd57d773331fb15fa6a27d. The original commit breaks s390x, for example Docker build fails: * https://github.com/docker/docker/issues/26440 As discussed in the above issue: Even though char is unsigned by default on s390x, (gcc)go forces the type of RawSockaddr.Data to be signed. It makes no practical difference if these fields are signed or unsigned, it's just an API issue. The (assumed) reason for the original commit: For a while RawSockaddr.Data was unsigned during development of the gcc s390x port (not in an upstream release though). Probably the patch has been developed in this time frame. Signed-off-by: Michael Holzheu --- drivers/bridge/netlink_deprecated_linux_notarm.go | 2 +- drivers/bridge/netlink_deprecated_linux_s390x.go | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 drivers/bridge/netlink_deprecated_linux_s390x.go diff --git a/drivers/bridge/netlink_deprecated_linux_notarm.go b/drivers/bridge/netlink_deprecated_linux_notarm.go index 0852d0f165..df526952f7 100644 --- a/drivers/bridge/netlink_deprecated_linux_notarm.go +++ b/drivers/bridge/netlink_deprecated_linux_notarm.go @@ -1,4 +1,4 @@ -// +build !arm,!ppc64,!ppc64le,!s390x +// +build !arm,!ppc64,!ppc64le package bridge diff --git a/drivers/bridge/netlink_deprecated_linux_s390x.go b/drivers/bridge/netlink_deprecated_linux_s390x.go deleted file mode 100644 index 2d9abdc2ce..0000000000 --- a/drivers/bridge/netlink_deprecated_linux_s390x.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build s390x - -package bridge - -func ifrDataByte(b byte) uint8 { - return uint8(b) -} From e51268a42951a3b12b87be5fc87a332e1fd927a2 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Fri, 9 Sep 2016 21:45:03 -0700 Subject: [PATCH 068/799] Drop queries in root doamin when ndots is set Signed-off-by: Santhosh Manohar --- resolver.go | 15 +++++++++++++++ sandbox.go | 1 + sandbox_dns_unix.go | 30 ++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/resolver.go b/resolver.go index b9eb4f3ff2..fcb1a00a02 100644 --- a/resolver.go +++ b/resolver.go @@ -325,6 +325,21 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { return } + // If the user sets ndots > 0 explicitly and the query is + // in the root domain don't forward it out. We will return + // failure and let the client retry with the search domain + // attached + if resp == nil { + switch query.Question[0].Qtype { + case dns.TypeA: + fallthrough + case dns.TypeAAAA: + if r.sb.ndotsSet && !strings.Contains(strings.TrimSuffix(name, "."), ".") { + resp = createRespMsg(query) + } + } + } + proto := w.LocalAddr().Network() maxSize := 0 if proto == "tcp" { diff --git a/sandbox.go b/sandbox.go index 775b92ab31..e077eb628b 100644 --- a/sandbox.go +++ b/sandbox.go @@ -86,6 +86,7 @@ type sandbox struct { isStub bool inDelete bool ingress bool + ndotsSet bool sync.Mutex } diff --git a/sandbox_dns_unix.go b/sandbox_dns_unix.go index 0c649a9b9e..cd9e66224f 100644 --- a/sandbox_dns_unix.go +++ b/sandbox_dns_unix.go @@ -8,6 +8,8 @@ import ( "os" "path" "path/filepath" + "strconv" + "strings" log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/etchosts" @@ -313,8 +315,32 @@ func (sb *sandbox) rebuildDNS() error { // external v6 DNS servers has to be listed in resolv.conf dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, types.IPv6)...) - // Resolver returns the options in the format resolv.conf expects - dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...) + // If the user config and embedded DNS server both have ndots option set, + // remember the user's config so that unqualified names not in the docker + // domain can be dropped. + resOptions := sb.resolver.ResolverOptions() + +dnsOpt: + for _, resOpt := range resOptions { + if strings.Contains(resOpt, "ndots") { + for _, option := range dnsOptionsList { + if strings.Contains(option, "ndots") { + parts := strings.Split(option, ":") + if len(parts) != 2 { + return fmt.Errorf("invalid ndots option %v", option) + } + if num, err := strconv.Atoi(parts[1]); err != nil { + return fmt.Errorf("invalid number for ndots option %v", option) + } else if num > 0 { + sb.ndotsSet = true + break dnsOpt + } + } + } + } + } + + dnsOptionsList = append(dnsOptionsList, resOptions...) _, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList) return err From 8a6bbae1e5f3161cb02232c199dfa9bb5976669e Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 12 Sep 2016 15:19:22 -0700 Subject: [PATCH 069/799] Serialize dynamic network creation When dynamic networks are created and there is a race in creation of the same network from two different tasks then one of them will fail while the other will succeed. For service tasks this is not a big problem because they will be rescheduled again. But for attachment tasks this can be a problem since they won't get recreated and making the whole connection fail. Fixed it by serializing network creation for the network with the same id and trying to see if the id is present after coming out of wait. Signed-off-by: Jana Radhakrishnan --- controller.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/controller.go b/controller.go index b2499dc7f5..c63535d1b8 100644 --- a/controller.go +++ b/controller.go @@ -52,6 +52,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" + "github.com/docker/docker/pkg/locker" "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/stringid" "github.com/docker/libnetwork/cluster" @@ -149,6 +150,7 @@ type controller struct { ingressSandbox *sandbox sboxOnce sync.Once agent *agent + networkLocker *locker.Locker agentInitDone chan struct{} keys []*types.EncryptionKey clusterConfigAvailable bool @@ -169,6 +171,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) { svcRecords: make(map[string]svcInfo), serviceBindings: make(map[serviceKey]*service), agentInitDone: make(chan struct{}), + networkLocker: locker.New(), } if err := c.initStores(); err != nil { @@ -614,6 +617,15 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, // NewNetwork creates a new network of the specified network type. The options // are network specific and modeled in a generic way. func (c *controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error) { + if id != "" { + c.networkLocker.Lock(id) + defer c.networkLocker.Unlock(id) + + if _, err := c.NetworkByID(id); err == nil { + return nil, NetworkNameError(id) + } + } + if !config.IsValidName(name) { return nil, ErrInvalidName(name) } From 59e0c6254a54d6fe09ddd33bb872d1446445d91e Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 12 Sep 2016 15:32:19 -0700 Subject: [PATCH 070/799] Update Godeps Signed-off-by: Jana Radhakrishnan --- Godeps/Godeps.json | 5 + .../docker/docker/pkg/locker/README.md | 65 ++++++++++ .../docker/docker/pkg/locker/locker.go | 112 ++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/locker/README.md create mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/locker/locker.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 476e88db76..f20f0e1ddc 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -120,6 +120,11 @@ "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" }, + { + "ImportPath": "github.com/docker/docker/pkg/locker", + "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", + "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + }, { "ImportPath": "github.com/docker/docker/pkg/longpath", "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/README.md new file mode 100644 index 0000000000..e84a815cc5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/README.md @@ -0,0 +1,65 @@ +Locker +===== + +locker provides a mechanism for creating finer-grained locking to help +free up more global locks to handle other tasks. + +The implementation looks close to a sync.Mutex, however the user must provide a +reference to use to refer to the underlying lock when locking and unlocking, +and unlock may generate an error. + +If a lock with a given name does not exist when `Lock` is called, one is +created. +Lock references are automatically cleaned up on `Unlock` if nothing else is +waiting for the lock. + + +## Usage + +```go +package important + +import ( + "sync" + "time" + + "github.com/docker/docker/pkg/locker" +) + +type important struct { + locks *locker.Locker + data map[string]interface{} + mu sync.Mutex +} + +func (i *important) Get(name string) interface{} { + i.locks.Lock(name) + defer i.locks.Unlock(name) + return data[name] +} + +func (i *important) Create(name string, data interface{}) { + i.locks.Lock(name) + defer i.locks.Unlock(name) + + i.createImportant(data) + + s.mu.Lock() + i.data[name] = data + s.mu.Unlock() +} + +func (i *important) createImportant(data interface{}) { + time.Sleep(10 * time.Second) +} +``` + +For functions dealing with a given name, always lock at the beginning of the +function (or before doing anything with the underlying state), this ensures any +other function that is dealing with the same name will block. + +When needing to modify the underlying data, use the global lock to ensure nothing +else is modfying it at the same time. +Since name lock is already in place, no reads will occur while the modification +is being performed. + diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/locker.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/locker.go new file mode 100644 index 0000000000..0b22ddfab8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/locker.go @@ -0,0 +1,112 @@ +/* +Package locker provides a mechanism for creating finer-grained locking to help +free up more global locks to handle other tasks. + +The implementation looks close to a sync.Mutex, however the user must provide a +reference to use to refer to the underlying lock when locking and unlocking, +and unlock may generate an error. + +If a lock with a given name does not exist when `Lock` is called, one is +created. +Lock references are automatically cleaned up on `Unlock` if nothing else is +waiting for the lock. +*/ +package locker + +import ( + "errors" + "sync" + "sync/atomic" +) + +// ErrNoSuchLock is returned when the requested lock does not exist +var ErrNoSuchLock = errors.New("no such lock") + +// Locker provides a locking mechanism based on the passed in reference name +type Locker struct { + mu sync.Mutex + locks map[string]*lockCtr +} + +// lockCtr is used by Locker to represent a lock with a given name. +type lockCtr struct { + mu sync.Mutex + // waiters is the number of waiters waiting to acquire the lock + // this is int32 instead of uint32 so we can add `-1` in `dec()` + waiters int32 +} + +// inc increments the number of waiters waiting for the lock +func (l *lockCtr) inc() { + atomic.AddInt32(&l.waiters, 1) +} + +// dec decrements the number of waiters waiting on the lock +func (l *lockCtr) dec() { + atomic.AddInt32(&l.waiters, -1) +} + +// count gets the current number of waiters +func (l *lockCtr) count() int32 { + return atomic.LoadInt32(&l.waiters) +} + +// Lock locks the mutex +func (l *lockCtr) Lock() { + l.mu.Lock() +} + +// Unlock unlocks the mutex +func (l *lockCtr) Unlock() { + l.mu.Unlock() +} + +// New creates a new Locker +func New() *Locker { + return &Locker{ + locks: make(map[string]*lockCtr), + } +} + +// Lock locks a mutex with the given name. If it doesn't exist, one is created +func (l *Locker) Lock(name string) { + l.mu.Lock() + if l.locks == nil { + l.locks = make(map[string]*lockCtr) + } + + nameLock, exists := l.locks[name] + if !exists { + nameLock = &lockCtr{} + l.locks[name] = nameLock + } + + // increment the nameLock waiters while inside the main mutex + // this makes sure that the lock isn't deleted if `Lock` and `Unlock` are called concurrently + nameLock.inc() + l.mu.Unlock() + + // Lock the nameLock outside the main mutex so we don't block other operations + // once locked then we can decrement the number of waiters for this lock + nameLock.Lock() + nameLock.dec() +} + +// Unlock unlocks the mutex with the given name +// If the given lock is not being waited on by any other callers, it is deleted +func (l *Locker) Unlock(name string) error { + l.mu.Lock() + nameLock, exists := l.locks[name] + if !exists { + l.mu.Unlock() + return ErrNoSuchLock + } + + if nameLock.count() == 0 { + delete(l.locks, name) + } + nameLock.Unlock() + + l.mu.Unlock() + return nil +} From 291de3dfcf9947c29c40ede4da09923c3a614bcd Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 13 Sep 2016 11:52:12 -0700 Subject: [PATCH 071/799] Fix bitseq.SetAnyInRange - size 1 range is a valid input Signed-off-by: Alessandro Boch --- bitseq/sequence.go | 2 +- bitseq/sequence_test.go | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bitseq/sequence.go b/bitseq/sequence.go index 550bcbb825..fb99944098 100644 --- a/bitseq/sequence.go +++ b/bitseq/sequence.go @@ -197,7 +197,7 @@ func (h *Handle) getCopy() *Handle { // SetAnyInRange atomically sets the first unset bit in the specified range in the sequence and returns the corresponding ordinal func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) { - if end-start <= 0 || end >= h.bits { + if end < start || end >= h.bits { return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end) } if h.Unselected() == 0 { diff --git a/bitseq/sequence_test.go b/bitseq/sequence_test.go index 339f5928ef..4ef3bbb6fe 100644 --- a/bitseq/sequence_test.go +++ b/bitseq/sequence_test.go @@ -639,10 +639,6 @@ func TestSetInRange(t *testing.T) { t.Fatalf("Expected failure. Got success with ordinal:%d", o) } - if o, err := hnd.SetAnyInRange(5, 5); err == nil { - t.Fatalf("Expected failure. Got success with ordinal:%d", o) - } - if o, err := hnd.SetAnyInRange(0, numBits); err == nil { t.Fatalf("Expected failure. Got success with ordinal:%d", o) } @@ -692,6 +688,11 @@ func TestSetInRange(t *testing.T) { t.Fatalf("Unexpected failure: %v", err) } + // set one bit using the set range with 1 bit size range + if _, err := hnd.SetAnyInRange(uint64(163*blockLen-1), uint64(163*blockLen-1)); err != nil { + t.Fatal(err) + } + // create a non multiple of 32 mask hnd, err = NewHandle("", nil, "", 30) if err != nil { From 44f6be4cbbbdcbb1955df61e286570826cccd2f4 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Wed, 14 Sep 2016 08:36:37 -0700 Subject: [PATCH 072/799] Revert "Add sandbox API for task insertion to service LB and service discovery" This reverts commit 2fb2fd20c7aea931a388d61c4994fc76c581957a. Signed-off-by: Santhosh Manohar --- endpoint.go | 23 ++++------------------- libnetwork_test.go | 8 -------- networkdb/networkdb.go | 5 ++--- sandbox.go | 30 ------------------------------ 4 files changed, 6 insertions(+), 60 deletions(-) diff --git a/endpoint.go b/endpoint.go index 70b2daf77e..44893573ff 100644 --- a/endpoint.go +++ b/endpoint.go @@ -74,7 +74,6 @@ type endpoint struct { ingressPorts []*PortConfig dbIndex uint64 dbExists bool - serviceEnabled bool sync.Mutex } @@ -304,24 +303,6 @@ func (ep *endpoint) isAnonymous() bool { return ep.anonymous } -// CompareAndSwap ep's serviceEnabled. If its in oldState, set it to newState -// and return true. If its not in oldState return false -func (ep *endpoint) casServiceEnabled(oldState, newState bool) bool { - ep.Lock() - defer ep.Unlock() - if ep.serviceEnabled == oldState { - ep.serviceEnabled = newState - return true - } - return false -} - -func (ep *endpoint) setServiceEnabled(state bool) { - ep.Lock() - defer ep.Unlock() - ep.serviceEnabled = state -} - func (ep *endpoint) needResolver() bool { ep.Lock() defer ep.Unlock() @@ -519,6 +500,10 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { return err } + if e := ep.addToCluster(); e != nil { + log.Errorf("Could not update state for endpoint %s into cluster: %v", ep.Name(), e) + } + if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil { return sb.setupDefaultGW() } diff --git a/libnetwork_test.go b/libnetwork_test.go index a981649fa2..eb09a1673f 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -1216,14 +1216,6 @@ func (f *fakeSandbox) Endpoints() []libnetwork.Endpoint { return nil } -func (f *fakeSandbox) EnableService() error { - return nil -} - -func (f *fakeSandbox) DisableService() error { - return nil -} - func TestExternalKey(t *testing.T) { externalKeyTest(t, false) } diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index ffb2d4690c..2f35be6ffa 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -203,10 +203,9 @@ func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) { // table, key) tuple and if the NetworkDB is part of the cluster // propogates this event to the cluster. It is an error to create an // entry for the same tuple for which there is already an existing -// entry unless the current entry is deleting state. +// entry. func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error { - e, _ := nDB.getEntry(tname, nid, key) - if e != nil && !e.deleting { + if _, err := nDB.GetEntry(tname, nid, key); err == nil { return fmt.Errorf("cannot create entry as the entry in table %s with network id %s and key %s already exists", tname, nid, key) } diff --git a/sandbox.go b/sandbox.go index 7fd368ebed..ed439ff608 100644 --- a/sandbox.go +++ b/sandbox.go @@ -50,12 +50,6 @@ type Sandbox interface { ResolveService(name string) ([]*net.SRV, []net.IP, error) // Endpoints returns all the endpoints connected to the sandbox Endpoints() []Endpoint - // EnableService makes a managed container's service available by adding the - // endpoint to the service load balancer and service discovery - EnableService() error - // DisableService removes a managed contianer's endpoints from the load balancer - // and service discovery - DisableService() error } // SandboxOption is an option setter function type used to pass various options to @@ -728,30 +722,6 @@ func (sb *sandbox) SetKey(basePath string) error { return nil } -func (sb *sandbox) EnableService() error { - for _, ep := range sb.getConnectedEndpoints() { - if ep.casServiceEnabled(false, true) { - if e := ep.addToCluster(); e != nil { - ep.setServiceEnabled(false) - return fmt.Errorf("could not update state for endpoint %s into cluster: %v", ep.Name(), e) - } - } - } - return nil -} - -func (sb *sandbox) DisableService() error { - for _, ep := range sb.getConnectedEndpoints() { - if ep.casServiceEnabled(true, false) { - if e := ep.deleteFromCluster(); e != nil { - ep.setServiceEnabled(true) - return fmt.Errorf("could not delete state for endpoint %s from cluster: %v", ep.Name(), e) - } - } - } - return nil -} - func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) { for _, i := range osSbox.Info().Interfaces() { // Only remove the interfaces owned by this endpoint from the sandbox. From 214f592fb6b962c86456114cc7bf7b18c4ae06f9 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Thu, 15 Sep 2016 11:21:33 -0700 Subject: [PATCH 073/799] Check if IPv6 is enabled before restoring the network pools Signed-off-by: Alessandro Boch --- controller.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/controller.go b/controller.go index c63535d1b8..039c80acb7 100644 --- a/controller.go +++ b/controller.go @@ -753,9 +753,11 @@ func (c *controller) reservePools() { c.Gateway = n.ipamV4Info[i].Gateway.IP.String() } } - for i, c := range n.ipamV6Config { - if c.Gateway == "" && n.ipamV6Info[i].Gateway != nil { - c.Gateway = n.ipamV6Info[i].Gateway.IP.String() + if n.enableIPv6 { + for i, c := range n.ipamV6Config { + if c.Gateway == "" && n.ipamV6Info[i].Gateway != nil { + c.Gateway = n.ipamV6Info[i].Gateway.IP.String() + } } } // Reserve pools From ccd4408636c06ef4facec2e2c205a6d0e253accc Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Thu, 15 Sep 2016 15:22:57 -0700 Subject: [PATCH 074/799] Name the ingress sandbox explicitly Signed-off-by: Santhosh Manohar --- controller.go | 1 + 1 file changed, 1 insertion(+) diff --git a/controller.go b/controller.go index c63535d1b8..1ddba9b7d6 100644 --- a/controller.go +++ b/controller.go @@ -920,6 +920,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s if sb.ingress { c.ingressSandbox = sb + sb.id = "ingress_sbox" } c.Unlock() defer func() { From 82fba3c357e202a0f70b6ab9929d16db4f28f5ad Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Fri, 16 Sep 2016 15:15:46 -0700 Subject: [PATCH 075/799] Make nodenames unique in Gossip cluster Signed-off-by: Santhosh Manohar --- agent.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/agent.go b/agent.go index 2b2ecf4324..e83ee9f375 100644 --- a/agent.go +++ b/agent.go @@ -9,6 +9,7 @@ import ( "sort" "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/stringid" "github.com/docker/go-events" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" @@ -247,9 +248,12 @@ func (c *controller) agentInit(bindAddrOrInterface, advertiseAddr string) error keys, tags := c.getKeys(subsysGossip) hostname, _ := os.Hostname() + nodeName := hostname + "-" + stringid.TruncateID(stringid.GenerateRandomID()) + logrus.Info("Gossip cluster hostname ", nodeName) + nDB, err := networkdb.New(&networkdb.Config{ AdvertiseAddr: advertiseAddr, - NodeName: hostname, + NodeName: nodeName, Keys: keys, }) From 1fe182e5942dcf375192780ae82503486fdb9732 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 19 Sep 2016 11:37:30 -0700 Subject: [PATCH 076/799] In overlay driver reset any state on setkey() Signed-off-by: Alessandro Boch --- drivers/overlay/encryption.go | 11 +++++------ drivers/overlay/overlay.go | 8 ++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/overlay/encryption.go b/drivers/overlay/encryption.go index 5b4800716b..fefb5da65c 100644 --- a/drivers/overlay/encryption.go +++ b/drivers/overlay/encryption.go @@ -392,10 +392,11 @@ func (d *driver) secMapWalk(f func(string, []*spi) ([]*spi, bool)) error { } func (d *driver) setKeys(keys []*key) error { - if d.keys != nil { - return types.ForbiddenErrorf("initial keys are already present") - } + // Accept the encryption keys and clear any stale encryption map + d.Lock() d.keys = keys + d.secMap = &encrMap{nodes: map[string][]*spi{}} + d.Unlock() log.Debugf("Initial encryption keys: %v", d.keys) return nil } @@ -433,10 +434,8 @@ func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { if (newKey != nil && newIdx == -1) || (primary != nil && priIdx == -1) || (pruneKey != nil && delIdx == -1) { - err := types.BadRequestErrorf("cannot find proper key indices while processing key update:"+ + return types.BadRequestErrorf("cannot find proper key indices while processing key update:"+ "(newIdx,priIdx,delIdx):(%d, %d, %d)", newIdx, priIdx, delIdx) - log.Warn(err) - return err } d.secMapWalk(func(rIPs string, spis []*spi) ([]*spi, bool) { diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index 59877dd1ac..492f7f4254 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -336,7 +336,9 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) } keys = append(keys, k) } - d.setKeys(keys) + if err := d.setKeys(keys); err != nil { + logrus.Warn(err) + } case discoverapi.EncryptionKeysUpdate: var newKey, delKey, priKey *key encrData, ok := data.(discoverapi.DriverEncryptionUpdate) @@ -361,7 +363,9 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) tag: uint32(encrData.PruneTag), } } - d.updateKeys(newKey, priKey, delKey) + if err := d.updateKeys(newKey, priKey, delKey); err != nil { + logrus.Warn(err) + } default: } return nil From 716810dc9f6aca2cff69641f7fcce1fe75c77931 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 14 Sep 2016 22:24:14 -0700 Subject: [PATCH 077/799] Recover from transient gossip failures Currently if there is any transient gossip failure in any node the recoevry process depends on other nodes propogating the information indirectly. In cases if these transient failures affects all the nodes that this node has in its memberlist then this node will be permenantly cutoff from the the gossip channel. Added node state management code in networkdb to address these problems by trying to rejoin the cluster via the failed nodes when there is a failure. This also necessitates the need to add new messages called node event messages to differentiate between node leave and node failure. Signed-off-by: Jana Radhakrishnan --- networkdb/broadcast.go | 52 +++++ networkdb/cluster.go | 105 ++++++++- networkdb/delegate.go | 87 +++++++- networkdb/event_delegate.go | 26 ++- networkdb/networkdb.go | 66 +++++- networkdb/networkdb.pb.go | 412 ++++++++++++++++++++++++++++++------ networkdb/networkdb.proto | 27 +++ 7 files changed, 685 insertions(+), 90 deletions(-) diff --git a/networkdb/broadcast.go b/networkdb/broadcast.go index 2e07729569..faaf642948 100644 --- a/networkdb/broadcast.go +++ b/networkdb/broadcast.go @@ -1,10 +1,15 @@ package networkdb import ( + "fmt" + "time" + "github.com/hashicorp/memberlist" "github.com/hashicorp/serf/serf" ) +const broadcastTimeout = 5 * time.Second + type networkEventMessage struct { id string node string @@ -44,6 +49,53 @@ func (nDB *NetworkDB) sendNetworkEvent(nid string, event NetworkEvent_Type, ltim return nil } +type nodeEventMessage struct { + msg []byte + notify chan<- struct{} +} + +func (m *nodeEventMessage) Invalidates(other memberlist.Broadcast) bool { + return false +} + +func (m *nodeEventMessage) Message() []byte { + return m.msg +} + +func (m *nodeEventMessage) Finished() { + if m.notify != nil { + close(m.notify) + } +} + +func (nDB *NetworkDB) sendNodeEvent(event NodeEvent_Type) error { + nEvent := NodeEvent{ + Type: event, + LTime: nDB.networkClock.Increment(), + NodeName: nDB.config.NodeName, + } + + raw, err := encodeMessage(MessageTypeNodeEvent, &nEvent) + if err != nil { + return err + } + + notifyCh := make(chan struct{}) + nDB.nodeBroadcasts.QueueBroadcast(&nodeEventMessage{ + msg: raw, + notify: notifyCh, + }) + + // Wait for the broadcast + select { + case <-notifyCh: + case <-time.After(broadcastTimeout): + return fmt.Errorf("timed out broadcasting node event") + } + + return nil +} + type tableEventMessage struct { id string tname string diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 17563589dc..0a21cae5ae 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -7,6 +7,7 @@ import ( "fmt" "math/big" rnd "math/rand" + "net" "strings" "time" @@ -14,7 +15,11 @@ import ( "github.com/hashicorp/memberlist" ) -const reapInterval = 30 * time.Second +const ( + reapInterval = 60 * time.Second + reapPeriod = 5 * time.Second + retryInterval = 1 * time.Second +) type logWriter struct{} @@ -111,6 +116,13 @@ func (nDB *NetworkDB) clusterInit() error { RetransmitMult: config.RetransmitMult, } + nDB.nodeBroadcasts = &memberlist.TransmitLimitedQueue{ + NumNodes: func() int { + return len(nDB.nodes) + }, + RetransmitMult: config.RetransmitMult, + } + mlist, err := memberlist.Create(config) if err != nil { return fmt.Errorf("failed to create memberlist: %v", err) @@ -124,9 +136,10 @@ func (nDB *NetworkDB) clusterInit() error { interval time.Duration fn func() }{ - {reapInterval, nDB.reapState}, + {reapPeriod, nDB.reapState}, {config.GossipInterval, nDB.gossip}, {config.PushPullInterval, nDB.bulkSyncTables}, + {retryInterval, nDB.reconnectNode}, } { t := time.NewTicker(trigger.interval) go nDB.triggerFunc(trigger.interval, t.C, nDB.stopCh, trigger.fn) @@ -136,19 +149,49 @@ func (nDB *NetworkDB) clusterInit() error { return nil } +func (nDB *NetworkDB) retryJoin(members []string, stop <-chan struct{}) { + t := time.NewTicker(retryInterval) + defer t.Stop() + + for { + select { + case <-t.C: + if _, err := nDB.memberlist.Join(members); err != nil { + logrus.Errorf("Failed to join memberlist %s on retry: %v", members, err) + continue + } + return + case <-stop: + return + } + } + +} + func (nDB *NetworkDB) clusterJoin(members []string) error { mlist := nDB.memberlist if _, err := mlist.Join(members); err != nil { + // Incase of failure, keep retrying join until it succeeds or the cluster is shutdown. + go nDB.retryJoin(members, nDB.stopCh) + return fmt.Errorf("could not join node to memberlist: %v", err) } + if err := nDB.sendNodeEvent(NodeEventTypeJoin); err != nil { + return fmt.Errorf("failed to send node join: %v", err) + } + return nil } func (nDB *NetworkDB) clusterLeave() error { mlist := nDB.memberlist + if err := nDB.sendNodeEvent(NodeEventTypeLeave); err != nil { + return fmt.Errorf("failed to send node leave: %v", err) + } + if err := mlist.Leave(time.Second); err != nil { return err } @@ -180,6 +223,42 @@ func (nDB *NetworkDB) triggerFunc(stagger time.Duration, C <-chan time.Time, sto } } +func (nDB *NetworkDB) reconnectNode() { + nDB.RLock() + if len(nDB.failedNodes) == 0 { + nDB.RUnlock() + return + } + + nodes := make([]*node, 0, len(nDB.failedNodes)) + for _, n := range nDB.failedNodes { + nodes = append(nodes, n) + } + nDB.RUnlock() + + // Update all the local state to a new time to force update on + // the node we are trying to rejoin, just in case that node + // has these in leaving/deleting state still. This is + // facilitate fast convergence after recovering from a gossip + // failure. + nDB.updateLocalStateTime() + + node := nodes[randomOffset(len(nodes))] + addr := net.UDPAddr{IP: node.Addr, Port: int(node.Port)} + + if _, err := nDB.memberlist.Join([]string{addr.String()}); err != nil { + return + } + + if err := nDB.sendNodeEvent(NodeEventTypeJoin); err != nil { + logrus.Errorf("failed to send node join during reconnect: %v", err) + return + } + + logrus.Debugf("Initiating bulk sync with node %s after reconnect", node.Name) + nDB.bulkSync([]string{node.Name}, true) +} + func (nDB *NetworkDB) reapState() { nDB.reapNetworks() nDB.reapTableEntries() @@ -288,7 +367,7 @@ func (nDB *NetworkDB) gossip() { } // Send the compound message - if err := nDB.memberlist.SendToUDP(mnode, compound); err != nil { + if err := nDB.memberlist.SendToUDP(&mnode.Node, compound); err != nil { logrus.Errorf("Failed to send gossip to %s: %s", mnode.Addr, err) } } @@ -323,7 +402,7 @@ func (nDB *NetworkDB) bulkSyncTables() { continue } - completed, err := nDB.bulkSync(nid, nodes, false) + completed, err := nDB.bulkSync(nodes, false) if err != nil { logrus.Errorf("periodic bulk sync failure for network %s: %v", nid, err) continue @@ -350,7 +429,7 @@ func (nDB *NetworkDB) bulkSyncTables() { } } -func (nDB *NetworkDB) bulkSync(nid string, nodes []string, all bool) ([]string, error) { +func (nDB *NetworkDB) bulkSync(nodes []string, all bool) ([]string, error) { if !all { // If not all, then just pick one. nodes = nDB.mRandomNodes(1, nodes) @@ -388,7 +467,12 @@ func (nDB *NetworkDB) bulkSync(nid string, nodes []string, all bool) ([]string, func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited bool) error { var msgs [][]byte - logrus.Debugf("%s: Initiating bulk sync for networks %v with node %s", nDB.config.NodeName, networks, node) + var unsolMsg string + if unsolicited { + unsolMsg = "unsolicited" + } + + logrus.Debugf("%s: Initiating %s bulk sync for networks %v with node %s", nDB.config.NodeName, unsolMsg, networks, node) nDB.RLock() mnode := nDB.nodes[node] @@ -404,15 +488,14 @@ func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited b return false } - // Do not bulk sync state which is in the - // process of getting deleted. + eType := TableEventTypeCreate if entry.deleting { - return false + eType = TableEventTypeDelete } params := strings.Split(path[1:], "/") tEvent := TableEvent{ - Type: TableEventTypeCreate, + Type: eType, LTime: entry.ltime, NodeName: entry.node, NetworkID: nid, @@ -454,7 +537,7 @@ func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited b nDB.bulkSyncAckTbl[node] = ch nDB.Unlock() - err = nDB.memberlist.SendToTCP(mnode, buf) + err = nDB.memberlist.SendToTCP(&mnode.Node, buf) if err != nil { nDB.Lock() delete(nDB.bulkSyncAckTbl, node) diff --git a/networkdb/delegate.go b/networkdb/delegate.go index 35c126a847..3e96384465 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -17,6 +17,56 @@ func (d *delegate) NodeMeta(limit int) []byte { return []byte{} } +func (nDB *NetworkDB) checkAndGetNode(nEvent *NodeEvent) *node { + nDB.Lock() + defer nDB.Unlock() + + for _, nodes := range []map[string]*node{ + nDB.failedNodes, + nDB.leftNodes, + nDB.nodes, + } { + if n, ok := nodes[nEvent.NodeName]; ok { + if n.ltime >= nEvent.LTime { + return nil + } + + delete(nDB.failedNodes, n.Name) + return n + } + } + + return nil +} + +func (nDB *NetworkDB) handleNodeEvent(nEvent *NodeEvent) bool { + // Update our local clock if the received messages has newer + // time. + nDB.networkClock.Witness(nEvent.LTime) + + n := nDB.checkAndGetNode(nEvent) + if n == nil { + return false + } + + n.ltime = nEvent.LTime + + switch nEvent.Type { + case NodeEventTypeJoin: + nDB.Lock() + nDB.nodes[n.Name] = n + nDB.Unlock() + return true + case NodeEventTypeLeave: + nDB.Lock() + nDB.leftNodes[n.Name] = n + nDB.Unlock() + return true + } + + return false +} + func (nDB *NetworkDB) handleNetworkEvent(nEvent *NetworkEvent) bool { // Update our local clock if the received messages has newer // time. @@ -188,6 +238,27 @@ func (nDB *NetworkDB) handleTableMessage(buf []byte, isBulkSync bool) { } } +func (nDB *NetworkDB) handleNodeMessage(buf []byte) { + var nEvent NodeEvent + if err := proto.Unmarshal(buf, &nEvent); err != nil { + logrus.Errorf("Error decoding node event message: %v", err) + return + } + + if rebroadcast := nDB.handleNodeEvent(&nEvent); rebroadcast { + var err error + buf, err = encodeRawMessage(MessageTypeNodeEvent, buf) + if err != nil { + logrus.Errorf("Error marshalling gossip message for node event rebroadcast: %v", err) + return + } + + nDB.nodeBroadcasts.QueueBroadcast(&nodeEventMessage{ + msg: buf, + }) + } +} + func (nDB *NetworkDB) handleNetworkMessage(buf []byte) { var nEvent NetworkEvent if err := proto.Unmarshal(buf, &nEvent); err != nil { @@ -256,6 +327,8 @@ func (nDB *NetworkDB) handleMessage(buf []byte, isBulkSync bool) { } switch mType { + case MessageTypeNodeEvent: + nDB.handleNodeMessage(data) case MessageTypeNetworkEvent: nDB.handleNetworkMessage(data) case MessageTypeTableEvent: @@ -278,7 +351,9 @@ func (d *delegate) NotifyMsg(buf []byte) { } func (d *delegate) GetBroadcasts(overhead, limit int) [][]byte { - return d.nDB.networkBroadcasts.GetBroadcasts(overhead, limit) + msgs := d.nDB.networkBroadcasts.GetBroadcasts(overhead, limit) + msgs = append(msgs, d.nDB.nodeBroadcasts.GetBroadcasts(overhead, limit)...) + return msgs } func (d *delegate) LocalState(join bool) []byte { @@ -286,7 +361,8 @@ func (d *delegate) LocalState(join bool) []byte { defer d.nDB.RUnlock() pp := NetworkPushPull{ - LTime: d.nDB.networkClock.Time(), + LTime: d.nDB.networkClock.Time(), + NodeName: d.nDB.config.NodeName, } for name, nn := range d.nDB.networks { @@ -336,6 +412,13 @@ func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) { d.nDB.networkClock.Witness(pp.LTime) } + nodeEvent := &NodeEvent{ + LTime: pp.LTime, + NodeName: pp.NodeName, + Type: NodeEventTypeJoin, + } + d.nDB.handleNodeEvent(nodeEvent) + for _, n := range pp.Networks { nEvent := &NetworkEvent{ LTime: n.LTime, diff --git a/networkdb/event_delegate.go b/networkdb/event_delegate.go index 7dfea84f6e..019cafbd06 100644 --- a/networkdb/event_delegate.go +++ b/networkdb/event_delegate.go @@ -6,17 +6,31 @@ type eventDelegate struct { nDB *NetworkDB } -func (e *eventDelegate) NotifyJoin(n *memberlist.Node) { +func (e *eventDelegate) NotifyJoin(mn *memberlist.Node) { e.nDB.Lock() - e.nDB.nodes[n.Name] = n + // In case the node is rejoining after a failure or leave, + // wait until an explicit join message arrives before adding + // it to the nodes just to make sure this is not a stale + // join. If you don't know about this node add it immediately. + _, fOk := e.nDB.failedNodes[mn.Name] + _, lOk := e.nDB.leftNodes[mn.Name] + if fOk || lOk { + e.nDB.Unlock() + return + } + + e.nDB.nodes[mn.Name] = &node{Node: *mn} e.nDB.Unlock() } -func (e *eventDelegate) NotifyLeave(n *memberlist.Node) { - e.nDB.deleteNodeTableEntries(n.Name) - e.nDB.deleteNetworkNodeEntries(n.Name) +func (e *eventDelegate) NotifyLeave(mn *memberlist.Node) { + e.nDB.deleteNodeTableEntries(mn.Name) + e.nDB.deleteNetworkEntriesForNode(mn.Name) e.nDB.Lock() - delete(e.nDB.nodes, n.Name) + if n, ok := e.nDB.nodes[mn.Name]; ok { + delete(e.nDB.nodes, mn.Name) + e.nDB.failedNodes[mn.Name] = n + } e.nDB.Unlock() } diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index ffb2d4690c..c452a90835 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -41,7 +41,13 @@ type NetworkDB struct { // List of all peer nodes in the cluster not-limited to any // network. - nodes map[string]*memberlist.Node + nodes map[string]*node + + // List of all peer nodes which have failed + failedNodes map[string]*node + + // List of all peer nodes which have left + leftNodes map[string]*node // A multi-dimensional map of network/node attachmemts. The // first key is a node name and the second key is a network ID @@ -66,6 +72,9 @@ type NetworkDB struct { // Broadcast queue for network event gossip. networkBroadcasts *memberlist.TransmitLimitedQueue + // Broadcast queue for node event gossip. + nodeBroadcasts *memberlist.TransmitLimitedQueue + // A central stop channel to stop all go routines running on // behalf of the NetworkDB instance. stopCh chan struct{} @@ -82,6 +91,11 @@ type NetworkDB struct { keyring *memberlist.Keyring } +type node struct { + memberlist.Node + ltime serf.LamportTime +} + // network describes the node/network attachment. type network struct { // Network ID @@ -146,7 +160,9 @@ func New(c *Config) (*NetworkDB, error) { config: c, indexes: make(map[int]*radix.Tree), networks: make(map[string]map[string]*network), - nodes: make(map[string]*memberlist.Node), + nodes: make(map[string]*node), + failedNodes: make(map[string]*node), + leftNodes: make(map[string]*node), networkNodes: make(map[string][]string), bulkSyncAckTbl: make(map[string]chan struct{}), broadcaster: events.NewBroadcaster(), @@ -203,10 +219,9 @@ func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) { // table, key) tuple and if the NetworkDB is part of the cluster // propogates this event to the cluster. It is an error to create an // entry for the same tuple for which there is already an existing -// entry unless the current entry is deleting state. +// entry. func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error { - e, _ := nDB.getEntry(tname, nid, key) - if e != nil && !e.deleting { + if _, err := nDB.GetEntry(tname, nid, key); err == nil { return fmt.Errorf("cannot create entry as the entry in table %s with network id %s and key %s already exists", tname, nid, key) } @@ -287,7 +302,7 @@ func (nDB *NetworkDB) DeleteEntry(tname, nid, key string) error { return nil } -func (nDB *NetworkDB) deleteNetworkNodeEntries(deletedNode string) { +func (nDB *NetworkDB) deleteNetworkEntriesForNode(deletedNode string) { nDB.Lock() for nid, nodes := range nDB.networkNodes { updatedNodes := make([]string, 0, len(nodes)) @@ -301,6 +316,8 @@ func (nDB *NetworkDB) deleteNetworkNodeEntries(deletedNode string) { nDB.networkNodes[nid] = updatedNodes } + + delete(nDB.networks, deletedNode) nDB.Unlock() } @@ -390,7 +407,7 @@ func (nDB *NetworkDB) JoinNetwork(nid string) error { } logrus.Debugf("%s: joined network %s", nDB.config.NodeName, nid) - if _, err := nDB.bulkSync(nid, networkNodes, true); err != nil { + if _, err := nDB.bulkSync(networkNodes, true); err != nil { logrus.Errorf("Error bulk syncing while joining network %s: %v", nid, err) } @@ -493,10 +510,41 @@ func (nDB *NetworkDB) findCommonNetworks(nodeName string) []string { var networks []string for nid := range nDB.networks[nDB.config.NodeName] { - if _, ok := nDB.networks[nodeName][nid]; ok { - networks = append(networks, nid) + if n, ok := nDB.networks[nodeName][nid]; ok { + if !n.leaving { + networks = append(networks, nid) + } } } return networks } + +func (nDB *NetworkDB) updateLocalStateTime() { + nDB.Lock() + defer nDB.Unlock() + + ltime := nDB.networkClock.Increment() + for _, n := range nDB.networks[nDB.config.NodeName] { + n.ltime = ltime + } + + ltime = nDB.tableClock.Increment() + nDB.indexes[byTable].Walk(func(path string, v interface{}) bool { + entry := v.(*entry) + if entry.node != nDB.config.NodeName { + return false + } + + params := strings.Split(path[1:], "/") + tname := params[0] + nid := params[1] + key := params[2] + entry.ltime = ltime + + nDB.indexes[byTable].Insert(fmt.Sprintf("/%s/%s/%s", tname, nid, key), entry) + nDB.indexes[byNetwork].Insert(fmt.Sprintf("/%s/%s/%s", nid, tname, key), entry) + + return false + }) +} diff --git a/networkdb/networkdb.pb.go b/networkdb/networkdb.pb.go index 86177cf315..dfbc7131fb 100644 --- a/networkdb/networkdb.pb.go +++ b/networkdb/networkdb.pb.go @@ -10,6 +10,7 @@ It has these top-level messages: GossipMessage + NodeEvent NetworkEvent NetworkEntry NetworkPushPull @@ -67,6 +68,9 @@ const ( // which is a pack of many message of above types, packed into // a single compound message. MessageTypeCompound MessageType = 5 + // NodeEvent message type is used to communicare node + // join/leave events in the cluster + MessageTypeNodeEvent MessageType = 6 ) var MessageType_name = map[int32]string{ @@ -76,6 +80,7 @@ var MessageType_name = map[int32]string{ 3: "PUSH_PULL", 4: "BULK_SYNC", 5: "COMPOUND", + 6: "NODE_EVENT", } var MessageType_value = map[string]int32{ "INVALID": 0, @@ -84,6 +89,7 @@ var MessageType_value = map[string]int32{ "PUSH_PULL": 3, "BULK_SYNC": 4, "COMPOUND": 5, + "NODE_EVENT": 6, } func (x MessageType) String() string { @@ -91,6 +97,32 @@ func (x MessageType) String() string { } func (MessageType) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{0} } +type NodeEvent_Type int32 + +const ( + NodeEventTypeInvalid NodeEvent_Type = 0 + // Join event is generated when this node joins the cluster. + NodeEventTypeJoin NodeEvent_Type = 1 + // Leave event is generated when this node leaves the cluster. + NodeEventTypeLeave NodeEvent_Type = 2 +) + +var NodeEvent_Type_name = map[int32]string{ + 0: "INVALID", + 1: "JOIN", + 2: "LEAVE", +} +var NodeEvent_Type_value = map[string]int32{ + "INVALID": 0, + "JOIN": 1, + "LEAVE": 2, +} + +func (x NodeEvent_Type) String() string { + return proto.EnumName(NodeEvent_Type_name, int32(x)) +} +func (NodeEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{1, 0} } + type NetworkEvent_Type int32 const ( @@ -115,7 +147,7 @@ var NetworkEvent_Type_value = map[string]int32{ func (x NetworkEvent_Type) String() string { return proto.EnumName(NetworkEvent_Type_name, int32(x)) } -func (NetworkEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{1, 0} } +func (NetworkEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{2, 0} } type TableEvent_Type int32 @@ -148,7 +180,7 @@ var TableEvent_Type_value = map[string]int32{ func (x TableEvent_Type) String() string { return proto.EnumName(TableEvent_Type_name, int32(x)) } -func (TableEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{4, 0} } +func (TableEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{5, 0} } // GossipMessage is a basic message header used by all messages types. type GossipMessage struct { @@ -160,6 +192,21 @@ func (m *GossipMessage) Reset() { *m = GossipMessage{} } func (*GossipMessage) ProtoMessage() {} func (*GossipMessage) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{0} } +// NodeEvent message payload definition. +type NodeEvent struct { + Type NodeEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=networkdb.NodeEvent_Type" json:"type,omitempty"` + // Lamport time using a network lamport clock indicating the + // time this event was generated on the node where it was + // generated. + LTime github_com_hashicorp_serf_serf.LamportTime `protobuf:"varint,2,opt,name=l_time,json=lTime,proto3,customtype=github.com/hashicorp/serf/serf.LamportTime" json:"l_time"` + // Source node name. + NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` +} + +func (m *NodeEvent) Reset() { *m = NodeEvent{} } +func (*NodeEvent) ProtoMessage() {} +func (*NodeEvent) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{1} } + // NetworkEvent message payload definition. type NetworkEvent struct { Type NetworkEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=networkdb.NetworkEvent_Type" json:"type,omitempty"` @@ -175,7 +222,7 @@ type NetworkEvent struct { func (m *NetworkEvent) Reset() { *m = NetworkEvent{} } func (*NetworkEvent) ProtoMessage() {} -func (*NetworkEvent) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{1} } +func (*NetworkEvent) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{2} } // NetworkEntry for push pull of networks. type NetworkEntry struct { @@ -192,18 +239,20 @@ type NetworkEntry struct { func (m *NetworkEntry) Reset() { *m = NetworkEntry{} } func (*NetworkEntry) ProtoMessage() {} -func (*NetworkEntry) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{2} } +func (*NetworkEntry) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{3} } // NetworkPushpull message payload definition. type NetworkPushPull struct { // Lamport time when this push pull was initiated. LTime github_com_hashicorp_serf_serf.LamportTime `protobuf:"varint,1,opt,name=l_time,json=lTime,proto3,customtype=github.com/hashicorp/serf/serf.LamportTime" json:"l_time"` Networks []*NetworkEntry `protobuf:"bytes,2,rep,name=networks" json:"networks,omitempty"` + // Name of the node sending this push pull payload. + NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` } func (m *NetworkPushPull) Reset() { *m = NetworkPushPull{} } func (*NetworkPushPull) ProtoMessage() {} -func (*NetworkPushPull) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{3} } +func (*NetworkPushPull) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{4} } func (m *NetworkPushPull) GetNetworks() []*NetworkEntry { if m != nil { @@ -231,7 +280,7 @@ type TableEvent struct { func (m *TableEvent) Reset() { *m = TableEvent{} } func (*TableEvent) ProtoMessage() {} -func (*TableEvent) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{4} } +func (*TableEvent) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{5} } // BulkSync message payload definition. type BulkSyncMessage struct { @@ -251,7 +300,7 @@ type BulkSyncMessage struct { func (m *BulkSyncMessage) Reset() { *m = BulkSyncMessage{} } func (*BulkSyncMessage) ProtoMessage() {} -func (*BulkSyncMessage) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{5} } +func (*BulkSyncMessage) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{6} } // Compound message payload definition. type CompoundMessage struct { @@ -261,7 +310,7 @@ type CompoundMessage struct { func (m *CompoundMessage) Reset() { *m = CompoundMessage{} } func (*CompoundMessage) ProtoMessage() {} -func (*CompoundMessage) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{6} } +func (*CompoundMessage) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{7} } func (m *CompoundMessage) GetMessages() []*CompoundMessage_SimpleMessage { if m != nil { @@ -279,11 +328,12 @@ type CompoundMessage_SimpleMessage struct { func (m *CompoundMessage_SimpleMessage) Reset() { *m = CompoundMessage_SimpleMessage{} } func (*CompoundMessage_SimpleMessage) ProtoMessage() {} func (*CompoundMessage_SimpleMessage) Descriptor() ([]byte, []int) { - return fileDescriptorNetworkdb, []int{6, 0} + return fileDescriptorNetworkdb, []int{7, 0} } func init() { proto.RegisterType((*GossipMessage)(nil), "networkdb.GossipMessage") + proto.RegisterType((*NodeEvent)(nil), "networkdb.NodeEvent") proto.RegisterType((*NetworkEvent)(nil), "networkdb.NetworkEvent") proto.RegisterType((*NetworkEntry)(nil), "networkdb.NetworkEntry") proto.RegisterType((*NetworkPushPull)(nil), "networkdb.NetworkPushPull") @@ -292,6 +342,7 @@ func init() { proto.RegisterType((*CompoundMessage)(nil), "networkdb.CompoundMessage") proto.RegisterType((*CompoundMessage_SimpleMessage)(nil), "networkdb.CompoundMessage.SimpleMessage") proto.RegisterEnum("networkdb.MessageType", MessageType_name, MessageType_value) + proto.RegisterEnum("networkdb.NodeEvent_Type", NodeEvent_Type_name, NodeEvent_Type_value) proto.RegisterEnum("networkdb.NetworkEvent_Type", NetworkEvent_Type_name, NetworkEvent_Type_value) proto.RegisterEnum("networkdb.TableEvent_Type", TableEvent_Type_name, TableEvent_Type_value) } @@ -306,6 +357,18 @@ func (this *GossipMessage) GoString() string { s = append(s, "}") return strings.Join(s, "") } +func (this *NodeEvent) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 7) + s = append(s, "&networkdb.NodeEvent{") + s = append(s, "Type: "+fmt.Sprintf("%#v", this.Type)+",\n") + s = append(s, "LTime: "+fmt.Sprintf("%#v", this.LTime)+",\n") + s = append(s, "NodeName: "+fmt.Sprintf("%#v", this.NodeName)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} func (this *NetworkEvent) GoString() string { if this == nil { return "nil" @@ -336,12 +399,13 @@ func (this *NetworkPushPull) GoString() string { if this == nil { return "nil" } - s := make([]string, 0, 6) + s := make([]string, 0, 7) s = append(s, "&networkdb.NetworkPushPull{") s = append(s, "LTime: "+fmt.Sprintf("%#v", this.LTime)+",\n") if this.Networks != nil { s = append(s, "Networks: "+fmt.Sprintf("%#v", this.Networks)+",\n") } + s = append(s, "NodeName: "+fmt.Sprintf("%#v", this.NodeName)+",\n") s = append(s, "}") return strings.Join(s, "") } @@ -451,6 +515,40 @@ func (m *GossipMessage) MarshalTo(data []byte) (int, error) { return i, nil } +func (m *NodeEvent) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *NodeEvent) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Type != 0 { + data[i] = 0x8 + i++ + i = encodeVarintNetworkdb(data, i, uint64(m.Type)) + } + if m.LTime != 0 { + data[i] = 0x10 + i++ + i = encodeVarintNetworkdb(data, i, uint64(m.LTime)) + } + if len(m.NodeName) > 0 { + data[i] = 0x1a + i++ + i = encodeVarintNetworkdb(data, i, uint64(len(m.NodeName))) + i += copy(data[i:], m.NodeName) + } + return i, nil +} + func (m *NetworkEvent) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -568,6 +666,12 @@ func (m *NetworkPushPull) MarshalTo(data []byte) (int, error) { i += n } } + if len(m.NodeName) > 0 { + data[i] = 0x1a + i++ + i = encodeVarintNetworkdb(data, i, uint64(len(m.NodeName))) + i += copy(data[i:], m.NodeName) + } return i, nil } @@ -783,6 +887,22 @@ func (m *GossipMessage) Size() (n int) { return n } +func (m *NodeEvent) Size() (n int) { + var l int + _ = l + if m.Type != 0 { + n += 1 + sovNetworkdb(uint64(m.Type)) + } + if m.LTime != 0 { + n += 1 + sovNetworkdb(uint64(m.LTime)) + } + l = len(m.NodeName) + if l > 0 { + n += 1 + l + sovNetworkdb(uint64(l)) + } + return n +} + func (m *NetworkEvent) Size() (n int) { var l int _ = l @@ -835,6 +955,10 @@ func (m *NetworkPushPull) Size() (n int) { n += 1 + l + sovNetworkdb(uint64(l)) } } + l = len(m.NodeName) + if l > 0 { + n += 1 + l + sovNetworkdb(uint64(l)) + } return n } @@ -942,6 +1066,18 @@ func (this *GossipMessage) String() string { }, "") return s } +func (this *NodeEvent) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&NodeEvent{`, + `Type:` + fmt.Sprintf("%v", this.Type) + `,`, + `LTime:` + fmt.Sprintf("%v", this.LTime) + `,`, + `NodeName:` + fmt.Sprintf("%v", this.NodeName) + `,`, + `}`, + }, "") + return s +} func (this *NetworkEvent) String() string { if this == nil { return "nil" @@ -975,6 +1111,7 @@ func (this *NetworkPushPull) String() string { s := strings.Join([]string{`&NetworkPushPull{`, `LTime:` + fmt.Sprintf("%v", this.LTime) + `,`, `Networks:` + strings.Replace(fmt.Sprintf("%v", this.Networks), "NetworkEntry", "NetworkEntry", 1) + `,`, + `NodeName:` + fmt.Sprintf("%v", this.NodeName) + `,`, `}`, }, "") return s @@ -1137,6 +1274,123 @@ func (m *GossipMessage) Unmarshal(data []byte) error { } return nil } +func (m *NodeEvent) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNetworkdb + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NodeEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NodeEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNetworkdb + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + m.Type |= (NodeEvent_Type(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LTime", wireType) + } + m.LTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNetworkdb + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + m.LTime |= (github_com_hashicorp_serf_serf.LamportTime(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NodeName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNetworkdb + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNetworkdb + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NodeName = string(data[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipNetworkdb(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthNetworkdb + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *NetworkEvent) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 @@ -1509,6 +1763,35 @@ func (m *NetworkPushPull) Unmarshal(data []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NodeName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNetworkdb + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNetworkdb + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NodeName = string(data[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipNetworkdb(data[iNdEx:]) @@ -2211,56 +2494,61 @@ var ( ) var fileDescriptorNetworkdb = []byte{ - // 812 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x95, 0x4d, 0x6f, 0xe2, 0x46, - 0x18, 0xc7, 0x31, 0x18, 0x02, 0x0f, 0xd0, 0x20, 0x27, 0x4d, 0x5c, 0xa7, 0x25, 0x91, 0x9b, 0x46, - 0x14, 0x55, 0x4e, 0x95, 0x7c, 0x02, 0x5e, 0xac, 0x96, 0xc4, 0x31, 0xc8, 0x40, 0xaa, 0x9e, 0x90, - 0xc1, 0x53, 0xb0, 0x62, 0x6c, 0x0b, 0x9b, 0x54, 0xdc, 0xaa, 0x9e, 0xa2, 0xde, 0x7a, 0xad, 0xd4, - 0x53, 0x7b, 0xee, 0x07, 0xe8, 0xa1, 0xe7, 0xa8, 0xa7, 0xf6, 0xb6, 0xda, 0x43, 0xb4, 0xc9, 0x27, - 0xd8, 0x8f, 0xb0, 0xe3, 0xc1, 0x86, 0x81, 0x44, 0xb9, 0xec, 0x6a, 0xb5, 0x07, 0xc3, 0xbc, 0xfc, - 0xe6, 0xd1, 0xff, 0x79, 0xe6, 0x3f, 0x33, 0xb0, 0x69, 0x23, 0xff, 0x47, 0x67, 0x72, 0x65, 0xf4, - 0x25, 0x77, 0xe2, 0xf8, 0x0e, 0x97, 0x59, 0x0c, 0x08, 0xdb, 0x43, 0x67, 0xe8, 0x90, 0xd1, 0xe3, - 0xa0, 0x35, 0x07, 0xc4, 0x26, 0xe4, 0xbf, 0x71, 0x3c, 0xcf, 0x74, 0x2f, 0x90, 0xe7, 0xe9, 0x43, - 0xc4, 0x95, 0x81, 0xf5, 0x67, 0x2e, 0xe2, 0x99, 0x03, 0xa6, 0xf4, 0xd1, 0xc9, 0x8e, 0xb4, 0x8c, - 0x18, 0x12, 0x1d, 0x3c, 0xab, 0x11, 0x86, 0xe3, 0x80, 0x35, 0x74, 0x5f, 0xe7, 0xe3, 0x98, 0xcd, - 0x69, 0xa4, 0x2d, 0xde, 0xc7, 0x21, 0xa7, 0xce, 0xd7, 0xc8, 0xd7, 0xc8, 0xf6, 0xb9, 0xaf, 0x57, - 0x02, 0x7e, 0x4a, 0x05, 0xa4, 0x31, 0x89, 0x0a, 0xdb, 0x80, 0x94, 0xd5, 0xf3, 0xcd, 0x31, 0x22, - 0x81, 0xd9, 0xea, 0xc9, 0xed, 0xdd, 0x7e, 0xec, 0xe5, 0xdd, 0x7e, 0x79, 0x68, 0xfa, 0xa3, 0x69, - 0x5f, 0x1a, 0x38, 0xe3, 0xe3, 0x91, 0xee, 0x8d, 0xcc, 0x81, 0x33, 0x71, 0x8f, 0x3d, 0x34, 0xf9, - 0x81, 0xfc, 0x48, 0x8a, 0x3e, 0x76, 0x9d, 0x89, 0xdf, 0xc1, 0x2b, 0xb5, 0xa4, 0x15, 0xfc, 0x71, - 0x7b, 0x90, 0xb1, 0x1d, 0x03, 0xf5, 0x6c, 0x1d, 0x47, 0x4b, 0xe0, 0x68, 0x19, 0x2d, 0x1d, 0x0c, - 0xa8, 0xb8, 0xcf, 0x7d, 0x05, 0x10, 0x8a, 0xe9, 0x99, 0x06, 0xcf, 0x06, 0xb3, 0xd5, 0xfc, 0xc3, - 0xdd, 0x7e, 0x26, 0x14, 0xd6, 0xa8, 0x6b, 0x51, 0xfd, 0x1a, 0x86, 0x78, 0xc3, 0x00, 0x1b, 0x88, - 0xe4, 0x4a, 0xb0, 0xd1, 0x50, 0x2f, 0x2b, 0x4a, 0xa3, 0x5e, 0x88, 0x09, 0x7b, 0xbf, 0xfc, 0x7e, - 0xb0, 0x4b, 0x27, 0x12, 0x20, 0x0d, 0xfb, 0x5a, 0xb7, 0x4c, 0x83, 0x13, 0x81, 0x3d, 0x6b, 0x36, - 0xd4, 0x02, 0x23, 0xf0, 0x18, 0xdb, 0x5e, 0xc7, 0xce, 0x1c, 0xd3, 0xe6, 0x0e, 0x21, 0xa9, 0xc8, - 0x95, 0x4b, 0xb9, 0x10, 0x17, 0x3e, 0xc1, 0xd0, 0xc7, 0xeb, 0x90, 0x82, 0xf4, 0x6b, 0x24, 0xe4, - 0x6e, 0xfe, 0x28, 0xc6, 0xfe, 0xfe, 0xb3, 0x48, 0x14, 0x88, 0xff, 0x30, 0xcb, 0x1a, 0xdb, 0xfe, - 0x64, 0xb6, 0x96, 0x09, 0xf3, 0x7c, 0x26, 0xef, 0xad, 0xbe, 0x3c, 0x6c, 0x58, 0x58, 0xbd, 0x69, - 0x0f, 0x49, 0x71, 0xd3, 0x5a, 0xd4, 0x15, 0x7f, 0x65, 0x60, 0x33, 0x94, 0xd6, 0x9a, 0x7a, 0xa3, - 0xd6, 0xd4, 0xb2, 0x28, 0x55, 0xcc, 0xdb, 0xaa, 0x3a, 0x85, 0x74, 0x98, 0xad, 0x87, 0x53, 0x4c, - 0x94, 0xb2, 0x27, 0xbb, 0x4f, 0xd8, 0x2e, 0xa8, 0x9c, 0xb6, 0x00, 0xc5, 0x7f, 0x13, 0x00, 0x1d, - 0xbd, 0x6f, 0xa1, 0xb9, 0x6d, 0xa5, 0x15, 0xdb, 0x0a, 0xd4, 0xfa, 0x25, 0xf4, 0xc1, 0x9b, 0x96, - 0xfb, 0x0c, 0xc0, 0x0f, 0xe4, 0xce, 0x63, 0x25, 0x49, 0xac, 0x0c, 0x19, 0x21, 0xc1, 0x0a, 0x90, - 0xb8, 0x42, 0x33, 0x3e, 0x45, 0xc6, 0x83, 0x26, 0xb7, 0x0d, 0x49, 0xec, 0xdd, 0x29, 0xe2, 0x37, - 0xc8, 0x99, 0x9e, 0x77, 0xc4, 0xbf, 0x22, 0xef, 0x1f, 0xd1, 0xde, 0x27, 0x7e, 0x5d, 0x56, 0x83, - 0x76, 0xfe, 0x21, 0xa4, 0x6a, 0x9a, 0x5c, 0xe9, 0xc8, 0x91, 0xf7, 0x57, 0xb1, 0xda, 0x04, 0xe9, - 0x3e, 0x0a, 0xa8, 0x6e, 0xab, 0x1e, 0x50, 0xf1, 0xa7, 0xa8, 0xae, 0x6b, 0x84, 0x54, 0x5d, 0x56, - 0x64, 0x4c, 0x25, 0x9e, 0xa2, 0xea, 0xc8, 0x42, 0xfe, 0xfa, 0x09, 0xf9, 0x1f, 0x1b, 0xac, 0x3a, - 0xb5, 0xae, 0xda, 0x33, 0x7b, 0x10, 0xdd, 0x6c, 0xef, 0xd0, 0x60, 0x07, 0x90, 0x9d, 0xda, 0x9e, - 0x63, 0x99, 0x03, 0xd3, 0x47, 0x06, 0xd9, 0xf1, 0xb4, 0x46, 0x0f, 0x3d, 0xbf, 0x87, 0x02, 0xe5, - 0x4f, 0x16, 0xfb, 0x33, 0xb3, 0xb4, 0x61, 0x70, 0x68, 0x5c, 0x7d, 0x66, 0x39, 0xba, 0x41, 0xb6, - 0x2b, 0xa7, 0x45, 0x5d, 0xf1, 0x67, 0x9c, 0x53, 0xcd, 0xc1, 0x5a, 0xa6, 0xb6, 0x11, 0xe5, 0x54, - 0x87, 0xf4, 0x78, 0xde, 0xf4, 0x70, 0x56, 0x81, 0xd3, 0x4b, 0x94, 0x53, 0xd7, 0x68, 0xa9, 0x6d, - 0x8e, 0x5d, 0x0b, 0x85, 0x3d, 0x6d, 0xb1, 0x52, 0xf8, 0x12, 0xf2, 0x2b, 0x53, 0x81, 0x88, 0x56, - 0x28, 0x82, 0x59, 0x11, 0x51, 0xfe, 0x2d, 0x0e, 0x59, 0xea, 0x21, 0xe0, 0x3e, 0xa7, 0x0d, 0xb1, - 0x83, 0x77, 0x87, 0xa3, 0x66, 0x23, 0x37, 0x48, 0x90, 0x57, 0xe5, 0xce, 0x77, 0x4d, 0xed, 0xbc, - 0x27, 0x5f, 0xca, 0x6a, 0x07, 0x9b, 0x82, 0xdc, 0x9b, 0x14, 0xba, 0xf2, 0x64, 0x94, 0x21, 0xdb, - 0xa9, 0x54, 0x15, 0x39, 0xa4, 0xc3, 0x9b, 0x91, 0xa2, 0xa9, 0x73, 0x7a, 0x04, 0x99, 0x56, 0xb7, - 0xfd, 0x6d, 0xaf, 0xd5, 0x55, 0x14, 0x6c, 0x90, 0x5d, 0x4c, 0x6e, 0x51, 0xe4, 0xe2, 0x7a, 0xc1, - 0x5c, 0xb5, 0xab, 0x9c, 0xf7, 0xda, 0xdf, 0xab, 0xb5, 0x02, 0xfb, 0x88, 0x8b, 0xcc, 0xc2, 0x7d, - 0x01, 0xe9, 0x5a, 0xf3, 0xa2, 0xd5, 0xec, 0xaa, 0xf5, 0x42, 0xf2, 0x11, 0x16, 0x55, 0x54, 0xd8, - 0x0a, 0xed, 0x46, 0x17, 0xa3, 0xca, 0xbf, 0xb8, 0x2f, 0xc6, 0x5e, 0xdf, 0x17, 0x99, 0x9f, 0x1e, - 0x8a, 0xcc, 0x2d, 0xfe, 0xfe, 0xc3, 0xdf, 0x2b, 0xfc, 0xf5, 0x53, 0xe4, 0xb5, 0x3d, 0x7d, 0x13, - 0x00, 0x00, 0xff, 0xff, 0x7d, 0x9c, 0x5f, 0x56, 0xa1, 0x07, 0x00, 0x00, + // 887 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x96, 0xc1, 0x6e, 0xe3, 0x44, + 0x18, 0xc7, 0xeb, 0xc4, 0x49, 0xe3, 0xaf, 0x0d, 0x1b, 0xbc, 0xdd, 0xad, 0xd7, 0x0b, 0x49, 0x31, + 0xcb, 0x2a, 0x44, 0xe0, 0xa2, 0xee, 0x13, 0x24, 0xb1, 0x05, 0xd9, 0xf5, 0x3a, 0x91, 0x93, 0x14, + 0x71, 0x8a, 0x9c, 0x78, 0x48, 0xac, 0x3a, 0xb6, 0x15, 0x3b, 0x45, 0x39, 0x81, 0x38, 0xad, 0x78, + 0x07, 0x4e, 0xcb, 0x99, 0x07, 0xe0, 0xc0, 0x89, 0xc3, 0x8a, 0x13, 0xdc, 0x10, 0x87, 0x8a, 0xee, + 0x13, 0xf0, 0x08, 0x8c, 0xc7, 0x76, 0x32, 0x4e, 0xa3, 0x5e, 0x40, 0xc0, 0xc1, 0xad, 0x67, 0xe6, + 0xe7, 0xcf, 0xdf, 0xf7, 0x9f, 0xff, 0xe7, 0x09, 0xdc, 0x71, 0x51, 0xf8, 0x85, 0xb7, 0xb8, 0xb0, + 0xc6, 0xb2, 0xbf, 0xf0, 0x42, 0x8f, 0xe7, 0xd6, 0x13, 0xe2, 0xd1, 0xd4, 0x9b, 0x7a, 0x64, 0xf6, + 0x34, 0xba, 0x8b, 0x01, 0xa9, 0x0b, 0xe5, 0x8f, 0xbd, 0x20, 0xb0, 0xfd, 0xe7, 0x28, 0x08, 0xcc, + 0x29, 0xe2, 0x1b, 0xc0, 0x86, 0x2b, 0x1f, 0x09, 0xcc, 0x09, 0x53, 0x7f, 0xe3, 0xec, 0xbe, 0xbc, + 0x89, 0x98, 0x10, 0x03, 0xbc, 0x6a, 0x10, 0x86, 0xe7, 0x81, 0xb5, 0xcc, 0xd0, 0x14, 0x72, 0x98, + 0x3d, 0x34, 0xc8, 0xbd, 0xf4, 0x32, 0x07, 0x9c, 0xee, 0x59, 0x48, 0xbd, 0x44, 0x6e, 0xc8, 0x7f, + 0x98, 0x89, 0xf6, 0x80, 0x8a, 0xb6, 0x66, 0x64, 0x2a, 0x60, 0x07, 0x8a, 0xce, 0x28, 0xb4, 0xe7, + 0x88, 0x84, 0x64, 0x5b, 0x67, 0xaf, 0xae, 0x6a, 0x7b, 0xbf, 0x5f, 0xd5, 0x1a, 0x53, 0x3b, 0x9c, + 0x2d, 0xc7, 0xf2, 0xc4, 0x9b, 0x9f, 0xce, 0xcc, 0x60, 0x66, 0x4f, 0xbc, 0x85, 0x7f, 0x1a, 0xa0, + 0xc5, 0xe7, 0xe4, 0x8f, 0xac, 0x99, 0x73, 0xdf, 0x5b, 0x84, 0x03, 0xfc, 0xa4, 0x51, 0x70, 0xa2, + 0x7f, 0xfc, 0x43, 0xe0, 0x5c, 0xfc, 0x8a, 0x91, 0x6b, 0xe2, 0x68, 0x79, 0x1c, 0x8d, 0x33, 0x4a, + 0xd1, 0x84, 0x8e, 0xc7, 0xd2, 0x97, 0xc0, 0x46, 0x6f, 0xe5, 0xdf, 0x83, 0xfd, 0x8e, 0x7e, 0xde, + 0xd4, 0x3a, 0x4a, 0x65, 0x4f, 0x14, 0xbe, 0xf9, 0xf6, 0xe4, 0x68, 0x9d, 0x56, 0xb4, 0xde, 0x71, + 0x2f, 0x4d, 0xc7, 0xb6, 0xf8, 0x1a, 0xb0, 0x4f, 0xbb, 0x1d, 0xbd, 0xc2, 0x88, 0xf7, 0x30, 0xf3, + 0x66, 0x86, 0x79, 0xea, 0xd9, 0x2e, 0xff, 0x0e, 0x14, 0x34, 0xb5, 0x79, 0xae, 0x56, 0x72, 0xe2, + 0x7d, 0x4c, 0xf0, 0x19, 0x42, 0x43, 0xe6, 0x25, 0x12, 0x0f, 0x5f, 0xbc, 0xac, 0xee, 0xfd, 0xf0, + 0x5d, 0x95, 0xbc, 0x58, 0xba, 0xce, 0xc1, 0xa1, 0x1e, 0x6b, 0x11, 0x0b, 0xf5, 0x51, 0x46, 0xa8, + 0xb7, 0x68, 0xa1, 0x28, 0xec, 0x3f, 0xd0, 0x8a, 0xff, 0x00, 0x20, 0x49, 0x66, 0x64, 0x5b, 0x02, + 0x1b, 0xad, 0xb6, 0xca, 0xaf, 0xaf, 0x6a, 0x5c, 0x92, 0x58, 0x47, 0x31, 0x52, 0x97, 0x75, 0x2c, + 0xe9, 0x05, 0x93, 0x48, 0x5b, 0xa7, 0xa5, 0x7d, 0x88, 0x45, 0x39, 0xa6, 0x0b, 0xa1, 0xd5, 0x95, + 0xd6, 0xea, 0xc6, 0x3b, 0xb0, 0x85, 0x11, 0x81, 0x1f, 0x6d, 0x04, 0x7e, 0x80, 0xa1, 0x7b, 0xdb, + 0xd0, 0x2e, 0x8d, 0x7f, 0x64, 0x36, 0x1a, 0xbb, 0xe1, 0x62, 0xb5, 0x55, 0x09, 0x73, 0x7b, 0x25, + 0xff, 0x9a, 0xbe, 0x02, 0xec, 0x3b, 0x38, 0x7b, 0xdb, 0x9d, 0x12, 0x71, 0x4b, 0x46, 0x3a, 0x94, + 0xbe, 0x67, 0xe0, 0x4e, 0x92, 0x5a, 0x6f, 0x19, 0xcc, 0x7a, 0x4b, 0xc7, 0xa1, 0xb2, 0x62, 0xfe, + 0x6e, 0x56, 0x4f, 0xa0, 0x94, 0x54, 0x1b, 0xe0, 0x12, 0xf3, 0xf5, 0x83, 0xb3, 0xe3, 0x1d, 0xb6, + 0x8b, 0x94, 0x33, 0xd6, 0xe0, 0xed, 0x6d, 0xf5, 0x73, 0x1e, 0x60, 0x60, 0x8e, 0x9d, 0xa4, 0xf9, + 0xe5, 0x8c, 0xa7, 0x45, 0x2a, 0xf8, 0x06, 0xfa, 0xdf, 0x3b, 0x9a, 0x7f, 0x1b, 0x20, 0x8c, 0xd2, + 0x8d, 0x63, 0x15, 0x48, 0x2c, 0x8e, 0xcc, 0x90, 0x60, 0x15, 0xc8, 0x5f, 0xa0, 0x95, 0x50, 0x24, + 0xf3, 0xd1, 0x2d, 0x7f, 0x04, 0x05, 0x6c, 0xec, 0x25, 0x12, 0xf6, 0xc9, 0x67, 0x31, 0x1e, 0x44, + 0x9b, 0x19, 0x37, 0xc6, 0x63, 0xba, 0x31, 0x88, 0x99, 0x37, 0x6a, 0xd0, 0x6d, 0xf1, 0x08, 0x8a, + 0x6d, 0x43, 0x6d, 0x0e, 0xd4, 0xb4, 0x31, 0xb2, 0x58, 0x7b, 0x81, 0xcc, 0x10, 0x45, 0xd4, 0xb0, + 0xa7, 0x44, 0x54, 0x6e, 0x17, 0x35, 0xf4, 0xad, 0x84, 0x52, 0x54, 0x4d, 0xc5, 0x54, 0x7e, 0x17, + 0xa5, 0x20, 0x07, 0x85, 0xdb, 0xed, 0xf3, 0x2b, 0x76, 0x5f, 0x6b, 0xe9, 0x5c, 0xf4, 0x57, 0xee, + 0x24, 0x3d, 0x1c, 0xfe, 0x41, 0xf7, 0x9d, 0xc0, 0xc1, 0xd2, 0x0d, 0x3c, 0xc7, 0x9e, 0xd8, 0x21, + 0xb2, 0xc8, 0x8e, 0x97, 0x0c, 0x7a, 0xea, 0xf6, 0x3d, 0x14, 0x29, 0xf3, 0xb2, 0xd8, 0xbc, 0x1c, + 0xe5, 0x51, 0xdc, 0x51, 0xbe, 0xb9, 0x72, 0x3c, 0xd3, 0x22, 0xdb, 0x75, 0x68, 0xa4, 0x43, 0xe9, + 0x6b, 0x5c, 0x53, 0xdb, 0xc3, 0xb9, 0x2c, 0x5d, 0x2b, 0xad, 0x49, 0x81, 0xd2, 0x3c, 0xbe, 0x0d, + 0x70, 0x55, 0x51, 0x1b, 0xd4, 0x29, 0xa7, 0x6e, 0xd1, 0x72, 0xdf, 0x9e, 0xfb, 0x0e, 0x4a, 0x46, + 0xc6, 0xfa, 0x49, 0xf1, 0x7d, 0x28, 0x67, 0x96, 0xa2, 0x24, 0x7a, 0x49, 0x12, 0x4c, 0x26, 0x89, + 0xc6, 0x4f, 0x39, 0x38, 0xa0, 0xce, 0x52, 0xfe, 0x5d, 0xda, 0x10, 0xe4, 0xf8, 0xa0, 0x56, 0x53, + 0x37, 0xc8, 0x50, 0xd6, 0xd5, 0xc1, 0xa7, 0x5d, 0xe3, 0xd9, 0x48, 0x3d, 0x57, 0xf5, 0x01, 0x36, + 0x05, 0xf9, 0xa8, 0x52, 0x68, 0xe6, 0x3c, 0x69, 0xc0, 0xc1, 0xa0, 0xd9, 0xd2, 0xd4, 0x84, 0x4e, + 0x3e, 0x9b, 0x14, 0x4d, 0xf5, 0xe9, 0x63, 0xe0, 0x7a, 0xc3, 0xfe, 0x27, 0xa3, 0xde, 0x50, 0xd3, + 0xb0, 0x41, 0x8e, 0x31, 0x79, 0x97, 0x22, 0xd7, 0xdf, 0x1e, 0xcc, 0xb5, 0x86, 0xda, 0xb3, 0x51, + 0xff, 0x33, 0xbd, 0x5d, 0x61, 0x6f, 0x70, 0xa9, 0x59, 0xf0, 0xa9, 0x5a, 0x6a, 0x77, 0x9f, 0xf7, + 0xba, 0x43, 0x5d, 0xa9, 0x14, 0x6e, 0x60, 0xa9, 0xa2, 0xf8, 0x84, 0x00, 0xbd, 0xab, 0xa4, 0x19, + 0x16, 0x63, 0x63, 0xd2, 0xf5, 0xa4, 0x87, 0xa8, 0x78, 0x37, 0x31, 0x26, 0x2d, 0x5b, 0x4b, 0xf8, + 0xed, 0xba, 0xba, 0xf7, 0xe7, 0x75, 0x95, 0xf9, 0xea, 0x75, 0x95, 0x79, 0x85, 0xaf, 0x5f, 0xf0, + 0xf5, 0x07, 0xbe, 0xc6, 0x45, 0xf2, 0xd3, 0xe6, 0xc9, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x21, + 0x78, 0x72, 0xc3, 0x0e, 0x09, 0x00, 0x00, } diff --git a/networkdb/networkdb.proto b/networkdb/networkdb.proto index dbc7a921d0..7df1b42dca 100644 --- a/networkdb/networkdb.proto +++ b/networkdb/networkdb.proto @@ -41,6 +41,10 @@ enum MessageType { // which is a pack of many message of above types, packed into // a single compound message. COMPOUND = 5 [(gogoproto.enumvalue_customname) = "MessageTypeCompound"]; + + // NodeEvent message type is used to communicare node + // join/leave events in the cluster + NODE_EVENT = 6 [(gogoproto.enumvalue_customname) = "MessageTypeNodeEvent"]; } // GossipMessage is a basic message header used by all messages types. @@ -49,6 +53,29 @@ message GossipMessage { bytes data = 2; // Payload of the message of any type defined here. } +// NodeEvent message payload definition. +message NodeEvent { + enum Type { + option (gogoproto.goproto_enum_prefix) = false; + option (gogoproto.enum_customname) = "Type"; + + INVALID = 0 [(gogoproto.enumvalue_customname) = "NodeEventTypeInvalid"]; + // Join event is generated when this node joins the cluster. + JOIN = 1 [(gogoproto.enumvalue_customname) = "NodeEventTypeJoin"];; + // Leave event is generated when this node leaves the cluster. + LEAVE = 2 [(gogoproto.enumvalue_customname) = "NodeEventTypeLeave"];; + } + + Type type = 1; + + // Lamport time using a network lamport clock indicating the + // time this event was generated on the node where it was + // generated. + uint64 l_time = 2 [(gogoproto.customtype) = "github.com/hashicorp/serf/serf.LamportTime", (gogoproto.nullable) = false]; + // Source node name. + string node_name = 3; +} + // NetworkEvent message payload definition. message NetworkEvent { enum Type { From 52d17c571799380c3a6f4aa7e7243b00590fa934 Mon Sep 17 00:00:00 2001 From: msabansal Date: Mon, 19 Sep 2016 15:48:06 -0700 Subject: [PATCH 078/799] DNS support Signed-off-by: msabansal --- controller.go | 2 + drivers/windows/labels.go | 15 ++++ drivers/windows/windows.go | 70 ++++++++++++++++- drivers/windows/windows_test.go | 2 +- endpoint.go | 8 ++ libnetwork_internal_test.go | 14 ++-- libnetwork_test.go | 4 +- netlabel/labels.go | 3 + network.go | 128 ++++++++++++++++++++++++++++++++ network_unix.go | 8 ++ network_windows.go | 52 +++++++++++++ resolver.go | 104 ++++++++++++++++++-------- resolver_unix.go | 4 +- sandbox.go | 119 +++++++---------------------- sandbox_dns_unix.go | 4 +- 15 files changed, 396 insertions(+), 141 deletions(-) create mode 100644 network_unix.go create mode 100644 network_windows.go diff --git a/controller.go b/controller.go index 039c80acb7..ba94622fb9 100644 --- a/controller.go +++ b/controller.go @@ -804,6 +804,8 @@ func (c *controller) addNetwork(n *network) error { return err } + n.startResolver() + return nil } diff --git a/drivers/windows/labels.go b/drivers/windows/labels.go index f1b77bf334..5740913c04 100644 --- a/drivers/windows/labels.go +++ b/drivers/windows/labels.go @@ -15,4 +15,19 @@ const ( // QosPolicies of the endpoint QosPolicies = "com.docker.endpoint.windowsshim.qospolicies" + + // VLAN of the network + VLAN = "com.docker.network.windowsshim.vlanid" + + // VSID of the network + VSID = "com.docker.network.windowsshim.vsid" + + // DNSSuffix of the network + DNSSuffix = "com.docker.network.windowsshim.dnssuffix" + + // DNSServers of the network + DNSServers = "com.docker.network.windowsshim.dnsservers" + + // SourceMac of the network + SourceMac = "com.docker.network.windowsshim.sourcemac" ) diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index aa4c7e5808..ed6f7c2f26 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -15,6 +15,7 @@ import ( "encoding/json" "fmt" "net" + "strconv" "strings" "sync" @@ -34,6 +35,11 @@ type networkConfiguration struct { Name string HnsID string RDID string + VLAN uint + VSID uint + DNSServers string + DNSSuffix string + SourceMac string NetworkAdapterName string } @@ -43,6 +49,7 @@ type endpointConfiguration struct { PortBindings []types.PortBinding ExposedPorts []types.TransportPort QosPolicies []types.QosPolicy + DNSServers []string } type hnsEndpoint struct { @@ -69,7 +76,7 @@ type driver struct { } func isValidNetworkType(networkType string) bool { - if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "transparent" == networkType { + if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "ics" == networkType || "transparent" == networkType { return true } @@ -129,6 +136,22 @@ func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string config.RDID = value case Interface: config.NetworkAdapterName = value + case DNSSuffix: + config.DNSSuffix = value + case DNSServers: + config.DNSServers = value + case VLAN: + vlan, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return nil, err + } + config.VLAN = uint(vlan) + case VSID: + vsid, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return nil, err + } + config.VSID = uint(vsid) } } @@ -207,9 +230,36 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d Name: config.Name, Type: d.name, Subnets: subnets, + DNSServerList: config.DNSServers, + DNSSuffix: config.DNSSuffix, + SourceMac: config.SourceMac, NetworkAdapterName: config.NetworkAdapterName, } + if config.VLAN != 0 { + vlanPolicy, err := json.Marshal(hcsshim.VlanPolicy{ + Type: "VLAN", + VLAN: config.VLAN, + }) + + if err != nil { + return err + } + network.Policies = append(network.Policies, vlanPolicy) + } + + if config.VSID != 0 { + vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{ + Type: "VSID", + VSID: config.VSID, + }) + + if err != nil { + return err + } + network.Policies = append(network.Policies, vsidPolicy) + } + if network.Name == "" { network.Name = id } @@ -379,6 +429,14 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfigurat } } + if opt, ok := epOptions[netlabel.DNSServers]; ok { + if dns, ok := opt.([]string); ok { + ec.DNSServers = dns + } else { + return nil, fmt.Errorf("Invalid endpoint configuration") + } + } + return ec, nil } @@ -421,6 +479,12 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, endpointStruct.IPAddress = ifInfo.Address().IP } + endpointStruct.DNSServerList = strings.Join(ec.DNSServers, ",") + + if n.driver.name == "nat" { + endpointStruct.EnableInternalDNS = true + } + configurationb, err := json.Marshal(endpointStruct) if err != nil { return err @@ -502,6 +566,10 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro } data := make(map[string]interface{}, 1) + if network.driver.name == "nat" { + data["AllowUnqualifiedDNSQuery"] = true + } + data["hnsid"] = ep.profileID if ep.config.ExposedPorts != nil { // Return a copy of the config data diff --git a/drivers/windows/windows_test.go b/drivers/windows/windows_test.go index 696aecec0f..a43355349e 100644 --- a/drivers/windows/windows_test.go +++ b/drivers/windows/windows_test.go @@ -29,7 +29,7 @@ func testNetwork(networkType string, t *testing.T) { }, } - err := d.CreateNetwork("dummy", netOption, ipdList, nil) + err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil) if err != nil { t.Fatalf("Failed to create bridge: %v", err) } diff --git a/endpoint.go b/endpoint.go index 44893573ff..1c75b6fea5 100644 --- a/endpoint.go +++ b/endpoint.go @@ -883,6 +883,14 @@ func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption { } } +// CreateOptionDNS function returns an option setter for dns entry option to +// be passed to container Create method. +func CreateOptionDNS(dns []string) EndpointOption { + return func(ep *endpoint) { + ep.generic[netlabel.DNSServers] = dns + } +} + // CreateOptionAnonymous function returns an option setter for setting // this endpoint as anonymous func CreateOptionAnonymous() EndpointOption { diff --git a/libnetwork_internal_test.go b/libnetwork_internal_test.go index 9eb7f6bab5..8bb4881cc6 100644 --- a/libnetwork_internal_test.go +++ b/libnetwork_internal_test.go @@ -389,10 +389,8 @@ func TestSRVServiceQuery(t *testing.T) { c.(*controller).svcRecords[n.ID()] = sr - _, ip, err := ep.Info().Sandbox().ResolveService("_http._tcp.web.swarm") - if err != nil { - t.Fatal(err) - } + _, ip := ep.Info().Sandbox().ResolveService("_http._tcp.web.swarm") + if len(ip) == 0 { t.Fatal(err) } @@ -400,10 +398,8 @@ func TestSRVServiceQuery(t *testing.T) { t.Fatal(err) } - _, ip, err = ep.Info().Sandbox().ResolveService("_host_http._tcp.web.swarm") - if err != nil { - t.Fatal(err) - } + _, ip = ep.Info().Sandbox().ResolveService("_host_http._tcp.web.swarm") + if len(ip) == 0 { t.Fatal(err) } @@ -412,7 +408,7 @@ func TestSRVServiceQuery(t *testing.T) { } // Service name with invalid protocol name. Should fail without error - _, ip, err = ep.Info().Sandbox().ResolveService("_http._icmp.web.swarm") + _, ip = ep.Info().Sandbox().ResolveService("_http._icmp.web.swarm") if len(ip) != 0 { t.Fatal("Valid response for invalid service name") } diff --git a/libnetwork_test.go b/libnetwork_test.go index eb09a1673f..6d59f303e4 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -1208,8 +1208,8 @@ func (f *fakeSandbox) ResolveIP(ip string) string { return "" } -func (f *fakeSandbox) ResolveService(name string) ([]*net.SRV, []net.IP, error) { - return nil, nil, nil +func (f *fakeSandbox) ResolveService(name string) ([]*net.SRV, []net.IP) { + return nil, nil } func (f *fakeSandbox) Endpoints() []libnetwork.Endpoint { diff --git a/netlabel/labels.go b/netlabel/labels.go index 7d5c35579b..49ba3081d3 100644 --- a/netlabel/labels.go +++ b/netlabel/labels.go @@ -27,6 +27,9 @@ const ( // ExposedPorts constant represents the container's Exposed Ports ExposedPorts = Prefix + ".endpoint.exposedports" + // DNSServers A list of DNS servers associated with the endpoint + DNSServers = Prefix + ".endpoint.dnsservers" + //EnableIPv6 constant represents enabling IPV6 at network level EnableIPv6 = Prefix + ".enable_ipv6" diff --git a/network.go b/network.go index 2cd857a462..6b35bc628b 100644 --- a/network.go +++ b/network.go @@ -184,6 +184,8 @@ type network struct { persist bool stopWatchCh chan struct{} drvOnce *sync.Once + resolverOnce sync.Once + resolver []Resolver internal bool inDelete bool ingress bool @@ -803,6 +805,9 @@ func (n *network) deleteNetwork() error { } } + for _, resolver := range n.resolver { + resolver.Stop() + } return nil } @@ -1528,3 +1533,126 @@ func (n *network) TableEventRegister(tableName string) error { func (n *network) hasSpecialDriver() bool { return n.Type() == "host" || n.Type() == "null" } + +func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) { + var ipv6Miss bool + + c := n.getController() + c.Lock() + sr, ok := c.svcRecords[n.ID()] + c.Unlock() + + if !ok { + return nil, false + } + + req = strings.TrimSuffix(req, ".") + var ip []net.IP + n.Lock() + ip, ok = sr.svcMap[req] + + if ipType == types.IPv6 { + // If the name resolved to v4 address then its a valid name in + // the docker network domain. If the network is not v6 enabled + // set ipv6Miss to filter the DNS query from going to external + // resolvers. + if ok && n.enableIPv6 == false { + ipv6Miss = true + } + ip = sr.svcIPv6Map[req] + } + n.Unlock() + + if ip != nil { + return ip, false + } + + return nil, ipv6Miss +} + +func (n *network) ResolveIP(ip string) string { + var svc string + + c := n.getController() + c.Lock() + sr, ok := c.svcRecords[n.ID()] + c.Unlock() + + if !ok { + return "" + } + + nwName := n.Name() + + n.Lock() + defer n.Unlock() + svc, ok = sr.ipMap[ip] + + if ok { + return svc + "." + nwName + } + + return svc +} + +func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) { + c := n.getController() + + srv := []*net.SRV{} + ip := []net.IP{} + + log.Debugf("Service name To resolve: %v", name) + + // There are DNS implementaions that allow SRV queries for names not in + // the format defined by RFC 2782. Hence specific validations checks are + // not done + parts := strings.Split(name, ".") + if len(parts) < 3 { + return nil, nil + } + + portName := parts[0] + proto := parts[1] + svcName := strings.Join(parts[2:], ".") + + c.Lock() + sr, ok := c.svcRecords[n.ID()] + c.Unlock() + + if !ok { + return nil, nil + } + + svcs, ok := sr.service[svcName] + if !ok { + return nil, nil + } + + for _, svc := range svcs { + if svc.portName != portName { + continue + } + if svc.proto != proto { + continue + } + for _, t := range svc.target { + srv = append(srv, + &net.SRV{ + Target: t.name, + Port: t.port, + }) + + ip = append(ip, t.ip) + } + } + + return srv, ip +} + +func (n *network) ExecFunc(f func()) error { + return types.NotImplementedErrorf("ExecFunc not supported by network") +} + +func (n *network) NdotsSet() bool { + return false +} diff --git a/network_unix.go b/network_unix.go new file mode 100644 index 0000000000..77b6e1ce97 --- /dev/null +++ b/network_unix.go @@ -0,0 +1,8 @@ +// +build !windows + +package libnetwork + +// Stub implementations for DNS related functions + +func (n *network) startResolver() { +} diff --git a/network_windows.go b/network_windows.go new file mode 100644 index 0000000000..f529d5b799 --- /dev/null +++ b/network_windows.go @@ -0,0 +1,52 @@ +// +build windows + +package libnetwork + +import ( + "runtime" + + "github.com/Microsoft/hcsshim" + log "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/drivers/windows" +) + +func executeInCompartment(compartmentID uint32, x func()) { + runtime.LockOSThread() + + if err := hcsshim.SetCurrentThreadCompartmentId(compartmentID); err != nil { + log.Error(err) + } + defer func() { + hcsshim.SetCurrentThreadCompartmentId(0) + runtime.UnlockOSThread() + }() + + x() +} + +func (n *network) startResolver() { + n.resolverOnce.Do(func() { + log.Debugf("Launching DNS server for network", n.Name()) + options := n.Info().DriverOptions() + hnsid := options[windows.HNSID] + + hnsresponse, err := hcsshim.HNSNetworkRequest("GET", hnsid, "") + if err != nil { + log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) + return + } + + for _, subnet := range hnsresponse.Subnets { + if subnet.GatewayAddress != "" { + resolver := NewResolver(subnet.GatewayAddress, false, "", n) + log.Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress) + executeInCompartment(hnsresponse.DNSServerCompartment, resolver.SetupFunc(53)) + if err = resolver.Start(); err != nil { + log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) + } else { + n.resolver = append(n.resolver, resolver) + } + } + } + }) +} diff --git a/resolver.go b/resolver.go index fcb1a00a02..81b3520ae2 100644 --- a/resolver.go +++ b/resolver.go @@ -23,7 +23,7 @@ type Resolver interface { Stop() // SetupFunc() provides the setup function that should be run // in the container's network namespace. - SetupFunc() func() + SetupFunc(int) func() // NameServer() returns the IP of the DNS resolver for the // containers. NameServer() string @@ -34,8 +34,29 @@ type Resolver interface { ResolverOptions() []string } +// DNSBackend represents a backend DNS resolver used for DNS name +// resolution. All the queries to the resolver are forwared to the +// backend resolver. +type DNSBackend interface { + // ResolveName resolves a service name to an IPv4 or IPv6 address by searching + // the networks the sandbox is connected to. For IPv6 queries, second return + // value will be true if the name exists in docker domain but doesn't have an + // IPv6 address. Such queries shouldn't be forwarded to external nameservers. + ResolveName(name string, iplen int) ([]net.IP, bool) + // ResolveIP returns the service name for the passed in IP. IP is in reverse dotted + // notation; the format used for DNS PTR records + ResolveIP(name string) string + // ResolveService returns all the backend details about the containers or hosts + // backing a service. Its purpose is to satisfy an SRV query + ResolveService(name string) ([]*net.SRV, []net.IP) + // ExecFunc allows a function to be executed in the context of the backend + // on behalf of the resolver. + ExecFunc(f func()) error + //NdotsSet queries the backends ndots dns option settings + NdotsSet() bool +} + const ( - resolverIP = "127.0.0.11" dnsPort = "53" ptrIPv4domain = ".in-addr.arpa." ptrIPv6domain = ".ip6.arpa." @@ -53,16 +74,19 @@ type extDNSEntry struct { // resolver implements the Resolver interface type resolver struct { - sb *sandbox - extDNSList [maxExtDNS]extDNSEntry - server *dns.Server - conn *net.UDPConn - tcpServer *dns.Server - tcpListen *net.TCPListener - err error - count int32 - tStamp time.Time - queryLock sync.Mutex + backend DNSBackend + extDNSList [maxExtDNS]extDNSEntry + server *dns.Server + conn *net.UDPConn + tcpServer *dns.Server + tcpListen *net.TCPListener + err error + count int32 + tStamp time.Time + queryLock sync.Mutex + listenAddress string + proxyDNS bool + resolverKey string } func init() { @@ -70,20 +94,24 @@ func init() { } // NewResolver creates a new instance of the Resolver -func NewResolver(sb *sandbox) Resolver { +func NewResolver(address string, proxyDNS bool, resolverKey string, backend DNSBackend) Resolver { return &resolver{ - sb: sb, - err: fmt.Errorf("setup not done yet"), + backend: backend, + proxyDNS: proxyDNS, + listenAddress: address, + resolverKey: resolverKey, + err: fmt.Errorf("setup not done yet"), } } -func (r *resolver) SetupFunc() func() { +func (r *resolver) SetupFunc(port int) func() { return (func() { var err error // DNS operates primarily on UDP addr := &net.UDPAddr{ - IP: net.ParseIP(resolverIP), + IP: net.ParseIP(r.listenAddress), + Port: port, } r.conn, err = net.ListenUDP("udp", addr) @@ -94,7 +122,8 @@ func (r *resolver) SetupFunc() func() { // Listen on a TCP as well tcpaddr := &net.TCPAddr{ - IP: net.ParseIP(resolverIP), + IP: net.ParseIP(r.listenAddress), + Port: port, } r.tcpListen, err = net.ListenTCP("tcp", tcpaddr) @@ -156,7 +185,7 @@ func (r *resolver) SetExtServers(dns []string) { } func (r *resolver) NameServer() string { - return resolverIP + return r.listenAddress } func (r *resolver) ResolverOptions() []string { @@ -184,7 +213,10 @@ func createRespMsg(query *dns.Msg) *dns.Msg { } func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) { - addr, ipv6Miss := r.sb.ResolveName(name, ipType) + var addr []net.IP + var ipv6Miss bool + addr, ipv6Miss = r.backend.ResolveName(name, ipType) + if addr == nil && ipv6Miss { // Send a reply without any Answer sections log.Debugf("Lookup name %s present without IPv6 address", name) @@ -230,7 +262,8 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error) return nil, fmt.Errorf("invalid PTR query, %v", ptr) } - host := r.sb.ResolveIP(parts[0]) + host := r.backend.ResolveIP(parts[0]) + if len(host) == 0 { return nil, nil } @@ -250,11 +283,9 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error) } func (r *resolver) handleSRVQuery(svc string, query *dns.Msg) (*dns.Msg, error) { - srv, ip, err := r.sb.ResolveService(svc) - if err != nil { - return nil, err - } + srv, ip := r.backend.ResolveService(svc) + if len(srv) == 0 { return nil, nil } @@ -325,16 +356,25 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { return } - // If the user sets ndots > 0 explicitly and the query is - // in the root domain don't forward it out. We will return - // failure and let the client retry with the search domain - // attached if resp == nil { + // If the backend doesn't support proxying dns request + // fail the response + if !r.proxyDNS { + resp = new(dns.Msg) + resp.SetRcode(query, dns.RcodeServerFailure) + w.WriteMsg(resp) + return + } + + // If the user sets ndots > 0 explicitly and the query is + // in the root domain don't forward it out. We will return + // failure and let the client retry with the search domain + // attached switch query.Question[0].Qtype { case dns.TypeA: fallthrough case dns.TypeAAAA: - if r.sb.ndotsSet && !strings.Contains(strings.TrimSuffix(name, "."), ".") { + if r.backend.NdotsSet() && !strings.Contains(strings.TrimSuffix(name, "."), ".") { resp = createRespMsg(query) } } @@ -369,8 +409,8 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { extConn, err = net.DialTimeout(proto, addr, extIOTimeout) } - r.sb.execFunc(extConnect) - if err != nil { + execErr := r.backend.ExecFunc(extConnect) + if execErr != nil || err != nil { log.Debugf("Connect failed, %s", err) continue } diff --git a/resolver_unix.go b/resolver_unix.go index cec2c7d493..17dce480d0 100644 --- a/resolver_unix.go +++ b/resolver_unix.go @@ -35,7 +35,7 @@ func reexecSetupResolver() { os.Exit(1) } - _, ipPort, _ := net.SplitHostPort(os.Args[2]) + resolverIP, ipPort, _ := net.SplitHostPort(os.Args[2]) _, tcpPort, _ := net.SplitHostPort(os.Args[3]) rules := [][]string{ {"-t", "nat", "-I", outputChain, "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[2]}, @@ -90,7 +90,7 @@ func (r *resolver) setupIPTable() error { cmd := &exec.Cmd{ Path: reexec.Self(), - Args: append([]string{"setup-resolver"}, r.sb.Key(), laddr, ltcpaddr), + Args: append([]string{"setup-resolver"}, r.resolverKey, laddr, ltcpaddr), Stdout: os.Stdout, Stderr: os.Stderr, } diff --git a/sandbox.go b/sandbox.go index ed439ff608..3bb1bb3644 100644 --- a/sandbox.go +++ b/sandbox.go @@ -37,19 +37,11 @@ type Sandbox interface { Rename(name string) error // Delete destroys this container after detaching it from all connected endpoints. Delete() error - // ResolveName resolves a service name to an IPv4 or IPv6 address by searching - // the networks the sandbox is connected to. For IPv6 queries, second return - // value will be true if the name exists in docker domain but doesn't have an - // IPv6 address. Such queries shouldn't be forwarded to external nameservers. - ResolveName(name string, iplen int) ([]net.IP, bool) - // ResolveIP returns the service name for the passed in IP. IP is in reverse dotted - // notation; the format used for DNS PTR records - ResolveIP(name string) string - // ResolveService returns all the backend details about the containers or hosts - // backing a service. Its purpose is to satisfy an SRV query - ResolveService(name string) ([]*net.SRV, []net.IP, error) // Endpoints returns all the endpoints connected to the sandbox Endpoints() []Endpoint + // ResolveService returns all the backend details about the containers or hosts + // backing a service. Its purpose is to satisfy an SRV query + ResolveService(name string) ([]*net.SRV, []net.IP) } // SandboxOption is an option setter function type used to pass various options to @@ -131,6 +123,10 @@ type containerConfig struct { exposedPorts []types.TransportPort } +const ( + resolverIPSandbox = "127.0.0.11" +) + func (sb *sandbox) ID() string { return sb.id } @@ -415,33 +411,21 @@ func (sb *sandbox) ResolveIP(ip string) string { for _, ep := range sb.getConnectedEndpoints() { n := ep.getNetwork() - - c := n.getController() - - c.Lock() - sr, ok := c.svcRecords[n.ID()] - c.Unlock() - - if !ok { - continue - } - - nwName := n.Name() - n.Lock() - svc, ok = sr.ipMap[ip] - n.Unlock() - if ok { - return svc + "." + nwName + svc = n.ResolveIP(ip) + if len(svc) != 0 { + return svc } } + return svc } -func (sb *sandbox) execFunc(f func()) { +func (sb *sandbox) ExecFunc(f func()) error { sb.osSbox.InvokeFunc(f) + return nil } -func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP, error) { +func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP) { srv := []*net.SRV{} ip := []net.IP{} @@ -452,53 +436,18 @@ func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP, error) { // not done parts := strings.Split(name, ".") if len(parts) < 3 { - return nil, nil, nil + return nil, nil } - portName := parts[0] - proto := parts[1] - svcName := strings.Join(parts[2:], ".") - for _, ep := range sb.getConnectedEndpoints() { n := ep.getNetwork() - c := n.getController() - - c.Lock() - sr, ok := c.svcRecords[n.ID()] - c.Unlock() - - if !ok { - continue - } - - svcs, ok := sr.service[svcName] - if !ok { - continue - } - - for _, svc := range svcs { - if svc.portName != portName { - continue - } - if svc.proto != proto { - continue - } - for _, t := range svc.target { - srv = append(srv, - &net.SRV{ - Target: t.name, - Port: t.port, - }) - - ip = append(ip, t.ip) - } - } + srv, ip = n.ResolveService(name) if len(srv) > 0 { break } } - return srv, ip, nil + return srv, ip } func getDynamicNwEndpoints(epList []*endpoint) []*endpoint { @@ -635,33 +584,15 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin ep.Unlock() } - c := n.getController() - c.Lock() - sr, ok := c.svcRecords[n.ID()] - c.Unlock() + ip, miss := n.ResolveName(name, ipType) - if !ok { - continue - } - - var ip []net.IP - n.Lock() - ip, ok = sr.svcMap[name] - - if ipType == types.IPv6 { - // If the name resolved to v4 address then its a valid name in - // the docker network domain. If the network is not v6 enabled - // set ipv6Miss to filter the DNS query from going to external - // resolvers. - if ok && n.enableIPv6 == false { - ipv6Miss = true - } - ip = sr.svcIPv6Map[name] - } - n.Unlock() if ip != nil { return ip, false } + + if miss { + ipv6Miss = miss + } } return nil, ipv6Miss } @@ -708,7 +639,7 @@ func (sb *sandbox) SetKey(basePath string) error { if oldosSbox != nil && sb.resolver != nil { sb.resolver.Stop() - sb.osSbox.InvokeFunc(sb.resolver.SetupFunc()) + sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)) if err := sb.resolver.Start(); err != nil { log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err) } @@ -1231,3 +1162,7 @@ func (eh *epHeap) Pop() interface{} { *eh = old[0 : n-1] return x } + +func (sb *sandbox) NdotsSet() bool { + return sb.ndotsSet +} diff --git a/sandbox_dns_unix.go b/sandbox_dns_unix.go index cd9e66224f..45b035e3e5 100644 --- a/sandbox_dns_unix.go +++ b/sandbox_dns_unix.go @@ -26,7 +26,7 @@ const ( func (sb *sandbox) startResolver(restore bool) { sb.resolverOnce.Do(func() { var err error - sb.resolver = NewResolver(sb) + sb.resolver = NewResolver(resolverIPSandbox, true, sb.Key(), sb) defer func() { if err != nil { sb.resolver = nil @@ -46,7 +46,7 @@ func (sb *sandbox) startResolver(restore bool) { } sb.resolver.SetExtServers(sb.extDNS) - sb.osSbox.InvokeFunc(sb.resolver.SetupFunc()) + sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)) if err = sb.resolver.Start(); err != nil { log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err) } From c35192aa544d55d5502bd4468348ccedf8ee0eba Mon Sep 17 00:00:00 2001 From: msabansal Date: Mon, 19 Sep 2016 15:48:21 -0700 Subject: [PATCH 079/799] Vendoring dependencies Signed-off-by: msabansal --- Godeps/Godeps.json | 11 +- .../github.com/Microsoft/go-winio/backup.go | 25 + .../github.com/Microsoft/go-winio/fileinfo.go | 32 +- .../Microsoft/go-winio/privilege.go | 79 +- .../github.com/Microsoft/go-winio/reparse.go | 12 +- .../github.com/Microsoft/go-winio/zsyscall.go | 12 +- .../github.com/Microsoft/hcsshim/README.md | 12 + .../github.com/Microsoft/hcsshim/baselayer.go | 172 ++ .../github.com/Microsoft/hcsshim/callback.go | 79 + .../src/github.com/Microsoft/hcsshim/cgo.go | 7 + .../github.com/Microsoft/hcsshim/container.go | 565 +++++ .../Microsoft/hcsshim/createcomputesystem.go | 22 - .../Microsoft/hcsshim/createprocess.go | 101 - .../github.com/Microsoft/hcsshim/errors.go | 190 ++ .../Microsoft/hcsshim/expandsandboxsize.go | 26 + .../Microsoft/hcsshim/exportlayer.go | 14 +- .../github.com/Microsoft/hcsshim/hcsshim.go | 63 + .../github.com/Microsoft/hcsshim/hnsfuncs.go | 37 +- .../Microsoft/hcsshim/importlayer.go | 64 +- .../github.com/Microsoft/hcsshim/interface.go | 144 ++ .../github.com/Microsoft/hcsshim/legacy.go | 132 +- .../Microsoft/hcsshim/mksyscall_windows.go | 16 +- .../github.com/Microsoft/hcsshim/process.go | 389 +++ .../Microsoft/hcsshim/resizeconsole.go | 22 - .../hcsshim/shutdownterminatecomputesystem.go | 43 - .../Microsoft/hcsshim/startcomputesystem.go | 21 - .../Microsoft/hcsshim/terminateprocess.go | 20 - .../src/github.com/Microsoft/hcsshim/utils.go | 39 + .../Microsoft/hcsshim/waithelper.go | 126 + .../Microsoft/hcsshim/waitprocess.go | 20 - .../github.com/Microsoft/hcsshim/zhcsshim.go | 585 ++++- .../src/golang.org/x/sys/windows/asm.s | 8 + .../x/sys/windows/asm_windows_386.s | 13 + .../x/sys/windows/asm_windows_amd64.s | 13 + .../golang.org/x/sys/windows/dll_windows.go | 275 ++ .../src/golang.org/x/sys/windows/env_unset.go | 14 + .../golang.org/x/sys/windows/env_windows.go | 25 + .../src/golang.org/x/sys/windows/eventlog.go | 20 + .../golang.org/x/sys/windows/exec_windows.go | 97 + .../src/golang.org/x/sys/windows/race.go | 30 + .../src/golang.org/x/sys/windows/race0.go | 25 + .../golang.org/x/sys/windows/registry/key.go | 178 ++ .../x/sys/windows/registry/syscall.go | 33 + .../x/sys/windows/registry/value.go | 384 +++ .../sys/windows/registry/zsyscall_windows.go | 82 + .../x/sys/windows/security_windows.go | 435 ++++ .../src/golang.org/x/sys/windows/service.go | 143 ++ .../src/golang.org/x/sys/windows/str.go | 22 + .../golang.org/x/sys/windows/svc/debug/log.go | 56 + .../x/sys/windows/svc/debug/service.go | 45 + .../src/golang.org/x/sys/windows/svc/event.go | 48 + .../x/sys/windows/svc/eventlog/install.go | 80 + .../x/sys/windows/svc/eventlog/log.go | 70 + .../x/sys/windows/svc/example/beep.go | 22 + .../x/sys/windows/svc/example/install.go | 92 + .../x/sys/windows/svc/example/main.go | 76 + .../x/sys/windows/svc/example/manage.go | 62 + .../x/sys/windows/svc/example/service.go | 82 + .../src/golang.org/x/sys/windows/svc/go12.c | 24 + .../src/golang.org/x/sys/windows/svc/go12.go | 11 + .../src/golang.org/x/sys/windows/svc/go13.go | 31 + .../x/sys/windows/svc/mgr/config.go | 139 ++ .../golang.org/x/sys/windows/svc/mgr/mgr.go | 119 + .../x/sys/windows/svc/mgr/service.go | 74 + .../golang.org/x/sys/windows/svc/security.go | 62 + .../golang.org/x/sys/windows/svc/service.go | 316 +++ .../golang.org/x/sys/windows/svc/sys_386.s | 67 + .../golang.org/x/sys/windows/svc/sys_amd64.s | 41 + .../src/golang.org/x/sys/windows/syscall.go | 77 + .../x/sys/windows/syscall_windows.go | 990 ++++++++ .../x/sys/windows/zsyscall_windows.go | 2220 +++++++++++++++++ .../x/sys/windows/ztypes_windows.go | 1242 +++++++++ .../x/sys/windows/ztypes_windows_386.go | 22 + .../x/sys/windows/ztypes_windows_amd64.go | 22 + 74 files changed, 10604 insertions(+), 363 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/README.md create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/callback.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/cgo.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/createcomputesystem.go delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/createprocess.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/expandsandboxsize.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/resizeconsole.go delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/shutdownterminatecomputesystem.go delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/startcomputesystem.go delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/terminateprocess.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go create mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/waitprocess.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/asm.s create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/asm_windows_386.s create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/asm_windows_amd64.s create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/dll_windows.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/env_unset.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/env_windows.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/eventlog.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/exec_windows.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/race.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/race0.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/registry/key.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/registry/syscall.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/registry/value.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/registry/zsyscall_windows.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/security_windows.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/service.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/str.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/log.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/service.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/event.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/install.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/log.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/beep.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/install.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/main.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/manage.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/service.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.c create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/go13.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/config.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/mgr.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/service.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/security.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/service.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_386.s create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_amd64.s create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/syscall.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/syscall_windows.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/zsyscall_windows.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows_386.go create mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows_amd64.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index f20f0e1ddc..de85ed333b 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -20,12 +20,11 @@ }, { "ImportPath": "github.com/Microsoft/go-winio", - "Comment": "v0.1.0", - "Rev": "8f9387ea7efabb228a981b9c381142be7667967f" + "Rev": "ce2922f643c8fd76b46cadc7f404a06282678b34" }, { "ImportPath": "github.com/Microsoft/hcsshim", - "Rev": "116e0e9f5ced0cec94ae46d0aa1b3002a325f532" + "Rev": "6611816fb4c1693b429ada0f358102119a0b1466" }, { "ImportPath": "github.com/Sirupsen/logrus", @@ -429,6 +428,10 @@ { "ImportPath": "golang.org/x/sys/unix", "Rev": "5eaf0df67e70d6997a9fe0ed24383fa1b01638d3" - } + }, + { + "ImportPath": "golang.org/x/sys/windows", + "Rev": "5eaf0df67e70d6997a9fe0ed24383fa1b01638d3" + } ] } diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/backup.go b/Godeps/_workspace/src/github.com/Microsoft/go-winio/backup.go index bfefd42c4d..08d9ac9d58 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/go-winio/backup.go +++ b/Godeps/_workspace/src/github.com/Microsoft/go-winio/backup.go @@ -26,10 +26,18 @@ const ( BackupReparseData BackupSparseBlock BackupTxfsData +) +const ( StreamSparseAttributes = uint32(8) ) +const ( + WRITE_DAC = 0x40000 + WRITE_OWNER = 0x80000 + ACCESS_SYSTEM_SECURITY = 0x1000000 +) + // BackupHeader represents a backup stream of a file. type BackupHeader struct { Id uint32 // The backup stream ID @@ -239,3 +247,20 @@ func (w *BackupFileWriter) Close() error { } return nil } + +// OpenForBackup opens a file or directory, potentially skipping access checks if the backup +// or restore privileges have been acquired. +// +// If the file opened was a directory, it cannot be used with Readdir(). +func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) { + winPath, err := syscall.UTF16FromString(path) + if err != nil { + return nil, err + } + h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0) + if err != nil { + err = &os.PathError{Op: "open", Path: path, Err: err} + return nil, err + } + return os.NewFile(uintptr(h), path), nil +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/fileinfo.go b/Godeps/_workspace/src/github.com/Microsoft/go-winio/fileinfo.go index dc05a8b334..d5acb72d5b 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/go-winio/fileinfo.go +++ b/Godeps/_workspace/src/github.com/Microsoft/go-winio/fileinfo.go @@ -9,22 +9,46 @@ import ( //sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx //sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle +const ( + fileBasicInfo = 0 + fileIDInfo = 0x12 +) + +// FileBasicInfo contains file access time and file attributes information. type FileBasicInfo struct { CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime FileAttributes uintptr // includes padding } +// GetFileBasicInfo retrieves times and attributes for a file. func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { bi := &FileBasicInfo{} - if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), 0, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { - return nil, &os.PathError{"GetFileInformationByHandleEx", f.Name(), err} + if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} } return bi, nil } +// SetFileBasicInfo sets times and attributes for a file. func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { - if err := setFileInformationByHandle(syscall.Handle(f.Fd()), 0, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { - return &os.PathError{"SetFileInformationByHandle", f.Name(), err} + if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { + return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} } return nil } + +// FileIDInfo contains the volume serial number and file ID for a file. This pair should be +// unique on a system. +type FileIDInfo struct { + VolumeSerialNumber uint64 + FileID [16]byte +} + +// GetFileID retrieves the unique (volume, file ID) pair for a file. +func GetFileID(f *os.File) (*FileIDInfo, error) { + fileID := &FileIDInfo{} + if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} + } + return fileID, nil +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/privilege.go b/Godeps/_workspace/src/github.com/Microsoft/go-winio/privilege.go index 81f9af7b70..3d59412c76 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/go-winio/privilege.go +++ b/Godeps/_workspace/src/github.com/Microsoft/go-winio/privilege.go @@ -5,14 +5,17 @@ import ( "encoding/binary" "fmt" "runtime" + "sync" "syscall" "unicode/utf16" + + "golang.org/x/sys/windows" ) -//sys adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges +//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges //sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf //sys revertToSelf() (err error) = advapi32.RevertToSelf -//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) = advapi32.OpenThreadToken +//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken //sys getCurrentThread() (h syscall.Handle) = GetCurrentThread //sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW //sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW @@ -34,6 +37,12 @@ const ( securityDelegation ) +var ( + privNames = make(map[string]uint64) + privNameMutex sync.Mutex +) + +// PrivilegeError represents an error enabling privileges. type PrivilegeError struct { privileges []uint64 } @@ -56,19 +65,16 @@ func (e *PrivilegeError) Error() string { return s } +// RunWithPrivilege enables a single privilege for a function call. func RunWithPrivilege(name string, fn func() error) error { return RunWithPrivileges([]string{name}, fn) } +// RunWithPrivileges enables privileges for a function call. func RunWithPrivileges(names []string, fn func() error) error { - var privileges []uint64 - for _, name := range names { - p := uint64(0) - err := lookupPrivilegeValue("", name, &p) - if err != nil { - return err - } - privileges = append(privileges, p) + privileges, err := mapPrivileges(names) + if err != nil { + return err } runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -84,7 +90,43 @@ func RunWithPrivileges(names []string, fn func() error) error { return fn() } -func adjustPrivileges(token syscall.Handle, privileges []uint64) error { +func mapPrivileges(names []string) ([]uint64, error) { + var privileges []uint64 + privNameMutex.Lock() + defer privNameMutex.Unlock() + for _, name := range names { + p, ok := privNames[name] + if !ok { + err := lookupPrivilegeValue("", name, &p) + if err != nil { + return nil, err + } + privNames[name] = p + } + privileges = append(privileges, p) + } + return privileges, nil +} + +// EnableProcessPrivileges enables privileges globally for the process. +func EnableProcessPrivileges(names []string) error { + privileges, err := mapPrivileges(names) + if err != nil { + return err + } + + p, _ := windows.GetCurrentProcess() + var token windows.Token + err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token) + if err != nil { + return err + } + + defer token.Close() + return adjustPrivileges(token, privileges) +} + +func adjustPrivileges(token windows.Token, privileges []uint64) error { var b bytes.Buffer binary.Write(&b, binary.LittleEndian, uint32(len(privileges))) for _, p := range privileges { @@ -113,23 +155,22 @@ func getPrivilegeName(luid uint64) string { var displayNameBuffer [256]uint16 displayBufSize := uint32(len(displayNameBuffer)) - var langId uint32 - err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langId) + var langID uint32 + err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID) if err != nil { - return fmt.Sprintf("", utf16.Decode(nameBuffer[:bufSize])) + return fmt.Sprintf("", string(utf16.Decode(nameBuffer[:bufSize]))) } return string(utf16.Decode(displayNameBuffer[:displayBufSize])) } -func newThreadToken() (syscall.Handle, error) { +func newThreadToken() (windows.Token, error) { err := impersonateSelf(securityImpersonation) if err != nil { - panic(err) return 0, err } - var token syscall.Handle + var token windows.Token err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token) if err != nil { rerr := revertToSelf() @@ -141,10 +182,10 @@ func newThreadToken() (syscall.Handle, error) { return token, nil } -func releaseThreadToken(h syscall.Handle) { +func releaseThreadToken(h windows.Token) { err := revertToSelf() if err != nil { panic(err) } - syscall.Close(h) + h.Close() } diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/reparse.go b/Godeps/_workspace/src/github.com/Microsoft/go-winio/reparse.go index 96d7b9a877..fc1ee4d3a3 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/go-winio/reparse.go +++ b/Godeps/_workspace/src/github.com/Microsoft/go-winio/reparse.go @@ -43,8 +43,12 @@ func (e *UnsupportedReparsePointError) Error() string { // DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink // or a mount point. func DecodeReparsePoint(b []byte) (*ReparsePoint, error) { - isMountPoint := false tag := binary.LittleEndian.Uint32(b[0:4]) + return DecodeReparsePointData(tag, b[8:]) +} + +func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) { + isMountPoint := false switch tag { case reparseTagMountPoint: isMountPoint = true @@ -52,11 +56,11 @@ func DecodeReparsePoint(b []byte) (*ReparsePoint, error) { default: return nil, &UnsupportedReparsePointError{tag} } - nameOffset := 16 + binary.LittleEndian.Uint16(b[12:14]) + nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6]) if !isMountPoint { nameOffset += 4 } - nameLength := binary.LittleEndian.Uint16(b[14:16]) + nameLength := binary.LittleEndian.Uint16(b[6:8]) name := make([]uint16, nameLength/2) err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name) if err != nil { @@ -76,7 +80,7 @@ func EncodeReparsePoint(rp *ReparsePoint) []byte { var ntTarget string relative := false if strings.HasPrefix(rp.Target, `\\?\`) { - ntTarget = rp.Target + ntTarget = `\??\` + rp.Target[4:] } else if strings.HasPrefix(rp.Target, `\\`) { ntTarget = `\??\UNC\` + rp.Target[2:] } else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' { diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/zsyscall.go b/Godeps/_workspace/src/github.com/Microsoft/go-winio/zsyscall.go index 74b6e97a66..6d047d3690 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/go-winio/zsyscall.go +++ b/Godeps/_workspace/src/github.com/Microsoft/go-winio/zsyscall.go @@ -2,8 +2,12 @@ package winio -import "unsafe" -import "syscall" +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) var _ unsafe.Pointer @@ -300,7 +304,7 @@ func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, si return } -func adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { +func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { var _p0 uint32 if releaseAll { _p0 = 1 @@ -343,7 +347,7 @@ func revertToSelf() (err error) { return } -func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) { +func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { var _p0 uint32 if openAsSelf { _p0 = 1 diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/README.md b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/README.md new file mode 100644 index 0000000000..30991a12e4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/README.md @@ -0,0 +1,12 @@ +# hcsshim + +This package supports launching Windows Server containers from Go. It is +primarily used in the [Docker Engine](https://github.com/docker/docker) project, +but it can be freely used by other projects as well. + +This project has adopted the [Microsoft Open Source Code of +Conduct](https://opensource.microsoft.com/codeofconduct/). For more information +see the [Code of Conduct +FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact +[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional +questions or comments. diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go new file mode 100644 index 0000000000..4b04a681e9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go @@ -0,0 +1,172 @@ +package hcsshim + +import ( + "errors" + "os" + "path/filepath" + "syscall" + + "github.com/Microsoft/go-winio" +) + +type baseLayerWriter struct { + root string + f *os.File + bw *winio.BackupFileWriter + err error + hasUtilityVM bool + dirInfo []dirInfo +} + +type dirInfo struct { + path string + fileInfo winio.FileBasicInfo +} + +func (w *baseLayerWriter) closeCurrentFile() error { + if w.f != nil { + err := w.bw.Close() + err2 := w.f.Close() + w.f = nil + w.bw = nil + if err != nil { + return err + } + if err2 != nil { + return err2 + } + } + return nil +} + +func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err error) { + defer func() { + if err != nil { + w.err = err + } + }() + + err = w.closeCurrentFile() + if err != nil { + return err + } + + if filepath.ToSlash(name) == `UtilityVM/Files` { + w.hasUtilityVM = true + } + + path := filepath.Join(w.root, name) + path, err = makeLongAbsPath(path) + if err != nil { + return err + } + + var f *os.File + defer func() { + if f != nil { + f.Close() + } + }() + + createmode := uint32(syscall.CREATE_NEW) + if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + err := os.Mkdir(path, 0) + if err != nil && !os.IsExist(err) { + return err + } + createmode = syscall.OPEN_EXISTING + if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { + w.dirInfo = append(w.dirInfo, dirInfo{path, *fileInfo}) + } + } + + mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY) + f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode) + if err != nil { + return makeError(err, "Failed to OpenForBackup", path) + } + + err = winio.SetFileBasicInfo(f, fileInfo) + if err != nil { + return makeError(err, "Failed to SetFileBasicInfo", path) + } + + w.f = f + w.bw = winio.NewBackupFileWriter(f, true) + f = nil + return nil +} + +func (w *baseLayerWriter) AddLink(name string, target string) (err error) { + defer func() { + if err != nil { + w.err = err + } + }() + + err = w.closeCurrentFile() + if err != nil { + return err + } + + linkpath, err := makeLongAbsPath(filepath.Join(w.root, name)) + if err != nil { + return err + } + + linktarget, err := makeLongAbsPath(filepath.Join(w.root, target)) + if err != nil { + return err + } + + return os.Link(linktarget, linkpath) +} + +func (w *baseLayerWriter) Remove(name string) error { + return errors.New("base layer cannot have tombstones") +} + +func (w *baseLayerWriter) Write(b []byte) (int, error) { + n, err := w.bw.Write(b) + if err != nil { + w.err = err + } + return n, err +} + +func (w *baseLayerWriter) Close() error { + err := w.closeCurrentFile() + if err != nil { + return err + } + if w.err == nil { + // Restore the file times of all the directories, since they may have + // been modified by creating child directories. + for i := range w.dirInfo { + di := &w.dirInfo[len(w.dirInfo)-i-1] + f, err := winio.OpenForBackup(di.path, uint32(syscall.GENERIC_READ|syscall.GENERIC_WRITE), syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING) + if err != nil { + return makeError(err, "Failed to OpenForBackup", di.path) + } + + err = winio.SetFileBasicInfo(f, &di.fileInfo) + f.Close() + if err != nil { + return makeError(err, "Failed to SetFileBasicInfo", di.path) + } + } + + err = ProcessBaseLayer(w.root) + if err != nil { + return err + } + + if w.hasUtilityVM { + err = ProcessUtilityVMImage(filepath.Join(w.root, "UtilityVM")) + if err != nil { + return err + } + } + } + return w.err +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/callback.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/callback.go new file mode 100644 index 0000000000..e8c2b00c8a --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/callback.go @@ -0,0 +1,79 @@ +package hcsshim + +import ( + "sync" + "syscall" +) + +var ( + nextCallback uintptr + callbackMap = map[uintptr]*notifcationWatcherContext{} + callbackMapLock = sync.RWMutex{} + + notificationWatcherCallback = syscall.NewCallback(notificationWatcher) + + // Notifications for HCS_SYSTEM handles + hcsNotificationSystemExited hcsNotification = 0x00000001 + hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002 + hcsNotificationSystemStartCompleted hcsNotification = 0x00000003 + hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004 + hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005 + + // Notifications for HCS_PROCESS handles + hcsNotificationProcessExited hcsNotification = 0x00010000 + + // Common notifications + hcsNotificationInvalid hcsNotification = 0x00000000 + hcsNotificationServiceDisconnect hcsNotification = 0x01000000 +) + +type hcsNotification uint32 +type notificationChannel chan error + +type notifcationWatcherContext struct { + channels notificationChannels + handle hcsCallback +} + +type notificationChannels map[hcsNotification]notificationChannel + +func newChannels() notificationChannels { + channels := make(notificationChannels) + + channels[hcsNotificationSystemExited] = make(notificationChannel, 1) + channels[hcsNotificationSystemCreateCompleted] = make(notificationChannel, 1) + channels[hcsNotificationSystemStartCompleted] = make(notificationChannel, 1) + channels[hcsNotificationSystemPauseCompleted] = make(notificationChannel, 1) + channels[hcsNotificationSystemResumeCompleted] = make(notificationChannel, 1) + channels[hcsNotificationProcessExited] = make(notificationChannel, 1) + channels[hcsNotificationServiceDisconnect] = make(notificationChannel, 1) + return channels +} +func closeChannels(channels notificationChannels) { + close(channels[hcsNotificationSystemExited]) + close(channels[hcsNotificationSystemCreateCompleted]) + close(channels[hcsNotificationSystemStartCompleted]) + close(channels[hcsNotificationSystemPauseCompleted]) + close(channels[hcsNotificationSystemResumeCompleted]) + close(channels[hcsNotificationProcessExited]) + close(channels[hcsNotificationServiceDisconnect]) +} + +func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr { + var result error + if int32(notificationStatus) < 0 { + result = syscall.Errno(win32FromHresult(notificationStatus)) + } + + callbackMapLock.RLock() + context := callbackMap[callbackNumber] + callbackMapLock.RUnlock() + + if context == nil { + return 0 + } + + context.channels[notificationType] <- result + + return 0 +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/cgo.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/cgo.go new file mode 100644 index 0000000000..2003332330 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/cgo.go @@ -0,0 +1,7 @@ +package hcsshim + +import "C" + +// This import is needed to make the library compile as CGO because HCSSHIM +// only works with CGO due to callbacks from HCS comming back from a C thread +// which is not supported without CGO. See https://github.com/golang/go/issues/10973 diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go new file mode 100644 index 0000000000..9e76e33230 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go @@ -0,0 +1,565 @@ +package hcsshim + +import ( + "encoding/json" + "runtime" + "syscall" + "time" + + "github.com/Sirupsen/logrus" +) + +var ( + defaultTimeout = time.Minute * 4 +) + +const ( + pendingUpdatesQuery = `{ "PropertyTypes" : ["PendingUpdates"]}` + statisticsQuery = `{ "PropertyTypes" : ["Statistics"]}` + processListQuery = `{ "PropertyTypes" : ["ProcessList"]}` +) + +type container struct { + handle hcsSystem + id string + callbackNumber uintptr +} + +type containerProperties struct { + ID string `json:"Id"` + Name string + SystemType string + Owner string + SiloGUID string `json:"SiloGuid,omitempty"` + IsDummy bool `json:",omitempty"` + RuntimeID string `json:"RuntimeId,omitempty"` + Stopped bool `json:",omitempty"` + ExitType string `json:",omitempty"` + AreUpdatesPending bool `json:",omitempty"` + ObRoot string `json:",omitempty"` + Statistics Statistics `json:",omitempty"` + ProcessList []ProcessListItem `json:",omitempty"` +} + +// MemoryStats holds the memory statistics for a container +type MemoryStats struct { + UsageCommitBytes uint64 `json:"MemoryUsageCommitBytes,omitempty"` + UsageCommitPeakBytes uint64 `json:"MemoryUsageCommitPeakBytes,omitempty"` + UsagePrivateWorkingSetBytes uint64 `json:"MemoryUsagePrivateWorkingSetBytes,omitempty"` +} + +// ProcessorStats holds the processor statistics for a container +type ProcessorStats struct { + TotalRuntime100ns uint64 `json:",omitempty"` + RuntimeUser100ns uint64 `json:",omitempty"` + RuntimeKernel100ns uint64 `json:",omitempty"` +} + +// StorageStats holds the storage statistics for a container +type StorageStats struct { + ReadCountNormalized uint64 `json:",omitempty"` + ReadSizeBytes uint64 `json:",omitempty"` + WriteCountNormalized uint64 `json:",omitempty"` + WriteSizeBytes uint64 `json:",omitempty"` +} + +// NetworkStats holds the network statistics for a container +type NetworkStats struct { + BytesReceived uint64 `json:",omitempty"` + BytesSent uint64 `json:",omitempty"` + PacketsReceived uint64 `json:",omitempty"` + PacketsSent uint64 `json:",omitempty"` + DroppedPacketsIncoming uint64 `json:",omitempty"` + DroppedPacketsOutgoing uint64 `json:",omitempty"` + EndpointId string `json:",omitempty"` + InstanceId string `json:",omitempty"` +} + +// Statistics is the structure returned by a statistics call on a container +type Statistics struct { + Timestamp time.Time `json:",omitempty"` + ContainerStartTime time.Time `json:",omitempty"` + Uptime100ns uint64 `json:",omitempty"` + Memory MemoryStats `json:",omitempty"` + Processor ProcessorStats `json:",omitempty"` + Storage StorageStats `json:",omitempty"` + Network []NetworkStats `json:",omitempty"` +} + +// ProcessList is the structure of an item returned by a ProcessList call on a container +type ProcessListItem struct { + CreateTimestamp time.Time `json:",omitempty"` + ImageName string `json:",omitempty"` + KernelTime100ns uint64 `json:",omitempty"` + MemoryCommitBytes uint64 `json:",omitempty"` + MemoryWorkingSetPrivateBytes uint64 `json:",omitempty"` + MemoryWorkingSetSharedBytes uint64 `json:",omitempty"` + ProcessId uint32 `json:",omitempty"` + UserTime100ns uint64 `json:",omitempty"` +} + +// CreateContainer creates a new container with the given configuration but does not start it. +func CreateContainer(id string, c *ContainerConfig) (Container, error) { + operation := "CreateContainer" + title := "HCSShim::" + operation + + container := &container{ + id: id, + } + + configurationb, err := json.Marshal(c) + if err != nil { + return nil, err + } + + configuration := string(configurationb) + logrus.Debugf(title+" id=%s config=%s", id, configuration) + + var ( + resultp *uint16 + createError error + ) + if hcsCallbacksSupported { + var identity syscall.Handle + createError = hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp) + + if createError == nil || IsPending(createError) { + if err := container.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) + } + } + } else { + createError = hcsCreateComputeSystemTP5(id, configuration, &container.handle, &resultp) + } + + err = processAsyncHcsResult(createError, resultp, container.callbackNumber, hcsNotificationSystemCreateCompleted, &defaultTimeout) + if err != nil { + return nil, makeContainerError(container, operation, configuration, err) + } + + logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle) + runtime.SetFinalizer(container, closeContainer) + return container, nil +} + +// OpenContainer opens an existing container by ID. +func OpenContainer(id string) (Container, error) { + operation := "OpenContainer" + title := "HCSShim::" + operation + logrus.Debugf(title+" id=%s", id) + + container := &container{ + id: id, + } + + var ( + handle hcsSystem + resultp *uint16 + ) + err := hcsOpenComputeSystem(id, &handle, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return nil, makeContainerError(container, operation, "", err) + } + + container.handle = handle + + logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle) + runtime.SetFinalizer(container, closeContainer) + return container, nil +} + +// Start synchronously starts the container. +func (container *container) Start() error { + operation := "Start" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + var resultp *uint16 + err := hcsStartComputeSystemTP5(container.handle, nil, &resultp) + err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemStartCompleted, &defaultTimeout) + if err != nil { + return makeContainerError(container, operation, "", err) + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// Shutdown requests a container shutdown, if IsPending() on the error returned is true, +// it may not actually be shut down until Wait() succeeds. +func (container *container) Shutdown() error { + operation := "Shutdown" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + var resultp *uint16 + err := hcsShutdownComputeSystemTP5(container.handle, nil, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return makeContainerError(container, operation, "", err) + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// Terminate requests a container terminate, if IsPending() on the error returned is true, +// it may not actually be shut down until Wait() succeeds. +func (container *container) Terminate() error { + operation := "Terminate" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + var resultp *uint16 + err := hcsTerminateComputeSystemTP5(container.handle, nil, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return makeContainerError(container, operation, "", err) + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// Wait synchronously waits for the container to shutdown or terminate. +func (container *container) Wait() error { + operation := "Wait" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + if hcsCallbacksSupported { + err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil) + if err != nil { + return makeContainerError(container, operation, "", err) + } + } else { + _, err := container.waitTimeoutInternal(syscall.INFINITE) + if err != nil { + return makeContainerError(container, operation, "", err) + } + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +func (container *container) waitTimeoutInternal(timeout uint32) (bool, error) { + return waitTimeoutInternalHelper(container, timeout) +} + +// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. +// If the timeout expires, IsTimeout(err) == true +func (container *container) WaitTimeout(timeout time.Duration) error { + operation := "WaitTimeout" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + if hcsCallbacksSupported { + err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout) + if err != nil { + return makeContainerError(container, operation, "", err) + } + } else { + finished, err := waitTimeoutHelper(container, timeout) + if !finished { + err = ErrTimeout + } + if err != nil { + return makeContainerError(container, operation, "", err) + } + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +func (container *container) hcsWait(timeout uint32) (bool, error) { + var ( + resultp *uint16 + exitEvent syscall.Handle + ) + + err := hcsCreateComputeSystemWait(container.handle, &exitEvent, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return false, err + } + defer syscall.CloseHandle(exitEvent) + + return waitForSingleObject(exitEvent, timeout) +} + +func (container *container) properties(query string) (*containerProperties, error) { + var ( + resultp *uint16 + propertiesp *uint16 + ) + err := hcsGetComputeSystemProperties(container.handle, query, &propertiesp, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return nil, err + } + + if propertiesp == nil { + return nil, ErrUnexpectedValue + } + propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp) + properties := &containerProperties{} + if err := json.Unmarshal(propertiesRaw, properties); err != nil { + return nil, err + } + return properties, nil +} + +// HasPendingUpdates returns true if the container has updates pending to install +func (container *container) HasPendingUpdates() (bool, error) { + operation := "HasPendingUpdates" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + properties, err := container.properties(pendingUpdatesQuery) + if err != nil { + return false, makeContainerError(container, operation, "", err) + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return properties.AreUpdatesPending, nil +} + +// Statistics returns statistics for the container +func (container *container) Statistics() (Statistics, error) { + operation := "Statistics" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + properties, err := container.properties(statisticsQuery) + if err != nil { + return Statistics{}, makeContainerError(container, operation, "", err) + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return properties.Statistics, nil +} + +// ProcessList returns an array of ProcessListItems for the container +func (container *container) ProcessList() ([]ProcessListItem, error) { + operation := "ProcessList" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + properties, err := container.properties(processListQuery) + if err != nil { + return nil, makeContainerError(container, operation, "", err) + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return properties.ProcessList, nil +} + +// Pause pauses the execution of the container. This feature is not enabled in TP5. +func (container *container) Pause() error { + operation := "Pause" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + var resultp *uint16 + err := hcsPauseComputeSystemTP5(container.handle, nil, &resultp) + err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemPauseCompleted, &defaultTimeout) + if err != nil { + return makeContainerError(container, operation, "", err) + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// Resume resumes the execution of the container. This feature is not enabled in TP5. +func (container *container) Resume() error { + operation := "Resume" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + var ( + resultp *uint16 + ) + + err := hcsResumeComputeSystemTP5(container.handle, nil, &resultp) + err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemResumeCompleted, &defaultTimeout) + if err != nil { + return makeContainerError(container, operation, "", err) + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// CreateProcess launches a new process within the container. +func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { + operation := "CreateProcess" + title := "HCSShim::Container::" + operation + var ( + processInfo hcsProcessInformation + processHandle hcsProcess + resultp *uint16 + ) + + // If we are not emulating a console, ignore any console size passed to us + if !c.EmulateConsole { + c.ConsoleSize[0] = 0 + c.ConsoleSize[1] = 0 + } + + configurationb, err := json.Marshal(c) + if err != nil { + return nil, makeContainerError(container, operation, "", err) + } + + configuration := string(configurationb) + logrus.Debugf(title+" id=%s config=%s", container.id, configuration) + + err = hcsCreateProcess(container.handle, configuration, &processInfo, &processHandle, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return nil, makeContainerError(container, operation, configuration, err) + } + + process := &process{ + handle: processHandle, + processID: int(processInfo.ProcessId), + container: container, + cachedPipes: &cachedPipes{ + stdIn: processInfo.StdInput, + stdOut: processInfo.StdOutput, + stdErr: processInfo.StdError, + }, + } + + if hcsCallbacksSupported { + if err := process.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) + } + } + + logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) + runtime.SetFinalizer(process, closeProcess) + return process, nil +} + +// OpenProcess gets an interface to an existing process within the container. +func (container *container) OpenProcess(pid int) (Process, error) { + operation := "OpenProcess" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s, processid=%d", container.id, pid) + var ( + processHandle hcsProcess + resultp *uint16 + ) + + err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return nil, makeContainerError(container, operation, "", err) + } + + process := &process{ + handle: processHandle, + processID: pid, + container: container, + } + + if hcsCallbacksSupported { + if err := process.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) + } + } + + logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) + runtime.SetFinalizer(process, closeProcess) + return process, nil +} + +// Close cleans up any state associated with the container but does not terminate or wait for it. +func (container *container) Close() error { + operation := "Close" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + // Don't double free this + if container.handle == 0 { + return nil + } + + if hcsCallbacksSupported { + if err := container.unregisterCallback(); err != nil { + return makeContainerError(container, operation, "", err) + } + } + + if err := hcsCloseComputeSystem(container.handle); err != nil { + return makeContainerError(container, operation, "", err) + } + + container.handle = 0 + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// closeContainer wraps container.Close for use by a finalizer +func closeContainer(container *container) { + container.Close() +} + +func (container *container) registerCallback() error { + context := ¬ifcationWatcherContext{ + channels: newChannels(), + } + + callbackMapLock.Lock() + callbackNumber := nextCallback + nextCallback++ + callbackMap[callbackNumber] = context + callbackMapLock.Unlock() + + var callbackHandle hcsCallback + err := hcsRegisterComputeSystemCallback(container.handle, notificationWatcherCallback, callbackNumber, &callbackHandle) + if err != nil { + return err + } + context.handle = callbackHandle + container.callbackNumber = callbackNumber + + return nil +} + +func (container *container) unregisterCallback() error { + callbackNumber := container.callbackNumber + + callbackMapLock.RLock() + context := callbackMap[callbackNumber] + callbackMapLock.RUnlock() + + if context == nil { + return nil + } + + handle := context.handle + + if handle == 0 { + return nil + } + + // hcsUnregisterComputeSystemCallback has its own syncronization + // to wait for all callbacks to complete. We must NOT hold the callbackMapLock. + err := hcsUnregisterComputeSystemCallback(handle) + if err != nil { + return err + } + + closeChannels(context.channels) + + callbackMapLock.Lock() + callbackMap[callbackNumber] = nil + callbackMapLock.Unlock() + + handle = 0 + + return nil +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createcomputesystem.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createcomputesystem.go deleted file mode 100644 index 3cc12a38ef..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createcomputesystem.go +++ /dev/null @@ -1,22 +0,0 @@ -package hcsshim - -import "github.com/Sirupsen/logrus" - -// CreateComputeSystem creates a container, initializing its configuration in -// the Host Compute Service such that it can be started by a call to the -// StartComputeSystem method. -func CreateComputeSystem(id string, configuration string) error { - - title := "HCSShim::CreateComputeSystem" - logrus.Debugln(title+" id=%s, configuration=%s", id, configuration) - - err := createComputeSystem(id, configuration) - if err != nil { - err = makeErrorf(err, title, "id=%s configuration=%s", id, configuration) - logrus.Error(err) - return err - } - - logrus.Debugf(title+"- succeeded %s", id) - return nil -} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createprocess.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createprocess.go deleted file mode 100644 index a2b6298546..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createprocess.go +++ /dev/null @@ -1,101 +0,0 @@ -package hcsshim - -import ( - "encoding/json" - "io" - "syscall" - - "github.com/Microsoft/go-winio" - "github.com/Sirupsen/logrus" -) - -// CreateProcessParams is used as both the input of CreateProcessInComputeSystem -// and to convert the parameters to JSON for passing onto the HCS -type CreateProcessParams struct { - ApplicationName string - CommandLine string - WorkingDirectory string - Environment map[string]string - EmulateConsole bool - ConsoleSize [2]int -} - -// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles -// if there is an error. -func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) { - fs := make([]io.ReadWriteCloser, len(hs)) - for i, h := range hs { - if h != syscall.Handle(0) { - if err == nil { - fs[i], err = winio.MakeOpenFile(h) - } - if err != nil { - syscall.Close(h) - } - } - } - if err != nil { - for _, f := range fs { - if f != nil { - f.Close() - } - } - return nil, err - } - return fs, nil -} - -// CreateProcessInComputeSystem starts a process in a container. This is invoked, for example, -// as a result of docker run, docker exec, or RUN in Dockerfile. If successful, -// it returns the PID of the process. -func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useStderr bool, params CreateProcessParams) (_ uint32, _ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) { - title := "HCSShim::CreateProcessInComputeSystem" - logrus.Debugf(title+" id=%s", id) - - // If we are not emulating a console, ignore any console size passed to us - if !params.EmulateConsole { - params.ConsoleSize[0] = 0 - params.ConsoleSize[1] = 0 - } - - paramsJson, err := json.Marshal(params) - if err != nil { - return - } - - logrus.Debugf(title+" - Calling Win32 %s %s", id, paramsJson) - - var pid uint32 - - handles := make([]syscall.Handle, 3) - var stdinParam, stdoutParam, stderrParam *syscall.Handle - if useStdin { - stdinParam = &handles[0] - } - if useStdout { - stdoutParam = &handles[1] - } - if useStderr { - stderrParam = &handles[2] - } - - err = createProcessWithStdHandlesInComputeSystem(id, string(paramsJson), &pid, stdinParam, stdoutParam, stderrParam) - if err != nil { - herr := makeErrorf(err, title, "id=%s params=%v", id, params) - // Windows TP4: Hyper-V Containers may return this error with more than one - // concurrent exec. Do not log it as an error - if err != WSAEINVAL { - logrus.Error(herr) - } - err = herr - return - } - - pipes, err := makeOpenFiles(handles) - if err != nil { - return - } - - logrus.Debugf(title+" - succeeded id=%s params=%s pid=%d", id, paramsJson, pid) - return pid, pipes[0], pipes[1], pipes[2], nil -} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go new file mode 100644 index 0000000000..0d4dad5950 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go @@ -0,0 +1,190 @@ +package hcsshim + +import ( + "errors" + "fmt" + "syscall" +) + +var ( + // ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists + ErrComputeSystemDoesNotExist = syscall.Errno(0xc037010e) + + // ErrElementNotFound is an error encountered when the object being referenced does not exist + ErrElementNotFound = syscall.Errno(0x490) + + // ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed + ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed") + + // ErrInvalidNotificationType is an error encountered when an invalid notification type is used + ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type") + + // ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation + ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation") + + // ErrTimeout is an error encountered when waiting on a notification times out + ErrTimeout = errors.New("hcsshim: timeout waiting for notification") + + // ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for + // a different expected notification + ErrUnexpectedContainerExit = errors.New("unexpected container exit") + + // ErrUnexpectedProcessAbort is the error encountered when communication with the compute service + // is lost while waiting for a notification + ErrUnexpectedProcessAbort = errors.New("lost communication with compute service") + + // ErrUnexpectedValue is an error encountered when hcs returns an invalid value + ErrUnexpectedValue = errors.New("unexpected value returned from hcs") + + // ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container + ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110) + + // ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously + ErrVmcomputeOperationPending = syscall.Errno(0xC0370103) + + // ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation + ErrVmcomputeOperationInvalidState = syscall.Errno(0xc0370105) + + // ErrProcNotFound is an error encountered when the the process cannot be found + ErrProcNotFound = syscall.Errno(0x7f) +) + +// ProcessError is an error encountered in HCS during an operation on a Process object +type ProcessError struct { + Process *process + Operation string + ExtraInfo string + Err error +} + +// ContainerError is an error encountered in HCS during an operation on a Container object +type ContainerError struct { + Container *container + Operation string + ExtraInfo string + Err error +} + +func (e *ContainerError) Error() string { + if e == nil { + return "" + } + + if e.Container == nil { + return "unexpected nil container for error: " + e.Err.Error() + } + + s := "container " + e.Container.id + + if e.Operation != "" { + s += " encountered an error during " + e.Operation + } + + if e.Err != nil { + s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) + } + + if e.ExtraInfo != "" { + s += " extra info: " + e.ExtraInfo + } + + return s +} + +func makeContainerError(container *container, operation string, extraInfo string, err error) error { + // Don't double wrap errors + if _, ok := err.(*ContainerError); ok { + return err + } + containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err} + return containerError +} + +func (e *ProcessError) Error() string { + if e == nil { + return "" + } + + if e.Process == nil { + return "Unexpected nil process for error: " + e.Err.Error() + } + + s := fmt.Sprintf("process %d", e.Process.processID) + + if e.Process.container != nil { + s += " in container " + e.Process.container.id + } + + if e.Operation != "" { + s += " " + e.Operation + } + + switch e.Err.(type) { + case nil: + break + case syscall.Errno: + s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) + default: + s += fmt.Sprintf(" failed: %s", e.Error()) + } + + return s +} + +func makeProcessError(process *process, operation string, extraInfo string, err error) error { + // Don't double wrap errors + if _, ok := err.(*ProcessError); ok { + return err + } + processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err} + return processError +} + +// IsNotExist checks if an error is caused by the Container or Process not existing. +// Note: Currently, ErrElementNotFound can mean that a Process has either +// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist +// will currently return true when the error is ErrElementNotFound or ErrProcNotFound. +func IsNotExist(err error) bool { + err = getInnerError(err) + return err == ErrComputeSystemDoesNotExist || + err == ErrElementNotFound || + err == ErrProcNotFound +} + +// IsPending returns a boolean indicating whether the error is that +// the requested operation is being completed in the background. +func IsPending(err error) bool { + err = getInnerError(err) + return err == ErrVmcomputeOperationPending +} + +// IsTimeout returns a boolean indicating whether the error is caused by +// a timeout waiting for the operation to complete. +func IsTimeout(err error) bool { + err = getInnerError(err) + return err == ErrTimeout +} + +// IsAlreadyStopped returns a boolean indicating whether the error is caused by +// a Container or Process being already stopped. +// Note: Currently, ErrElementNotFound can mean that a Process has either +// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist +// will currently return true when the error is ErrElementNotFound or ErrProcNotFound. +func IsAlreadyStopped(err error) bool { + err = getInnerError(err) + return err == ErrVmcomputeAlreadyStopped || + err == ErrElementNotFound || + err == ErrProcNotFound +} + +func getInnerError(err error) error { + switch pe := err.(type) { + case nil: + return nil + case *ContainerError: + err = pe.Err + case *ProcessError: + err = pe.Err + } + return err +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/expandsandboxsize.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/expandsandboxsize.go new file mode 100644 index 0000000000..e168921841 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/expandsandboxsize.go @@ -0,0 +1,26 @@ +package hcsshim + +import "github.com/Sirupsen/logrus" + +// ExpandSandboxSize expands the size of a layer to at least size bytes. +func ExpandSandboxSize(info DriverInfo, layerId string, size uint64) error { + title := "hcsshim::ExpandSandboxSize " + logrus.Debugf(title+"layerId=%s size=%d", layerId, size) + + // Convert info to API calling convention + infop, err := convertDriverInfo(info) + if err != nil { + logrus.Error(err) + return err + } + + err = expandSandboxSize(&infop, layerId, size) + if err != nil { + err = makeErrorf(err, title, "layerId=%s size=%d", layerId, size) + logrus.Error(err) + return err + } + + logrus.Debugf(title+"- succeeded layerId=%s size=%d", layerId, size) + return nil +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/exportlayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/exportlayer.go index e197d575e5..903e08519d 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/exportlayer.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/exportlayer.go @@ -112,7 +112,9 @@ func (r *FilterLayerReader) Close() (err error) { } // NewLayerReader returns a new layer reader for reading the contents of an on-disk layer. -func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) (LayerReader, error) { +// The caller must have taken the SeBackupPrivilege privilege +// to call this and any methods on the resulting LayerReader. +func NewLayerReader(info DriverInfo, layerID string, parentLayerPaths []string) (LayerReader, error) { if procExportLayerBegin.Find() != nil { // The new layer reader is not available on this Windows build. Fall back to the // legacy export code path. @@ -120,12 +122,12 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) if err != nil { return nil, err } - err = ExportLayer(info, layerId, path, parentLayerPaths) + err = ExportLayer(info, layerID, path, parentLayerPaths) if err != nil { os.RemoveAll(path) return nil, err } - return &legacyLayerReaderWrapper{NewLegacyLayerReader(path)}, nil + return &legacyLayerReaderWrapper{newLegacyLayerReader(path)}, nil } layers, err := layerPathsToDescriptors(parentLayerPaths) @@ -137,7 +139,7 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) return nil, err } r := &FilterLayerReader{} - err = exportLayerBegin(&infop, layerId, layers, &r.context) + err = exportLayerBegin(&infop, layerID, layers, &r.context) if err != nil { return nil, makeError(err, "ExportLayerBegin", "") } @@ -146,11 +148,11 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) } type legacyLayerReaderWrapper struct { - *LegacyLayerReader + *legacyLayerReader } func (r *legacyLayerReaderWrapper) Close() error { - err := r.LegacyLayerReader.Close() + err := r.legacyLayerReader.Close() os.RemoveAll(r.root) return err } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go index 88650b8ac9..eaecf1321e 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go @@ -7,16 +7,20 @@ import ( "fmt" "syscall" "unsafe" + + "github.com/Sirupsen/logrus" ) //go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go //sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree +//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId //sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer? //sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer? //sys createLayer(info *driverInfo, id string, parent string) (hr error) = vmcompute.CreateLayer? //sys createSandboxLayer(info *driverInfo, id string, parent string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CreateSandboxLayer? +//sys expandSandboxSize(info *driverInfo, id string, size uint64) (hr error) = vmcompute.ExpandSandboxSize? //sys deactivateLayer(info *driverInfo, id string) (hr error) = vmcompute.DeactivateLayer? //sys destroyLayer(info *driverInfo, id string) (hr error) = vmcompute.DestroyLayer? //sys exportLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ExportLayer? @@ -48,6 +52,41 @@ import ( //sys terminateComputeSystem(id string) (hr error) = vmcompute.TerminateComputeSystem? //sys terminateProcessInComputeSystem(id string, pid uint32) (hr error) = vmcompute.TerminateProcessInComputeSystem? //sys waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) = vmcompute.WaitForProcessInComputeSystem? +//sys getComputeSystemProperties(id string, flags uint32, properties **uint16) (hr error) = vmcompute.GetComputeSystemProperties? + +//sys hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) = vmcompute.HcsEnumerateComputeSystems? +//sys hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem? +//sys hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsOpenComputeSystem? +//sys hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) = vmcompute.HcsCloseComputeSystem? +//sys hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem? +//sys hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem? +//sys hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem? +//sys hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem? +//sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? +//sys hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties? +//sys hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem? +//sys hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystemWait? +//sys hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess? +//sys hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess? +//sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess? +//sys hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) = vmcompute.HcsTerminateProcess? +//sys hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) = vmcompute.HcsGetProcessInfo? +//sys hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties? +//sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess? +//sys hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateProcessWait? +//sys hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetServiceProperties? +//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings? + +//sys hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem? +//sys hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem? +//sys hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem? +//sys hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem? +//sys hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem? +//sys hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? +//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback? +//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback? +//sys hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback? +//sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback? //sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall? @@ -69,6 +108,18 @@ type HcsError struct { Err error } +type hcsSystem syscall.Handle +type hcsProcess syscall.Handle +type hcsCallback syscall.Handle + +type hcsProcessInformation struct { + ProcessId uint32 + Reserved uint32 + StdInput syscall.Handle + StdOutput syscall.Handle + StdError syscall.Handle +} + func makeError(err error, title, rest string) error { // Pass through DLL errors directly since they do not originate from HCS. if _, ok := err.(*syscall.DLLError); ok { @@ -118,3 +169,15 @@ func convertAndFreeCoTaskMemString(buffer *uint16) string { coTaskMemFree(unsafe.Pointer(buffer)) return str } + +func convertAndFreeCoTaskMemBytes(buffer *uint16) []byte { + return []byte(convertAndFreeCoTaskMemString(buffer)) +} + +func processHcsResult(err error, resultp *uint16) error { + if resultp != nil { + result := convertAndFreeCoTaskMemString(resultp) + logrus.Debugf("Result: %s", result) + } + return err +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go index 590d6e381f..7bf46a6881 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go @@ -20,11 +20,22 @@ type QosPolicy struct { MaximumOutgoingBandwidthInBytes uint64 } +type VlanPolicy struct { + Type string + VLAN uint +} + +type VsidPolicy struct { + Type string + VSID uint +} + // Subnet is assoicated with a network and represents a list // of subnets available to the network type Subnet struct { - AddressPrefix string `json:",omitempty"` - GatewayAddress string `json:",omitempty"` + AddressPrefix string `json:",omitempty"` + GatewayAddress string `json:",omitempty"` + Policies []json.RawMessage `json:",omitempty"` } // MacPool is assoicated with a network and represents a list @@ -36,16 +47,17 @@ type MacPool struct { // HNSNetwork represents a network in HNS type HNSNetwork struct { - Id string `json:",omitempty"` - Name string `json:",omitempty"` - Type string `json:",omitempty"` - NetworkAdapterName string `json:",omitempty"` - SourceMac string `json:",omitempty"` - Policies []json.RawMessage `json:",omitempty"` - MacPools []MacPool `json:",omitempty"` - Subnets []Subnet `json:",omitempty"` - DNSSuffix string `json:",omitempty"` - DNSServerList string `json:",omitempty"` + Id string `json:",omitempty"` + Name string `json:",omitempty"` + Type string `json:",omitempty"` + NetworkAdapterName string `json:",omitempty"` + SourceMac string `json:",omitempty"` + Policies []json.RawMessage `json:",omitempty"` + MacPools []MacPool `json:",omitempty"` + Subnets []Subnet `json:",omitempty"` + DNSSuffix string `json:",omitempty"` + DNSServerList string `json:",omitempty"` + DNSServerCompartment uint32 `json:",omitempty"` } // HNSEndpoint represents a network endpoint in HNS @@ -60,6 +72,7 @@ type HNSEndpoint struct { DNSSuffix string `json:",omitempty"` DNSServerList string `json:",omitempty"` GatewayAddress string `json:",omitempty"` + EnableInternalDNS bool `json:",omitempty"` PrefixLength uint8 `json:",omitempty"` } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go index 800b300b3a..42d7270448 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go @@ -1,8 +1,10 @@ package hcsshim import ( + "errors" "io/ioutil" "os" + "path/filepath" "runtime" "github.com/Microsoft/go-winio" @@ -13,9 +15,9 @@ import ( // that into a layer with the id layerId. Note that in order to correctly populate // the layer and interperet the transport format, all parent layers must already // be present on the system at the paths provided in parentLayerPaths. -func ImportLayer(info DriverInfo, layerId string, importFolderPath string, parentLayerPaths []string) error { +func ImportLayer(info DriverInfo, layerID string, importFolderPath string, parentLayerPaths []string) error { title := "hcsshim::ImportLayer " - logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerId, importFolderPath) + logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerID, importFolderPath) // Generate layer descriptors layers, err := layerPathsToDescriptors(parentLayerPaths) @@ -30,21 +32,29 @@ func ImportLayer(info DriverInfo, layerId string, importFolderPath string, paren return err } - err = importLayer(&infop, layerId, importFolderPath, layers) + err = importLayer(&infop, layerID, importFolderPath, layers) if err != nil { - err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerId, info.Flavour, importFolderPath) + err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerID, info.Flavour, importFolderPath) logrus.Error(err) return err } - logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, importFolderPath) + logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerID, importFolderPath) return nil } +// LayerWriter is an interface that supports writing a new container image layer. type LayerWriter interface { + // Add adds a file to the layer with given metadata. Add(name string, fileInfo *winio.FileBasicInfo) error + // AddLink adds a hard link to the layer. The target must already have been added. + AddLink(name string, target string) error + // Remove removes a file that was present in a parent layer from the layer. Remove(name string) error + // Write writes data to the current file. The data must be in the format of a Win32 + // backup stream. Write(b []byte) (int, error) + // Close finishes the layer writing process and releases any resources. Close() error } @@ -69,6 +79,11 @@ func (w *FilterLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro return nil } +// AddLink adds a hard link to the layer. The target of the link must have already been added. +func (w *FilterLayerWriter) AddLink(name string, target string) error { + return errors.New("hard links not yet supported") +} + // Remove removes a file from the layer. The file must have been present in the parent layer. // // name contains the file's relative path. @@ -107,23 +122,42 @@ func (w *FilterLayerWriter) Close() (err error) { } type legacyLayerWriterWrapper struct { - *LegacyLayerWriter + *legacyLayerWriter info DriverInfo - layerId string + layerID string + path string parentLayerPaths []string } func (r *legacyLayerWriterWrapper) Close() error { - err := r.LegacyLayerWriter.Close() + err := r.legacyLayerWriter.Close() if err == nil { - err = ImportLayer(r.info, r.layerId, r.root, r.parentLayerPaths) + var fullPath string + // Use the original path here because ImportLayer does not support long paths for the source in TP5. + // But do use a long path for the destination to work around another bug with directories + // with MAX_PATH - 12 < length < MAX_PATH. + info := r.info + fullPath, err = makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID)) + if err == nil { + info.HomeDir = "" + err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths) + } } os.RemoveAll(r.root) return err } // NewLayerWriter returns a new layer writer for creating a layer on disk. -func NewLayerWriter(info DriverInfo, layerId string, parentLayerPaths []string) (LayerWriter, error) { +// The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges +// to call this and any methods on the resulting LayerWriter. +func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) { + if len(parentLayerPaths) == 0 { + // This is a base layer. It gets imported differently. + return &baseLayerWriter{ + root: filepath.Join(info.HomeDir, layerID), + }, nil + } + if procImportLayerBegin.Find() != nil { // The new layer reader is not available on this Windows build. Fall back to the // legacy export code path. @@ -131,7 +165,13 @@ func NewLayerWriter(info DriverInfo, layerId string, parentLayerPaths []string) if err != nil { return nil, err } - return &legacyLayerWriterWrapper{NewLegacyLayerWriter(path), info, layerId, parentLayerPaths}, nil + return &legacyLayerWriterWrapper{ + legacyLayerWriter: newLegacyLayerWriter(path), + info: info, + layerID: layerID, + path: path, + parentLayerPaths: parentLayerPaths, + }, nil } layers, err := layerPathsToDescriptors(parentLayerPaths) if err != nil { @@ -144,7 +184,7 @@ func NewLayerWriter(info DriverInfo, layerId string, parentLayerPaths []string) } w := &FilterLayerWriter{} - err = importLayerBegin(&infop, layerId, layers, &w.context) + err = importLayerBegin(&infop, layerID, layers, &w.context) if err != nil { return nil, makeError(err, "ImportLayerStart", "") } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go new file mode 100644 index 0000000000..528cde2f86 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go @@ -0,0 +1,144 @@ +package hcsshim + +import ( + "io" + "time" +) + +// ProcessConfig is used as both the input of Container.CreateProcess +// and to convert the parameters to JSON for passing onto the HCS +type ProcessConfig struct { + ApplicationName string + CommandLine string + WorkingDirectory string + Environment map[string]string + EmulateConsole bool + CreateStdInPipe bool + CreateStdOutPipe bool + CreateStdErrPipe bool + ConsoleSize [2]int +} + +type Layer struct { + ID string + Path string +} + +type MappedDir struct { + HostPath string + ContainerPath string + ReadOnly bool +} + +type HvRuntime struct { + ImagePath string `json:",omitempty"` + SkipTemplate bool `json:",omitempty"` +} + +// ContainerConfig is used as both the input of CreateContainer +// and to convert the parameters to JSON for passing onto the HCS +type ContainerConfig struct { + SystemType string // HCS requires this to be hard-coded to "Container" + Name string // Name of the container. We use the docker ID. + Owner string // The management platform that created this container + IsDummy bool // Used for development purposes. + VolumePath string // Windows volume path for scratch space + IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows + LayerFolderPath string // Where the layer folders are located + Layers []Layer // List of storage layers + Credentials string `json:",omitempty"` // Credentials information + ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container. + ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default. + ProcessorMaximum int64 `json:",omitempty"` // CPU maximum usage percent 1..100 + StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS + StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second + StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller + MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes + HostName string // Hostname + MappedDirectories []MappedDir // List of mapped directories (volumes/mounts) + SandboxPath string // Location of unmounted sandbox (used for Hyper-V containers) + HvPartition bool // True if it a Hyper-V Container + EndpointList []string // List of networking endpoints to be attached to container + HvRuntime *HvRuntime // Hyper-V container settings + Servicing bool // True if this container is for servicing + AllowUnqualifiedDNSQuery bool // True to allow unqualified DNS name resolution +} + +// Container represents a created (but not necessarily running) container. +type Container interface { + // Start synchronously starts the container. + Start() error + + // Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds. + Shutdown() error + + // Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds. + Terminate() error + + // Waits synchronously waits for the container to shutdown or terminate. + Wait() error + + // WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It + // returns false if timeout occurs. + WaitTimeout(time.Duration) error + + // Pause pauses the execution of a container. + Pause() error + + // Resume resumes the execution of a container. + Resume() error + + // HasPendingUpdates returns true if the container has updates pending to install. + HasPendingUpdates() (bool, error) + + // Statistics returns statistics for a container. + Statistics() (Statistics, error) + + // ProcessList returns details for the processes in a container. + ProcessList() ([]ProcessListItem, error) + + // CreateProcess launches a new process within the container. + CreateProcess(c *ProcessConfig) (Process, error) + + // OpenProcess gets an interface to an existing process within the container. + OpenProcess(pid int) (Process, error) + + // Close cleans up any state associated with the container but does not terminate or wait for it. + Close() error +} + +// Process represents a running or exited process. +type Process interface { + // Pid returns the process ID of the process within the container. + Pid() int + + // Kill signals the process to terminate but does not wait for it to finish terminating. + Kill() error + + // Wait waits for the process to exit. + Wait() error + + // WaitTimeout waits for the process to exit or the duration to elapse. It returns + // false if timeout occurs. + WaitTimeout(time.Duration) error + + // ExitCode returns the exit code of the process. The process must have + // already terminated. + ExitCode() (int, error) + + // ResizeConsole resizes the console of the process. + ResizeConsole(width, height uint16) error + + // Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing + // these pipes does not close the underlying pipes; it should be possible to + // call this multiple times to get multiple interfaces. + Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) + + // CloseStdin closes the write side of the stdin pipe so that the process is + // notified on the read side that there is no more data in stdin. + CloseStdin() error + + // Close cleans up any state associated with the process but does not kill + // or wait on it. + Close() error +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go index bc31f23656..e19ac8a902 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go @@ -4,6 +4,7 @@ import ( "bufio" "encoding/binary" "errors" + "fmt" "io" "os" "path/filepath" @@ -16,17 +17,24 @@ import ( var errorIterationCanceled = errors.New("") func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os.File, err error) { - winPath, err := syscall.UTF16FromString(path) - if err != nil { - return + return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition) +} + +func makeLongAbsPath(path string) (string, error) { + if strings.HasPrefix(path, `\\?\`) || strings.HasPrefix(path, `\\.\`) { + return path, nil } - h, err := syscall.CreateFile(&winPath[0], mode, syscall.FILE_SHARE_READ, nil, createDisposition, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) - if err != nil { - err = &os.PathError{"open", path, err} - return + if !filepath.IsAbs(path) { + absPath, err := filepath.Abs(path) + if err != nil { + return "", err + } + path = absPath } - file = os.NewFile(uintptr(h), path) - return + if strings.HasPrefix(path, `\\`) { + return `\\?\UNC\` + path[2:], nil + } + return `\\?\` + path, nil } type fileEntry struct { @@ -35,7 +43,7 @@ type fileEntry struct { err error } -type LegacyLayerReader struct { +type legacyLayerReader struct { root string result chan *fileEntry proceed chan bool @@ -44,10 +52,10 @@ type LegacyLayerReader struct { isTP4Format bool } -// NewLegacyLayerReader returns a new LayerReader that can read the Windows +// newLegacyLayerReader returns a new LayerReader that can read the Windows // TP4 transport format from disk. -func NewLegacyLayerReader(root string) *LegacyLayerReader { - r := &LegacyLayerReader{ +func newLegacyLayerReader(root string) *legacyLayerReader { + r := &legacyLayerReader{ root: root, result: make(chan *fileEntry), proceed: make(chan bool), @@ -70,7 +78,7 @@ func readTombstones(path string) (map[string]([]string), error) { ts := make(map[string]([]string)) for s.Scan() { - t := s.Text()[1:] // skip leading `\` + t := filepath.Join("Files", s.Text()[1:]) // skip leading `\` dir := filepath.Dir(t) ts[dir] = append(ts[dir], t) } @@ -81,15 +89,16 @@ func readTombstones(path string) (map[string]([]string), error) { return ts, nil } -func (r *LegacyLayerReader) walk() { - defer close(r.result) - if !<-r.proceed { - return +func (r *legacyLayerReader) walkUntilCancelled() error { + root, err := makeLongAbsPath(r.root) + if err != nil { + return err } + r.root = root ts, err := readTombstones(r.root) if err != nil { - goto ErrorLoop + return err } err = filepath.Walk(r.root, func(path string, info os.FileInfo, err error) error { @@ -99,6 +108,7 @@ func (r *LegacyLayerReader) walk() { if path == r.root || path == filepath.Join(r.root, "tombstones.txt") || strings.HasSuffix(path, ".$wcidirs$") { return nil } + r.result <- &fileEntry{path, info, nil} if !<-r.proceed { return errorIterationCanceled @@ -112,7 +122,7 @@ func (r *LegacyLayerReader) walk() { } if dts, ok := ts[relPath]; ok { for _, t := range dts { - r.result <- &fileEntry{t, nil, nil} + r.result <- &fileEntry{filepath.Join(r.root, t), nil, nil} if !<-r.proceed { return errorIterationCanceled } @@ -122,22 +132,32 @@ func (r *LegacyLayerReader) walk() { return nil }) if err == errorIterationCanceled { - return + return nil } if err == nil { - err = io.EOF + return io.EOF } + return err +} -ErrorLoop: - for { - r.result <- &fileEntry{err: err} - if !<-r.proceed { - break +func (r *legacyLayerReader) walk() { + defer close(r.result) + if !<-r.proceed { + return + } + + err := r.walkUntilCancelled() + if err != nil { + for { + r.result <- &fileEntry{err: err} + if !<-r.proceed { + return + } } } } -func (r *LegacyLayerReader) reset() { +func (r *legacyLayerReader) reset() { if r.backupReader != nil { r.backupReader.Close() r.backupReader = nil @@ -164,7 +184,7 @@ func findBackupStreamSize(r io.Reader) (int64, error) { } } -func (r *LegacyLayerReader) Next() (path string, size int64, fileInfo *winio.FileBasicInfo, err error) { +func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.FileBasicInfo, err error) { r.reset() r.proceed <- true fe := <-r.result @@ -247,7 +267,7 @@ func (r *LegacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil if !fe.fi.IsDir() { size, err = findBackupStreamSize(f) if err != nil { - err = &os.PathError{"findBackupStreamSize", fe.path, err} + err = &os.PathError{Op: "findBackupStreamSize", Path: fe.path, Err: err} return } } @@ -264,7 +284,7 @@ func (r *LegacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil return } -func (r *LegacyLayerReader) Read(b []byte) (int, error) { +func (r *legacyLayerReader) Read(b []byte) (int, error) { if r.backupReader == nil { if r.currentFile == nil { return 0, io.EOF @@ -274,31 +294,44 @@ func (r *LegacyLayerReader) Read(b []byte) (int, error) { return r.backupReader.Read(b) } -func (r *LegacyLayerReader) Close() error { +func (r *legacyLayerReader) Close() error { r.proceed <- false <-r.result r.reset() return nil } -type LegacyLayerWriter struct { +type legacyLayerWriter struct { root string currentFile *os.File backupWriter *winio.BackupFileWriter tombstones []string isTP4Format bool + pathFixed bool } -// NewLegacyLayerWriter returns a LayerWriter that can write the TP4 transport format +// newLegacyLayerWriter returns a LayerWriter that can write the TP4 transport format // to disk. -func NewLegacyLayerWriter(root string) *LegacyLayerWriter { - return &LegacyLayerWriter{ +func newLegacyLayerWriter(root string) *legacyLayerWriter { + return &legacyLayerWriter{ root: root, isTP4Format: IsTP4(), } } -func (w *LegacyLayerWriter) reset() { +func (w *legacyLayerWriter) init() error { + if !w.pathFixed { + path, err := makeLongAbsPath(w.root) + if err != nil { + return err + } + w.root = path + w.pathFixed = true + } + return nil +} + +func (w *legacyLayerWriter) reset() { if w.backupWriter != nil { w.backupWriter.Close() w.backupWriter = nil @@ -309,8 +342,12 @@ func (w *LegacyLayerWriter) reset() { } } -func (w *LegacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error { +func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error { w.reset() + err := w.init() + if err != nil { + return err + } path := filepath.Join(w.root, name) createDisposition := uint32(syscall.CREATE_NEW) @@ -357,12 +394,19 @@ func (w *LegacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro return nil } -func (w *LegacyLayerWriter) Remove(name string) error { - w.tombstones = append(w.tombstones, name) +func (w *legacyLayerWriter) AddLink(name string, target string) error { + return errors.New("hard links not supported with legacy writer") +} + +func (w *legacyLayerWriter) Remove(name string) error { + if !strings.HasPrefix(name, `Files\`) { + return fmt.Errorf("invalid tombstone %s", name) + } + w.tombstones = append(w.tombstones, name[len(`Files\`):]) return nil } -func (w *LegacyLayerWriter) Write(b []byte) (int, error) { +func (w *legacyLayerWriter) Write(b []byte) (int, error) { if w.backupWriter == nil { if w.currentFile == nil { return 0, errors.New("closed") @@ -372,8 +416,12 @@ func (w *LegacyLayerWriter) Write(b []byte) (int, error) { return w.backupWriter.Write(b) } -func (w *LegacyLayerWriter) Close() error { +func (w *legacyLayerWriter) Close() error { w.reset() + err := w.init() + if err != nil { + return err + } tf, err := os.Create(filepath.Join(w.root, "tombstones.txt")) if err != nil { return err diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/mksyscall_windows.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/mksyscall_windows.go index 7c9a00110a..a76bb4414c 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/mksyscall_windows.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/mksyscall_windows.go @@ -598,6 +598,19 @@ func (f *Fn) HasStringParam() bool { return false } +var uniqDllFuncName = make(map[string]bool) + +// IsNotDuplicate is true if f is not a duplicated function +func (f *Fn) IsNotDuplicate() bool { + funcName := f.DLLFuncName() + if uniqDllFuncName[funcName] == false { + uniqDllFuncName[funcName] = true + return true + } + + return false +} + // HelperName returns name of function f helper. func (f *Fn) HelperName() string { if !f.HasStringParam() { @@ -748,6 +761,7 @@ const srcTemplate = ` package {{packagename}} +import "github.com/Microsoft/go-winio" import "unsafe"{{if syscalldot}} import "syscall"{{end}} @@ -764,7 +778,7 @@ var ( {{define "dlls"}}{{range .DLLs}} mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll") {{end}}{{end}} -{{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}") +{{define "funcnames"}}{{range .Funcs}}{{if .IsNotDuplicate}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}"){{end}} {{end}}{{end}} {{define "helperbody"}} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go new file mode 100644 index 0000000000..d6e63c9223 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go @@ -0,0 +1,389 @@ +package hcsshim + +import ( + "encoding/json" + "io" + "syscall" + "time" + + "github.com/Sirupsen/logrus" +) + +// ContainerError is an error encountered in HCS +type process struct { + handle hcsProcess + processID int + container *container + cachedPipes *cachedPipes + callbackNumber uintptr +} + +type cachedPipes struct { + stdIn syscall.Handle + stdOut syscall.Handle + stdErr syscall.Handle +} + +type processModifyRequest struct { + Operation string + ConsoleSize *consoleSize `json:",omitempty"` + CloseHandle *closeHandle `json:",omitempty"` +} + +type consoleSize struct { + Height uint16 + Width uint16 +} + +type closeHandle struct { + Handle string +} + +type processStatus struct { + ProcessID uint32 + Exited bool + ExitCode uint32 + LastWaitResult int32 +} + +const ( + stdIn string = "StdIn" + stdOut string = "StdOut" + stdErr string = "StdErr" +) + +const ( + modifyConsoleSize string = "ConsoleSize" + modifyCloseHandle string = "CloseHandle" +) + +// Pid returns the process ID of the process within the container. +func (process *process) Pid() int { + return process.processID +} + +// Kill signals the process to terminate but does not wait for it to finish terminating. +func (process *process) Kill() error { + operation := "Kill" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + var resultp *uint16 + err := hcsTerminateProcess(process.handle, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return makeProcessError(process, operation, "", err) + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +// Wait waits for the process to exit. +func (process *process) Wait() error { + operation := "Wait" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + if hcsCallbacksSupported { + err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil) + if err != nil { + return makeProcessError(process, operation, "", err) + } + } else { + _, err := process.waitTimeoutInternal(syscall.INFINITE) + if err != nil { + return makeProcessError(process, operation, "", err) + } + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +// WaitTimeout waits for the process to exit or the duration to elapse. It returns +// false if timeout occurs. +func (process *process) WaitTimeout(timeout time.Duration) error { + operation := "WaitTimeout" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + if hcsCallbacksSupported { + err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout) + if err != nil { + return makeProcessError(process, operation, "", err) + } + } else { + finished, err := waitTimeoutHelper(process, timeout) + if !finished { + err = ErrTimeout + } + if err != nil { + return makeProcessError(process, operation, "", err) + } + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +func (process *process) hcsWait(timeout uint32) (bool, error) { + var ( + resultp *uint16 + exitEvent syscall.Handle + ) + err := hcsCreateProcessWait(process.handle, &exitEvent, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return false, err + } + defer syscall.CloseHandle(exitEvent) + + return waitForSingleObject(exitEvent, timeout) +} + +func (process *process) waitTimeoutInternal(timeout uint32) (bool, error) { + return waitTimeoutInternalHelper(process, timeout) +} + +// ExitCode returns the exit code of the process. The process must have +// already terminated. +func (process *process) ExitCode() (int, error) { + operation := "ExitCode" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + properties, err := process.properties() + if err != nil { + return 0, makeProcessError(process, operation, "", err) + } + + if properties.Exited == false { + return 0, makeProcessError(process, operation, "", ErrInvalidProcessState) + } + + logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode) + return int(properties.ExitCode), nil +} + +// ResizeConsole resizes the console of the process. +func (process *process) ResizeConsole(width, height uint16) error { + operation := "ResizeConsole" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + modifyRequest := processModifyRequest{ + Operation: modifyConsoleSize, + ConsoleSize: &consoleSize{ + Height: height, + Width: width, + }, + } + + modifyRequestb, err := json.Marshal(modifyRequest) + if err != nil { + return err + } + + modifyRequestStr := string(modifyRequestb) + + var resultp *uint16 + err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return makeProcessError(process, operation, "", err) + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +func (process *process) properties() (*processStatus, error) { + operation := "properties" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + var ( + resultp *uint16 + propertiesp *uint16 + ) + err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return nil, err + } + + if propertiesp == nil { + return nil, ErrUnexpectedValue + } + propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp) + + properties := &processStatus{} + if err := json.Unmarshal(propertiesRaw, properties); err != nil { + return nil, err + } + + logrus.Debugf(title+" succeeded processid=%d, properties=%s", process.processID, propertiesRaw) + return properties, nil +} + +// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing +// these pipes does not close the underlying pipes; it should be possible to +// call this multiple times to get multiple interfaces. +func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) { + operation := "Stdio" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + var stdIn, stdOut, stdErr syscall.Handle + + if process.cachedPipes == nil { + var ( + processInfo hcsProcessInformation + resultp *uint16 + ) + err := hcsGetProcessInfo(process.handle, &processInfo, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return nil, nil, nil, makeProcessError(process, operation, "", err) + } + + stdIn, stdOut, stdErr = processInfo.StdInput, processInfo.StdOutput, processInfo.StdError + } else { + // Use cached pipes + stdIn, stdOut, stdErr = process.cachedPipes.stdIn, process.cachedPipes.stdOut, process.cachedPipes.stdErr + + // Invalidate the cache + process.cachedPipes = nil + } + + pipes, err := makeOpenFiles([]syscall.Handle{stdIn, stdOut, stdErr}) + if err != nil { + return nil, nil, nil, makeProcessError(process, operation, "", err) + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return pipes[0], pipes[1], pipes[2], nil +} + +// CloseStdin closes the write side of the stdin pipe so that the process is +// notified on the read side that there is no more data in stdin. +func (process *process) CloseStdin() error { + operation := "CloseStdin" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + modifyRequest := processModifyRequest{ + Operation: modifyCloseHandle, + CloseHandle: &closeHandle{ + Handle: stdIn, + }, + } + + modifyRequestb, err := json.Marshal(modifyRequest) + if err != nil { + return err + } + + modifyRequestStr := string(modifyRequestb) + + var resultp *uint16 + err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return makeProcessError(process, operation, "", err) + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +// Close cleans up any state associated with the process but does not kill +// or wait on it. +func (process *process) Close() error { + operation := "Close" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + // Don't double free this + if process.handle == 0 { + return nil + } + + if hcsCallbacksSupported { + if err := process.unregisterCallback(); err != nil { + return makeProcessError(process, operation, "", err) + } + } + + if err := hcsCloseProcess(process.handle); err != nil { + return makeProcessError(process, operation, "", err) + } + + process.handle = 0 + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +// closeProcess wraps process.Close for use by a finalizer +func closeProcess(process *process) { + process.Close() +} + +func (process *process) registerCallback() error { + context := ¬ifcationWatcherContext{ + channels: newChannels(), + } + + callbackMapLock.Lock() + callbackNumber := nextCallback + nextCallback++ + callbackMap[callbackNumber] = context + callbackMapLock.Unlock() + + var callbackHandle hcsCallback + err := hcsRegisterProcessCallback(process.handle, notificationWatcherCallback, callbackNumber, &callbackHandle) + if err != nil { + return err + } + context.handle = callbackHandle + process.callbackNumber = callbackNumber + + return nil +} + +func (process *process) unregisterCallback() error { + callbackNumber := process.callbackNumber + + callbackMapLock.RLock() + context := callbackMap[callbackNumber] + callbackMapLock.RUnlock() + + if context == nil { + return nil + } + + handle := context.handle + + if handle == 0 { + return nil + } + + // hcsUnregisterProcessCallback has its own syncronization + // to wait for all callbacks to complete. We must NOT hold the callbackMapLock. + err := hcsUnregisterProcessCallback(handle) + if err != nil { + return err + } + + closeChannels(context.channels) + + callbackMapLock.Lock() + callbackMap[callbackNumber] = nil + callbackMapLock.Unlock() + + handle = 0 + + return nil +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/resizeconsole.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/resizeconsole.go deleted file mode 100644 index d04ce70d85..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/resizeconsole.go +++ /dev/null @@ -1,22 +0,0 @@ -package hcsshim - -import "github.com/Sirupsen/logrus" - -// ResizeConsoleInComputeSystem updates the height and width of the console -// session for the process with the given id in the container with the given id. -func ResizeConsoleInComputeSystem(id string, processid uint32, h, w int) error { - - title := "HCSShim::ResizeConsoleInComputeSystem" - logrus.Debugf(title+" id=%s processid=%d (%d,%d)", id, processid, h, w) - - err := resizeConsoleInComputeSystem(id, processid, uint16(h), uint16(w), 0) - if err != nil { - err = makeErrorf(err, title, "id=%s pid=%d", id, processid) - logrus.Error(err) - return err - } - - logrus.Debugf(title+" succeeded id=%s processid=%d (%d,%d)", id, processid, h, w) - return nil - -} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/shutdownterminatecomputesystem.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/shutdownterminatecomputesystem.go deleted file mode 100644 index 27ac734bd8..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/shutdownterminatecomputesystem.go +++ /dev/null @@ -1,43 +0,0 @@ -package hcsshim - -import "github.com/Sirupsen/logrus" - -// TerminateComputeSystem force terminates a container. -func TerminateComputeSystem(id string, timeout uint32, context string) error { - return shutdownTerminate(false, id, timeout, context) -} - -// ShutdownComputeSystem shuts down a container by requesting a shutdown within -// the container operating system. -func ShutdownComputeSystem(id string, timeout uint32, context string) error { - return shutdownTerminate(true, id, timeout, context) -} - -// shutdownTerminate is a wrapper for ShutdownComputeSystem and TerminateComputeSystem -// which have very similar calling semantics -func shutdownTerminate(shutdown bool, id string, timeout uint32, context string) error { - - var ( - title = "HCSShim::" - ) - if shutdown { - title = title + "ShutdownComputeSystem" - } else { - title = title + "TerminateComputeSystem" - } - logrus.Debugf(title+" id=%s context=%s", id, context) - - var err error - if shutdown { - err = shutdownComputeSystem(id, timeout) - } else { - err = terminateComputeSystem(id) - } - - if err != nil { - return makeErrorf(err, title, "id=%s context=%s", id, context) - } - - logrus.Debugf(title+" succeeded id=%s context=%s", id, context) - return nil -} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/startcomputesystem.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/startcomputesystem.go deleted file mode 100644 index 41a7e676f7..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/startcomputesystem.go +++ /dev/null @@ -1,21 +0,0 @@ -package hcsshim - -import "github.com/Sirupsen/logrus" - -// StartComputeSystem starts a container that has previously been created via -// CreateComputeSystem. -func StartComputeSystem(id string) error { - - title := "HCSShim::StartComputeSystem" - logrus.Debugf(title+" id=%s", id) - - err := startComputeSystem(id) - if err != nil { - err = makeErrorf(err, title, "id=%s", id) - logrus.Error(err) - return err - } - - logrus.Debugf(title+" succeeded id=%s", id) - return nil -} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/terminateprocess.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/terminateprocess.go deleted file mode 100644 index 47880afce1..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/terminateprocess.go +++ /dev/null @@ -1,20 +0,0 @@ -package hcsshim - -import "github.com/Sirupsen/logrus" - -// TerminateProcessInComputeSystem kills a process in a running container. -func TerminateProcessInComputeSystem(id string, processid uint32) (err error) { - - title := "HCSShim::TerminateProcessInComputeSystem" - logrus.Debugf(title+" id=%s processid=%d", id, processid) - - err = terminateProcessInComputeSystem(id, processid) - if err != nil { - err = makeErrorf(err, title, "err=%s id=%s", id) - logrus.Error(err) - return err - } - - logrus.Debugf(title+" succeeded id=%s", id) - return nil -} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go new file mode 100644 index 0000000000..c219e2c07d --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go @@ -0,0 +1,39 @@ +package hcsshim + +import ( + "io" + "syscall" + + "github.com/Microsoft/go-winio" +) + +var ( + vmcomputedll = syscall.NewLazyDLL("vmcompute.dll") + hcsCallbackAPI = vmcomputedll.NewProc("HcsRegisterComputeSystemCallback") + hcsCallbacksSupported = hcsCallbackAPI.Find() == nil +) + +// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles +// if there is an error. +func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) { + fs := make([]io.ReadWriteCloser, len(hs)) + for i, h := range hs { + if h != syscall.Handle(0) { + if err == nil { + fs[i], err = winio.MakeOpenFile(h) + } + if err != nil { + syscall.Close(h) + } + } + } + if err != nil { + for _, f := range fs { + if f != nil { + f.Close() + } + } + return nil, err + } + return fs, nil +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go new file mode 100644 index 0000000000..8ce65ae110 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go @@ -0,0 +1,126 @@ +package hcsshim + +import ( + "github.com/Sirupsen/logrus" + "syscall" + "time" +) + +type waitable interface { + waitTimeoutInternal(timeout uint32) (bool, error) + hcsWait(timeout uint32) (bool, error) +} + +func waitTimeoutHelper(object waitable, timeout time.Duration) (bool, error) { + var ( + millis uint32 + ) + + for totalMillis := uint64(timeout / time.Millisecond); totalMillis > 0; totalMillis = totalMillis - uint64(millis) { + if totalMillis >= syscall.INFINITE { + millis = syscall.INFINITE - 1 + } else { + millis = uint32(totalMillis) + } + + result, err := object.waitTimeoutInternal(millis) + + if err != nil { + return result, err + } + } + return true, nil +} + +func waitTimeoutInternalHelper(object waitable, timeout uint32) (bool, error) { + return object.hcsWait(timeout) +} + +func waitForSingleObject(handle syscall.Handle, timeout uint32) (bool, error) { + s, e := syscall.WaitForSingleObject(handle, timeout) + switch s { + case syscall.WAIT_OBJECT_0: + return true, nil + case syscall.WAIT_TIMEOUT: + return false, nil + default: + return false, e + } +} + +func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error { + err = processHcsResult(err, resultp) + if IsPending(err) { + return waitForNotification(callbackNumber, expectedNotification, timeout) + } + + return err +} + +func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error { + callbackMapLock.RLock() + channels := callbackMap[callbackNumber].channels + callbackMapLock.RUnlock() + + expectedChannel := channels[expectedNotification] + if expectedChannel == nil { + logrus.Errorf("unknown notification type in waitForNotification %x", expectedNotification) + return ErrInvalidNotificationType + } + + if timeout != nil { + timer := time.NewTimer(*timeout) + defer timer.Stop() + + select { + case err, ok := <-expectedChannel: + if !ok { + return ErrHandleClose + } + return err + case err, ok := <-channels[hcsNotificationSystemExited]: + if !ok { + return ErrHandleClose + } + // If the expected notification is hcsNotificationSystemExited which of the two selects + // chosen is random. Return the raw error if hcsNotificationSystemExited is expected + if channels[hcsNotificationSystemExited] == expectedChannel { + return err + } + return ErrUnexpectedContainerExit + case _, ok := <-channels[hcsNotificationServiceDisconnect]: + if !ok { + return ErrHandleClose + } + // hcsNotificationServiceDisconnect should never be an expected notification + // it does not need the same handling as hcsNotificationSystemExited + return ErrUnexpectedProcessAbort + case <-timer.C: + return ErrTimeout + } + } + select { + case err, ok := <-expectedChannel: + if !ok { + return ErrHandleClose + } + return err + case err, ok := <-channels[hcsNotificationSystemExited]: + if !ok { + return ErrHandleClose + } + // If the expected notification is hcsNotificationSystemExited which of the two selects + // chosen is random. Return the raw error if hcsNotificationSystemExited is expected + if channels[hcsNotificationSystemExited] == expectedChannel { + return err + } + return ErrUnexpectedContainerExit + case _, ok := <-channels[hcsNotificationServiceDisconnect]: + if !ok { + return ErrHandleClose + } + // hcsNotificationServiceDisconnect should never be an expected notification + // it does not need the same handling as hcsNotificationSystemExited + return ErrUnexpectedProcessAbort + } +} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waitprocess.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waitprocess.go deleted file mode 100644 index e916140399..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waitprocess.go +++ /dev/null @@ -1,20 +0,0 @@ -package hcsshim - -import "github.com/Sirupsen/logrus" - -// WaitForProcessInComputeSystem waits for a process ID to terminate and returns -// the exit code. Returns exitcode, error -func WaitForProcessInComputeSystem(id string, processid uint32, timeout uint32) (int32, error) { - - title := "HCSShim::WaitForProcessInComputeSystem" - logrus.Debugf(title+" id=%s processid=%d", id, processid) - - var exitCode uint32 - err := waitForProcessInComputeSystem(id, processid, timeout, &exitCode) - if err != nil { - return 0, makeErrorf(err, title, "id=%s", id) - } - - logrus.Debugf(title+" succeeded id=%s processid=%d exitcode=%d", id, processid, exitCode) - return int32(exitCode), nil -} diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go index 03924b6fcc..3ae95864cc 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go @@ -2,24 +2,24 @@ package hcsshim -import ( - "unsafe" - - "github.com/Microsoft/go-winio" -) +import "github.com/Microsoft/go-winio" +import "unsafe" import "syscall" var _ unsafe.Pointer var ( modole32 = syscall.NewLazyDLL("ole32.dll") + modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") modvmcompute = syscall.NewLazyDLL("vmcompute.dll") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") + procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId") procActivateLayer = modvmcompute.NewProc("ActivateLayer") procCopyLayer = modvmcompute.NewProc("CopyLayer") procCreateLayer = modvmcompute.NewProc("CreateLayer") procCreateSandboxLayer = modvmcompute.NewProc("CreateSandboxLayer") + procExpandSandboxSize = modvmcompute.NewProc("ExpandSandboxSize") procDeactivateLayer = modvmcompute.NewProc("DeactivateLayer") procDestroyLayer = modvmcompute.NewProc("DestroyLayer") procExportLayer = modvmcompute.NewProc("ExportLayer") @@ -48,7 +48,35 @@ var ( procTerminateComputeSystem = modvmcompute.NewProc("TerminateComputeSystem") procTerminateProcessInComputeSystem = modvmcompute.NewProc("TerminateProcessInComputeSystem") procWaitForProcessInComputeSystem = modvmcompute.NewProc("WaitForProcessInComputeSystem") - procHNSCall = modvmcompute.NewProc("HNSCall") + procGetComputeSystemProperties = modvmcompute.NewProc("GetComputeSystemProperties") + procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems") + procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem") + procHcsOpenComputeSystem = modvmcompute.NewProc("HcsOpenComputeSystem") + procHcsCloseComputeSystem = modvmcompute.NewProc("HcsCloseComputeSystem") + procHcsStartComputeSystem = modvmcompute.NewProc("HcsStartComputeSystem") + procHcsShutdownComputeSystem = modvmcompute.NewProc("HcsShutdownComputeSystem") + procHcsTerminateComputeSystem = modvmcompute.NewProc("HcsTerminateComputeSystem") + procHcsPauseComputeSystem = modvmcompute.NewProc("HcsPauseComputeSystem") + procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem") + procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties") + procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem") + procHcsCreateComputeSystemWait = modvmcompute.NewProc("HcsCreateComputeSystemWait") + procHcsCreateProcess = modvmcompute.NewProc("HcsCreateProcess") + procHcsOpenProcess = modvmcompute.NewProc("HcsOpenProcess") + procHcsCloseProcess = modvmcompute.NewProc("HcsCloseProcess") + procHcsTerminateProcess = modvmcompute.NewProc("HcsTerminateProcess") + procHcsGetProcessInfo = modvmcompute.NewProc("HcsGetProcessInfo") + procHcsGetProcessProperties = modvmcompute.NewProc("HcsGetProcessProperties") + procHcsModifyProcess = modvmcompute.NewProc("HcsModifyProcess") + procHcsCreateProcessWait = modvmcompute.NewProc("HcsCreateProcessWait") + procHcsGetServiceProperties = modvmcompute.NewProc("HcsGetServiceProperties") + procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings") + + procHcsRegisterComputeSystemCallback = modvmcompute.NewProc("HcsRegisterComputeSystemCallback") + procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback") + procHcsRegisterProcessCallback = modvmcompute.NewProc("HcsRegisterProcessCallback") + procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback") + procHNSCall = modvmcompute.NewProc("HNSCall") ) func coTaskMemFree(buffer unsafe.Pointer) { @@ -56,6 +84,14 @@ func coTaskMemFree(buffer unsafe.Pointer) { return } +func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) { + r0, _, _ := syscall.Syscall(procSetCurrentThreadCompartmentId.Addr(), 1, uintptr(compartmentId), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + func activateLayer(info *driverInfo, id string) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(id) @@ -159,6 +195,26 @@ func _createSandboxLayer(info *driverInfo, id *uint16, parent *uint16, descripto return } +func expandSandboxSize(info *driverInfo, id string, size uint64) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(id) + if hr != nil { + return + } + return _expandSandboxSize(info, _p0, size) +} + +func _expandSandboxSize(info *driverInfo, id *uint16, size uint64) (hr error) { + if hr = procExpandSandboxSize.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procExpandSandboxSize.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(size)) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + func deactivateLayer(info *driverInfo, id string) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(id) @@ -713,6 +769,523 @@ func _waitForProcessInComputeSystem(id *uint16, pid uint32, timeout uint32, exit return } +func getComputeSystemProperties(id string, flags uint32, properties **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(id) + if hr != nil { + return + } + return _getComputeSystemProperties(_p0, flags, properties) +} + +func _getComputeSystemProperties(id *uint16, flags uint32, properties **uint16) (hr error) { + if hr = procGetComputeSystemProperties.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procGetComputeSystemProperties.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(flags), uintptr(unsafe.Pointer(properties))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(query) + if hr != nil { + return + } + return _hcsEnumerateComputeSystems(_p0, computeSystems, result) +} + +func _hcsEnumerateComputeSystems(query *uint16, computeSystems **uint16, result **uint16) (hr error) { + if hr = procHcsEnumerateComputeSystems.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(id) + if hr != nil { + return + } + var _p1 *uint16 + _p1, hr = syscall.UTF16PtrFromString(configuration) + if hr != nil { + return + } + return _hcsCreateComputeSystem(_p0, _p1, identity, computeSystem, result) +} + +func _hcsCreateComputeSystem(id *uint16, configuration *uint16, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) { + if hr = procHcsCreateComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(id) + if hr != nil { + return + } + return _hcsOpenComputeSystem(_p0, computeSystem, result) +} + +func _hcsOpenComputeSystem(id *uint16, computeSystem *hcsSystem, result **uint16) (hr error) { + if hr = procHcsOpenComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) { + if hr = procHcsCloseComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsStartComputeSystem(computeSystem, _p0, result) +} + +func _hcsStartComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsStartComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsShutdownComputeSystem(computeSystem, _p0, result) +} + +func _hcsShutdownComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsShutdownComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsTerminateComputeSystem(computeSystem, _p0, result) +} + +func _hcsTerminateComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsTerminateComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsPauseComputeSystem(computeSystem, _p0, result) +} + +func _hcsPauseComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsPauseComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsResumeComputeSystem(computeSystem, _p0, result) +} + +func _hcsResumeComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsResumeComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(propertyQuery) + if hr != nil { + return + } + return _hcsGetComputeSystemProperties(computeSystem, _p0, properties, result) +} + +func _hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery *uint16, properties **uint16, result **uint16) (hr error) { + if hr = procHcsGetComputeSystemProperties.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(configuration) + if hr != nil { + return + } + return _hcsModifyComputeSystem(computeSystem, _p0, result) +} + +func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, result **uint16) (hr error) { + if hr = procHcsModifyComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) { + if hr = procHcsCreateComputeSystemWait.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsCreateComputeSystemWait.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(exitEvent)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(processParameters) + if hr != nil { + return + } + return _hcsCreateProcess(computeSystem, _p0, processInformation, process, result) +} + +func _hcsCreateProcess(computeSystem hcsSystem, processParameters *uint16, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) { + if hr = procHcsCreateProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) { + if hr = procHcsOpenProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCloseProcess(process hcsProcess) (hr error) { + if hr = procHcsCloseProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) { + if hr = procHcsTerminateProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) { + if hr = procHcsGetProcessInfo.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) { + if hr = procHcsGetProcessProperties.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(settings) + if hr != nil { + return + } + return _hcsModifyProcess(process, _p0, result) +} + +func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (hr error) { + if hr = procHcsModifyProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) { + if hr = procHcsCreateProcessWait.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsCreateProcessWait.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(propertyQuery) + if hr != nil { + return + } + return _hcsGetServiceProperties(_p0, properties, result) +} + +func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result **uint16) (hr error) { + if hr = procHcsGetServiceProperties.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsModifyServiceSettings(settings string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(settings) + if hr != nil { + return + } + return _hcsModifyServiceSettings(_p0, result) +} + +func _hcsModifyServiceSettings(settings *uint16, result **uint16) (hr error) { + if hr = procHcsModifyServiceSettings.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsModifyServiceSettings.Addr(), 2, uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)), 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(id) + if hr != nil { + return + } + var _p1 *uint16 + _p1, hr = syscall.UTF16PtrFromString(configuration) + if hr != nil { + return + } + return _hcsCreateComputeSystemTP5(_p0, _p1, computeSystem, result) +} + +func _hcsCreateComputeSystemTP5(id *uint16, configuration *uint16, computeSystem *hcsSystem, result **uint16) (hr error) { + if hr = procHcsCreateComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsStartComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsShutdownComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsTerminateComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsPauseComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsResumeComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { + if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) { + if hr = procHcsUnregisterComputeSystemCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { + if hr = procHcsRegisterProcessCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) { + if hr = procHcsUnregisterProcessCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + func _hnsCall(method string, path string, object string, response **uint16) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(method) diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/asm.s b/Godeps/_workspace/src/golang.org/x/sys/windows/asm.s new file mode 100644 index 0000000000..d4ca868f17 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/asm.s @@ -0,0 +1,8 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +TEXT ·use(SB),NOSPLIT,$0 + RET diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/asm_windows_386.s b/Godeps/_workspace/src/golang.org/x/sys/windows/asm_windows_386.s new file mode 100644 index 0000000000..1c20dd2f89 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/asm_windows_386.s @@ -0,0 +1,13 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +// System calls for 386, Windows are implemented in runtime/syscall_windows.goc +// + +TEXT ·getprocaddress(SB), 7, $0-8 + JMP syscall·getprocaddress(SB) + +TEXT ·loadlibrary(SB), 7, $0-4 + JMP syscall·loadlibrary(SB) diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/asm_windows_amd64.s b/Godeps/_workspace/src/golang.org/x/sys/windows/asm_windows_amd64.s new file mode 100644 index 0000000000..4d025ab556 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/asm_windows_amd64.s @@ -0,0 +1,13 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +// System calls for amd64, Windows are implemented in runtime/syscall_windows.goc +// + +TEXT ·getprocaddress(SB), 7, $0-32 + JMP syscall·getprocaddress(SB) + +TEXT ·loadlibrary(SB), 7, $0-8 + JMP syscall·loadlibrary(SB) diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/dll_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/dll_windows.go new file mode 100644 index 0000000000..7f9f05f934 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/dll_windows.go @@ -0,0 +1,275 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import ( + "sync" + "sync/atomic" + "syscall" + "unsafe" +) + +// DLLError describes reasons for DLL load failures. +type DLLError struct { + Err error + ObjName string + Msg string +} + +func (e *DLLError) Error() string { return e.Msg } + +// Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file. +func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno) +func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno) + +// A DLL implements access to a single DLL. +type DLL struct { + Name string + Handle Handle +} + +// LoadDLL loads DLL file into memory. +func LoadDLL(name string) (dll *DLL, err error) { + namep, err := UTF16PtrFromString(name) + if err != nil { + return nil, err + } + h, e := loadlibrary(namep) + if e != 0 { + return nil, &DLLError{ + Err: e, + ObjName: name, + Msg: "Failed to load " + name + ": " + e.Error(), + } + } + d := &DLL{ + Name: name, + Handle: Handle(h), + } + return d, nil +} + +// MustLoadDLL is like LoadDLL but panics if load operation failes. +func MustLoadDLL(name string) *DLL { + d, e := LoadDLL(name) + if e != nil { + panic(e) + } + return d +} + +// FindProc searches DLL d for procedure named name and returns *Proc +// if found. It returns an error if search fails. +func (d *DLL) FindProc(name string) (proc *Proc, err error) { + namep, err := BytePtrFromString(name) + if err != nil { + return nil, err + } + a, e := getprocaddress(uintptr(d.Handle), namep) + if e != 0 { + return nil, &DLLError{ + Err: e, + ObjName: name, + Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(), + } + } + p := &Proc{ + Dll: d, + Name: name, + addr: a, + } + return p, nil +} + +// MustFindProc is like FindProc but panics if search fails. +func (d *DLL) MustFindProc(name string) *Proc { + p, e := d.FindProc(name) + if e != nil { + panic(e) + } + return p +} + +// Release unloads DLL d from memory. +func (d *DLL) Release() (err error) { + return FreeLibrary(d.Handle) +} + +// A Proc implements access to a procedure inside a DLL. +type Proc struct { + Dll *DLL + Name string + addr uintptr +} + +// Addr returns the address of the procedure represented by p. +// The return value can be passed to Syscall to run the procedure. +func (p *Proc) Addr() uintptr { + return p.addr +} + +// Call executes procedure p with arguments a. It will panic, if more then 15 arguments +// are supplied. +// +// The returned error is always non-nil, constructed from the result of GetLastError. +// Callers must inspect the primary return value to decide whether an error occurred +// (according to the semantics of the specific function being called) before consulting +// the error. The error will be guaranteed to contain windows.Errno. +func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { + switch len(a) { + case 0: + return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0) + case 1: + return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0) + case 2: + return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0) + case 3: + return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2]) + case 4: + return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0) + case 5: + return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0) + case 6: + return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5]) + case 7: + return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0) + case 8: + return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0) + case 9: + return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]) + case 10: + return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0) + case 11: + return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0) + case 12: + return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]) + case 13: + return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0) + case 14: + return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0) + case 15: + return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14]) + default: + panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") + } + return +} + +// A LazyDLL implements access to a single DLL. +// It will delay the load of the DLL until the first +// call to its Handle method or to one of its +// LazyProc's Addr method. +type LazyDLL struct { + mu sync.Mutex + dll *DLL // non nil once DLL is loaded + Name string +} + +// Load loads DLL file d.Name into memory. It returns an error if fails. +// Load will not try to load DLL, if it is already loaded into memory. +func (d *LazyDLL) Load() error { + // Non-racy version of: + // if d.dll == nil { + if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil { + d.mu.Lock() + defer d.mu.Unlock() + if d.dll == nil { + dll, e := LoadDLL(d.Name) + if e != nil { + return e + } + // Non-racy version of: + // d.dll = dll + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll)) + } + } + return nil +} + +// mustLoad is like Load but panics if search fails. +func (d *LazyDLL) mustLoad() { + e := d.Load() + if e != nil { + panic(e) + } +} + +// Handle returns d's module handle. +func (d *LazyDLL) Handle() uintptr { + d.mustLoad() + return uintptr(d.dll.Handle) +} + +// NewProc returns a LazyProc for accessing the named procedure in the DLL d. +func (d *LazyDLL) NewProc(name string) *LazyProc { + return &LazyProc{l: d, Name: name} +} + +// NewLazyDLL creates new LazyDLL associated with DLL file. +func NewLazyDLL(name string) *LazyDLL { + return &LazyDLL{Name: name} +} + +// A LazyProc implements access to a procedure inside a LazyDLL. +// It delays the lookup until the Addr method is called. +type LazyProc struct { + mu sync.Mutex + Name string + l *LazyDLL + proc *Proc +} + +// Find searches DLL for procedure named p.Name. It returns +// an error if search fails. Find will not search procedure, +// if it is already found and loaded into memory. +func (p *LazyProc) Find() error { + // Non-racy version of: + // if p.proc == nil { + if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil { + p.mu.Lock() + defer p.mu.Unlock() + if p.proc == nil { + e := p.l.Load() + if e != nil { + return e + } + proc, e := p.l.dll.FindProc(p.Name) + if e != nil { + return e + } + // Non-racy version of: + // p.proc = proc + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc)) + } + } + return nil +} + +// mustFind is like Find but panics if search fails. +func (p *LazyProc) mustFind() { + e := p.Find() + if e != nil { + panic(e) + } +} + +// Addr returns the address of the procedure represented by p. +// The return value can be passed to Syscall to run the procedure. +func (p *LazyProc) Addr() uintptr { + p.mustFind() + return p.proc.Addr() +} + +// Call executes procedure p with arguments a. It will panic, if more then 15 arguments +// are supplied. +// +// The returned error is always non-nil, constructed from the result of GetLastError. +// Callers must inspect the primary return value to decide whether an error occurred +// (according to the semantics of the specific function being called) before consulting +// the error. The error will be guaranteed to contain windows.Errno. +func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { + p.mustFind() + return p.proc.Call(a...) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/env_unset.go b/Godeps/_workspace/src/golang.org/x/sys/windows/env_unset.go new file mode 100644 index 0000000000..999ffac434 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/env_unset.go @@ -0,0 +1,14 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.4 + +package windows + +import "syscall" + +func Unsetenv(key string) error { + // This was added in Go 1.4. + return syscall.Unsetenv(key) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/env_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/env_windows.go new file mode 100644 index 0000000000..a9d8ef4b7d --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/env_windows.go @@ -0,0 +1,25 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Windows environment variables. + +package windows + +import "syscall" + +func Getenv(key string) (value string, found bool) { + return syscall.Getenv(key) +} + +func Setenv(key, value string) error { + return syscall.Setenv(key, value) +} + +func Clearenv() { + syscall.Clearenv() +} + +func Environ() []string { + return syscall.Environ() +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/eventlog.go b/Godeps/_workspace/src/golang.org/x/sys/windows/eventlog.go new file mode 100644 index 0000000000..40af946e16 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/eventlog.go @@ -0,0 +1,20 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package windows + +const ( + EVENTLOG_SUCCESS = 0 + EVENTLOG_ERROR_TYPE = 1 + EVENTLOG_WARNING_TYPE = 2 + EVENTLOG_INFORMATION_TYPE = 4 + EVENTLOG_AUDIT_SUCCESS = 8 + EVENTLOG_AUDIT_FAILURE = 16 +) + +//sys RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) [failretval==0] = advapi32.RegisterEventSourceW +//sys DeregisterEventSource(handle Handle) (err error) = advapi32.DeregisterEventSource +//sys ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) = advapi32.ReportEventW diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/exec_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/exec_windows.go new file mode 100644 index 0000000000..3606c3a8b3 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/exec_windows.go @@ -0,0 +1,97 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Fork, exec, wait, etc. + +package windows + +// EscapeArg rewrites command line argument s as prescribed +// in http://msdn.microsoft.com/en-us/library/ms880421. +// This function returns "" (2 double quotes) if s is empty. +// Alternatively, these transformations are done: +// - every back slash (\) is doubled, but only if immediately +// followed by double quote ("); +// - every double quote (") is escaped by back slash (\); +// - finally, s is wrapped with double quotes (arg -> "arg"), +// but only if there is space or tab inside s. +func EscapeArg(s string) string { + if len(s) == 0 { + return "\"\"" + } + n := len(s) + hasSpace := false + for i := 0; i < len(s); i++ { + switch s[i] { + case '"', '\\': + n++ + case ' ', '\t': + hasSpace = true + } + } + if hasSpace { + n += 2 + } + if n == len(s) { + return s + } + + qs := make([]byte, n) + j := 0 + if hasSpace { + qs[j] = '"' + j++ + } + slashes := 0 + for i := 0; i < len(s); i++ { + switch s[i] { + default: + slashes = 0 + qs[j] = s[i] + case '\\': + slashes++ + qs[j] = s[i] + case '"': + for ; slashes > 0; slashes-- { + qs[j] = '\\' + j++ + } + qs[j] = '\\' + j++ + qs[j] = s[i] + } + j++ + } + if hasSpace { + for ; slashes > 0; slashes-- { + qs[j] = '\\' + j++ + } + qs[j] = '"' + j++ + } + return string(qs[:j]) +} + +func CloseOnExec(fd Handle) { + SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0) +} + +// FullPath retrieves the full path of the specified file. +func FullPath(name string) (path string, err error) { + p, err := UTF16PtrFromString(name) + if err != nil { + return "", err + } + n := uint32(100) + for { + buf := make([]uint16, n) + n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil) + if err != nil { + return "", err + } + if n <= uint32(len(buf)) { + return UTF16ToString(buf[:n]), nil + } + } +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/race.go b/Godeps/_workspace/src/golang.org/x/sys/windows/race.go new file mode 100644 index 0000000000..343e18ab69 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/race.go @@ -0,0 +1,30 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows,race + +package windows + +import ( + "runtime" + "unsafe" +) + +const raceenabled = true + +func raceAcquire(addr unsafe.Pointer) { + runtime.RaceAcquire(addr) +} + +func raceReleaseMerge(addr unsafe.Pointer) { + runtime.RaceReleaseMerge(addr) +} + +func raceReadRange(addr unsafe.Pointer, len int) { + runtime.RaceReadRange(addr, len) +} + +func raceWriteRange(addr unsafe.Pointer, len int) { + runtime.RaceWriteRange(addr, len) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/race0.go b/Godeps/_workspace/src/golang.org/x/sys/windows/race0.go new file mode 100644 index 0000000000..17af843b91 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/race0.go @@ -0,0 +1,25 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows,!race + +package windows + +import ( + "unsafe" +) + +const raceenabled = false + +func raceAcquire(addr unsafe.Pointer) { +} + +func raceReleaseMerge(addr unsafe.Pointer) { +} + +func raceReadRange(addr unsafe.Pointer, len int) { +} + +func raceWriteRange(addr unsafe.Pointer, len int) { +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/key.go b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/key.go new file mode 100644 index 0000000000..f087ce5ada --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/key.go @@ -0,0 +1,178 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package registry provides access to the Windows registry. +// +// Here is a simple example, opening a registry key and reading a string value from it. +// +// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) +// if err != nil { +// log.Fatal(err) +// } +// defer k.Close() +// +// s, _, err := k.GetStringValue("SystemRoot") +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("Windows system root is %q\n", s) +// +package registry + +import ( + "io" + "syscall" + "time" +) + +const ( + // Registry key security and access rights. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx + // for details. + ALL_ACCESS = 0xf003f + CREATE_LINK = 0x00020 + CREATE_SUB_KEY = 0x00004 + ENUMERATE_SUB_KEYS = 0x00008 + EXECUTE = 0x20019 + NOTIFY = 0x00010 + QUERY_VALUE = 0x00001 + READ = 0x20019 + SET_VALUE = 0x00002 + WOW64_32KEY = 0x00200 + WOW64_64KEY = 0x00100 + WRITE = 0x20006 +) + +// Key is a handle to an open Windows registry key. +// Keys can be obtained by calling OpenKey; there are +// also some predefined root keys such as CURRENT_USER. +// Keys can be used directly in the Windows API. +type Key syscall.Handle + +const ( + // Windows defines some predefined root keys that are always open. + // An application can use these keys as entry points to the registry. + // Normally these keys are used in OpenKey to open new keys, + // but they can also be used anywhere a Key is required. + CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT) + CURRENT_USER = Key(syscall.HKEY_CURRENT_USER) + LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE) + USERS = Key(syscall.HKEY_USERS) + CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG) +) + +// Close closes open key k. +func (k Key) Close() error { + return syscall.RegCloseKey(syscall.Handle(k)) +} + +// OpenKey opens a new key with path name relative to key k. +// It accepts any open key, including CURRENT_USER and others, +// and returns the new key and an error. +// The access parameter specifies desired access rights to the +// key to be opened. +func OpenKey(k Key, path string, access uint32) (Key, error) { + p, err := syscall.UTF16PtrFromString(path) + if err != nil { + return 0, err + } + var subkey syscall.Handle + err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey) + if err != nil { + return 0, err + } + return Key(subkey), nil +} + +// ReadSubKeyNames returns the names of subkeys of key k. +// The parameter n controls the number of returned names, +// analogous to the way os.File.Readdirnames works. +func (k Key) ReadSubKeyNames(n int) ([]string, error) { + ki, err := k.Stat() + if err != nil { + return nil, err + } + names := make([]string, 0, ki.SubKeyCount) + buf := make([]uint16, ki.MaxSubKeyLen+1) // extra room for terminating zero byte +loopItems: + for i := uint32(0); ; i++ { + if n > 0 { + if len(names) == n { + return names, nil + } + } + l := uint32(len(buf)) + for { + err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) + if err == nil { + break + } + if err == syscall.ERROR_MORE_DATA { + // Double buffer size and try again. + l = uint32(2 * len(buf)) + buf = make([]uint16, l) + continue + } + if err == _ERROR_NO_MORE_ITEMS { + break loopItems + } + return names, err + } + names = append(names, syscall.UTF16ToString(buf[:l])) + } + if n > len(names) { + return names, io.EOF + } + return names, nil +} + +// CreateKey creates a key named path under open key k. +// CreateKey returns the new key and a boolean flag that reports +// whether the key already existed. +// The access parameter specifies the access rights for the key +// to be created. +func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) { + var h syscall.Handle + var d uint32 + err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path), + 0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d) + if err != nil { + return 0, false, err + } + return Key(h), d == _REG_OPENED_EXISTING_KEY, nil +} + +// DeleteKey deletes the subkey path of key k and its values. +func DeleteKey(k Key, path string) error { + return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path)) +} + +// A KeyInfo describes the statistics of a key. It is returned by Stat. +type KeyInfo struct { + SubKeyCount uint32 + MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte + ValueCount uint32 + MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte + MaxValueLen uint32 // longest data component among the key's values, in bytes + lastWriteTime syscall.Filetime +} + +// ModTime returns the key's last write time. +func (ki *KeyInfo) ModTime() time.Time { + return time.Unix(0, ki.lastWriteTime.Nanoseconds()) +} + +// Stat retrieves information about the open key k. +func (k Key) Stat() (*KeyInfo, error) { + var ki KeyInfo + err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil, + &ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount, + &ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime) + if err != nil { + return nil, err + } + return &ki, nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/syscall.go b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/syscall.go new file mode 100644 index 0000000000..5426cae909 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/syscall.go @@ -0,0 +1,33 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package registry + +import "syscall" + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go + +const ( + _REG_OPTION_NON_VOLATILE = 0 + + _REG_CREATED_NEW_KEY = 1 + _REG_OPENED_EXISTING_KEY = 2 + + _ERROR_NO_MORE_ITEMS syscall.Errno = 259 +) + +func LoadRegLoadMUIString() error { + return procRegLoadMUIStringW.Find() +} + +//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW +//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW +//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW +//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW +//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW +//sys regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW + +//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/value.go b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/value.go new file mode 100644 index 0000000000..71d4e15bab --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/value.go @@ -0,0 +1,384 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package registry + +import ( + "errors" + "io" + "syscall" + "unicode/utf16" + "unsafe" +) + +const ( + // Registry value types. + NONE = 0 + SZ = 1 + EXPAND_SZ = 2 + BINARY = 3 + DWORD = 4 + DWORD_BIG_ENDIAN = 5 + LINK = 6 + MULTI_SZ = 7 + RESOURCE_LIST = 8 + FULL_RESOURCE_DESCRIPTOR = 9 + RESOURCE_REQUIREMENTS_LIST = 10 + QWORD = 11 +) + +var ( + // ErrShortBuffer is returned when the buffer was too short for the operation. + ErrShortBuffer = syscall.ERROR_MORE_DATA + + // ErrNotExist is returned when a registry key or value does not exist. + ErrNotExist = syscall.ERROR_FILE_NOT_FOUND + + // ErrUnexpectedType is returned by Get*Value when the value's type was unexpected. + ErrUnexpectedType = errors.New("unexpected key value type") +) + +// GetValue retrieves the type and data for the specified value associated +// with an open key k. It fills up buffer buf and returns the retrieved +// byte count n. If buf is too small to fit the stored value it returns +// ErrShortBuffer error along with the required buffer size n. +// If no buffer is provided, it returns true and actual buffer size n. +// If no buffer is provided, GetValue returns the value's type only. +// If the value does not exist, the error returned is ErrNotExist. +// +// GetValue is a low level function. If value's type is known, use the appropriate +// Get*Value function instead. +func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) { + pname, err := syscall.UTF16PtrFromString(name) + if err != nil { + return 0, 0, err + } + var pbuf *byte + if len(buf) > 0 { + pbuf = (*byte)(unsafe.Pointer(&buf[0])) + } + l := uint32(len(buf)) + err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l) + if err != nil { + return int(l), valtype, err + } + return int(l), valtype, nil +} + +func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) { + p, err := syscall.UTF16PtrFromString(name) + if err != nil { + return nil, 0, err + } + var t uint32 + n := uint32(len(buf)) + for { + err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n) + if err == nil { + return buf[:n], t, nil + } + if err != syscall.ERROR_MORE_DATA { + return nil, 0, err + } + if n <= uint32(len(buf)) { + return nil, 0, err + } + buf = make([]byte, n) + } +} + +// GetStringValue retrieves the string value for the specified +// value name associated with an open key k. It also returns the value's type. +// If value does not exist, GetStringValue returns ErrNotExist. +// If value is not SZ or EXPAND_SZ, it will return the correct value +// type and ErrUnexpectedType. +func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) { + data, typ, err2 := k.getValue(name, make([]byte, 64)) + if err2 != nil { + return "", typ, err2 + } + switch typ { + case SZ, EXPAND_SZ: + default: + return "", typ, ErrUnexpectedType + } + if len(data) == 0 { + return "", typ, nil + } + u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:] + return syscall.UTF16ToString(u), typ, nil +} + +// GetMUIStringValue retrieves the localized string value for +// the specified value name associated with an open key k. +// If the value name doesn't exist or the localized string value +// can't be resolved, GetMUIStringValue returns ErrNotExist. +// GetMUIStringValue panics if the system doesn't support +// regLoadMUIString; use LoadRegLoadMUIString to check if +// regLoadMUIString is supported before calling this function. +func (k Key) GetMUIStringValue(name string) (string, error) { + pname, err := syscall.UTF16PtrFromString(name) + if err != nil { + return "", err + } + + buf := make([]uint16, 1024) + var buflen uint32 + var pdir *uint16 + + err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) + if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path + + // Try to resolve the string value using the system directory as + // a DLL search path; this assumes the string value is of the form + // @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320. + + // This approach works with tzres.dll but may have to be revised + // in the future to allow callers to provide custom search paths. + + var s string + s, err = ExpandString("%SystemRoot%\\system32\\") + if err != nil { + return "", err + } + pdir, err = syscall.UTF16PtrFromString(s) + if err != nil { + return "", err + } + + err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) + } + + for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed + if buflen <= uint32(len(buf)) { + break // Buffer not growing, assume race; break + } + buf = make([]uint16, buflen) + err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) + } + + if err != nil { + return "", err + } + + return syscall.UTF16ToString(buf), nil +} + +// ExpandString expands environment-variable strings and replaces +// them with the values defined for the current user. +// Use ExpandString to expand EXPAND_SZ strings. +func ExpandString(value string) (string, error) { + if value == "" { + return "", nil + } + p, err := syscall.UTF16PtrFromString(value) + if err != nil { + return "", err + } + r := make([]uint16, 100) + for { + n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r))) + if err != nil { + return "", err + } + if n <= uint32(len(r)) { + u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:] + return syscall.UTF16ToString(u), nil + } + r = make([]uint16, n) + } +} + +// GetStringsValue retrieves the []string value for the specified +// value name associated with an open key k. It also returns the value's type. +// If value does not exist, GetStringsValue returns ErrNotExist. +// If value is not MULTI_SZ, it will return the correct value +// type and ErrUnexpectedType. +func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) { + data, typ, err2 := k.getValue(name, make([]byte, 64)) + if err2 != nil { + return nil, typ, err2 + } + if typ != MULTI_SZ { + return nil, typ, ErrUnexpectedType + } + if len(data) == 0 { + return nil, typ, nil + } + p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2] + if len(p) == 0 { + return nil, typ, nil + } + if p[len(p)-1] == 0 { + p = p[:len(p)-1] // remove terminating null + } + val = make([]string, 0, 5) + from := 0 + for i, c := range p { + if c == 0 { + val = append(val, string(utf16.Decode(p[from:i]))) + from = i + 1 + } + } + return val, typ, nil +} + +// GetIntegerValue retrieves the integer value for the specified +// value name associated with an open key k. It also returns the value's type. +// If value does not exist, GetIntegerValue returns ErrNotExist. +// If value is not DWORD or QWORD, it will return the correct value +// type and ErrUnexpectedType. +func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) { + data, typ, err2 := k.getValue(name, make([]byte, 8)) + if err2 != nil { + return 0, typ, err2 + } + switch typ { + case DWORD: + if len(data) != 4 { + return 0, typ, errors.New("DWORD value is not 4 bytes long") + } + return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil + case QWORD: + if len(data) != 8 { + return 0, typ, errors.New("QWORD value is not 8 bytes long") + } + return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil + default: + return 0, typ, ErrUnexpectedType + } +} + +// GetBinaryValue retrieves the binary value for the specified +// value name associated with an open key k. It also returns the value's type. +// If value does not exist, GetBinaryValue returns ErrNotExist. +// If value is not BINARY, it will return the correct value +// type and ErrUnexpectedType. +func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) { + data, typ, err2 := k.getValue(name, make([]byte, 64)) + if err2 != nil { + return nil, typ, err2 + } + if typ != BINARY { + return nil, typ, ErrUnexpectedType + } + return data, typ, nil +} + +func (k Key) setValue(name string, valtype uint32, data []byte) error { + p, err := syscall.UTF16PtrFromString(name) + if err != nil { + return err + } + if len(data) == 0 { + return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0) + } + return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data))) +} + +// SetDWordValue sets the data and type of a name value +// under key k to value and DWORD. +func (k Key) SetDWordValue(name string, value uint32) error { + return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:]) +} + +// SetQWordValue sets the data and type of a name value +// under key k to value and QWORD. +func (k Key) SetQWordValue(name string, value uint64) error { + return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:]) +} + +func (k Key) setStringValue(name string, valtype uint32, value string) error { + v, err := syscall.UTF16FromString(value) + if err != nil { + return err + } + buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2] + return k.setValue(name, valtype, buf) +} + +// SetStringValue sets the data and type of a name value +// under key k to value and SZ. The value must not contain a zero byte. +func (k Key) SetStringValue(name, value string) error { + return k.setStringValue(name, SZ, value) +} + +// SetExpandStringValue sets the data and type of a name value +// under key k to value and EXPAND_SZ. The value must not contain a zero byte. +func (k Key) SetExpandStringValue(name, value string) error { + return k.setStringValue(name, EXPAND_SZ, value) +} + +// SetStringsValue sets the data and type of a name value +// under key k to value and MULTI_SZ. The value strings +// must not contain a zero byte. +func (k Key) SetStringsValue(name string, value []string) error { + ss := "" + for _, s := range value { + for i := 0; i < len(s); i++ { + if s[i] == 0 { + return errors.New("string cannot have 0 inside") + } + } + ss += s + "\x00" + } + v := utf16.Encode([]rune(ss + "\x00")) + buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2] + return k.setValue(name, MULTI_SZ, buf) +} + +// SetBinaryValue sets the data and type of a name value +// under key k to value and BINARY. +func (k Key) SetBinaryValue(name string, value []byte) error { + return k.setValue(name, BINARY, value) +} + +// DeleteValue removes a named value from the key k. +func (k Key) DeleteValue(name string) error { + return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name)) +} + +// ReadValueNames returns the value names of key k. +// The parameter n controls the number of returned names, +// analogous to the way os.File.Readdirnames works. +func (k Key) ReadValueNames(n int) ([]string, error) { + ki, err := k.Stat() + if err != nil { + return nil, err + } + names := make([]string, 0, ki.ValueCount) + buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character +loopItems: + for i := uint32(0); ; i++ { + if n > 0 { + if len(names) == n { + return names, nil + } + } + l := uint32(len(buf)) + for { + err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) + if err == nil { + break + } + if err == syscall.ERROR_MORE_DATA { + // Double buffer size and try again. + l = uint32(2 * len(buf)) + buf = make([]uint16, l) + continue + } + if err == _ERROR_NO_MORE_ITEMS { + break loopItems + } + return names, err + } + names = append(names, syscall.UTF16ToString(buf[:l])) + } + if n > len(names) { + return names, io.EOF + } + return names, nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/zsyscall_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/zsyscall_windows.go new file mode 100644 index 0000000000..9c17675a24 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/zsyscall_windows.go @@ -0,0 +1,82 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package registry + +import "unsafe" +import "syscall" + +var _ unsafe.Pointer + +var ( + modadvapi32 = syscall.NewLazyDLL("advapi32.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + + procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW") + procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW") + procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW") + procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") + procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW") + procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW") + procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") +) + +func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) { + r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition))) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) { + r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) { + r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize)) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { + r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) { + r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) { + r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/security_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/security_windows.go new file mode 100644 index 0000000000..ca09bdd701 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/security_windows.go @@ -0,0 +1,435 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import ( + "syscall" + "unsafe" +) + +const ( + STANDARD_RIGHTS_REQUIRED = 0xf0000 + STANDARD_RIGHTS_READ = 0x20000 + STANDARD_RIGHTS_WRITE = 0x20000 + STANDARD_RIGHTS_EXECUTE = 0x20000 + STANDARD_RIGHTS_ALL = 0x1F0000 +) + +const ( + NameUnknown = 0 + NameFullyQualifiedDN = 1 + NameSamCompatible = 2 + NameDisplay = 3 + NameUniqueId = 6 + NameCanonical = 7 + NameUserPrincipal = 8 + NameCanonicalEx = 9 + NameServicePrincipal = 10 + NameDnsDomain = 12 +) + +// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL. +// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx +//sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW +//sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW + +// TranslateAccountName converts a directory service +// object name from one format to another. +func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) { + u, e := UTF16PtrFromString(username) + if e != nil { + return "", e + } + n := uint32(50) + for { + b := make([]uint16, n) + e = TranslateName(u, from, to, &b[0], &n) + if e == nil { + return UTF16ToString(b[:n]), nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return "", e + } + if n <= uint32(len(b)) { + return "", e + } + } +} + +const ( + // do not reorder + NetSetupUnknownStatus = iota + NetSetupUnjoined + NetSetupWorkgroupName + NetSetupDomainName +) + +type UserInfo10 struct { + Name *uint16 + Comment *uint16 + UsrComment *uint16 + FullName *uint16 +} + +//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo +//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation +//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree + +const ( + // do not reorder + SidTypeUser = 1 + iota + SidTypeGroup + SidTypeDomain + SidTypeAlias + SidTypeWellKnownGroup + SidTypeDeletedAccount + SidTypeInvalid + SidTypeUnknown + SidTypeComputer + SidTypeLabel +) + +type SidIdentifierAuthority struct { + Value [6]byte +} + +var ( + SECURITY_NULL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 0}} + SECURITY_WORLD_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 1}} + SECURITY_LOCAL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 2}} + SECURITY_CREATOR_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 3}} + SECURITY_NON_UNIQUE_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 4}} + SECURITY_NT_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 5}} + SECURITY_MANDATORY_LABEL_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 16}} +) + +const ( + SECURITY_NULL_RID = 0 + SECURITY_WORLD_RID = 0 + SECURITY_LOCAL_RID = 0 + SECURITY_CREATOR_OWNER_RID = 0 + SECURITY_CREATOR_GROUP_RID = 1 + SECURITY_DIALUP_RID = 1 + SECURITY_NETWORK_RID = 2 + SECURITY_BATCH_RID = 3 + SECURITY_INTERACTIVE_RID = 4 + SECURITY_LOGON_IDS_RID = 5 + SECURITY_SERVICE_RID = 6 + SECURITY_LOCAL_SYSTEM_RID = 18 + SECURITY_BUILTIN_DOMAIN_RID = 32 + SECURITY_PRINCIPAL_SELF_RID = 10 + SECURITY_CREATOR_OWNER_SERVER_RID = 0x2 + SECURITY_CREATOR_GROUP_SERVER_RID = 0x3 + SECURITY_LOGON_IDS_RID_COUNT = 0x3 + SECURITY_ANONYMOUS_LOGON_RID = 0x7 + SECURITY_PROXY_RID = 0x8 + SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9 + SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID + SECURITY_AUTHENTICATED_USER_RID = 0xb + SECURITY_RESTRICTED_CODE_RID = 0xc + SECURITY_NT_NON_UNIQUE_RID = 0x15 +) + +//sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW +//sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW +//sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW +//sys ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW +//sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid +//sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid +//sys AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid +//sys FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid +//sys EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid + +// The security identifier (SID) structure is a variable-length +// structure used to uniquely identify users or groups. +type SID struct{} + +// StringToSid converts a string-format security identifier +// sid into a valid, functional sid. +func StringToSid(s string) (*SID, error) { + var sid *SID + p, e := UTF16PtrFromString(s) + if e != nil { + return nil, e + } + e = ConvertStringSidToSid(p, &sid) + if e != nil { + return nil, e + } + defer LocalFree((Handle)(unsafe.Pointer(sid))) + return sid.Copy() +} + +// LookupSID retrieves a security identifier sid for the account +// and the name of the domain on which the account was found. +// System specify target computer to search. +func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) { + if len(account) == 0 { + return nil, "", 0, syscall.EINVAL + } + acc, e := UTF16PtrFromString(account) + if e != nil { + return nil, "", 0, e + } + var sys *uint16 + if len(system) > 0 { + sys, e = UTF16PtrFromString(system) + if e != nil { + return nil, "", 0, e + } + } + n := uint32(50) + dn := uint32(50) + for { + b := make([]byte, n) + db := make([]uint16, dn) + sid = (*SID)(unsafe.Pointer(&b[0])) + e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType) + if e == nil { + return sid, UTF16ToString(db), accType, nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return nil, "", 0, e + } + if n <= uint32(len(b)) { + return nil, "", 0, e + } + } +} + +// String converts sid to a string format +// suitable for display, storage, or transmission. +func (sid *SID) String() (string, error) { + var s *uint16 + e := ConvertSidToStringSid(sid, &s) + if e != nil { + return "", e + } + defer LocalFree((Handle)(unsafe.Pointer(s))) + return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil +} + +// Len returns the length, in bytes, of a valid security identifier sid. +func (sid *SID) Len() int { + return int(GetLengthSid(sid)) +} + +// Copy creates a duplicate of security identifier sid. +func (sid *SID) Copy() (*SID, error) { + b := make([]byte, sid.Len()) + sid2 := (*SID)(unsafe.Pointer(&b[0])) + e := CopySid(uint32(len(b)), sid2, sid) + if e != nil { + return nil, e + } + return sid2, nil +} + +// LookupAccount retrieves the name of the account for this sid +// and the name of the first domain on which this sid is found. +// System specify target computer to search for. +func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) { + var sys *uint16 + if len(system) > 0 { + sys, err = UTF16PtrFromString(system) + if err != nil { + return "", "", 0, err + } + } + n := uint32(50) + dn := uint32(50) + for { + b := make([]uint16, n) + db := make([]uint16, dn) + e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType) + if e == nil { + return UTF16ToString(b), UTF16ToString(db), accType, nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return "", "", 0, e + } + if n <= uint32(len(b)) { + return "", "", 0, e + } + } +} + +const ( + // do not reorder + TOKEN_ASSIGN_PRIMARY = 1 << iota + TOKEN_DUPLICATE + TOKEN_IMPERSONATE + TOKEN_QUERY + TOKEN_QUERY_SOURCE + TOKEN_ADJUST_PRIVILEGES + TOKEN_ADJUST_GROUPS + TOKEN_ADJUST_DEFAULT + + TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | + TOKEN_ASSIGN_PRIMARY | + TOKEN_DUPLICATE | + TOKEN_IMPERSONATE | + TOKEN_QUERY | + TOKEN_QUERY_SOURCE | + TOKEN_ADJUST_PRIVILEGES | + TOKEN_ADJUST_GROUPS | + TOKEN_ADJUST_DEFAULT + TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY + TOKEN_WRITE = STANDARD_RIGHTS_WRITE | + TOKEN_ADJUST_PRIVILEGES | + TOKEN_ADJUST_GROUPS | + TOKEN_ADJUST_DEFAULT + TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE +) + +const ( + // do not reorder + TokenUser = 1 + iota + TokenGroups + TokenPrivileges + TokenOwner + TokenPrimaryGroup + TokenDefaultDacl + TokenSource + TokenType + TokenImpersonationLevel + TokenStatistics + TokenRestrictedSids + TokenSessionId + TokenGroupsAndPrivileges + TokenSessionReference + TokenSandBoxInert + TokenAuditPolicy + TokenOrigin + TokenElevationType + TokenLinkedToken + TokenElevation + TokenHasRestrictions + TokenAccessInformation + TokenVirtualizationAllowed + TokenVirtualizationEnabled + TokenIntegrityLevel + TokenUIAccess + TokenMandatoryPolicy + TokenLogonSid + MaxTokenInfoClass +) + +type SIDAndAttributes struct { + Sid *SID + Attributes uint32 +} + +type Tokenuser struct { + User SIDAndAttributes +} + +type Tokenprimarygroup struct { + PrimaryGroup *SID +} + +type Tokengroups struct { + GroupCount uint32 + Groups [1]SIDAndAttributes +} + +//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken +//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation +//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW + +// An access token contains the security information for a logon session. +// The system creates an access token when a user logs on, and every +// process executed on behalf of the user has a copy of the token. +// The token identifies the user, the user's groups, and the user's +// privileges. The system uses the token to control access to securable +// objects and to control the ability of the user to perform various +// system-related operations on the local computer. +type Token Handle + +// OpenCurrentProcessToken opens the access token +// associated with current process. +func OpenCurrentProcessToken() (Token, error) { + p, e := GetCurrentProcess() + if e != nil { + return 0, e + } + var t Token + e = OpenProcessToken(p, TOKEN_QUERY, &t) + if e != nil { + return 0, e + } + return t, nil +} + +// Close releases access to access token. +func (t Token) Close() error { + return CloseHandle(Handle(t)) +} + +// getInfo retrieves a specified type of information about an access token. +func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) { + n := uint32(initSize) + for { + b := make([]byte, n) + e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n) + if e == nil { + return unsafe.Pointer(&b[0]), nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return nil, e + } + if n <= uint32(len(b)) { + return nil, e + } + } +} + +// GetTokenUser retrieves access token t user account information. +func (t Token) GetTokenUser() (*Tokenuser, error) { + i, e := t.getInfo(TokenUser, 50) + if e != nil { + return nil, e + } + return (*Tokenuser)(i), nil +} + +// GetTokenGroups retrieves group accounts associated with access token t. +func (t Token) GetTokenGroups() (*Tokengroups, error) { + i, e := t.getInfo(TokenGroups, 50) + if e != nil { + return nil, e + } + return (*Tokengroups)(i), nil +} + +// GetTokenPrimaryGroup retrieves access token t primary group information. +// A pointer to a SID structure representing a group that will become +// the primary group of any objects created by a process using this access token. +func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) { + i, e := t.getInfo(TokenPrimaryGroup, 50) + if e != nil { + return nil, e + } + return (*Tokenprimarygroup)(i), nil +} + +// GetUserProfileDirectory retrieves path to the +// root directory of the access token t user's profile. +func (t Token) GetUserProfileDirectory() (string, error) { + n := uint32(100) + for { + b := make([]uint16, n) + e := GetUserProfileDirectory(t, &b[0], &n) + if e == nil { + return UTF16ToString(b), nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return "", e + } + if n <= uint32(len(b)) { + return "", e + } + } +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/service.go new file mode 100644 index 0000000000..1c11d392f0 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/service.go @@ -0,0 +1,143 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package windows + +const ( + SC_MANAGER_CONNECT = 1 + SC_MANAGER_CREATE_SERVICE = 2 + SC_MANAGER_ENUMERATE_SERVICE = 4 + SC_MANAGER_LOCK = 8 + SC_MANAGER_QUERY_LOCK_STATUS = 16 + SC_MANAGER_MODIFY_BOOT_CONFIG = 32 + SC_MANAGER_ALL_ACCESS = 0xf003f +) + +//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW + +const ( + SERVICE_KERNEL_DRIVER = 1 + SERVICE_FILE_SYSTEM_DRIVER = 2 + SERVICE_ADAPTER = 4 + SERVICE_RECOGNIZER_DRIVER = 8 + SERVICE_WIN32_OWN_PROCESS = 16 + SERVICE_WIN32_SHARE_PROCESS = 32 + SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS + SERVICE_INTERACTIVE_PROCESS = 256 + SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER + SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS + + SERVICE_BOOT_START = 0 + SERVICE_SYSTEM_START = 1 + SERVICE_AUTO_START = 2 + SERVICE_DEMAND_START = 3 + SERVICE_DISABLED = 4 + + SERVICE_ERROR_IGNORE = 0 + SERVICE_ERROR_NORMAL = 1 + SERVICE_ERROR_SEVERE = 2 + SERVICE_ERROR_CRITICAL = 3 + + SC_STATUS_PROCESS_INFO = 0 + + SERVICE_STOPPED = 1 + SERVICE_START_PENDING = 2 + SERVICE_STOP_PENDING = 3 + SERVICE_RUNNING = 4 + SERVICE_CONTINUE_PENDING = 5 + SERVICE_PAUSE_PENDING = 6 + SERVICE_PAUSED = 7 + SERVICE_NO_CHANGE = 0xffffffff + + SERVICE_ACCEPT_STOP = 1 + SERVICE_ACCEPT_PAUSE_CONTINUE = 2 + SERVICE_ACCEPT_SHUTDOWN = 4 + SERVICE_ACCEPT_PARAMCHANGE = 8 + SERVICE_ACCEPT_NETBINDCHANGE = 16 + SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32 + SERVICE_ACCEPT_POWEREVENT = 64 + SERVICE_ACCEPT_SESSIONCHANGE = 128 + + SERVICE_CONTROL_STOP = 1 + SERVICE_CONTROL_PAUSE = 2 + SERVICE_CONTROL_CONTINUE = 3 + SERVICE_CONTROL_INTERROGATE = 4 + SERVICE_CONTROL_SHUTDOWN = 5 + SERVICE_CONTROL_PARAMCHANGE = 6 + SERVICE_CONTROL_NETBINDADD = 7 + SERVICE_CONTROL_NETBINDREMOVE = 8 + SERVICE_CONTROL_NETBINDENABLE = 9 + SERVICE_CONTROL_NETBINDDISABLE = 10 + SERVICE_CONTROL_DEVICEEVENT = 11 + SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12 + SERVICE_CONTROL_POWEREVENT = 13 + SERVICE_CONTROL_SESSIONCHANGE = 14 + + SERVICE_ACTIVE = 1 + SERVICE_INACTIVE = 2 + SERVICE_STATE_ALL = 3 + + SERVICE_QUERY_CONFIG = 1 + SERVICE_CHANGE_CONFIG = 2 + SERVICE_QUERY_STATUS = 4 + SERVICE_ENUMERATE_DEPENDENTS = 8 + SERVICE_START = 16 + SERVICE_STOP = 32 + SERVICE_PAUSE_CONTINUE = 64 + SERVICE_INTERROGATE = 128 + SERVICE_USER_DEFINED_CONTROL = 256 + SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL + SERVICE_RUNS_IN_SYSTEM_PROCESS = 1 + SERVICE_CONFIG_DESCRIPTION = 1 + SERVICE_CONFIG_FAILURE_ACTIONS = 2 + + NO_ERROR = 0 +) + +type SERVICE_STATUS struct { + ServiceType uint32 + CurrentState uint32 + ControlsAccepted uint32 + Win32ExitCode uint32 + ServiceSpecificExitCode uint32 + CheckPoint uint32 + WaitHint uint32 +} + +type SERVICE_TABLE_ENTRY struct { + ServiceName *uint16 + ServiceProc uintptr +} + +type QUERY_SERVICE_CONFIG struct { + ServiceType uint32 + StartType uint32 + ErrorControl uint32 + BinaryPathName *uint16 + LoadOrderGroup *uint16 + TagId uint32 + Dependencies *uint16 + ServiceStartName *uint16 + DisplayName *uint16 +} + +type SERVICE_DESCRIPTION struct { + Description *uint16 +} + +//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle +//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW +//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW +//sys DeleteService(service Handle) (err error) = advapi32.DeleteService +//sys StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) = advapi32.StartServiceW +//sys QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus +//sys ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) = advapi32.ControlService +//sys StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) = advapi32.StartServiceCtrlDispatcherW +//sys SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) = advapi32.SetServiceStatus +//sys ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) = advapi32.ChangeServiceConfigW +//sys QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfigW +//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W +//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/str.go b/Godeps/_workspace/src/golang.org/x/sys/windows/str.go new file mode 100644 index 0000000000..917cc2aae4 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/str.go @@ -0,0 +1,22 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package windows + +func itoa(val int) string { // do it here rather than with fmt to avoid dependency + if val < 0 { + return "-" + itoa(-val) + } + var buf [32]byte // big enough for int64 + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return string(buf[i:]) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/log.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/log.go new file mode 100644 index 0000000000..e51ab42a1a --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/log.go @@ -0,0 +1,56 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package debug + +import ( + "os" + "strconv" +) + +// Log interface allows different log implementations to be used. +type Log interface { + Close() error + Info(eid uint32, msg string) error + Warning(eid uint32, msg string) error + Error(eid uint32, msg string) error +} + +// ConsoleLog provides access to the console. +type ConsoleLog struct { + Name string +} + +// New creates new ConsoleLog. +func New(source string) *ConsoleLog { + return &ConsoleLog{Name: source} +} + +// Close closes console log l. +func (l *ConsoleLog) Close() error { + return nil +} + +func (l *ConsoleLog) report(kind string, eid uint32, msg string) error { + s := l.Name + "." + kind + "(" + strconv.Itoa(int(eid)) + "): " + msg + "\n" + _, err := os.Stdout.Write([]byte(s)) + return err +} + +// Info writes an information event msg with event id eid to the console l. +func (l *ConsoleLog) Info(eid uint32, msg string) error { + return l.report("info", eid, msg) +} + +// Warning writes an warning event msg with event id eid to the console l. +func (l *ConsoleLog) Warning(eid uint32, msg string) error { + return l.report("warn", eid, msg) +} + +// Error writes an error event msg with event id eid to the console l. +func (l *ConsoleLog) Error(eid uint32, msg string) error { + return l.report("error", eid, msg) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/service.go new file mode 100644 index 0000000000..d5ab94b2c7 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/service.go @@ -0,0 +1,45 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package debug provides facilities to execute svc.Handler on console. +// +package debug + +import ( + "os" + "os/signal" + "syscall" + + "golang.org/x/sys/windows/svc" +) + +// Run executes service name by calling appropriate handler function. +// The process is running on console, unlike real service. Use Ctrl+C to +// send "Stop" command to your service. +func Run(name string, handler svc.Handler) error { + cmds := make(chan svc.ChangeRequest) + changes := make(chan svc.Status) + + sig := make(chan os.Signal) + signal.Notify(sig) + + go func() { + status := svc.Status{State: svc.Stopped} + for { + select { + case <-sig: + cmds <- svc.ChangeRequest{svc.Stop, status} + case status = <-changes: + } + } + }() + + _, errno := handler.Execute([]string{name}, cmds, changes) + if errno != 0 { + return syscall.Errno(errno) + } + return nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/event.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/event.go new file mode 100644 index 0000000000..0508e22881 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/event.go @@ -0,0 +1,48 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package svc + +import ( + "errors" + + "golang.org/x/sys/windows" +) + +// event represents auto-reset, initially non-signaled Windows event. +// It is used to communicate between go and asm parts of this package. +type event struct { + h windows.Handle +} + +func newEvent() (*event, error) { + h, err := windows.CreateEvent(nil, 0, 0, nil) + if err != nil { + return nil, err + } + return &event{h: h}, nil +} + +func (e *event) Close() error { + return windows.CloseHandle(e.h) +} + +func (e *event) Set() error { + return windows.SetEvent(e.h) +} + +func (e *event) Wait() error { + s, err := windows.WaitForSingleObject(e.h, windows.INFINITE) + switch s { + case windows.WAIT_OBJECT_0: + break + case windows.WAIT_FAILED: + return err + default: + return errors.New("unexpected result from WaitForSingleObject") + } + return nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/install.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/install.go new file mode 100644 index 0000000000..c76a3760a4 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/install.go @@ -0,0 +1,80 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package eventlog + +import ( + "errors" + + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" +) + +const ( + // Log levels. + Info = windows.EVENTLOG_INFORMATION_TYPE + Warning = windows.EVENTLOG_WARNING_TYPE + Error = windows.EVENTLOG_ERROR_TYPE +) + +const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application` + +// Install modifies PC registry to allow logging with an event source src. +// It adds all required keys and values to the event log registry key. +// Install uses msgFile as the event message file. If useExpandKey is true, +// the event message file is installed as REG_EXPAND_SZ value, +// otherwise as REG_SZ. Use bitwise of log.Error, log.Warning and +// log.Info to specify events supported by the new event source. +func Install(src, msgFile string, useExpandKey bool, eventsSupported uint32) error { + appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.CREATE_SUB_KEY) + if err != nil { + return err + } + defer appkey.Close() + + sk, alreadyExist, err := registry.CreateKey(appkey, src, registry.SET_VALUE) + if err != nil { + return err + } + defer sk.Close() + if alreadyExist { + return errors.New(addKeyName + `\` + src + " registry key already exists") + } + + err = sk.SetDWordValue("CustomSource", 1) + if err != nil { + return err + } + if useExpandKey { + err = sk.SetExpandStringValue("EventMessageFile", msgFile) + } else { + err = sk.SetStringValue("EventMessageFile", msgFile) + } + if err != nil { + return err + } + err = sk.SetDWordValue("TypesSupported", eventsSupported) + if err != nil { + return err + } + return nil +} + +// InstallAsEventCreate is the same as Install, but uses +// %SystemRoot%\System32\EventCreate.exe as the event message file. +func InstallAsEventCreate(src string, eventsSupported uint32) error { + return Install(src, "%SystemRoot%\\System32\\EventCreate.exe", true, eventsSupported) +} + +// Remove deletes all registry elements installed by the correspondent Install. +func Remove(src string) error { + appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.SET_VALUE) + if err != nil { + return err + } + defer appkey.Close() + return registry.DeleteKey(appkey, src) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/log.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/log.go new file mode 100644 index 0000000000..46e5153d02 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/log.go @@ -0,0 +1,70 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package eventlog implements access to Windows event log. +// +package eventlog + +import ( + "errors" + "syscall" + + "golang.org/x/sys/windows" +) + +// Log provides access to the system log. +type Log struct { + Handle windows.Handle +} + +// Open retrieves a handle to the specified event log. +func Open(source string) (*Log, error) { + return OpenRemote("", source) +} + +// OpenRemote does the same as Open, but on different computer host. +func OpenRemote(host, source string) (*Log, error) { + if source == "" { + return nil, errors.New("Specify event log source") + } + var s *uint16 + if host != "" { + s = syscall.StringToUTF16Ptr(host) + } + h, err := windows.RegisterEventSource(s, syscall.StringToUTF16Ptr(source)) + if err != nil { + return nil, err + } + return &Log{Handle: h}, nil +} + +// Close closes event log l. +func (l *Log) Close() error { + return windows.DeregisterEventSource(l.Handle) +} + +func (l *Log) report(etype uint16, eid uint32, msg string) error { + ss := []*uint16{syscall.StringToUTF16Ptr(msg)} + return windows.ReportEvent(l.Handle, etype, 0, eid, 0, 1, 0, &ss[0], nil) +} + +// Info writes an information event msg with event id eid to the end of event log l. +// When EventCreate.exe is used, eid must be between 1 and 1000. +func (l *Log) Info(eid uint32, msg string) error { + return l.report(windows.EVENTLOG_INFORMATION_TYPE, eid, msg) +} + +// Warning writes an warning event msg with event id eid to the end of event log l. +// When EventCreate.exe is used, eid must be between 1 and 1000. +func (l *Log) Warning(eid uint32, msg string) error { + return l.report(windows.EVENTLOG_WARNING_TYPE, eid, msg) +} + +// Error writes an error event msg with event id eid to the end of event log l. +// When EventCreate.exe is used, eid must be between 1 and 1000. +func (l *Log) Error(eid uint32, msg string) error { + return l.report(windows.EVENTLOG_ERROR_TYPE, eid, msg) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/beep.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/beep.go new file mode 100644 index 0000000000..dcf23408d3 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/beep.go @@ -0,0 +1,22 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package main + +import ( + "syscall" +) + +// BUG(brainman): MessageBeep Windows api is broken on Windows 7, +// so this example does not beep when runs as service on Windows 7. + +var ( + beepFunc = syscall.MustLoadDLL("user32.dll").MustFindProc("MessageBeep") +) + +func beep() { + beepFunc.Call(0xffffffff) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/install.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/install.go new file mode 100644 index 0000000000..39cb00d2ad --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/install.go @@ -0,0 +1,92 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package main + +import ( + "fmt" + "os" + "path/filepath" + + "golang.org/x/sys/windows/svc/eventlog" + "golang.org/x/sys/windows/svc/mgr" +) + +func exePath() (string, error) { + prog := os.Args[0] + p, err := filepath.Abs(prog) + if err != nil { + return "", err + } + fi, err := os.Stat(p) + if err == nil { + if !fi.Mode().IsDir() { + return p, nil + } + err = fmt.Errorf("%s is directory", p) + } + if filepath.Ext(p) == "" { + p += ".exe" + fi, err := os.Stat(p) + if err == nil { + if !fi.Mode().IsDir() { + return p, nil + } + err = fmt.Errorf("%s is directory", p) + } + } + return "", err +} + +func installService(name, desc string) error { + exepath, err := exePath() + if err != nil { + return err + } + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + s, err := m.OpenService(name) + if err == nil { + s.Close() + return fmt.Errorf("service %s already exists", name) + } + s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: desc}, "is", "auto-started") + if err != nil { + return err + } + defer s.Close() + err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info) + if err != nil { + s.Delete() + return fmt.Errorf("SetupEventLogSource() failed: %s", err) + } + return nil +} + +func removeService(name string) error { + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + s, err := m.OpenService(name) + if err != nil { + return fmt.Errorf("service %s is not installed", name) + } + defer s.Close() + err = s.Delete() + if err != nil { + return err + } + err = eventlog.Remove(name) + if err != nil { + return fmt.Errorf("RemoveEventLogSource() failed: %s", err) + } + return nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/main.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/main.go new file mode 100644 index 0000000000..dc96c081af --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/main.go @@ -0,0 +1,76 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Example service program that beeps. +// +// The program demonstrates how to create Windows service and +// install / remove it on a computer. It also shows how to +// stop / start / pause / continue any service, and how to +// write to event log. It also shows how to use debug +// facilities available in debug package. +// +package main + +import ( + "fmt" + "log" + "os" + "strings" + + "golang.org/x/sys/windows/svc" +) + +func usage(errmsg string) { + fmt.Fprintf(os.Stderr, + "%s\n\n"+ + "usage: %s \n"+ + " where is one of\n"+ + " install, remove, debug, start, stop, pause or continue.\n", + errmsg, os.Args[0]) + os.Exit(2) +} + +func main() { + const svcName = "myservice" + + isIntSess, err := svc.IsAnInteractiveSession() + if err != nil { + log.Fatalf("failed to determine if we are running in an interactive session: %v", err) + } + if !isIntSess { + runService(svcName, false) + return + } + + if len(os.Args) < 2 { + usage("no command specified") + } + + cmd := strings.ToLower(os.Args[1]) + switch cmd { + case "debug": + runService(svcName, true) + return + case "install": + err = installService(svcName, "my service") + case "remove": + err = removeService(svcName) + case "start": + err = startService(svcName) + case "stop": + err = controlService(svcName, svc.Stop, svc.Stopped) + case "pause": + err = controlService(svcName, svc.Pause, svc.Paused) + case "continue": + err = controlService(svcName, svc.Continue, svc.Running) + default: + usage(fmt.Sprintf("invalid command %s", cmd)) + } + if err != nil { + log.Fatalf("failed to %s %s: %v", cmd, svcName, err) + } + return +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/manage.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/manage.go new file mode 100644 index 0000000000..782dbd96ca --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/manage.go @@ -0,0 +1,62 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package main + +import ( + "fmt" + "time" + + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/mgr" +) + +func startService(name string) error { + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + s, err := m.OpenService(name) + if err != nil { + return fmt.Errorf("could not access service: %v", err) + } + defer s.Close() + err = s.Start("is", "manual-started") + if err != nil { + return fmt.Errorf("could not start service: %v", err) + } + return nil +} + +func controlService(name string, c svc.Cmd, to svc.State) error { + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + s, err := m.OpenService(name) + if err != nil { + return fmt.Errorf("could not access service: %v", err) + } + defer s.Close() + status, err := s.Control(c) + if err != nil { + return fmt.Errorf("could not send control=%d: %v", c, err) + } + timeout := time.Now().Add(10 * time.Second) + for status.State != to { + if timeout.Before(time.Now()) { + return fmt.Errorf("timeout waiting for service to go to state=%d", to) + } + time.Sleep(300 * time.Millisecond) + status, err = s.Query() + if err != nil { + return fmt.Errorf("could not retrieve service status: %v", err) + } + } + return nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/service.go new file mode 100644 index 0000000000..237e80984d --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/service.go @@ -0,0 +1,82 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package main + +import ( + "fmt" + "time" + + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/debug" + "golang.org/x/sys/windows/svc/eventlog" +) + +var elog debug.Log + +type myservice struct{} + +func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) { + const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue + changes <- svc.Status{State: svc.StartPending} + fasttick := time.Tick(500 * time.Millisecond) + slowtick := time.Tick(2 * time.Second) + tick := fasttick + changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} +loop: + for { + select { + case <-tick: + beep() + elog.Info(1, "beep") + case c := <-r: + switch c.Cmd { + case svc.Interrogate: + changes <- c.CurrentStatus + // Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4 + time.Sleep(100 * time.Millisecond) + changes <- c.CurrentStatus + case svc.Stop, svc.Shutdown: + break loop + case svc.Pause: + changes <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted} + tick = slowtick + case svc.Continue: + changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} + tick = fasttick + default: + elog.Error(1, fmt.Sprintf("unexpected control request #%d", c)) + } + } + } + changes <- svc.Status{State: svc.StopPending} + return +} + +func runService(name string, isDebug bool) { + var err error + if isDebug { + elog = debug.New(name) + } else { + elog, err = eventlog.Open(name) + if err != nil { + return + } + } + defer elog.Close() + + elog.Info(1, fmt.Sprintf("starting %s service", name)) + run := svc.Run + if isDebug { + run = debug.Run + } + err = run(name, &myservice{}) + if err != nil { + elog.Error(1, fmt.Sprintf("%s service failed: %v", name, err)) + return + } + elog.Info(1, fmt.Sprintf("%s service stopped", name)) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.c b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.c new file mode 100644 index 0000000000..6f1be1fa3b --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.c @@ -0,0 +1,24 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows +// +build !go1.3 + +// copied from pkg/runtime +typedef unsigned int uint32; +typedef unsigned long long int uint64; +#ifdef _64BIT +typedef uint64 uintptr; +#else +typedef uint32 uintptr; +#endif + +// from sys_386.s or sys_amd64.s +void ·servicemain(void); + +void +·getServiceMain(uintptr *r) +{ + *r = (uintptr)·servicemain; +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.go new file mode 100644 index 0000000000..6f0a924eaf --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.go @@ -0,0 +1,11 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows +// +build !go1.3 + +package svc + +// from go12.c +func getServiceMain(r *uintptr) diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go13.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go13.go new file mode 100644 index 0000000000..432a9e796a --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go13.go @@ -0,0 +1,31 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows +// +build go1.3 + +package svc + +import "unsafe" + +const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const + +// Should be a built-in for unsafe.Pointer? +func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + x) +} + +// funcPC returns the entry PC of the function f. +// It assumes that f is a func value. Otherwise the behavior is undefined. +func funcPC(f interface{}) uintptr { + return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize)) +} + +// from sys_386.s and sys_amd64.s +func servicectlhandler(ctl uint32) uintptr +func servicemain(argc uint32, argv **uint16) + +func getServiceMain(r *uintptr) { + *r = funcPC(servicemain) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/config.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/config.go new file mode 100644 index 0000000000..0a6edba4f5 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/config.go @@ -0,0 +1,139 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package mgr + +import ( + "syscall" + "unicode/utf16" + "unsafe" + + "golang.org/x/sys/windows" +) + +const ( + // Service start types. + StartManual = windows.SERVICE_DEMAND_START // the service must be started manually + StartAutomatic = windows.SERVICE_AUTO_START // the service will start by itself whenever the computer reboots + StartDisabled = windows.SERVICE_DISABLED // the service cannot be started + + // The severity of the error, and action taken, + // if this service fails to start. + ErrorCritical = windows.SERVICE_ERROR_CRITICAL + ErrorIgnore = windows.SERVICE_ERROR_IGNORE + ErrorNormal = windows.SERVICE_ERROR_NORMAL + ErrorSevere = windows.SERVICE_ERROR_SEVERE +) + +// TODO(brainman): Password is not returned by windows.QueryServiceConfig, not sure how to get it. + +type Config struct { + ServiceType uint32 + StartType uint32 + ErrorControl uint32 + BinaryPathName string // fully qualified path to the service binary file, can also include arguments for an auto-start service + LoadOrderGroup string + TagId uint32 + Dependencies []string + ServiceStartName string // name of the account under which the service should run + DisplayName string + Password string + Description string +} + +func toString(p *uint16) string { + if p == nil { + return "" + } + return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:]) +} + +func toStringSlice(ps *uint16) []string { + if ps == nil { + return nil + } + r := make([]string, 0) + for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ { + if p[i] == 0 { + // empty string marks the end + if i <= from { + break + } + r = append(r, string(utf16.Decode(p[from:i]))) + from = i + 1 + } + } + return r +} + +// Config retrieves service s configuration paramteres. +func (s *Service) Config() (Config, error) { + var p *windows.QUERY_SERVICE_CONFIG + n := uint32(1024) + for { + b := make([]byte, n) + p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0])) + err := windows.QueryServiceConfig(s.Handle, p, n, &n) + if err == nil { + break + } + if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER { + return Config{}, err + } + if n <= uint32(len(b)) { + return Config{}, err + } + } + + var p2 *windows.SERVICE_DESCRIPTION + n = uint32(1024) + for { + b := make([]byte, n) + p2 = (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0])) + err := windows.QueryServiceConfig2(s.Handle, + windows.SERVICE_CONFIG_DESCRIPTION, &b[0], n, &n) + if err == nil { + break + } + if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER { + return Config{}, err + } + if n <= uint32(len(b)) { + return Config{}, err + } + } + + return Config{ + ServiceType: p.ServiceType, + StartType: p.StartType, + ErrorControl: p.ErrorControl, + BinaryPathName: toString(p.BinaryPathName), + LoadOrderGroup: toString(p.LoadOrderGroup), + TagId: p.TagId, + Dependencies: toStringSlice(p.Dependencies), + ServiceStartName: toString(p.ServiceStartName), + DisplayName: toString(p.DisplayName), + Description: toString(p2.Description), + }, nil +} + +func updateDescription(handle windows.Handle, desc string) error { + d := windows.SERVICE_DESCRIPTION{toPtr(desc)} + return windows.ChangeServiceConfig2(handle, + windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d))) +} + +// UpdateConfig updates service s configuration parameters. +func (s *Service) UpdateConfig(c Config) error { + err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType, + c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup), + nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), + toPtr(c.Password), toPtr(c.DisplayName)) + if err != nil { + return err + } + return updateDescription(s.Handle, c.Description) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/mgr.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/mgr.go new file mode 100644 index 0000000000..da8ceb6ed8 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/mgr.go @@ -0,0 +1,119 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package mgr can be used to manage Windows service programs. +// It can be used to install and remove them. It can also start, +// stop and pause them. The package can query / change current +// service state and config parameters. +// +package mgr + +import ( + "syscall" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +// Mgr is used to manage Windows service. +type Mgr struct { + Handle windows.Handle +} + +// Connect establishes a connection to the service control manager. +func Connect() (*Mgr, error) { + return ConnectRemote("") +} + +// ConnectRemote establishes a connection to the +// service control manager on computer named host. +func ConnectRemote(host string) (*Mgr, error) { + var s *uint16 + if host != "" { + s = syscall.StringToUTF16Ptr(host) + } + h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS) + if err != nil { + return nil, err + } + return &Mgr{Handle: h}, nil +} + +// Disconnect closes connection to the service control manager m. +func (m *Mgr) Disconnect() error { + return windows.CloseServiceHandle(m.Handle) +} + +func toPtr(s string) *uint16 { + if len(s) == 0 { + return nil + } + return syscall.StringToUTF16Ptr(s) +} + +// toStringBlock terminates strings in ss with 0, and then +// concatenates them together. It also adds extra 0 at the end. +func toStringBlock(ss []string) *uint16 { + if len(ss) == 0 { + return nil + } + t := "" + for _, s := range ss { + if s != "" { + t += s + "\x00" + } + } + if t == "" { + return nil + } + t += "\x00" + return &utf16.Encode([]rune(t))[0] +} + +// CreateService installs new service name on the system. +// The service will be executed by running exepath binary. +// Use config c to specify service parameters. +// If service StartType is set to StartAutomatic, +// args will be passed to svc.Handle.Execute. +func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) { + if c.StartType == 0 { + c.StartType = StartManual + } + if c.ErrorControl == 0 { + c.ErrorControl = ErrorNormal + } + if c.ServiceType == 0 { + c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS + } + s := syscall.EscapeArg(exepath) + for _, v := range args { + s += " " + syscall.EscapeArg(v) + } + h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName), + windows.SERVICE_ALL_ACCESS, c.ServiceType, + c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup), + nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password)) + if err != nil { + return nil, err + } + if c.Description != "" { + err = updateDescription(h, c.Description) + if err != nil { + return nil, err + } + } + return &Service{Name: name, Handle: h}, nil +} + +// OpenService retrieves access to service name, so it can +// be interrogated and controlled. +func (m *Mgr) OpenService(name string) (*Service, error) { + h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS) + if err != nil { + return nil, err + } + return &Service{Name: name, Handle: h}, nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/service.go new file mode 100644 index 0000000000..465f3c3d23 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/service.go @@ -0,0 +1,74 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package mgr + +import ( + "syscall" + + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc" +) + +// TODO(brainman): Use EnumDependentServices to enumerate dependent services. + +// TODO(brainman): Use EnumServicesStatus to enumerate services in the specified service control manager database. + +// Service is used to access Windows service. +type Service struct { + Name string + Handle windows.Handle +} + +// Delete marks service s for deletion from the service control manager database. +func (s *Service) Delete() error { + return windows.DeleteService(s.Handle) +} + +// Close relinquish access to the service s. +func (s *Service) Close() error { + return windows.CloseServiceHandle(s.Handle) +} + +// Start starts service s. +// args will be passed to svc.Handler.Execute. +func (s *Service) Start(args ...string) error { + var p **uint16 + if len(args) > 0 { + vs := make([]*uint16, len(args)) + for i, _ := range vs { + vs[i] = syscall.StringToUTF16Ptr(args[i]) + } + p = &vs[0] + } + return windows.StartService(s.Handle, uint32(len(args)), p) +} + +// Control sends state change request c to the servce s. +func (s *Service) Control(c svc.Cmd) (svc.Status, error) { + var t windows.SERVICE_STATUS + err := windows.ControlService(s.Handle, uint32(c), &t) + if err != nil { + return svc.Status{}, err + } + return svc.Status{ + State: svc.State(t.CurrentState), + Accepts: svc.Accepted(t.ControlsAccepted), + }, nil +} + +// Query returns current status of service s. +func (s *Service) Query() (svc.Status, error) { + var t windows.SERVICE_STATUS + err := windows.QueryServiceStatus(s.Handle, &t) + if err != nil { + return svc.Status{}, err + } + return svc.Status{ + State: svc.State(t.CurrentState), + Accepts: svc.Accepted(t.ControlsAccepted), + }, nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/security.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/security.go new file mode 100644 index 0000000000..6fbc9236ed --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/security.go @@ -0,0 +1,62 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package svc + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +func allocSid(subAuth0 uint32) (*windows.SID, error) { + var sid *windows.SID + err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY, + 1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid) + if err != nil { + return nil, err + } + return sid, nil +} + +// IsAnInteractiveSession determines if calling process is running interactively. +// It queries the process token for membership in the Interactive group. +// http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s +func IsAnInteractiveSession() (bool, error) { + interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID) + if err != nil { + return false, err + } + defer windows.FreeSid(interSid) + + serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID) + if err != nil { + return false, err + } + defer windows.FreeSid(serviceSid) + + t, err := windows.OpenCurrentProcessToken() + if err != nil { + return false, err + } + defer t.Close() + + gs, err := t.GetTokenGroups() + if err != nil { + return false, err + } + p := unsafe.Pointer(&gs.Groups[0]) + groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount] + for _, g := range groups { + if windows.EqualSid(g.Sid, interSid) { + return true, nil + } + if windows.EqualSid(g.Sid, serviceSid) { + return false, nil + } + } + return false, nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/service.go new file mode 100644 index 0000000000..9864f7a72f --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/service.go @@ -0,0 +1,316 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package svc provides everything required to build Windows service. +// +package svc + +import ( + "errors" + "runtime" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +// State describes service execution state (Stopped, Running and so on). +type State uint32 + +const ( + Stopped = State(windows.SERVICE_STOPPED) + StartPending = State(windows.SERVICE_START_PENDING) + StopPending = State(windows.SERVICE_STOP_PENDING) + Running = State(windows.SERVICE_RUNNING) + ContinuePending = State(windows.SERVICE_CONTINUE_PENDING) + PausePending = State(windows.SERVICE_PAUSE_PENDING) + Paused = State(windows.SERVICE_PAUSED) +) + +// Cmd represents service state change request. It is sent to a service +// by the service manager, and should be actioned upon by the service. +type Cmd uint32 + +const ( + Stop = Cmd(windows.SERVICE_CONTROL_STOP) + Pause = Cmd(windows.SERVICE_CONTROL_PAUSE) + Continue = Cmd(windows.SERVICE_CONTROL_CONTINUE) + Interrogate = Cmd(windows.SERVICE_CONTROL_INTERROGATE) + Shutdown = Cmd(windows.SERVICE_CONTROL_SHUTDOWN) +) + +// Accepted is used to describe commands accepted by the service. +// Note that Interrogate is always accepted. +type Accepted uint32 + +const ( + AcceptStop = Accepted(windows.SERVICE_ACCEPT_STOP) + AcceptShutdown = Accepted(windows.SERVICE_ACCEPT_SHUTDOWN) + AcceptPauseAndContinue = Accepted(windows.SERVICE_ACCEPT_PAUSE_CONTINUE) +) + +// Status combines State and Accepted commands to fully describe running service. +type Status struct { + State State + Accepts Accepted + CheckPoint uint32 // used to report progress during a lengthy operation + WaitHint uint32 // estimated time required for a pending operation, in milliseconds +} + +// ChangeRequest is sent to the service Handler to request service status change. +type ChangeRequest struct { + Cmd Cmd + CurrentStatus Status +} + +// Handler is the interface that must be implemented to build Windows service. +type Handler interface { + + // Execute will be called by the package code at the start of + // the service, and the service will exit once Execute completes. + // Inside Execute you must read service change requests from r and + // act accordingly. You must keep service control manager up to date + // about state of your service by writing into s as required. + // args contains service name followed by argument strings passed + // to the service. + // You can provide service exit code in exitCode return parameter, + // with 0 being "no error". You can also indicate if exit code, + // if any, is service specific or not by using svcSpecificEC + // parameter. + Execute(args []string, r <-chan ChangeRequest, s chan<- Status) (svcSpecificEC bool, exitCode uint32) +} + +var ( + // These are used by asm code. + goWaitsH uintptr + cWaitsH uintptr + ssHandle uintptr + sName *uint16 + sArgc uintptr + sArgv **uint16 + ctlHandlerProc uintptr + cSetEvent uintptr + cWaitForSingleObject uintptr + cRegisterServiceCtrlHandlerW uintptr +) + +func init() { + k := syscall.MustLoadDLL("kernel32.dll") + cSetEvent = k.MustFindProc("SetEvent").Addr() + cWaitForSingleObject = k.MustFindProc("WaitForSingleObject").Addr() + a := syscall.MustLoadDLL("advapi32.dll") + cRegisterServiceCtrlHandlerW = a.MustFindProc("RegisterServiceCtrlHandlerW").Addr() +} + +type ctlEvent struct { + cmd Cmd + errno uint32 +} + +// service provides access to windows service api. +type service struct { + name string + h windows.Handle + cWaits *event + goWaits *event + c chan ctlEvent + handler Handler +} + +func newService(name string, handler Handler) (*service, error) { + var s service + var err error + s.name = name + s.c = make(chan ctlEvent) + s.handler = handler + s.cWaits, err = newEvent() + if err != nil { + return nil, err + } + s.goWaits, err = newEvent() + if err != nil { + s.cWaits.Close() + return nil, err + } + return &s, nil +} + +func (s *service) close() error { + s.cWaits.Close() + s.goWaits.Close() + return nil +} + +type exitCode struct { + isSvcSpecific bool + errno uint32 +} + +func (s *service) updateStatus(status *Status, ec *exitCode) error { + if s.h == 0 { + return errors.New("updateStatus with no service status handle") + } + var t windows.SERVICE_STATUS + t.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS + t.CurrentState = uint32(status.State) + if status.Accepts&AcceptStop != 0 { + t.ControlsAccepted |= windows.SERVICE_ACCEPT_STOP + } + if status.Accepts&AcceptShutdown != 0 { + t.ControlsAccepted |= windows.SERVICE_ACCEPT_SHUTDOWN + } + if status.Accepts&AcceptPauseAndContinue != 0 { + t.ControlsAccepted |= windows.SERVICE_ACCEPT_PAUSE_CONTINUE + } + if ec.errno == 0 { + t.Win32ExitCode = windows.NO_ERROR + t.ServiceSpecificExitCode = windows.NO_ERROR + } else if ec.isSvcSpecific { + t.Win32ExitCode = uint32(windows.ERROR_SERVICE_SPECIFIC_ERROR) + t.ServiceSpecificExitCode = ec.errno + } else { + t.Win32ExitCode = ec.errno + t.ServiceSpecificExitCode = windows.NO_ERROR + } + t.CheckPoint = status.CheckPoint + t.WaitHint = status.WaitHint + return windows.SetServiceStatus(s.h, &t) +} + +const ( + sysErrSetServiceStatusFailed = uint32(syscall.APPLICATION_ERROR) + iota + sysErrNewThreadInCallback +) + +func (s *service) run() { + s.goWaits.Wait() + s.h = windows.Handle(ssHandle) + argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc] + args := make([]string, len(argv)) + for i, a := range argv { + args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:]) + } + + cmdsToHandler := make(chan ChangeRequest) + changesFromHandler := make(chan Status) + exitFromHandler := make(chan exitCode) + + go func() { + ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler) + exitFromHandler <- exitCode{ss, errno} + }() + + status := Status{State: Stopped} + ec := exitCode{isSvcSpecific: true, errno: 0} + var outch chan ChangeRequest + inch := s.c + var cmd Cmd +loop: + for { + select { + case r := <-inch: + if r.errno != 0 { + ec.errno = r.errno + break loop + } + inch = nil + outch = cmdsToHandler + cmd = r.cmd + case outch <- ChangeRequest{cmd, status}: + inch = s.c + outch = nil + case c := <-changesFromHandler: + err := s.updateStatus(&c, &ec) + if err != nil { + // best suitable error number + ec.errno = sysErrSetServiceStatusFailed + if err2, ok := err.(syscall.Errno); ok { + ec.errno = uint32(err2) + } + break loop + } + status = c + case ec = <-exitFromHandler: + break loop + } + } + + s.updateStatus(&Status{State: Stopped}, &ec) + s.cWaits.Set() +} + +func newCallback(fn interface{}) (cb uintptr, err error) { + defer func() { + r := recover() + if r == nil { + return + } + cb = 0 + switch v := r.(type) { + case string: + err = errors.New(v) + case error: + err = v + default: + err = errors.New("unexpected panic in syscall.NewCallback") + } + }() + return syscall.NewCallback(fn), nil +} + +// BUG(brainman): There is no mechanism to run multiple services +// inside one single executable. Perhaps, it can be overcome by +// using RegisterServiceCtrlHandlerEx Windows api. + +// Run executes service name by calling appropriate handler function. +func Run(name string, handler Handler) error { + runtime.LockOSThread() + + tid := windows.GetCurrentThreadId() + + s, err := newService(name, handler) + if err != nil { + return err + } + + ctlHandler := func(ctl uint32) uintptr { + e := ctlEvent{cmd: Cmd(ctl)} + // We assume that this callback function is running on + // the same thread as Run. Nowhere in MS documentation + // I could find statement to guarantee that. So putting + // check here to verify, otherwise things will go bad + // quickly, if ignored. + i := windows.GetCurrentThreadId() + if i != tid { + e.errno = sysErrNewThreadInCallback + } + s.c <- e + return 0 + } + + var svcmain uintptr + getServiceMain(&svcmain) + t := []windows.SERVICE_TABLE_ENTRY{ + {syscall.StringToUTF16Ptr(s.name), svcmain}, + {nil, 0}, + } + + goWaitsH = uintptr(s.goWaits.h) + cWaitsH = uintptr(s.cWaits.h) + sName = t[0].ServiceName + ctlHandlerProc, err = newCallback(ctlHandler) + if err != nil { + return err + } + + go s.run() + + err = windows.StartServiceCtrlDispatcher(&t[0]) + if err != nil { + return err + } + return nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_386.s b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_386.s new file mode 100644 index 0000000000..5e11bfadb5 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_386.s @@ -0,0 +1,67 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// func servicemain(argc uint32, argv **uint16) +TEXT ·servicemain(SB),7,$0 + MOVL argc+0(FP), AX + MOVL AX, ·sArgc(SB) + MOVL argv+4(FP), AX + MOVL AX, ·sArgv(SB) + + PUSHL BP + PUSHL BX + PUSHL SI + PUSHL DI + + SUBL $12, SP + + MOVL ·sName(SB), AX + MOVL AX, (SP) + MOVL $·servicectlhandler(SB), AX + MOVL AX, 4(SP) + MOVL ·cRegisterServiceCtrlHandlerW(SB), AX + MOVL SP, BP + CALL AX + MOVL BP, SP + CMPL AX, $0 + JE exit + MOVL AX, ·ssHandle(SB) + + MOVL ·goWaitsH(SB), AX + MOVL AX, (SP) + MOVL ·cSetEvent(SB), AX + MOVL SP, BP + CALL AX + MOVL BP, SP + + MOVL ·cWaitsH(SB), AX + MOVL AX, (SP) + MOVL $-1, AX + MOVL AX, 4(SP) + MOVL ·cWaitForSingleObject(SB), AX + MOVL SP, BP + CALL AX + MOVL BP, SP + +exit: + ADDL $12, SP + + POPL DI + POPL SI + POPL BX + POPL BP + + MOVL 0(SP), CX + ADDL $12, SP + JMP CX + +// I do not know why, but this seems to be the only way to call +// ctlHandlerProc on Windows 7. + +// func servicectlhandler(ctl uint32) uintptr +TEXT ·servicectlhandler(SB),7,$0 + MOVL ·ctlHandlerProc(SB), CX + JMP CX diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_amd64.s b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_amd64.s new file mode 100644 index 0000000000..87dbec8395 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_amd64.s @@ -0,0 +1,41 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// func servicemain(argc uint32, argv **uint16) +TEXT ·servicemain(SB),7,$0 + MOVL CX, ·sArgc(SB) + MOVL DX, ·sArgv(SB) + + SUBQ $32, SP // stack for the first 4 syscall params + + MOVQ ·sName(SB), CX + MOVQ $·servicectlhandler(SB), DX + MOVQ ·cRegisterServiceCtrlHandlerW(SB), AX + CALL AX + CMPQ AX, $0 + JE exit + MOVQ AX, ·ssHandle(SB) + + MOVQ ·goWaitsH(SB), CX + MOVQ ·cSetEvent(SB), AX + CALL AX + + MOVQ ·cWaitsH(SB), CX + MOVQ $4294967295, DX + MOVQ ·cWaitForSingleObject(SB), AX + CALL AX + +exit: + ADDQ $32, SP + RET + +// I do not know why, but this seems to be the only way to call +// ctlHandlerProc on Windows 7. + +// func servicectlhandler(ctl uint32) uintptr +TEXT ·servicectlhandler(SB),7,$0 + MOVQ ·ctlHandlerProc(SB), AX + JMP AX diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/syscall.go b/Godeps/_workspace/src/golang.org/x/sys/windows/syscall.go new file mode 100644 index 0000000000..a8cc609b32 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/syscall.go @@ -0,0 +1,77 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package windows contains an interface to the low-level operating system +// primitives. OS details vary depending on the underlying system, and +// by default, godoc will display the OS-specific documentation for the current +// system. If you want godoc to display syscall documentation for another +// system, set $GOOS and $GOARCH to the desired system. For example, if +// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS +// to freebsd and $GOARCH to arm. +// The primary use of this package is inside other packages that provide a more +// portable interface to the system, such as "os", "time" and "net". Use +// those packages rather than this one if you can. +// For details of the functions and data types in this package consult +// the manuals for the appropriate operating system. +// These calls return err == nil to indicate success; otherwise +// err represents an operating system error describing the failure and +// holds a value of type syscall.Errno. +package windows // import "golang.org/x/sys/windows" + +import ( + "syscall" + "unsafe" +) + +// ByteSliceFromString returns a NUL-terminated slice of bytes +// containing the text of s. If s contains a NUL byte at any +// location, it returns (nil, syscall.EINVAL). +func ByteSliceFromString(s string) ([]byte, error) { + for i := 0; i < len(s); i++ { + if s[i] == 0 { + return nil, syscall.EINVAL + } + } + a := make([]byte, len(s)+1) + copy(a, s) + return a, nil +} + +// BytePtrFromString returns a pointer to a NUL-terminated array of +// bytes containing the text of s. If s contains a NUL byte at any +// location, it returns (nil, syscall.EINVAL). +func BytePtrFromString(s string) (*byte, error) { + a, err := ByteSliceFromString(s) + if err != nil { + return nil, err + } + return &a[0], nil +} + +// Single-word zero for use when we need a valid pointer to 0 bytes. +// See mksyscall.pl. +var _zero uintptr + +func (ts *Timespec) Unix() (sec int64, nsec int64) { + return int64(ts.Sec), int64(ts.Nsec) +} + +func (tv *Timeval) Unix() (sec int64, nsec int64) { + return int64(tv.Sec), int64(tv.Usec) * 1000 +} + +func (ts *Timespec) Nano() int64 { + return int64(ts.Sec)*1e9 + int64(ts.Nsec) +} + +func (tv *Timeval) Nano() int64 { + return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 +} + +// use is a no-op, but the compiler cannot see that it is. +// Calling use(p) ensures that p is kept live until that point. +//go:noescape +func use(p unsafe.Pointer) diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/syscall_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/syscall_windows.go new file mode 100644 index 0000000000..75def60924 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/syscall_windows.go @@ -0,0 +1,990 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Windows system calls. + +package windows + +import ( + errorspkg "errors" + "sync" + "syscall" + "unicode/utf16" + "unsafe" +) + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go + +type Handle uintptr + +const InvalidHandle = ^Handle(0) + +// StringToUTF16 is deprecated. Use UTF16FromString instead. +// If s contains a NUL byte this function panics instead of +// returning an error. +func StringToUTF16(s string) []uint16 { + a, err := UTF16FromString(s) + if err != nil { + panic("windows: string with NUL passed to StringToUTF16") + } + return a +} + +// UTF16FromString returns the UTF-16 encoding of the UTF-8 string +// s, with a terminating NUL added. If s contains a NUL byte at any +// location, it returns (nil, syscall.EINVAL). +func UTF16FromString(s string) ([]uint16, error) { + for i := 0; i < len(s); i++ { + if s[i] == 0 { + return nil, syscall.EINVAL + } + } + return utf16.Encode([]rune(s + "\x00")), nil +} + +// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s, +// with a terminating NUL removed. +func UTF16ToString(s []uint16) string { + for i, v := range s { + if v == 0 { + s = s[0:i] + break + } + } + return string(utf16.Decode(s)) +} + +// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead. +// If s contains a NUL byte this function panics instead of +// returning an error. +func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] } + +// UTF16PtrFromString returns pointer to the UTF-16 encoding of +// the UTF-8 string s, with a terminating NUL added. If s +// contains a NUL byte at any location, it returns (nil, syscall.EINVAL). +func UTF16PtrFromString(s string) (*uint16, error) { + a, err := UTF16FromString(s) + if err != nil { + return nil, err + } + return &a[0], nil +} + +func Getpagesize() int { return 4096 } + +// Converts a Go function to a function pointer conforming +// to the stdcall or cdecl calling convention. This is useful when +// interoperating with Windows code requiring callbacks. +// Implemented in runtime/syscall_windows.goc +func NewCallback(fn interface{}) uintptr +func NewCallbackCDecl(fn interface{}) uintptr + +// windows api calls + +//sys GetLastError() (lasterr error) +//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW +//sys FreeLibrary(handle Handle) (err error) +//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error) +//sys GetVersion() (ver uint32, err error) +//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW +//sys ExitProcess(exitcode uint32) +//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW +//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) +//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) +//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff] +//sys CloseHandle(handle Handle) (err error) +//sys GetStdHandle(stdhandle int) (handle Handle, err error) [failretval==InvalidHandle] +//sys findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW +//sys findNextFile1(handle Handle, data *win32finddata1) (err error) = FindNextFileW +//sys FindClose(handle Handle) (err error) +//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) +//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW +//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW +//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW +//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW +//sys DeleteFile(path *uint16) (err error) = DeleteFileW +//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW +//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW +//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW +//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW +//sys SetEndOfFile(handle Handle) (err error) +//sys GetSystemTimeAsFileTime(time *Filetime) +//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] +//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) +//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) +//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) +//sys CancelIo(s Handle) (err error) +//sys CancelIoEx(s Handle, o *Overlapped) (err error) +//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW +//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) +//sys TerminateProcess(handle Handle, exitcode uint32) (err error) +//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) +//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW +//sys GetCurrentProcess() (pseudoHandle Handle, err error) +//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) +//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) +//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] +//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW +//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) +//sys GetFileType(filehandle Handle) (n uint32, err error) +//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW +//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext +//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom +//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW +//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW +//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW +//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW +//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) +//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW +//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW +//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW +//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW +//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW +//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0] +//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) +//sys FlushFileBuffers(handle Handle) (err error) +//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW +//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW +//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW +//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW +//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) +//sys UnmapViewOfFile(addr uintptr) (err error) +//sys FlushViewOfFile(addr uintptr, length uintptr) (err error) +//sys VirtualLock(addr uintptr, length uintptr) (err error) +//sys VirtualUnlock(addr uintptr, length uintptr) (err error) +//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile +//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW +//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW +//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore +//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore +//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore +//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore +//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain +//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain +//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext +//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext +//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy +//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW +//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey +//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW +//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW +//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW +//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId +//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode +//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW +//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW +//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot +//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW +//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW +//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) +// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL. +//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW +//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW +//sys GetCurrentThreadId() (id uint32) +//sys CreateEvent(eventAttrs *syscall.SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) = kernel32.CreateEventW +//sys SetEvent(event Handle) (err error) = kernel32.SetEvent + +// syscall interface implementation for other packages + +func Exit(code int) { ExitProcess(uint32(code)) } + +func makeInheritSa() *SecurityAttributes { + var sa SecurityAttributes + sa.Length = uint32(unsafe.Sizeof(sa)) + sa.InheritHandle = 1 + return &sa +} + +func Open(path string, mode int, perm uint32) (fd Handle, err error) { + if len(path) == 0 { + return InvalidHandle, ERROR_FILE_NOT_FOUND + } + pathp, err := UTF16PtrFromString(path) + if err != nil { + return InvalidHandle, err + } + var access uint32 + switch mode & (O_RDONLY | O_WRONLY | O_RDWR) { + case O_RDONLY: + access = GENERIC_READ + case O_WRONLY: + access = GENERIC_WRITE + case O_RDWR: + access = GENERIC_READ | GENERIC_WRITE + } + if mode&O_CREAT != 0 { + access |= GENERIC_WRITE + } + if mode&O_APPEND != 0 { + access &^= GENERIC_WRITE + access |= FILE_APPEND_DATA + } + sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE) + var sa *SecurityAttributes + if mode&O_CLOEXEC == 0 { + sa = makeInheritSa() + } + var createmode uint32 + switch { + case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL): + createmode = CREATE_NEW + case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC): + createmode = CREATE_ALWAYS + case mode&O_CREAT == O_CREAT: + createmode = OPEN_ALWAYS + case mode&O_TRUNC == O_TRUNC: + createmode = TRUNCATE_EXISTING + default: + createmode = OPEN_EXISTING + } + h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0) + return h, e +} + +func Read(fd Handle, p []byte) (n int, err error) { + var done uint32 + e := ReadFile(fd, p, &done, nil) + if e != nil { + if e == ERROR_BROKEN_PIPE { + // NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin + return 0, nil + } + return 0, e + } + if raceenabled { + if done > 0 { + raceWriteRange(unsafe.Pointer(&p[0]), int(done)) + } + raceAcquire(unsafe.Pointer(&ioSync)) + } + return int(done), nil +} + +func Write(fd Handle, p []byte) (n int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + var done uint32 + e := WriteFile(fd, p, &done, nil) + if e != nil { + return 0, e + } + if raceenabled && done > 0 { + raceReadRange(unsafe.Pointer(&p[0]), int(done)) + } + return int(done), nil +} + +var ioSync int64 + +func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) { + var w uint32 + switch whence { + case 0: + w = FILE_BEGIN + case 1: + w = FILE_CURRENT + case 2: + w = FILE_END + } + hi := int32(offset >> 32) + lo := int32(offset) + // use GetFileType to check pipe, pipe can't do seek + ft, _ := GetFileType(fd) + if ft == FILE_TYPE_PIPE { + return 0, syscall.EPIPE + } + rlo, e := SetFilePointer(fd, lo, &hi, w) + if e != nil { + return 0, e + } + return int64(hi)<<32 + int64(rlo), nil +} + +func Close(fd Handle) (err error) { + return CloseHandle(fd) +} + +var ( + Stdin = getStdHandle(STD_INPUT_HANDLE) + Stdout = getStdHandle(STD_OUTPUT_HANDLE) + Stderr = getStdHandle(STD_ERROR_HANDLE) +) + +func getStdHandle(h int) (fd Handle) { + r, _ := GetStdHandle(h) + CloseOnExec(r) + return r +} + +const ImplementsGetwd = true + +func Getwd() (wd string, err error) { + b := make([]uint16, 300) + n, e := GetCurrentDirectory(uint32(len(b)), &b[0]) + if e != nil { + return "", e + } + return string(utf16.Decode(b[0:n])), nil +} + +func Chdir(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return SetCurrentDirectory(pathp) +} + +func Mkdir(path string, mode uint32) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return CreateDirectory(pathp, nil) +} + +func Rmdir(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return RemoveDirectory(pathp) +} + +func Unlink(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return DeleteFile(pathp) +} + +func Rename(oldpath, newpath string) (err error) { + from, err := UTF16PtrFromString(oldpath) + if err != nil { + return err + } + to, err := UTF16PtrFromString(newpath) + if err != nil { + return err + } + return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) +} + +func ComputerName() (name string, err error) { + var n uint32 = MAX_COMPUTERNAME_LENGTH + 1 + b := make([]uint16, n) + e := GetComputerName(&b[0], &n) + if e != nil { + return "", e + } + return string(utf16.Decode(b[0:n])), nil +} + +func Ftruncate(fd Handle, length int64) (err error) { + curoffset, e := Seek(fd, 0, 1) + if e != nil { + return e + } + defer Seek(fd, curoffset, 0) + _, e = Seek(fd, length, 0) + if e != nil { + return e + } + e = SetEndOfFile(fd) + if e != nil { + return e + } + return nil +} + +func Gettimeofday(tv *Timeval) (err error) { + var ft Filetime + GetSystemTimeAsFileTime(&ft) + *tv = NsecToTimeval(ft.Nanoseconds()) + return nil +} + +func Pipe(p []Handle) (err error) { + if len(p) != 2 { + return syscall.EINVAL + } + var r, w Handle + e := CreatePipe(&r, &w, makeInheritSa(), 0) + if e != nil { + return e + } + p[0] = r + p[1] = w + return nil +} + +func Utimes(path string, tv []Timeval) (err error) { + if len(tv) != 2 { + return syscall.EINVAL + } + pathp, e := UTF16PtrFromString(path) + if e != nil { + return e + } + h, e := CreateFile(pathp, + FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) + if e != nil { + return e + } + defer Close(h) + a := NsecToFiletime(tv[0].Nanoseconds()) + w := NsecToFiletime(tv[1].Nanoseconds()) + return SetFileTime(h, nil, &a, &w) +} + +func UtimesNano(path string, ts []Timespec) (err error) { + if len(ts) != 2 { + return syscall.EINVAL + } + pathp, e := UTF16PtrFromString(path) + if e != nil { + return e + } + h, e := CreateFile(pathp, + FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) + if e != nil { + return e + } + defer Close(h) + a := NsecToFiletime(TimespecToNsec(ts[0])) + w := NsecToFiletime(TimespecToNsec(ts[1])) + return SetFileTime(h, nil, &a, &w) +} + +func Fsync(fd Handle) (err error) { + return FlushFileBuffers(fd) +} + +func Chmod(path string, mode uint32) (err error) { + if mode == 0 { + return syscall.EINVAL + } + p, e := UTF16PtrFromString(path) + if e != nil { + return e + } + attrs, e := GetFileAttributes(p) + if e != nil { + return e + } + if mode&S_IWRITE != 0 { + attrs &^= FILE_ATTRIBUTE_READONLY + } else { + attrs |= FILE_ATTRIBUTE_READONLY + } + return SetFileAttributes(p, attrs) +} + +func LoadCancelIoEx() error { + return procCancelIoEx.Find() +} + +func LoadSetFileCompletionNotificationModes() error { + return procSetFileCompletionNotificationModes.Find() +} + +// net api calls + +const socket_error = uintptr(^uint32(0)) + +//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup +//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup +//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl +//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket +//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt +//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt +//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind +//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect +//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname +//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername +//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen +//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown +//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket +//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx +//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs +//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv +//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend +//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom +//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo +//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname +//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname +//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs +//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname +//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W +//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree +//sys DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) = dnsapi.DnsNameCompare_W +//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW +//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW +//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry +//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo +//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes +//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW +//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses +//sys GetACP() (acp uint32) = kernel32.GetACP +//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar + +// For testing: clients can set this flag to force +// creation of IPv6 sockets to return EAFNOSUPPORT. +var SocketDisableIPv6 bool + +type RawSockaddrInet4 struct { + Family uint16 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]uint8 +} + +type RawSockaddrInet6 struct { + Family uint16 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddr struct { + Family uint16 + Data [14]int8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [96]int8 +} + +type Sockaddr interface { + sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs +} + +type SockaddrInet4 struct { + Port int + Addr [4]byte + raw RawSockaddrInet4 +} + +func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, syscall.EINVAL + } + sa.raw.Family = AF_INET + p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + for i := 0; i < len(sa.Addr); i++ { + sa.raw.Addr[i] = sa.Addr[i] + } + return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil +} + +type SockaddrInet6 struct { + Port int + ZoneId uint32 + Addr [16]byte + raw RawSockaddrInet6 +} + +func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, syscall.EINVAL + } + sa.raw.Family = AF_INET6 + p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + sa.raw.Scope_id = sa.ZoneId + for i := 0; i < len(sa.Addr); i++ { + sa.raw.Addr[i] = sa.Addr[i] + } + return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil +} + +type SockaddrUnix struct { + Name string +} + +func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) { + // TODO(brainman): implement SockaddrUnix.sockaddr() + return nil, 0, syscall.EWINDOWS +} + +func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) { + switch rsa.Addr.Family { + case AF_UNIX: + return nil, syscall.EWINDOWS + + case AF_INET: + pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) + sa := new(SockaddrInet4) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + for i := 0; i < len(sa.Addr); i++ { + sa.Addr[i] = pp.Addr[i] + } + return sa, nil + + case AF_INET6: + pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) + sa := new(SockaddrInet6) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + sa.ZoneId = pp.Scope_id + for i := 0; i < len(sa.Addr); i++ { + sa.Addr[i] = pp.Addr[i] + } + return sa, nil + } + return nil, syscall.EAFNOSUPPORT +} + +func Socket(domain, typ, proto int) (fd Handle, err error) { + if domain == AF_INET6 && SocketDisableIPv6 { + return InvalidHandle, syscall.EAFNOSUPPORT + } + return socket(int32(domain), int32(typ), int32(proto)) +} + +func SetsockoptInt(fd Handle, level, opt int, value int) (err error) { + v := int32(value) + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))) +} + +func Bind(fd Handle, sa Sockaddr) (err error) { + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return bind(fd, ptr, n) +} + +func Connect(fd Handle, sa Sockaddr) (err error) { + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return connect(fd, ptr, n) +} + +func Getsockname(fd Handle) (sa Sockaddr, err error) { + var rsa RawSockaddrAny + l := int32(unsafe.Sizeof(rsa)) + if err = getsockname(fd, &rsa, &l); err != nil { + return + } + return rsa.Sockaddr() +} + +func Getpeername(fd Handle) (sa Sockaddr, err error) { + var rsa RawSockaddrAny + l := int32(unsafe.Sizeof(rsa)) + if err = getpeername(fd, &rsa, &l); err != nil { + return + } + return rsa.Sockaddr() +} + +func Listen(s Handle, n int) (err error) { + return listen(s, int32(n)) +} + +func Shutdown(fd Handle, how int) (err error) { + return shutdown(fd, int32(how)) +} + +func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) { + rsa, l, err := to.sockaddr() + if err != nil { + return err + } + return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine) +} + +func LoadGetAddrInfo() error { + return procGetAddrInfoW.Find() +} + +var connectExFunc struct { + once sync.Once + addr uintptr + err error +} + +func LoadConnectEx() error { + connectExFunc.once.Do(func() { + var s Handle + s, connectExFunc.err = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) + if connectExFunc.err != nil { + return + } + defer CloseHandle(s) + var n uint32 + connectExFunc.err = WSAIoctl(s, + SIO_GET_EXTENSION_FUNCTION_POINTER, + (*byte)(unsafe.Pointer(&WSAID_CONNECTEX)), + uint32(unsafe.Sizeof(WSAID_CONNECTEX)), + (*byte)(unsafe.Pointer(&connectExFunc.addr)), + uint32(unsafe.Sizeof(connectExFunc.addr)), + &n, nil, 0) + }) + return connectExFunc.err +} + +func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ConnectEx(fd Handle, sa Sockaddr, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) error { + err := LoadConnectEx() + if err != nil { + return errorspkg.New("failed to find ConnectEx: " + err.Error()) + } + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped) +} + +// Invented structures to support what package os expects. +type Rusage struct { + CreationTime Filetime + ExitTime Filetime + KernelTime Filetime + UserTime Filetime +} + +type WaitStatus struct { + ExitCode uint32 +} + +func (w WaitStatus) Exited() bool { return true } + +func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) } + +func (w WaitStatus) Signal() Signal { return -1 } + +func (w WaitStatus) CoreDump() bool { return false } + +func (w WaitStatus) Stopped() bool { return false } + +func (w WaitStatus) Continued() bool { return false } + +func (w WaitStatus) StopSignal() Signal { return -1 } + +func (w WaitStatus) Signaled() bool { return false } + +func (w WaitStatus) TrapCause() int { return -1 } + +// Timespec is an invented structure on Windows, but here for +// consistency with the corresponding package for other operating systems. +type Timespec struct { + Sec int64 + Nsec int64 +} + +func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } + +func NsecToTimespec(nsec int64) (ts Timespec) { + ts.Sec = nsec / 1e9 + ts.Nsec = nsec % 1e9 + return +} + +// TODO(brainman): fix all needed for net + +func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, syscall.EWINDOWS } +func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) { + return 0, nil, syscall.EWINDOWS +} +func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return syscall.EWINDOWS } +func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return syscall.EWINDOWS } + +// The Linger struct is wrong but we only noticed after Go 1. +// sysLinger is the real system call structure. + +// BUG(brainman): The definition of Linger is not appropriate for direct use +// with Setsockopt and Getsockopt. +// Use SetsockoptLinger instead. + +type Linger struct { + Onoff int32 + Linger int32 +} + +type sysLinger struct { + Onoff uint16 + Linger uint16 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, syscall.EWINDOWS } + +func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { + sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)} + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&sys)), int32(unsafe.Sizeof(sys))) +} + +func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) { + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4) +} +func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) { + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq))) +} +func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) { + return syscall.EWINDOWS +} + +func Getpid() (pid int) { return int(getCurrentProcessId()) } + +func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) { + // NOTE(rsc): The Win32finddata struct is wrong for the system call: + // the two paths are each one uint16 short. Use the correct struct, + // a win32finddata1, and then copy the results out. + // There is no loss of expressivity here, because the final + // uint16, if it is used, is supposed to be a NUL, and Go doesn't need that. + // For Go 1.1, we might avoid the allocation of win32finddata1 here + // by adding a final Bug [2]uint16 field to the struct and then + // adjusting the fields in the result directly. + var data1 win32finddata1 + handle, err = findFirstFile1(name, &data1) + if err == nil { + copyFindData(data, &data1) + } + return +} + +func FindNextFile(handle Handle, data *Win32finddata) (err error) { + var data1 win32finddata1 + err = findNextFile1(handle, &data1) + if err == nil { + copyFindData(data, &data1) + } + return +} + +func getProcessEntry(pid int) (*ProcessEntry32, error) { + snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err + } + defer CloseHandle(snapshot) + var procEntry ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = Process32First(snapshot, &procEntry); err != nil { + return nil, err + } + for { + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil + } + err = Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err + } + } +} + +func Getppid() (ppid int) { + pe, err := getProcessEntry(Getpid()) + if err != nil { + return -1 + } + return int(pe.ParentProcessID) +} + +// TODO(brainman): fix all needed for os +func Fchdir(fd Handle) (err error) { return syscall.EWINDOWS } +func Link(oldpath, newpath string) (err error) { return syscall.EWINDOWS } +func Symlink(path, link string) (err error) { return syscall.EWINDOWS } + +func Fchmod(fd Handle, mode uint32) (err error) { return syscall.EWINDOWS } +func Chown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS } +func Lchown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS } +func Fchown(fd Handle, uid int, gid int) (err error) { return syscall.EWINDOWS } + +func Getuid() (uid int) { return -1 } +func Geteuid() (euid int) { return -1 } +func Getgid() (gid int) { return -1 } +func Getegid() (egid int) { return -1 } +func Getgroups() (gids []int, err error) { return nil, syscall.EWINDOWS } + +type Signal int + +func (s Signal) Signal() {} + +func (s Signal) String() string { + if 0 <= s && int(s) < len(signals) { + str := signals[s] + if str != "" { + return str + } + } + return "signal " + itoa(int(s)) +} + +func LoadCreateSymbolicLink() error { + return procCreateSymbolicLinkW.Find() +} + +// Readlink returns the destination of the named symbolic link. +func Readlink(path string, buf []byte) (n int, err error) { + fd, err := CreateFile(StringToUTF16Ptr(path), GENERIC_READ, 0, nil, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0) + if err != nil { + return -1, err + } + defer CloseHandle(fd) + + rdbbuf := make([]byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE) + var bytesReturned uint32 + err = DeviceIoControl(fd, FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil) + if err != nil { + return -1, err + } + + rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0])) + var s string + switch rdb.ReparseTag { + case IO_REPARSE_TAG_SYMLINK: + data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) + p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) + s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2]) + case IO_REPARSE_TAG_MOUNT_POINT: + data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) + p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) + s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2]) + default: + // the path is not a symlink or junction but another type of reparse + // point + return -1, syscall.ENOENT + } + n = copy(buf, []byte(s)) + + return n, nil +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/zsyscall_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/zsyscall_windows.go new file mode 100644 index 0000000000..10dd30ae24 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/zsyscall_windows.go @@ -0,0 +1,2220 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package windows + +import "unsafe" +import "syscall" + +var _ unsafe.Pointer + +var ( + modadvapi32 = syscall.NewLazyDLL("advapi32.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + modshell32 = syscall.NewLazyDLL("shell32.dll") + modmswsock = syscall.NewLazyDLL("mswsock.dll") + modcrypt32 = syscall.NewLazyDLL("crypt32.dll") + modws2_32 = syscall.NewLazyDLL("ws2_32.dll") + moddnsapi = syscall.NewLazyDLL("dnsapi.dll") + modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") + modsecur32 = syscall.NewLazyDLL("secur32.dll") + modnetapi32 = syscall.NewLazyDLL("netapi32.dll") + moduserenv = syscall.NewLazyDLL("userenv.dll") + + procRegisterEventSourceW = modadvapi32.NewProc("RegisterEventSourceW") + procDeregisterEventSource = modadvapi32.NewProc("DeregisterEventSource") + procReportEventW = modadvapi32.NewProc("ReportEventW") + procOpenSCManagerW = modadvapi32.NewProc("OpenSCManagerW") + procCloseServiceHandle = modadvapi32.NewProc("CloseServiceHandle") + procCreateServiceW = modadvapi32.NewProc("CreateServiceW") + procOpenServiceW = modadvapi32.NewProc("OpenServiceW") + procDeleteService = modadvapi32.NewProc("DeleteService") + procStartServiceW = modadvapi32.NewProc("StartServiceW") + procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") + procControlService = modadvapi32.NewProc("ControlService") + procStartServiceCtrlDispatcherW = modadvapi32.NewProc("StartServiceCtrlDispatcherW") + procSetServiceStatus = modadvapi32.NewProc("SetServiceStatus") + procChangeServiceConfigW = modadvapi32.NewProc("ChangeServiceConfigW") + procQueryServiceConfigW = modadvapi32.NewProc("QueryServiceConfigW") + procChangeServiceConfig2W = modadvapi32.NewProc("ChangeServiceConfig2W") + procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W") + procGetLastError = modkernel32.NewProc("GetLastError") + procLoadLibraryW = modkernel32.NewProc("LoadLibraryW") + procFreeLibrary = modkernel32.NewProc("FreeLibrary") + procGetProcAddress = modkernel32.NewProc("GetProcAddress") + procGetVersion = modkernel32.NewProc("GetVersion") + procFormatMessageW = modkernel32.NewProc("FormatMessageW") + procExitProcess = modkernel32.NewProc("ExitProcess") + procCreateFileW = modkernel32.NewProc("CreateFileW") + procReadFile = modkernel32.NewProc("ReadFile") + procWriteFile = modkernel32.NewProc("WriteFile") + procSetFilePointer = modkernel32.NewProc("SetFilePointer") + procCloseHandle = modkernel32.NewProc("CloseHandle") + procGetStdHandle = modkernel32.NewProc("GetStdHandle") + procFindFirstFileW = modkernel32.NewProc("FindFirstFileW") + procFindNextFileW = modkernel32.NewProc("FindNextFileW") + procFindClose = modkernel32.NewProc("FindClose") + procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle") + procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW") + procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW") + procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW") + procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW") + procDeleteFileW = modkernel32.NewProc("DeleteFileW") + procMoveFileW = modkernel32.NewProc("MoveFileW") + procMoveFileExW = modkernel32.NewProc("MoveFileExW") + procGetComputerNameW = modkernel32.NewProc("GetComputerNameW") + procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") + procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") + procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime") + procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") + procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") + procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus") + procCancelIo = modkernel32.NewProc("CancelIo") + procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procCreateProcessW = modkernel32.NewProc("CreateProcessW") + procOpenProcess = modkernel32.NewProc("OpenProcess") + procTerminateProcess = modkernel32.NewProc("TerminateProcess") + procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess") + procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW") + procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess") + procGetProcessTimes = modkernel32.NewProc("GetProcessTimes") + procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") + procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") + procGetTempPathW = modkernel32.NewProc("GetTempPathW") + procCreatePipe = modkernel32.NewProc("CreatePipe") + procGetFileType = modkernel32.NewProc("GetFileType") + procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW") + procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext") + procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom") + procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW") + procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW") + procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW") + procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") + procSetFileTime = modkernel32.NewProc("SetFileTime") + procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW") + procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW") + procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW") + procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") + procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") + procLocalFree = modkernel32.NewProc("LocalFree") + procSetHandleInformation = modkernel32.NewProc("SetHandleInformation") + procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers") + procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW") + procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW") + procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW") + procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW") + procMapViewOfFile = modkernel32.NewProc("MapViewOfFile") + procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile") + procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile") + procVirtualLock = modkernel32.NewProc("VirtualLock") + procVirtualUnlock = modkernel32.NewProc("VirtualUnlock") + procTransmitFile = modmswsock.NewProc("TransmitFile") + procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW") + procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW") + procCertOpenStore = modcrypt32.NewProc("CertOpenStore") + procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore") + procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore") + procCertCloseStore = modcrypt32.NewProc("CertCloseStore") + procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain") + procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain") + procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext") + procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext") + procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy") + procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW") + procRegCloseKey = modadvapi32.NewProc("RegCloseKey") + procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW") + procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW") + procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW") + procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId") + procGetConsoleMode = modkernel32.NewProc("GetConsoleMode") + procWriteConsoleW = modkernel32.NewProc("WriteConsoleW") + procReadConsoleW = modkernel32.NewProc("ReadConsoleW") + procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") + procProcess32FirstW = modkernel32.NewProc("Process32FirstW") + procProcess32NextW = modkernel32.NewProc("Process32NextW") + procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") + procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW") + procCreateHardLinkW = modkernel32.NewProc("CreateHardLinkW") + procGetCurrentThreadId = modkernel32.NewProc("GetCurrentThreadId") + procCreateEventW = modkernel32.NewProc("CreateEventW") + procSetEvent = modkernel32.NewProc("SetEvent") + procWSAStartup = modws2_32.NewProc("WSAStartup") + procWSACleanup = modws2_32.NewProc("WSACleanup") + procWSAIoctl = modws2_32.NewProc("WSAIoctl") + procsocket = modws2_32.NewProc("socket") + procsetsockopt = modws2_32.NewProc("setsockopt") + procgetsockopt = modws2_32.NewProc("getsockopt") + procbind = modws2_32.NewProc("bind") + procconnect = modws2_32.NewProc("connect") + procgetsockname = modws2_32.NewProc("getsockname") + procgetpeername = modws2_32.NewProc("getpeername") + proclisten = modws2_32.NewProc("listen") + procshutdown = modws2_32.NewProc("shutdown") + procclosesocket = modws2_32.NewProc("closesocket") + procAcceptEx = modmswsock.NewProc("AcceptEx") + procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs") + procWSARecv = modws2_32.NewProc("WSARecv") + procWSASend = modws2_32.NewProc("WSASend") + procWSARecvFrom = modws2_32.NewProc("WSARecvFrom") + procWSASendTo = modws2_32.NewProc("WSASendTo") + procgethostbyname = modws2_32.NewProc("gethostbyname") + procgetservbyname = modws2_32.NewProc("getservbyname") + procntohs = modws2_32.NewProc("ntohs") + procgetprotobyname = modws2_32.NewProc("getprotobyname") + procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W") + procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree") + procDnsNameCompare_W = moddnsapi.NewProc("DnsNameCompare_W") + procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW") + procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW") + procGetIfEntry = modiphlpapi.NewProc("GetIfEntry") + procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo") + procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") + procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW") + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procGetACP = modkernel32.NewProc("GetACP") + procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar") + procTranslateNameW = modsecur32.NewProc("TranslateNameW") + procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") + procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") + procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") + procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") + procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW") + procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") + procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") + procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW") + procGetLengthSid = modadvapi32.NewProc("GetLengthSid") + procCopySid = modadvapi32.NewProc("CopySid") + procAllocateAndInitializeSid = modadvapi32.NewProc("AllocateAndInitializeSid") + procFreeSid = modadvapi32.NewProc("FreeSid") + procEqualSid = modadvapi32.NewProc("EqualSid") + procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") + procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation") + procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") +) + +func RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procRegisterEventSourceW.Addr(), 2, uintptr(unsafe.Pointer(uncServerName)), uintptr(unsafe.Pointer(sourceName)), 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeregisterEventSource(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procDeregisterEventSource.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procReportEventW.Addr(), 9, uintptr(log), uintptr(etype), uintptr(category), uintptr(eventId), uintptr(usrSId), uintptr(numStrings), uintptr(dataSize), uintptr(unsafe.Pointer(strings)), uintptr(unsafe.Pointer(rawData))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(access)) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CloseServiceHandle(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procCloseServiceHandle.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall15(procCreateServiceW.Addr(), 13, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(unsafe.Pointer(displayName)), uintptr(access), uintptr(srvType), uintptr(startType), uintptr(errCtl), uintptr(unsafe.Pointer(pathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), 0, 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procOpenServiceW.Addr(), 3, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(access)) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeleteService(service Handle) (err error) { + r1, _, e1 := syscall.Syscall(procDeleteService.Addr(), 1, uintptr(service), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) { + r1, _, e1 := syscall.Syscall(procStartServiceW.Addr(), 3, uintptr(service), uintptr(numArgs), uintptr(unsafe.Pointer(argVectors))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) { + r1, _, e1 := syscall.Syscall(procQueryServiceStatus.Addr(), 2, uintptr(service), uintptr(unsafe.Pointer(status)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) { + r1, _, e1 := syscall.Syscall(procControlService.Addr(), 3, uintptr(service), uintptr(control), uintptr(unsafe.Pointer(status))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) { + r1, _, e1 := syscall.Syscall(procStartServiceCtrlDispatcherW.Addr(), 1, uintptr(unsafe.Pointer(serviceTable)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) { + r1, _, e1 := syscall.Syscall(procSetServiceStatus.Addr(), 2, uintptr(service), uintptr(unsafe.Pointer(serviceStatus)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) { + r1, _, e1 := syscall.Syscall12(procChangeServiceConfigW.Addr(), 11, uintptr(service), uintptr(serviceType), uintptr(startType), uintptr(errorControl), uintptr(unsafe.Pointer(binaryPathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), uintptr(unsafe.Pointer(displayName)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procQueryServiceConfigW.Addr(), 4, uintptr(service), uintptr(unsafe.Pointer(serviceConfig)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) { + r1, _, e1 := syscall.Syscall(procChangeServiceConfig2W.Addr(), 3, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(info))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procQueryServiceConfig2W.Addr(), 5, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetLastError() (lasterr error) { + r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0) + if r0 != 0 { + lasterr = syscall.Errno(r0) + } + return +} + +func LoadLibrary(libname string) (handle Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(libname) + if err != nil { + return + } + return _LoadLibrary(_p0) +} + +func _LoadLibrary(libname *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(libname)), 0, 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FreeLibrary(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(procname) + if err != nil { + return + } + return _GetProcAddress(module, _p0) +} + +func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) { + r0, _, e1 := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(procname)), 0) + proc = uintptr(r0) + if proc == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetVersion() (ver uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetVersion.Addr(), 0, 0, 0, 0) + ver = uint32(r0) + if ver == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) { + var _p0 *uint16 + if len(buf) > 0 { + _p0 = &buf[0] + } + r0, _, e1 := syscall.Syscall9(procFormatMessageW.Addr(), 7, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ExitProcess(exitcode uint32) { + syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0) + return +} + +func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r1, _, e1 := syscall.Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r1, _, e1 := syscall.Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) { + r0, _, e1 := syscall.Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0) + newlowoffset = uint32(r0) + if newlowoffset == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CloseHandle(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetStdHandle(stdhandle int) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func findNextFile1(handle Handle, data *win32finddata1) (err error) { + r1, _, e1 := syscall.Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FindClose(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) { + r1, _, e1 := syscall.Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetCurrentDirectory(path *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) { + r1, _, e1 := syscall.Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func RemoveDirectory(path *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeleteFile(path *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func MoveFile(from *uint16, to *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetComputerName(buf *uint16, n *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nametype), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetEndOfFile(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetSystemTimeAsFileTime(time *Filetime) { + syscall.Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0) + return +} + +func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0) + rc = uint32(r0) + if rc == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CancelIo(s Handle) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CancelIoEx(s Handle, o *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(s), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { + var _p0 uint32 + if inheritHandles { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) { + var _p0 uint32 + if inheritHandle { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, e1 := syscall.Syscall(procOpenProcess.Addr(), 3, uintptr(da), uintptr(_p0), uintptr(pid)) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func TerminateProcess(handle Handle, exitcode uint32) (err error) { + r1, _, e1 := syscall.Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetStartupInfo(startupInfo *StartupInfo) (err error) { + r1, _, e1 := syscall.Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetCurrentProcess() (pseudoHandle Handle, err error) { + r0, _, e1 := syscall.Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0) + pseudoHandle = Handle(r0) + if pseudoHandle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) { + r1, _, e1 := syscall.Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) { + var _p0 uint32 + if bInheritHandle { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) { + r0, _, e1 := syscall.Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0) + event = uint32(r0) + if event == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFileType(filehandle Handle) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CryptReleaseContext(provhandle Handle, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) { + r1, _, e1 := syscall.Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetEnvironmentStrings() (envs *uint16, err error) { + r0, _, e1 := syscall.Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0) + envs = (*uint16)(unsafe.Pointer(r0)) + if envs == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FreeEnvironmentStrings(envs *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetEnvironmentVariableW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) { + r1, _, e1 := syscall.Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFileAttributes(name *uint16) (attrs uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + attrs = uint32(r0) + if attrs == INVALID_FILE_ATTRIBUTES { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetFileAttributes(name *uint16, attrs uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) { + r1, _, e1 := syscall.Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetCommandLine() (cmd *uint16) { + r0, _, _ := syscall.Syscall(procGetCommandLineW.Addr(), 0, 0, 0, 0) + cmd = (*uint16)(unsafe.Pointer(r0)) + return +} + +func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) { + r0, _, e1 := syscall.Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) + argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0)) + if argv == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func LocalFree(hmem Handle) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0) + handle = Handle(r0) + if handle != 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FlushFileBuffers(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetShortPathNameW.Addr(), 3, uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name))) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) { + r0, _, e1 := syscall.Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0) + addr = uintptr(r0) + if addr == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func UnmapViewOfFile(addr uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FlushViewOfFile(addr uintptr, length uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func VirtualLock(addr uintptr, length uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func VirtualUnlock(addr uintptr, length uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { + var _p0 uint32 + if watchSubTree { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) { + r0, _, e1 := syscall.Syscall(procCertOpenSystemStoreW.Addr(), 2, uintptr(hprov), uintptr(unsafe.Pointer(name)), 0) + store = Handle(r0) + if store == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) { + r0, _, e1 := syscall.Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0) + context = (*CertContext)(unsafe.Pointer(r0)) + if context == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) { + r1, _, e1 := syscall.Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertCloseStore(store Handle, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) { + r1, _, e1 := syscall.Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertFreeCertificateChain(ctx *CertChainContext) { + syscall.Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) + return +} + +func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) { + r0, _, e1 := syscall.Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen)) + context = (*CertContext)(unsafe.Pointer(r0)) + if context == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertFreeCertificateContext(ctx *CertContext) (err error) { + r1, _, e1 := syscall.Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) { + r1, _, e1 := syscall.Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) { + r0, _, _ := syscall.Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func RegCloseKey(key Handle) (regerrno error) { + r0, _, _ := syscall.Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) { + r0, _, _ := syscall.Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime))) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) { + r0, _, _ := syscall.Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { + r0, _, _ := syscall.Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen))) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func getCurrentProcessId() (pid uint32) { + r0, _, _ := syscall.Syscall(procGetCurrentProcessId.Addr(), 0, 0, 0, 0) + pid = uint32(r0) + return +} + +func GetConsoleMode(console Handle, mode *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) { + r1, _, e1 := syscall.Syscall6(procWriteConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(towrite), uintptr(unsafe.Pointer(written)), uintptr(unsafe.Pointer(reserved)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) { + r1, _, e1 := syscall.Syscall6(procReadConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags)) + if r1&0xff == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procCreateHardLinkW.Addr(), 3, uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(existingfilename)), uintptr(reserved)) + if r1&0xff == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetCurrentThreadId() (id uint32) { + r0, _, _ := syscall.Syscall(procGetCurrentThreadId.Addr(), 0, 0, 0, 0) + id = uint32(r0) + return +} + +func CreateEvent(eventAttrs *syscall.SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name)), 0, 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetEvent(event Handle) (err error) { + r1, _, e1 := syscall.Syscall(procSetEvent.Addr(), 1, uintptr(event), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSAStartup(verreq uint32, data *WSAData) (sockerr error) { + r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) + if r0 != 0 { + sockerr = syscall.Errno(r0) + } + return +} + +func WSACleanup() (err error) { + r1, _, e1 := syscall.Syscall(procWSACleanup.Addr(), 0, 0, 0, 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { + r1, _, e1 := syscall.Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine)) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func socket(af int32, typ int32, protocol int32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol)) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) { + r1, _, e1 := syscall.Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) { + r1, _, e1 := syscall.Syscall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(unsafe.Pointer(optlen)), 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := syscall.Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { + r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { + r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func listen(s Handle, backlog int32) (err error) { + r1, _, e1 := syscall.Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func shutdown(s Handle, how int32) (err error) { + r1, _, e1 := syscall.Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Closesocket(s Handle) (err error) { + r1, _, e1 := syscall.Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) { + syscall.Syscall9(procGetAcceptExSockaddrs.Addr(), 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0) + return +} + +func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetHostByName(name string) (h *Hostent, err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(name) + if err != nil { + return + } + return _GetHostByName(_p0) +} + +func _GetHostByName(name *byte) (h *Hostent, err error) { + r0, _, e1 := syscall.Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + h = (*Hostent)(unsafe.Pointer(r0)) + if h == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetServByName(name string, proto string) (s *Servent, err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(name) + if err != nil { + return + } + var _p1 *byte + _p1, err = syscall.BytePtrFromString(proto) + if err != nil { + return + } + return _GetServByName(_p0, _p1) +} + +func _GetServByName(name *byte, proto *byte) (s *Servent, err error) { + r0, _, e1 := syscall.Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(proto)), 0) + s = (*Servent)(unsafe.Pointer(r0)) + if s == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Ntohs(netshort uint16) (u uint16) { + r0, _, _ := syscall.Syscall(procntohs.Addr(), 1, uintptr(netshort), 0, 0) + u = uint16(r0) + return +} + +func GetProtoByName(name string) (p *Protoent, err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(name) + if err != nil { + return + } + return _GetProtoByName(_p0) +} + +func _GetProtoByName(name *byte) (p *Protoent, err error) { + r0, _, e1 := syscall.Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + p = (*Protoent)(unsafe.Pointer(r0)) + if p == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { + var _p0 *uint16 + _p0, status = syscall.UTF16PtrFromString(name) + if status != nil { + return + } + return _DnsQuery(_p0, qtype, options, extra, qrs, pr) +} + +func _DnsQuery(name *uint16, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { + r0, _, _ := syscall.Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(name)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) + if r0 != 0 { + status = syscall.Errno(r0) + } + return +} + +func DnsRecordListFree(rl *DNSRecord, freetype uint32) { + syscall.Syscall(procDnsRecordListFree.Addr(), 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0) + return +} + +func DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) { + r0, _, _ := syscall.Syscall(procDnsNameCompare_W.Addr(), 2, uintptr(unsafe.Pointer(name1)), uintptr(unsafe.Pointer(name2)), 0) + same = r0 != 0 + return +} + +func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) { + r0, _, _ := syscall.Syscall6(procGetAddrInfoW.Addr(), 4, uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result)), 0, 0) + if r0 != 0 { + sockerr = syscall.Errno(r0) + } + return +} + +func FreeAddrInfoW(addrinfo *AddrinfoW) { + syscall.Syscall(procFreeAddrInfoW.Addr(), 1, uintptr(unsafe.Pointer(addrinfo)), 0, 0) + return +} + +func GetIfEntry(pIfRow *MibIfRow) (errcode error) { + r0, _, _ := syscall.Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) { + r0, _, _ := syscall.Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) { + r0, _, e1 := syscall.Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength))) + n = int32(r0) + if n == -1 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { + r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func GetACP() (acp uint32) { + r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0) + acp = uint32(r0) + return +} + +func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) { + r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar)) + nwrite = int32(r0) + if nwrite == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0) + if r1&0xff == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) + if r1&0xff == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) { + r0, _, _ := syscall.Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) { + r0, _, _ := syscall.Syscall(procNetGetJoinInformation.Addr(), 3, uintptr(unsafe.Pointer(server)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bufType))) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func NetApiBufferFree(buf *byte) (neterr error) { + r0, _, _ := syscall.Syscall(procNetApiBufferFree.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) { + r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) { + r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetLengthSid(sid *SID) (len uint32) { + r0, _, _ := syscall.Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + len = uint32(r0) + return +} + +func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) { + r1, _, e1 := syscall.Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) { + r1, _, e1 := syscall.Syscall12(procAllocateAndInitializeSid.Addr(), 11, uintptr(unsafe.Pointer(identAuth)), uintptr(subAuth), uintptr(subAuth0), uintptr(subAuth1), uintptr(subAuth2), uintptr(subAuth3), uintptr(subAuth4), uintptr(subAuth5), uintptr(subAuth6), uintptr(subAuth7), uintptr(unsafe.Pointer(sid)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FreeSid(sid *SID) (err error) { + r1, _, e1 := syscall.Syscall(procFreeSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + if r1 != 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) { + r0, _, _ := syscall.Syscall(procEqualSid.Addr(), 2, uintptr(unsafe.Pointer(sid1)), uintptr(unsafe.Pointer(sid2)), 0) + isEqual = r0 != 0 + return +} + +func OpenProcessToken(h Handle, access uint32, token *Token) (err error) { + r1, _, e1 := syscall.Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetTokenInformation.Addr(), 5, uintptr(t), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows.go new file mode 100644 index 0000000000..1fe19d1d7f --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows.go @@ -0,0 +1,1242 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import "syscall" + +const ( + // Windows errors. + ERROR_FILE_NOT_FOUND syscall.Errno = 2 + ERROR_PATH_NOT_FOUND syscall.Errno = 3 + ERROR_ACCESS_DENIED syscall.Errno = 5 + ERROR_NO_MORE_FILES syscall.Errno = 18 + ERROR_HANDLE_EOF syscall.Errno = 38 + ERROR_NETNAME_DELETED syscall.Errno = 64 + ERROR_FILE_EXISTS syscall.Errno = 80 + ERROR_BROKEN_PIPE syscall.Errno = 109 + ERROR_BUFFER_OVERFLOW syscall.Errno = 111 + ERROR_INSUFFICIENT_BUFFER syscall.Errno = 122 + ERROR_MOD_NOT_FOUND syscall.Errno = 126 + ERROR_PROC_NOT_FOUND syscall.Errno = 127 + ERROR_ALREADY_EXISTS syscall.Errno = 183 + ERROR_ENVVAR_NOT_FOUND syscall.Errno = 203 + ERROR_MORE_DATA syscall.Errno = 234 + ERROR_OPERATION_ABORTED syscall.Errno = 995 + ERROR_IO_PENDING syscall.Errno = 997 + ERROR_SERVICE_SPECIFIC_ERROR syscall.Errno = 1066 + ERROR_NOT_FOUND syscall.Errno = 1168 + ERROR_PRIVILEGE_NOT_HELD syscall.Errno = 1314 + WSAEACCES syscall.Errno = 10013 + WSAECONNRESET syscall.Errno = 10054 +) + +const ( + // Invented values to support what package os expects. + O_RDONLY = 0x00000 + O_WRONLY = 0x00001 + O_RDWR = 0x00002 + O_CREAT = 0x00040 + O_EXCL = 0x00080 + O_NOCTTY = 0x00100 + O_TRUNC = 0x00200 + O_NONBLOCK = 0x00800 + O_APPEND = 0x00400 + O_SYNC = 0x01000 + O_ASYNC = 0x02000 + O_CLOEXEC = 0x80000 +) + +const ( + // More invented values for signals + SIGHUP = Signal(0x1) + SIGINT = Signal(0x2) + SIGQUIT = Signal(0x3) + SIGILL = Signal(0x4) + SIGTRAP = Signal(0x5) + SIGABRT = Signal(0x6) + SIGBUS = Signal(0x7) + SIGFPE = Signal(0x8) + SIGKILL = Signal(0x9) + SIGSEGV = Signal(0xb) + SIGPIPE = Signal(0xd) + SIGALRM = Signal(0xe) + SIGTERM = Signal(0xf) +) + +var signals = [...]string{ + 1: "hangup", + 2: "interrupt", + 3: "quit", + 4: "illegal instruction", + 5: "trace/breakpoint trap", + 6: "aborted", + 7: "bus error", + 8: "floating point exception", + 9: "killed", + 10: "user defined signal 1", + 11: "segmentation fault", + 12: "user defined signal 2", + 13: "broken pipe", + 14: "alarm clock", + 15: "terminated", +} + +const ( + GENERIC_READ = 0x80000000 + GENERIC_WRITE = 0x40000000 + GENERIC_EXECUTE = 0x20000000 + GENERIC_ALL = 0x10000000 + + FILE_LIST_DIRECTORY = 0x00000001 + FILE_APPEND_DATA = 0x00000004 + FILE_WRITE_ATTRIBUTES = 0x00000100 + + FILE_SHARE_READ = 0x00000001 + FILE_SHARE_WRITE = 0x00000002 + FILE_SHARE_DELETE = 0x00000004 + FILE_ATTRIBUTE_READONLY = 0x00000001 + FILE_ATTRIBUTE_HIDDEN = 0x00000002 + FILE_ATTRIBUTE_SYSTEM = 0x00000004 + FILE_ATTRIBUTE_DIRECTORY = 0x00000010 + FILE_ATTRIBUTE_ARCHIVE = 0x00000020 + FILE_ATTRIBUTE_NORMAL = 0x00000080 + FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 + + INVALID_FILE_ATTRIBUTES = 0xffffffff + + CREATE_NEW = 1 + CREATE_ALWAYS = 2 + OPEN_EXISTING = 3 + OPEN_ALWAYS = 4 + TRUNCATE_EXISTING = 5 + + FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 + FILE_FLAG_OVERLAPPED = 0x40000000 + + HANDLE_FLAG_INHERIT = 0x00000001 + STARTF_USESTDHANDLES = 0x00000100 + STARTF_USESHOWWINDOW = 0x00000001 + DUPLICATE_CLOSE_SOURCE = 0x00000001 + DUPLICATE_SAME_ACCESS = 0x00000002 + + STD_INPUT_HANDLE = -10 + STD_OUTPUT_HANDLE = -11 + STD_ERROR_HANDLE = -12 + + FILE_BEGIN = 0 + FILE_CURRENT = 1 + FILE_END = 2 + + LANG_ENGLISH = 0x09 + SUBLANG_ENGLISH_US = 0x01 + + FORMAT_MESSAGE_ALLOCATE_BUFFER = 256 + FORMAT_MESSAGE_IGNORE_INSERTS = 512 + FORMAT_MESSAGE_FROM_STRING = 1024 + FORMAT_MESSAGE_FROM_HMODULE = 2048 + FORMAT_MESSAGE_FROM_SYSTEM = 4096 + FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192 + FORMAT_MESSAGE_MAX_WIDTH_MASK = 255 + + MAX_PATH = 260 + MAX_LONG_PATH = 32768 + + MAX_COMPUTERNAME_LENGTH = 15 + + TIME_ZONE_ID_UNKNOWN = 0 + TIME_ZONE_ID_STANDARD = 1 + + TIME_ZONE_ID_DAYLIGHT = 2 + IGNORE = 0 + INFINITE = 0xffffffff + + WAIT_TIMEOUT = 258 + WAIT_ABANDONED = 0x00000080 + WAIT_OBJECT_0 = 0x00000000 + WAIT_FAILED = 0xFFFFFFFF + + CREATE_NEW_PROCESS_GROUP = 0x00000200 + CREATE_UNICODE_ENVIRONMENT = 0x00000400 + + PROCESS_TERMINATE = 1 + PROCESS_QUERY_INFORMATION = 0x00000400 + SYNCHRONIZE = 0x00100000 + + PAGE_READONLY = 0x02 + PAGE_READWRITE = 0x04 + PAGE_WRITECOPY = 0x08 + PAGE_EXECUTE_READ = 0x20 + PAGE_EXECUTE_READWRITE = 0x40 + PAGE_EXECUTE_WRITECOPY = 0x80 + + FILE_MAP_COPY = 0x01 + FILE_MAP_WRITE = 0x02 + FILE_MAP_READ = 0x04 + FILE_MAP_EXECUTE = 0x20 + + CTRL_C_EVENT = 0 + CTRL_BREAK_EVENT = 1 + + // Windows reserves errors >= 1<<29 for application use. + APPLICATION_ERROR = 1 << 29 +) + +const ( + // flags for CreateToolhelp32Snapshot + TH32CS_SNAPHEAPLIST = 0x01 + TH32CS_SNAPPROCESS = 0x02 + TH32CS_SNAPTHREAD = 0x04 + TH32CS_SNAPMODULE = 0x08 + TH32CS_SNAPMODULE32 = 0x10 + TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD + TH32CS_INHERIT = 0x80000000 +) + +const ( + // filters for ReadDirectoryChangesW + FILE_NOTIFY_CHANGE_FILE_NAME = 0x001 + FILE_NOTIFY_CHANGE_DIR_NAME = 0x002 + FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x004 + FILE_NOTIFY_CHANGE_SIZE = 0x008 + FILE_NOTIFY_CHANGE_LAST_WRITE = 0x010 + FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x020 + FILE_NOTIFY_CHANGE_CREATION = 0x040 + FILE_NOTIFY_CHANGE_SECURITY = 0x100 +) + +const ( + // do not reorder + FILE_ACTION_ADDED = iota + 1 + FILE_ACTION_REMOVED + FILE_ACTION_MODIFIED + FILE_ACTION_RENAMED_OLD_NAME + FILE_ACTION_RENAMED_NEW_NAME +) + +const ( + // wincrypt.h + PROV_RSA_FULL = 1 + PROV_RSA_SIG = 2 + PROV_DSS = 3 + PROV_FORTEZZA = 4 + PROV_MS_EXCHANGE = 5 + PROV_SSL = 6 + PROV_RSA_SCHANNEL = 12 + PROV_DSS_DH = 13 + PROV_EC_ECDSA_SIG = 14 + PROV_EC_ECNRA_SIG = 15 + PROV_EC_ECDSA_FULL = 16 + PROV_EC_ECNRA_FULL = 17 + PROV_DH_SCHANNEL = 18 + PROV_SPYRUS_LYNKS = 20 + PROV_RNG = 21 + PROV_INTEL_SEC = 22 + PROV_REPLACE_OWF = 23 + PROV_RSA_AES = 24 + CRYPT_VERIFYCONTEXT = 0xF0000000 + CRYPT_NEWKEYSET = 0x00000008 + CRYPT_DELETEKEYSET = 0x00000010 + CRYPT_MACHINE_KEYSET = 0x00000020 + CRYPT_SILENT = 0x00000040 + CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080 + + USAGE_MATCH_TYPE_AND = 0 + USAGE_MATCH_TYPE_OR = 1 + + X509_ASN_ENCODING = 0x00000001 + PKCS_7_ASN_ENCODING = 0x00010000 + + CERT_STORE_PROV_MEMORY = 2 + + CERT_STORE_ADD_ALWAYS = 4 + + CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004 + + CERT_TRUST_NO_ERROR = 0x00000000 + CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001 + CERT_TRUST_IS_REVOKED = 0x00000004 + CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008 + CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010 + CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020 + CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040 + CERT_TRUST_IS_CYCLIC = 0x00000080 + CERT_TRUST_INVALID_EXTENSION = 0x00000100 + CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200 + CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400 + CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800 + CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000 + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000 + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000 + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000 + CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000 + CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000 + CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000 + CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000 + + CERT_CHAIN_POLICY_BASE = 1 + CERT_CHAIN_POLICY_AUTHENTICODE = 2 + CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3 + CERT_CHAIN_POLICY_SSL = 4 + CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = 5 + CERT_CHAIN_POLICY_NT_AUTH = 6 + CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7 + CERT_CHAIN_POLICY_EV = 8 + + CERT_E_EXPIRED = 0x800B0101 + CERT_E_ROLE = 0x800B0103 + CERT_E_PURPOSE = 0x800B0106 + CERT_E_UNTRUSTEDROOT = 0x800B0109 + CERT_E_CN_NO_MATCH = 0x800B010F + + AUTHTYPE_CLIENT = 1 + AUTHTYPE_SERVER = 2 +) + +var ( + OID_PKIX_KP_SERVER_AUTH = []byte("1.3.6.1.5.5.7.3.1\x00") + OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\x00") + OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\x00") +) + +// Invented values to support what package os expects. +type Timeval struct { + Sec int32 + Usec int32 +} + +func (tv *Timeval) Nanoseconds() int64 { + return (int64(tv.Sec)*1e6 + int64(tv.Usec)) * 1e3 +} + +func NsecToTimeval(nsec int64) (tv Timeval) { + tv.Sec = int32(nsec / 1e9) + tv.Usec = int32(nsec % 1e9 / 1e3) + return +} + +type SecurityAttributes struct { + Length uint32 + SecurityDescriptor uintptr + InheritHandle uint32 +} + +type Overlapped struct { + Internal uintptr + InternalHigh uintptr + Offset uint32 + OffsetHigh uint32 + HEvent Handle +} + +type FileNotifyInformation struct { + NextEntryOffset uint32 + Action uint32 + FileNameLength uint32 + FileName uint16 +} + +type Filetime struct { + LowDateTime uint32 + HighDateTime uint32 +} + +// Nanoseconds returns Filetime ft in nanoseconds +// since Epoch (00:00:00 UTC, January 1, 1970). +func (ft *Filetime) Nanoseconds() int64 { + // 100-nanosecond intervals since January 1, 1601 + nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) + // change starting time to the Epoch (00:00:00 UTC, January 1, 1970) + nsec -= 116444736000000000 + // convert into nanoseconds + nsec *= 100 + return nsec +} + +func NsecToFiletime(nsec int64) (ft Filetime) { + // convert into 100-nanosecond + nsec /= 100 + // change starting time to January 1, 1601 + nsec += 116444736000000000 + // split into high / low + ft.LowDateTime = uint32(nsec & 0xffffffff) + ft.HighDateTime = uint32(nsec >> 32 & 0xffffffff) + return ft +} + +type Win32finddata struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 + Reserved0 uint32 + Reserved1 uint32 + FileName [MAX_PATH - 1]uint16 + AlternateFileName [13]uint16 +} + +// This is the actual system call structure. +// Win32finddata is what we committed to in Go 1. +type win32finddata1 struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 + Reserved0 uint32 + Reserved1 uint32 + FileName [MAX_PATH]uint16 + AlternateFileName [14]uint16 +} + +func copyFindData(dst *Win32finddata, src *win32finddata1) { + dst.FileAttributes = src.FileAttributes + dst.CreationTime = src.CreationTime + dst.LastAccessTime = src.LastAccessTime + dst.LastWriteTime = src.LastWriteTime + dst.FileSizeHigh = src.FileSizeHigh + dst.FileSizeLow = src.FileSizeLow + dst.Reserved0 = src.Reserved0 + dst.Reserved1 = src.Reserved1 + + // The src is 1 element bigger than dst, but it must be NUL. + copy(dst.FileName[:], src.FileName[:]) + copy(dst.AlternateFileName[:], src.AlternateFileName[:]) +} + +type ByHandleFileInformation struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + VolumeSerialNumber uint32 + FileSizeHigh uint32 + FileSizeLow uint32 + NumberOfLinks uint32 + FileIndexHigh uint32 + FileIndexLow uint32 +} + +const ( + GetFileExInfoStandard = 0 + GetFileExMaxInfoLevel = 1 +) + +type Win32FileAttributeData struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 +} + +// ShowWindow constants +const ( + // winuser.h + SW_HIDE = 0 + SW_NORMAL = 1 + SW_SHOWNORMAL = 1 + SW_SHOWMINIMIZED = 2 + SW_SHOWMAXIMIZED = 3 + SW_MAXIMIZE = 3 + SW_SHOWNOACTIVATE = 4 + SW_SHOW = 5 + SW_MINIMIZE = 6 + SW_SHOWMINNOACTIVE = 7 + SW_SHOWNA = 8 + SW_RESTORE = 9 + SW_SHOWDEFAULT = 10 + SW_FORCEMINIMIZE = 11 +) + +type StartupInfo struct { + Cb uint32 + _ *uint16 + Desktop *uint16 + Title *uint16 + X uint32 + Y uint32 + XSize uint32 + YSize uint32 + XCountChars uint32 + YCountChars uint32 + FillAttribute uint32 + Flags uint32 + ShowWindow uint16 + _ uint16 + _ *byte + StdInput Handle + StdOutput Handle + StdErr Handle +} + +type ProcessInformation struct { + Process Handle + Thread Handle + ProcessId uint32 + ThreadId uint32 +} + +type ProcessEntry32 struct { + Size uint32 + Usage uint32 + ProcessID uint32 + DefaultHeapID uintptr + ModuleID uint32 + Threads uint32 + ParentProcessID uint32 + PriClassBase int32 + Flags uint32 + ExeFile [MAX_PATH]uint16 +} + +type Systemtime struct { + Year uint16 + Month uint16 + DayOfWeek uint16 + Day uint16 + Hour uint16 + Minute uint16 + Second uint16 + Milliseconds uint16 +} + +type Timezoneinformation struct { + Bias int32 + StandardName [32]uint16 + StandardDate Systemtime + StandardBias int32 + DaylightName [32]uint16 + DaylightDate Systemtime + DaylightBias int32 +} + +// Socket related. + +const ( + AF_UNSPEC = 0 + AF_UNIX = 1 + AF_INET = 2 + AF_INET6 = 23 + AF_NETBIOS = 17 + + SOCK_STREAM = 1 + SOCK_DGRAM = 2 + SOCK_RAW = 3 + SOCK_SEQPACKET = 5 + + IPPROTO_IP = 0 + IPPROTO_IPV6 = 0x29 + IPPROTO_TCP = 6 + IPPROTO_UDP = 17 + + SOL_SOCKET = 0xffff + SO_REUSEADDR = 4 + SO_KEEPALIVE = 8 + SO_DONTROUTE = 16 + SO_BROADCAST = 32 + SO_LINGER = 128 + SO_RCVBUF = 0x1002 + SO_SNDBUF = 0x1001 + SO_UPDATE_ACCEPT_CONTEXT = 0x700b + SO_UPDATE_CONNECT_CONTEXT = 0x7010 + + IOC_OUT = 0x40000000 + IOC_IN = 0x80000000 + IOC_VENDOR = 0x18000000 + IOC_INOUT = IOC_IN | IOC_OUT + IOC_WS2 = 0x08000000 + SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6 + SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4 + SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 + + // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460 + + IP_TOS = 0x3 + IP_TTL = 0x4 + IP_MULTICAST_IF = 0x9 + IP_MULTICAST_TTL = 0xa + IP_MULTICAST_LOOP = 0xb + IP_ADD_MEMBERSHIP = 0xc + IP_DROP_MEMBERSHIP = 0xd + + IPV6_V6ONLY = 0x1b + IPV6_UNICAST_HOPS = 0x4 + IPV6_MULTICAST_IF = 0x9 + IPV6_MULTICAST_HOPS = 0xa + IPV6_MULTICAST_LOOP = 0xb + IPV6_JOIN_GROUP = 0xc + IPV6_LEAVE_GROUP = 0xd + + SOMAXCONN = 0x7fffffff + + TCP_NODELAY = 1 + + SHUT_RD = 0 + SHUT_WR = 1 + SHUT_RDWR = 2 + + WSADESCRIPTION_LEN = 256 + WSASYS_STATUS_LEN = 128 +) + +type WSABuf struct { + Len uint32 + Buf *byte +} + +// Invented values to support what package os expects. +const ( + S_IFMT = 0x1f000 + S_IFIFO = 0x1000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFBLK = 0x6000 + S_IFREG = 0x8000 + S_IFLNK = 0xa000 + S_IFSOCK = 0xc000 + S_ISUID = 0x800 + S_ISGID = 0x400 + S_ISVTX = 0x200 + S_IRUSR = 0x100 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXUSR = 0x40 +) + +const ( + FILE_TYPE_CHAR = 0x0002 + FILE_TYPE_DISK = 0x0001 + FILE_TYPE_PIPE = 0x0003 + FILE_TYPE_REMOTE = 0x8000 + FILE_TYPE_UNKNOWN = 0x0000 +) + +type Hostent struct { + Name *byte + Aliases **byte + AddrType uint16 + Length uint16 + AddrList **byte +} + +type Protoent struct { + Name *byte + Aliases **byte + Proto uint16 +} + +const ( + DNS_TYPE_A = 0x0001 + DNS_TYPE_NS = 0x0002 + DNS_TYPE_MD = 0x0003 + DNS_TYPE_MF = 0x0004 + DNS_TYPE_CNAME = 0x0005 + DNS_TYPE_SOA = 0x0006 + DNS_TYPE_MB = 0x0007 + DNS_TYPE_MG = 0x0008 + DNS_TYPE_MR = 0x0009 + DNS_TYPE_NULL = 0x000a + DNS_TYPE_WKS = 0x000b + DNS_TYPE_PTR = 0x000c + DNS_TYPE_HINFO = 0x000d + DNS_TYPE_MINFO = 0x000e + DNS_TYPE_MX = 0x000f + DNS_TYPE_TEXT = 0x0010 + DNS_TYPE_RP = 0x0011 + DNS_TYPE_AFSDB = 0x0012 + DNS_TYPE_X25 = 0x0013 + DNS_TYPE_ISDN = 0x0014 + DNS_TYPE_RT = 0x0015 + DNS_TYPE_NSAP = 0x0016 + DNS_TYPE_NSAPPTR = 0x0017 + DNS_TYPE_SIG = 0x0018 + DNS_TYPE_KEY = 0x0019 + DNS_TYPE_PX = 0x001a + DNS_TYPE_GPOS = 0x001b + DNS_TYPE_AAAA = 0x001c + DNS_TYPE_LOC = 0x001d + DNS_TYPE_NXT = 0x001e + DNS_TYPE_EID = 0x001f + DNS_TYPE_NIMLOC = 0x0020 + DNS_TYPE_SRV = 0x0021 + DNS_TYPE_ATMA = 0x0022 + DNS_TYPE_NAPTR = 0x0023 + DNS_TYPE_KX = 0x0024 + DNS_TYPE_CERT = 0x0025 + DNS_TYPE_A6 = 0x0026 + DNS_TYPE_DNAME = 0x0027 + DNS_TYPE_SINK = 0x0028 + DNS_TYPE_OPT = 0x0029 + DNS_TYPE_DS = 0x002B + DNS_TYPE_RRSIG = 0x002E + DNS_TYPE_NSEC = 0x002F + DNS_TYPE_DNSKEY = 0x0030 + DNS_TYPE_DHCID = 0x0031 + DNS_TYPE_UINFO = 0x0064 + DNS_TYPE_UID = 0x0065 + DNS_TYPE_GID = 0x0066 + DNS_TYPE_UNSPEC = 0x0067 + DNS_TYPE_ADDRS = 0x00f8 + DNS_TYPE_TKEY = 0x00f9 + DNS_TYPE_TSIG = 0x00fa + DNS_TYPE_IXFR = 0x00fb + DNS_TYPE_AXFR = 0x00fc + DNS_TYPE_MAILB = 0x00fd + DNS_TYPE_MAILA = 0x00fe + DNS_TYPE_ALL = 0x00ff + DNS_TYPE_ANY = 0x00ff + DNS_TYPE_WINS = 0xff01 + DNS_TYPE_WINSR = 0xff02 + DNS_TYPE_NBSTAT = 0xff01 +) + +const ( + DNS_INFO_NO_RECORDS = 0x251D +) + +const ( + // flags inside DNSRecord.Dw + DnsSectionQuestion = 0x0000 + DnsSectionAnswer = 0x0001 + DnsSectionAuthority = 0x0002 + DnsSectionAdditional = 0x0003 +) + +type DNSSRVData struct { + Target *uint16 + Priority uint16 + Weight uint16 + Port uint16 + Pad uint16 +} + +type DNSPTRData struct { + Host *uint16 +} + +type DNSMXData struct { + NameExchange *uint16 + Preference uint16 + Pad uint16 +} + +type DNSTXTData struct { + StringCount uint16 + StringArray [1]*uint16 +} + +type DNSRecord struct { + Next *DNSRecord + Name *uint16 + Type uint16 + Length uint16 + Dw uint32 + Ttl uint32 + Reserved uint32 + Data [40]byte +} + +const ( + TF_DISCONNECT = 1 + TF_REUSE_SOCKET = 2 + TF_WRITE_BEHIND = 4 + TF_USE_DEFAULT_WORKER = 0 + TF_USE_SYSTEM_THREAD = 16 + TF_USE_KERNEL_APC = 32 +) + +type TransmitFileBuffers struct { + Head uintptr + HeadLength uint32 + Tail uintptr + TailLength uint32 +} + +const ( + IFF_UP = 1 + IFF_BROADCAST = 2 + IFF_LOOPBACK = 4 + IFF_POINTTOPOINT = 8 + IFF_MULTICAST = 16 +) + +const SIO_GET_INTERFACE_LIST = 0x4004747F + +// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old. +// will be fixed to change variable type as suitable. + +type SockaddrGen [24]byte + +type InterfaceInfo struct { + Flags uint32 + Address SockaddrGen + BroadcastAddress SockaddrGen + Netmask SockaddrGen +} + +type IpAddressString struct { + String [16]byte +} + +type IpMaskString IpAddressString + +type IpAddrString struct { + Next *IpAddrString + IpAddress IpAddressString + IpMask IpMaskString + Context uint32 +} + +const MAX_ADAPTER_NAME_LENGTH = 256 +const MAX_ADAPTER_DESCRIPTION_LENGTH = 128 +const MAX_ADAPTER_ADDRESS_LENGTH = 8 + +type IpAdapterInfo struct { + Next *IpAdapterInfo + ComboIndex uint32 + AdapterName [MAX_ADAPTER_NAME_LENGTH + 4]byte + Description [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte + AddressLength uint32 + Address [MAX_ADAPTER_ADDRESS_LENGTH]byte + Index uint32 + Type uint32 + DhcpEnabled uint32 + CurrentIpAddress *IpAddrString + IpAddressList IpAddrString + GatewayList IpAddrString + DhcpServer IpAddrString + HaveWins bool + PrimaryWinsServer IpAddrString + SecondaryWinsServer IpAddrString + LeaseObtained int64 + LeaseExpires int64 +} + +const MAXLEN_PHYSADDR = 8 +const MAX_INTERFACE_NAME_LEN = 256 +const MAXLEN_IFDESCR = 256 + +type MibIfRow struct { + Name [MAX_INTERFACE_NAME_LEN]uint16 + Index uint32 + Type uint32 + Mtu uint32 + Speed uint32 + PhysAddrLen uint32 + PhysAddr [MAXLEN_PHYSADDR]byte + AdminStatus uint32 + OperStatus uint32 + LastChange uint32 + InOctets uint32 + InUcastPkts uint32 + InNUcastPkts uint32 + InDiscards uint32 + InErrors uint32 + InUnknownProtos uint32 + OutOctets uint32 + OutUcastPkts uint32 + OutNUcastPkts uint32 + OutDiscards uint32 + OutErrors uint32 + OutQLen uint32 + DescrLen uint32 + Descr [MAXLEN_IFDESCR]byte +} + +type CertContext struct { + EncodingType uint32 + EncodedCert *byte + Length uint32 + CertInfo uintptr + Store Handle +} + +type CertChainContext struct { + Size uint32 + TrustStatus CertTrustStatus + ChainCount uint32 + Chains **CertSimpleChain + LowerQualityChainCount uint32 + LowerQualityChains **CertChainContext + HasRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 +} + +type CertSimpleChain struct { + Size uint32 + TrustStatus CertTrustStatus + NumElements uint32 + Elements **CertChainElement + TrustListInfo uintptr + HasRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 +} + +type CertChainElement struct { + Size uint32 + CertContext *CertContext + TrustStatus CertTrustStatus + RevocationInfo *CertRevocationInfo + IssuanceUsage *CertEnhKeyUsage + ApplicationUsage *CertEnhKeyUsage + ExtendedErrorInfo *uint16 +} + +type CertRevocationInfo struct { + Size uint32 + RevocationResult uint32 + RevocationOid *byte + OidSpecificInfo uintptr + HasFreshnessTime uint32 + FreshnessTime uint32 + CrlInfo uintptr // *CertRevocationCrlInfo +} + +type CertTrustStatus struct { + ErrorStatus uint32 + InfoStatus uint32 +} + +type CertUsageMatch struct { + Type uint32 + Usage CertEnhKeyUsage +} + +type CertEnhKeyUsage struct { + Length uint32 + UsageIdentifiers **byte +} + +type CertChainPara struct { + Size uint32 + RequestedUsage CertUsageMatch + RequstedIssuancePolicy CertUsageMatch + URLRetrievalTimeout uint32 + CheckRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 + CacheResync *Filetime +} + +type CertChainPolicyPara struct { + Size uint32 + Flags uint32 + ExtraPolicyPara uintptr +} + +type SSLExtraCertChainPolicyPara struct { + Size uint32 + AuthType uint32 + Checks uint32 + ServerName *uint16 +} + +type CertChainPolicyStatus struct { + Size uint32 + Error uint32 + ChainIndex uint32 + ElementIndex uint32 + ExtraPolicyStatus uintptr +} + +const ( + // do not reorder + HKEY_CLASSES_ROOT = 0x80000000 + iota + HKEY_CURRENT_USER + HKEY_LOCAL_MACHINE + HKEY_USERS + HKEY_PERFORMANCE_DATA + HKEY_CURRENT_CONFIG + HKEY_DYN_DATA + + KEY_QUERY_VALUE = 1 + KEY_SET_VALUE = 2 + KEY_CREATE_SUB_KEY = 4 + KEY_ENUMERATE_SUB_KEYS = 8 + KEY_NOTIFY = 16 + KEY_CREATE_LINK = 32 + KEY_WRITE = 0x20006 + KEY_EXECUTE = 0x20019 + KEY_READ = 0x20019 + KEY_WOW64_64KEY = 0x0100 + KEY_WOW64_32KEY = 0x0200 + KEY_ALL_ACCESS = 0xf003f +) + +const ( + // do not reorder + REG_NONE = iota + REG_SZ + REG_EXPAND_SZ + REG_BINARY + REG_DWORD_LITTLE_ENDIAN + REG_DWORD_BIG_ENDIAN + REG_LINK + REG_MULTI_SZ + REG_RESOURCE_LIST + REG_FULL_RESOURCE_DESCRIPTOR + REG_RESOURCE_REQUIREMENTS_LIST + REG_QWORD_LITTLE_ENDIAN + REG_DWORD = REG_DWORD_LITTLE_ENDIAN + REG_QWORD = REG_QWORD_LITTLE_ENDIAN +) + +type AddrinfoW struct { + Flags int32 + Family int32 + Socktype int32 + Protocol int32 + Addrlen uintptr + Canonname *uint16 + Addr uintptr + Next *AddrinfoW +} + +const ( + AI_PASSIVE = 1 + AI_CANONNAME = 2 + AI_NUMERICHOST = 4 +) + +type GUID struct { + Data1 uint32 + Data2 uint16 + Data3 uint16 + Data4 [8]byte +} + +var WSAID_CONNECTEX = GUID{ + 0x25a207b9, + 0xddf3, + 0x4660, + [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}, +} + +const ( + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 + FILE_SKIP_SET_EVENT_ON_HANDLE = 2 +) + +const ( + WSAPROTOCOL_LEN = 255 + MAX_PROTOCOL_CHAIN = 7 + BASE_PROTOCOL = 1 + LAYERED_PROTOCOL = 0 + + XP1_CONNECTIONLESS = 0x00000001 + XP1_GUARANTEED_DELIVERY = 0x00000002 + XP1_GUARANTEED_ORDER = 0x00000004 + XP1_MESSAGE_ORIENTED = 0x00000008 + XP1_PSEUDO_STREAM = 0x00000010 + XP1_GRACEFUL_CLOSE = 0x00000020 + XP1_EXPEDITED_DATA = 0x00000040 + XP1_CONNECT_DATA = 0x00000080 + XP1_DISCONNECT_DATA = 0x00000100 + XP1_SUPPORT_BROADCAST = 0x00000200 + XP1_SUPPORT_MULTIPOINT = 0x00000400 + XP1_MULTIPOINT_CONTROL_PLANE = 0x00000800 + XP1_MULTIPOINT_DATA_PLANE = 0x00001000 + XP1_QOS_SUPPORTED = 0x00002000 + XP1_UNI_SEND = 0x00008000 + XP1_UNI_RECV = 0x00010000 + XP1_IFS_HANDLES = 0x00020000 + XP1_PARTIAL_MESSAGE = 0x00040000 + XP1_SAN_SUPPORT_SDP = 0x00080000 + + PFL_MULTIPLE_PROTO_ENTRIES = 0x00000001 + PFL_RECOMMENDED_PROTO_ENTRY = 0x00000002 + PFL_HIDDEN = 0x00000004 + PFL_MATCHES_PROTOCOL_ZERO = 0x00000008 + PFL_NETWORKDIRECT_PROVIDER = 0x00000010 +) + +type WSAProtocolInfo struct { + ServiceFlags1 uint32 + ServiceFlags2 uint32 + ServiceFlags3 uint32 + ServiceFlags4 uint32 + ProviderFlags uint32 + ProviderId GUID + CatalogEntryId uint32 + ProtocolChain WSAProtocolChain + Version int32 + AddressFamily int32 + MaxSockAddr int32 + MinSockAddr int32 + SocketType int32 + Protocol int32 + ProtocolMaxOffset int32 + NetworkByteOrder int32 + SecurityScheme int32 + MessageSize uint32 + ProviderReserved uint32 + ProtocolName [WSAPROTOCOL_LEN + 1]uint16 +} + +type WSAProtocolChain struct { + ChainLen int32 + ChainEntries [MAX_PROTOCOL_CHAIN]uint32 +} + +type TCPKeepalive struct { + OnOff uint32 + Time uint32 + Interval uint32 +} + +type symbolicLinkReparseBuffer struct { + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 + Flags uint32 + PathBuffer [1]uint16 +} + +type mountPointReparseBuffer struct { + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 + PathBuffer [1]uint16 +} + +type reparseDataBuffer struct { + ReparseTag uint32 + ReparseDataLength uint16 + Reserved uint16 + + // GenericReparseBuffer + reparseBuffer byte +} + +const ( + FSCTL_GET_REPARSE_POINT = 0x900A8 + MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024 + IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 + IO_REPARSE_TAG_SYMLINK = 0xA000000C + SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1 +) + +const ( + ComputerNameNetBIOS = 0 + ComputerNameDnsHostname = 1 + ComputerNameDnsDomain = 2 + ComputerNameDnsFullyQualified = 3 + ComputerNamePhysicalNetBIOS = 4 + ComputerNamePhysicalDnsHostname = 5 + ComputerNamePhysicalDnsDomain = 6 + ComputerNamePhysicalDnsFullyQualified = 7 + ComputerNameMax = 8 +) + +const ( + MOVEFILE_REPLACE_EXISTING = 0x1 + MOVEFILE_COPY_ALLOWED = 0x2 + MOVEFILE_DELAY_UNTIL_REBOOT = 0x4 + MOVEFILE_WRITE_THROUGH = 0x8 + MOVEFILE_CREATE_HARDLINK = 0x10 + MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 +) + +const GAA_FLAG_INCLUDE_PREFIX = 0x00000010 + +const ( + IF_TYPE_OTHER = 1 + IF_TYPE_ETHERNET_CSMACD = 6 + IF_TYPE_ISO88025_TOKENRING = 9 + IF_TYPE_PPP = 23 + IF_TYPE_SOFTWARE_LOOPBACK = 24 + IF_TYPE_ATM = 37 + IF_TYPE_IEEE80211 = 71 + IF_TYPE_TUNNEL = 131 + IF_TYPE_IEEE1394 = 144 +) + +type SocketAddress struct { + Sockaddr *syscall.RawSockaddrAny + SockaddrLength int32 +} + +type IpAdapterUnicastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterUnicastAddress + Address SocketAddress + PrefixOrigin int32 + SuffixOrigin int32 + DadState int32 + ValidLifetime uint32 + PreferredLifetime uint32 + LeaseLifetime uint32 + OnLinkPrefixLength uint8 +} + +type IpAdapterAnycastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterAnycastAddress + Address SocketAddress +} + +type IpAdapterMulticastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterMulticastAddress + Address SocketAddress +} + +type IpAdapterDnsServerAdapter struct { + Length uint32 + Reserved uint32 + Next *IpAdapterDnsServerAdapter + Address SocketAddress +} + +type IpAdapterPrefix struct { + Length uint32 + Flags uint32 + Next *IpAdapterPrefix + Address SocketAddress + PrefixLength uint32 +} + +type IpAdapterAddresses struct { + Length uint32 + IfIndex uint32 + Next *IpAdapterAddresses + AdapterName *byte + FirstUnicastAddress *IpAdapterUnicastAddress + FirstAnycastAddress *IpAdapterAnycastAddress + FirstMulticastAddress *IpAdapterMulticastAddress + FirstDnsServerAddress *IpAdapterDnsServerAdapter + DnsSuffix *uint16 + Description *uint16 + FriendlyName *uint16 + PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte + PhysicalAddressLength uint32 + Flags uint32 + Mtu uint32 + IfType uint32 + OperStatus uint32 + Ipv6IfIndex uint32 + ZoneIndices [16]uint32 + FirstPrefix *IpAdapterPrefix + /* more fields might be present here. */ +} + +const ( + IfOperStatusUp = 1 + IfOperStatusDown = 2 + IfOperStatusTesting = 3 + IfOperStatusUnknown = 4 + IfOperStatusDormant = 5 + IfOperStatusNotPresent = 6 + IfOperStatusLowerLayerDown = 7 +) diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows_386.go b/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows_386.go new file mode 100644 index 0000000000..10f33be0b7 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows_386.go @@ -0,0 +1,22 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +type WSAData struct { + Version uint16 + HighVersion uint16 + Description [WSADESCRIPTION_LEN + 1]byte + SystemStatus [WSASYS_STATUS_LEN + 1]byte + MaxSockets uint16 + MaxUdpDg uint16 + VendorInfo *byte +} + +type Servent struct { + Name *byte + Aliases **byte + Port uint16 + Proto *byte +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows_amd64.go b/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows_amd64.go new file mode 100644 index 0000000000..3f272c2499 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/ztypes_windows_amd64.go @@ -0,0 +1,22 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +type WSAData struct { + Version uint16 + HighVersion uint16 + MaxSockets uint16 + MaxUdpDg uint16 + VendorInfo *byte + Description [WSADESCRIPTION_LEN + 1]byte + SystemStatus [WSASYS_STATUS_LEN + 1]byte +} + +type Servent struct { + Name *byte + Aliases **byte + Proto *byte + Port uint16 +} From 5bba3aac650fec9ca82ee5ccf042c8e0528ce0a5 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 20 Sep 2016 14:18:49 -0700 Subject: [PATCH 080/799] Lock agent access in addDriverWatches Signed-off-by: Alessandro Boch --- agent.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/agent.go b/agent.go index e83ee9f375..837653e499 100644 --- a/agent.go +++ b/agent.go @@ -468,8 +468,12 @@ func (n *network) addDriverWatches() { c := n.getController() for _, tableName := range n.driverTables { - ch, cancel := c.agent.networkDB.Watch(tableName, n.ID(), "") c.Lock() + if c.agent == nil { + c.Unlock() + return + } + ch, cancel := c.agent.networkDB.Watch(tableName, n.ID(), "") c.agent.driverCancelFuncs[n.ID()] = append(c.agent.driverCancelFuncs[n.ID()], cancel) c.Unlock() From ab555e2bc40e39d1e785cc91cfe2952d9cb6a3e2 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 7 Sep 2016 10:10:00 -0700 Subject: [PATCH 081/799] Use complete port configs when plumbing mark rules Currently, a reference counting scheme is used to reference count all individual port configs that need to be plumbed in the ingress to make sure that in situations where a service with the same set of port configs is getting added or removed doesn't accidentally remove the port config plumbing if the add/remove notifications come out of order. This same reference counting scheme is also used for plumbing the port-based marking rules. But marking rules should not be plumbed based on that because marks are always different for different instantiations of the same service. So fixed the code to plumb port-based mark rules based on the complete set of port configs, while plumbing pure port rules and proxies based on a filter set of port configs based on the reference count. Signed-off-by: Jana Radhakrishnan --- service_linux.go | 115 +++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 39 deletions(-) diff --git a/service_linux.go b/service_linux.go index 3fafa9af44..e9d09fe40d 100644 --- a/service_linux.go +++ b/service_linux.go @@ -380,17 +380,17 @@ func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*P } if addService { - var iPorts []*PortConfig + var filteredPorts []*PortConfig if sb.ingress { - iPorts = filterPortConfigs(ingressPorts, false) - if err := programIngress(gwIP, iPorts, false); err != nil { + filteredPorts = filterPortConfigs(ingressPorts, false) + if err := programIngress(gwIP, filteredPorts, false); err != nil { logrus.Errorf("Failed to add ingress: %v", err) return } } - logrus.Debugf("Creating service for vip %s fwMark %d ingressPorts %#v", vip, fwMark, iPorts) - if err := invokeFWMarker(sb.Key(), vip, fwMark, iPorts, eIP, false); err != nil { + logrus.Debugf("Creating service for vip %s fwMark %d ingressPorts %#v", vip, fwMark, ingressPorts) + if err := invokeFWMarker(sb.Key(), vip, fwMark, ingressPorts, filteredPorts, eIP, false); err != nil { logrus.Errorf("Failed to add firewall mark rule in sbox %s: %v", sb.Key(), err) return } @@ -453,15 +453,15 @@ func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po logrus.Errorf("Failed to delete a new service for vip %s fwmark %d: %v", vip, fwMark, err) } - var iPorts []*PortConfig + var filteredPorts []*PortConfig if sb.ingress { - iPorts = filterPortConfigs(ingressPorts, true) - if err := programIngress(gwIP, iPorts, true); err != nil { + filteredPorts = filterPortConfigs(ingressPorts, true) + if err := programIngress(gwIP, filteredPorts, true); err != nil { logrus.Errorf("Failed to delete ingress: %v", err) } } - if err := invokeFWMarker(sb.Key(), vip, fwMark, iPorts, eIP, true); err != nil { + if err := invokeFWMarker(sb.Key(), vip, fwMark, ingressPorts, filteredPorts, eIP, true); err != nil { logrus.Errorf("Failed to add firewall mark rule in sbox %s: %v", sb.Key(), err) } } @@ -715,33 +715,66 @@ func plumbProxy(iPort *PortConfig, isDelete bool) error { return nil } +func writePortsToFile(ports []*PortConfig) (string, error) { + f, err := ioutil.TempFile("", "port_configs") + if err != nil { + return "", err + } + defer f.Close() + + buf, err := proto.Marshal(&EndpointRecord{ + IngressPorts: ports, + }) + + n, err := f.Write(buf) + if err != nil { + return "", err + } + + if n < len(buf) { + return "", io.ErrShortWrite + } + + return f.Name(), nil +} + +func readPortsFromFile(fileName string) ([]*PortConfig, error) { + buf, err := ioutil.ReadFile(fileName) + if err != nil { + return nil, err + } + + var epRec EndpointRecord + err = proto.Unmarshal(buf, &epRec) + if err != nil { + return nil, err + } + + return epRec.IngressPorts, nil +} + // Invoke fwmarker reexec routine to mark vip destined packets with // the passed firewall mark. -func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, isDelete bool) error { - var ingressPortsFile string +func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, filteredPorts []*PortConfig, eIP *net.IPNet, isDelete bool) error { + var ( + ingressPortsFile string + filteredPortsFile string + ) + if len(ingressPorts) != 0 { - f, err := ioutil.TempFile("", "port_configs") + var err error + ingressPortsFile, err = writePortsToFile(ingressPorts) if err != nil { return err } + } - buf, err := proto.Marshal(&EndpointRecord{ - IngressPorts: ingressPorts, - }) - - n, err := f.Write(buf) + if len(filteredPorts) != 0 { + var err error + filteredPortsFile, err = writePortsToFile(filteredPorts) if err != nil { - f.Close() return err } - - if n < len(buf) { - f.Close() - return io.ErrShortWrite - } - - ingressPortsFile = f.Name() - f.Close() } addDelOpt := "-A" @@ -751,7 +784,7 @@ func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*Port cmd := &exec.Cmd{ Path: reexec.Self(), - Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, eIP.String()), + Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, filteredPortsFile, eIP.String()), Stdout: os.Stdout, Stderr: os.Stderr, } @@ -768,27 +801,29 @@ func fwMarker() { runtime.LockOSThread() defer runtime.UnlockOSThread() - if len(os.Args) < 7 { + if len(os.Args) < 8 { logrus.Error("invalid number of arguments..") os.Exit(1) } var ingressPorts []*PortConfig + var filteredPorts []*PortConfig if os.Args[5] != "" { - buf, err := ioutil.ReadFile(os.Args[5]) + var err error + ingressPorts, err = readPortsFromFile(os.Args[5]) if err != nil { - logrus.Errorf("Failed to read ports config file: %v", err) + logrus.Errorf("Failed reading ingress ports file: %v", err) os.Exit(6) } + } - var epRec EndpointRecord - err = proto.Unmarshal(buf, &epRec) + if os.Args[6] != "" { + var err error + filteredPorts, err = readPortsFromFile(os.Args[6]) if err != nil { - logrus.Errorf("Failed to unmarshal ports config data: %v", err) + logrus.Errorf("Failed reading filtered ports file: %v", err) os.Exit(7) } - - ingressPorts = epRec.IngressPorts } vip := os.Args[2] @@ -800,12 +835,14 @@ func fwMarker() { addDelOpt := os.Args[4] rules := [][]string{} - for _, iPort := range ingressPorts { + for _, iPort := range filteredPorts { rule := strings.Fields(fmt.Sprintf("-t nat %s PREROUTING -p %s --dport %d -j REDIRECT --to-port %d", addDelOpt, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, iPort.TargetPort)) rules = append(rules, rule) + } - rule = strings.Fields(fmt.Sprintf("-t mangle %s PREROUTING -p %s --dport %d -j MARK --set-mark %d", + for _, iPort := range ingressPorts { + rule := strings.Fields(fmt.Sprintf("-t mangle %s PREROUTING -p %s --dport %d -j MARK --set-mark %d", addDelOpt, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, fwMark)) rules = append(rules, rule) } @@ -823,9 +860,9 @@ func fwMarker() { } if addDelOpt == "-A" { - eIP, subnet, err := net.ParseCIDR(os.Args[6]) + eIP, subnet, err := net.ParseCIDR(os.Args[7]) if err != nil { - logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[6], err) + logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[7], err) os.Exit(9) } From 752f15e630fab61ef61650074d2bcc9eaa1d27c1 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Wed, 21 Sep 2016 13:38:29 -0700 Subject: [PATCH 082/799] Check for ExecFunc failure Signed-off-by: Santhosh Manohar --- sandbox.go | 12 +++++++----- sandbox_dns_unix.go | 8 ++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/sandbox.go b/sandbox.go index 3bb1bb3644..f5d86ef20e 100644 --- a/sandbox.go +++ b/sandbox.go @@ -421,8 +421,7 @@ func (sb *sandbox) ResolveIP(ip string) string { } func (sb *sandbox) ExecFunc(f func()) error { - sb.osSbox.InvokeFunc(f) - return nil + return sb.osSbox.InvokeFunc(f) } func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP) { @@ -639,9 +638,12 @@ func (sb *sandbox) SetKey(basePath string) error { if oldosSbox != nil && sb.resolver != nil { sb.resolver.Stop() - sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)) - if err := sb.resolver.Start(); err != nil { - log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err) + if err := sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err == nil { + if err := sb.resolver.Start(); err != nil { + log.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) + } + } else { + log.Errorf("Resolver Setup Function failed for container %s, %q", sb.ContainerID(), err) } } diff --git a/sandbox_dns_unix.go b/sandbox_dns_unix.go index 45b035e3e5..3f734511d8 100644 --- a/sandbox_dns_unix.go +++ b/sandbox_dns_unix.go @@ -46,9 +46,13 @@ func (sb *sandbox) startResolver(restore bool) { } sb.resolver.SetExtServers(sb.extDNS) - sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)) + if err = sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err != nil { + log.Errorf("Resolver Setup function failed for container %s, %q", sb.ContainerID(), err) + return + } + if err = sb.resolver.Start(); err != nil { - log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err) + log.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) } }) } From 6d441466098f220057bf0e35751c3f2ebcdcf7ed Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 21 Sep 2016 12:15:14 -0700 Subject: [PATCH 083/799] Delay port redirect until packet reaches container With port redirect in the ingress path happening before ipvs in the ingess sandbox, there is a chance of 5-tuple collision in the ipvs connection table for two entirely different services have different PublishedPorts but the same TargetPort. To disambiguate the ipvs connection table, delay the port redirect from PublishedPort to TargetPort until after the loadbalancing has happened in ipvs. To be specific, perform the redirect after the packet enters the real backend container namespace. Signed-off-by: Jana Radhakrishnan --- service_linux.go | 129 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 34 deletions(-) diff --git a/service_linux.go b/service_linux.go index e9d09fe40d..5e3802a823 100644 --- a/service_linux.go +++ b/service_linux.go @@ -26,6 +26,7 @@ import ( func init() { reexec.Register("fwmarker", fwMarker) + reexec.Register("redirecter", redirecter) } func newService(name string, id string, ingressPorts []*PortConfig, aliases []string) *service { @@ -275,6 +276,12 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) { n := ep.getNetwork() eIP := ep.Iface().Address() + if n.ingress { + if err := addRedirectRules(sb.Key(), eIP, ep.ingressPorts); err != nil { + logrus.Errorf("Failed to add redirect rules for ep %s: %v", ep.Name(), err) + } + } + if sb.ingress { // For the ingress sandbox if this is not gateway // endpoint do nothing. @@ -390,7 +397,7 @@ func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*P } logrus.Debugf("Creating service for vip %s fwMark %d ingressPorts %#v", vip, fwMark, ingressPorts) - if err := invokeFWMarker(sb.Key(), vip, fwMark, ingressPorts, filteredPorts, eIP, false); err != nil { + if err := invokeFWMarker(sb.Key(), vip, fwMark, ingressPorts, eIP, false); err != nil { logrus.Errorf("Failed to add firewall mark rule in sbox %s: %v", sb.Key(), err) return } @@ -461,7 +468,7 @@ func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po } } - if err := invokeFWMarker(sb.Key(), vip, fwMark, ingressPorts, filteredPorts, eIP, true); err != nil { + if err := invokeFWMarker(sb.Key(), vip, fwMark, ingressPorts, eIP, true); err != nil { logrus.Errorf("Failed to add firewall mark rule in sbox %s: %v", sb.Key(), err) } } @@ -755,11 +762,8 @@ func readPortsFromFile(fileName string) ([]*PortConfig, error) { // Invoke fwmarker reexec routine to mark vip destined packets with // the passed firewall mark. -func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, filteredPorts []*PortConfig, eIP *net.IPNet, isDelete bool) error { - var ( - ingressPortsFile string - filteredPortsFile string - ) +func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, isDelete bool) error { + var ingressPortsFile string if len(ingressPorts) != 0 { var err error @@ -767,14 +771,8 @@ func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*Port if err != nil { return err } - } - if len(filteredPorts) != 0 { - var err error - filteredPortsFile, err = writePortsToFile(filteredPorts) - if err != nil { - return err - } + defer os.Remove(ingressPortsFile) } addDelOpt := "-A" @@ -784,7 +782,7 @@ func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*Port cmd := &exec.Cmd{ Path: reexec.Self(), - Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, filteredPortsFile, eIP.String()), + Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, eIP.String()), Stdout: os.Stdout, Stderr: os.Stderr, } @@ -801,13 +799,12 @@ func fwMarker() { runtime.LockOSThread() defer runtime.UnlockOSThread() - if len(os.Args) < 8 { + if len(os.Args) < 7 { logrus.Error("invalid number of arguments..") os.Exit(1) } var ingressPorts []*PortConfig - var filteredPorts []*PortConfig if os.Args[5] != "" { var err error ingressPorts, err = readPortsFromFile(os.Args[5]) @@ -817,15 +814,6 @@ func fwMarker() { } } - if os.Args[6] != "" { - var err error - filteredPorts, err = readPortsFromFile(os.Args[6]) - if err != nil { - logrus.Errorf("Failed reading filtered ports file: %v", err) - os.Exit(7) - } - } - vip := os.Args[2] fwMark, err := strconv.ParseUint(os.Args[3], 10, 32) if err != nil { @@ -835,12 +823,6 @@ func fwMarker() { addDelOpt := os.Args[4] rules := [][]string{} - for _, iPort := range filteredPorts { - rule := strings.Fields(fmt.Sprintf("-t nat %s PREROUTING -p %s --dport %d -j REDIRECT --to-port %d", - addDelOpt, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, iPort.TargetPort)) - rules = append(rules, rule) - } - for _, iPort := range ingressPorts { rule := strings.Fields(fmt.Sprintf("-t mangle %s PREROUTING -p %s --dport %d -j MARK --set-mark %d", addDelOpt, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, fwMark)) @@ -860,9 +842,9 @@ func fwMarker() { } if addDelOpt == "-A" { - eIP, subnet, err := net.ParseCIDR(os.Args[7]) + eIP, subnet, err := net.ParseCIDR(os.Args[6]) if err != nil { - logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[7], err) + logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[6], err) os.Exit(9) } @@ -889,3 +871,82 @@ func fwMarker() { } } } + +func addRedirectRules(path string, eIP *net.IPNet, ingressPorts []*PortConfig) error { + var ingressPortsFile string + + if len(ingressPorts) != 0 { + var err error + ingressPortsFile, err = writePortsToFile(ingressPorts) + if err != nil { + return err + } + defer os.Remove(ingressPortsFile) + } + + cmd := &exec.Cmd{ + Path: reexec.Self(), + Args: append([]string{"redirecter"}, path, eIP.String(), ingressPortsFile), + Stdout: os.Stdout, + Stderr: os.Stderr, + } + + if err := cmd.Run(); err != nil { + return fmt.Errorf("reexec failed: %v", err) + } + + return nil +} + +// Redirecter reexec function. +func redirecter() { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if len(os.Args) < 4 { + logrus.Error("invalid number of arguments..") + os.Exit(1) + } + + var ingressPorts []*PortConfig + if os.Args[3] != "" { + var err error + ingressPorts, err = readPortsFromFile(os.Args[3]) + if err != nil { + logrus.Errorf("Failed reading ingress ports file: %v", err) + os.Exit(2) + } + } + + eIP, _, err := net.ParseCIDR(os.Args[2]) + if err != nil { + logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[2], err) + os.Exit(3) + } + + rules := [][]string{} + for _, iPort := range ingressPorts { + rule := strings.Fields(fmt.Sprintf("-t nat -A PREROUTING -d %s -p %s --dport %d -j REDIRECT --to-port %d", + eIP.String(), strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, iPort.TargetPort)) + rules = append(rules, rule) + } + + ns, err := netns.GetFromPath(os.Args[1]) + if err != nil { + logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err) + os.Exit(4) + } + defer ns.Close() + + if err := netns.Set(ns); err != nil { + logrus.Errorf("setting into container net ns %v failed, %v", os.Args[1], err) + os.Exit(5) + } + + for _, rule := range rules { + if err := iptables.RawCombinedOutputNative(rule...); err != nil { + logrus.Errorf("setting up rule failed, %v: %v", rule, err) + os.Exit(5) + } + } +} From 8b04ffb31a4828a357f511a095f82292102f8ebe Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Thu, 22 Sep 2016 11:38:35 -0700 Subject: [PATCH 084/799] Honor user provided listen address for gossip If user provided a non-zero listen address, honor that and bind only to that address. Right now it is not honored and we always bind to all ip addresses in the host. Signed-off-by: Jana Radhakrishnan --- agent.go | 9 ++++++--- cluster/provider.go | 1 + cmd/dnet/dnet.go | 4 ++++ networkdb/cluster.go | 1 + networkdb/networkdb.go | 4 ++++ 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/agent.go b/agent.go index 837653e499..fb0c342257 100644 --- a/agent.go +++ b/agent.go @@ -172,10 +172,12 @@ func (c *controller) agentSetup() error { advAddr := clusterProvider.GetAdvertiseAddress() remote := clusterProvider.GetRemoteAddress() remoteAddr, _, _ := net.SplitHostPort(remote) + listen := clusterProvider.GetListenAddress() + listenAddr, _, _ := net.SplitHostPort(listen) - logrus.Infof("Initializing Libnetwork Agent Local-addr=%s Adv-addr=%s Remote-addr =%s", bindAddr, advAddr, remoteAddr) + logrus.Infof("Initializing Libnetwork Agent Listen-Addr=%s Local-addr=%s Adv-addr=%s Remote-addr =%s", listenAddr, bindAddr, advAddr, remoteAddr) if advAddr != "" && c.agent == nil { - if err := c.agentInit(bindAddr, advAddr); err != nil { + if err := c.agentInit(listenAddr, bindAddr, advAddr); err != nil { logrus.Errorf("Error in agentInit : %v", err) } else { c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { @@ -236,7 +238,7 @@ func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64, error) { return keys[1].Key, keys[1].LamportTime, nil } -func (c *controller) agentInit(bindAddrOrInterface, advertiseAddr string) error { +func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr string) error { if !c.isAgent() { return nil } @@ -252,6 +254,7 @@ func (c *controller) agentInit(bindAddrOrInterface, advertiseAddr string) error logrus.Info("Gossip cluster hostname ", nodeName) nDB, err := networkdb.New(&networkdb.Config{ + BindAddr: listenAddr, AdvertiseAddr: advertiseAddr, NodeName: nodeName, Keys: keys, diff --git a/cluster/provider.go b/cluster/provider.go index 7bbf5d3557..572bac85a6 100644 --- a/cluster/provider.go +++ b/cluster/provider.go @@ -10,6 +10,7 @@ type Provider interface { IsManager() bool IsAgent() bool GetLocalAddress() string + GetListenAddress() string GetAdvertiseAddress() string GetRemoteAddress() string ListenClusterEvents() <-chan struct{} diff --git a/cmd/dnet/dnet.go b/cmd/dnet/dnet.go index 8d88eecc94..2df69d5115 100644 --- a/cmd/dnet/dnet.go +++ b/cmd/dnet/dnet.go @@ -316,6 +316,10 @@ func (d *dnetConnection) GetLocalAddress() string { return d.Orchestration.Bind } +func (d *dnetConnection) GetListenAddress() string { + return d.Orchestration.Bind +} + func (d *dnetConnection) GetRemoteAddress() string { return d.Orchestration.Peer } diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 0a21cae5ae..ed24e4c7a6 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -86,6 +86,7 @@ func (nDB *NetworkDB) RemoveKey(key []byte) { func (nDB *NetworkDB) clusterInit() error { config := memberlist.DefaultLANConfig() config.Name = nDB.config.NodeName + config.BindAddr = nDB.config.BindAddr config.AdvertiseAddr = nDB.config.AdvertiseAddr if nDB.config.BindPort != 0 { diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index c452a90835..1502d7300e 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -121,6 +121,10 @@ type Config struct { // NodeName is the cluster wide unique name for this node. NodeName string + // BindAddr is the IP on which networkdb listens. It can be + // 0.0.0.0 to listen on all addresses on the host. + BindAddr string + // AdvertiseAddr is the node's IP address that we advertise for // cluster communication. AdvertiseAddr string From 37027b4de81b35ef362d1ff92a69fba62e451c74 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 20 Sep 2016 18:09:12 +0000 Subject: [PATCH 085/799] Fix test failures * TestwriteJSON and TestontainerInvalidLeave were never executed due to the typos. Recent govet found them. * TestWriteJSON was failing due to the comparison between string and []byte. Also, it didn't considered that json.Encode appends LF. * TestContainerInvalidLeave was faling due to a typo Signed-off-by: Akihiro Suda --- api/api_test.go | 16 +++++++++++----- libnetwork_test.go | 8 ++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/api/api_test.go b/api/api_test.go index c944cc0ff7..b1241188aa 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -1667,9 +1667,8 @@ func (f *localResponseWriter) WriteHeader(c int) { f.statusCode = c } -func TestwriteJSON(t *testing.T) { - testCode := 55 - testData, err := json.Marshal("test data") +func testWriteJSON(t *testing.T, testCode int, testData interface{}) { + testDataMarshalled, err := json.Marshal(testData) if err != nil { t.Fatal(err) } @@ -1679,10 +1678,17 @@ func TestwriteJSON(t *testing.T) { if rsp.statusCode != testCode { t.Fatalf("writeJSON() failed to set the status code. Expected %d. Got %d", testCode, rsp.statusCode) } - if !bytes.Equal(testData, rsp.body) { - t.Fatalf("writeJSON() failed to set the body. Expected %s. Got %s", testData, rsp.body) + // writeJSON calls json.Encode and it appends '\n' to the result, + // while json.Marshal not + expected := append(testDataMarshalled, byte('\n')) + if !bytes.Equal(expected, rsp.body) { + t.Fatalf("writeJSON() failed to set the body. Expected %q. Got %q", expected, rsp.body) } +} +func TestWriteJSON(t *testing.T) { + testWriteJSON(t, 55, "test data as string") + testWriteJSON(t, 55, []byte("test data as bytes")) } func TestHttpHandlerUninit(t *testing.T) { diff --git a/libnetwork_test.go b/libnetwork_test.go index eb09a1673f..0894423474 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -1545,7 +1545,7 @@ func TestLeaveAll(t *testing.T) { } } -func TestontainerInvalidLeave(t *testing.T) { +func TestContainerInvalidLeave(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() } @@ -1595,11 +1595,11 @@ func TestontainerInvalidLeave(t *testing.T) { t.Fatalf("Failed with unexpected error type: %T. Desc: %s", err, err.Error()) } - if err := ep.Leave(nil); err == nil { + if err = ep.Leave(nil); err == nil { t.Fatalf("Expected to fail leave nil Sandbox") } if _, ok := err.(types.BadRequestError); !ok { - t.Fatalf("Unexpected error type returned: %T", err) + t.Fatalf("Unexpected error type returned: %T. Desc: %s", err, err.Error()) } fsbx := &fakeSandbox{} @@ -1607,7 +1607,7 @@ func TestontainerInvalidLeave(t *testing.T) { t.Fatalf("Expected to fail leave with invalid Sandbox") } if _, ok := err.(types.BadRequestError); !ok { - t.Fatalf("Unexpected error type returned: %T", err) + t.Fatalf("Unexpected error type returned: %T. Desc: %s", err, err.Error()) } } From 80690d7f581ff6f9fe5c0e5a912228d8a6bcf595 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Thu, 22 Sep 2016 17:50:19 -0700 Subject: [PATCH 086/799] Serialize overlay filter plumbing When plumbing overlay filter rules serialize this to make sure that multiple sandbox join or leave is not causing erroneous behavior while moving the RETURN rule in the predefined chains. Signed-off-by: Jana Radhakrishnan --- drivers/overlay/filter.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/overlay/filter.go b/drivers/overlay/filter.go index 2bf76b33a5..40cd7d9f28 100644 --- a/drivers/overlay/filter.go +++ b/drivers/overlay/filter.go @@ -12,6 +12,13 @@ const globalChain = "DOCKER-OVERLAY" var filterOnce sync.Once +var filterChan = make(chan struct{}, 1) + +func filterWait() func() { + filterChan <- struct{}{} + return func() { <-filterChan } +} + func chainExists(cname string) bool { if _, err := iptables.Raw("-L", cname); err != nil { return false @@ -69,10 +76,14 @@ func setNetworkChain(cname string, remove bool) error { } func addNetworkChain(cname string) error { + defer filterWait()() + return setNetworkChain(cname, false) } func removeNetworkChain(cname string) error { + defer filterWait()() + return setNetworkChain(cname, true) } @@ -119,9 +130,13 @@ func setFilters(cname, brName string, remove bool) error { } func addFilters(cname, brName string) error { + defer filterWait()() + return setFilters(cname, brName, false) } func removeFilters(cname, brName string) error { + defer filterWait()() + return setFilters(cname, brName, true) } From 80f00a000d01f3caaf465ee3c99499f2873281af Mon Sep 17 00:00:00 2001 From: ronyweng Date: Fri, 23 Sep 2016 18:51:16 +0800 Subject: [PATCH 087/799] Fix macvlan private mode argument vaildation Signed-off-by: Rony Weng --- drivers/macvlan/macvlan_network.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/macvlan/macvlan_network.go b/drivers/macvlan/macvlan_network.go index 071fe349f3..2975596593 100644 --- a/drivers/macvlan/macvlan_network.go +++ b/drivers/macvlan/macvlan_network.go @@ -44,8 +44,8 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo case "", modeBridge: // default to macvlan bridge mode if -o macvlan_mode is empty config.MacvlanMode = modeBridge - case modeOpt: - config.MacvlanMode = modeOpt + case modePrivate: + config.MacvlanMode = modePrivate case modePassthru: config.MacvlanMode = modePassthru case modeVepa: From 5c7cb2823e70b1dcd20d02c810fcd177591b22a2 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Fri, 23 Sep 2016 05:19:07 -0700 Subject: [PATCH 088/799] Allow the memberlist shutdown even if networkdb leave fails Signed-off-by: Madhu Venugopal --- networkdb/cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index ed24e4c7a6..9d9ea163d6 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -190,7 +190,7 @@ func (nDB *NetworkDB) clusterLeave() error { mlist := nDB.memberlist if err := nDB.sendNodeEvent(NodeEventTypeLeave); err != nil { - return fmt.Errorf("failed to send node leave: %v", err) + logrus.Errorf("failed to send node leave: %v", err) } if err := mlist.Leave(time.Second); err != nil { From 520a4c52b8d1702afcff648be1aecb22104b1d33 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Fri, 23 Sep 2016 14:42:17 -0700 Subject: [PATCH 089/799] Purge stale nodes with same prefix and IP Since the node name randomization fix, we need to make sure that we purge the old node with the same prefix and same IP from the nodes database if it still present. This causes unnecessary reconnect attempts. Also added a change to avoid unnecessary update of local lamport time and only do it of we are ready to do a push pull on a join. Join should happen only when the node is bootstrapped or when trying to reconnect with a failed node. Signed-off-by: Jana Radhakrishnan --- networkdb/cluster.go | 14 +++++++------- networkdb/delegate.go | 44 +++++++++++++++++++++++++++++++++--------- networkdb/networkdb.go | 9 +++++++-- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 9d9ea163d6..3b624c9a27 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -237,13 +237,6 @@ func (nDB *NetworkDB) reconnectNode() { } nDB.RUnlock() - // Update all the local state to a new time to force update on - // the node we are trying to rejoin, just in case that node - // has these in leaving/deleting state still. This is - // facilitate fast convergence after recovering from a gossip - // failure. - nDB.updateLocalStateTime() - node := nodes[randomOffset(len(nodes))] addr := net.UDPAddr{IP: node.Addr, Port: int(node.Port)} @@ -256,6 +249,13 @@ func (nDB *NetworkDB) reconnectNode() { return } + // Update all the local table state to a new time to + // force update on the node we are trying to rejoin, just in + // case that node has these in deleting state still. This is + // facilitate fast convergence after recovering from a gossip + // failure. + nDB.updateLocalTableTime() + logrus.Debugf("Initiating bulk sync with node %s after reconnect", node.Name) nDB.bulkSync([]string{node.Name}, true) } diff --git a/networkdb/delegate.go b/networkdb/delegate.go index 3e96384465..eb8d18557d 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -3,6 +3,7 @@ package networkdb import ( "fmt" "net" + "strings" "time" "github.com/Sirupsen/logrus" @@ -31,7 +32,7 @@ func (nDB *NetworkDB) checkAndGetNode(nEvent *NodeEvent) *node { return nil } - delete(nDB.failedNodes, n.Name) + delete(nodes, n.Name) return n } } @@ -39,16 +40,36 @@ func (nDB *NetworkDB) checkAndGetNode(nEvent *NodeEvent) *node { return nil } -func (nDB *NetworkDB) handleNodeEvent(nEvent *NodeEvent) bool { - // Update our local clock if the received messages has newer - // time. - nDB.networkClock.Witness(nEvent.LTime) +func (nDB *NetworkDB) purgeSameNode(n *node) { + nDB.Lock() + defer nDB.Unlock() + prefix := strings.Split(n.Name, "-")[0] + for _, nodes := range []map[string]*node{ + nDB.failedNodes, + nDB.leftNodes, + nDB.nodes, + } { + var nodeNames []string + for name, node := range nodes { + if strings.HasPrefix(name, prefix) && n.Addr.Equal(node.Addr) { + nodeNames = append(nodeNames, name) + } + } + + for _, name := range nodeNames { + delete(nodes, name) + } + } +} + +func (nDB *NetworkDB) handleNodeEvent(nEvent *NodeEvent) bool { n := nDB.checkAndGetNode(nEvent) if n == nil { return false } + nDB.purgeSameNode(n) n.ltime = nEvent.LTime switch nEvent.Type { @@ -357,6 +378,15 @@ func (d *delegate) GetBroadcasts(overhead, limit int) [][]byte { } func (d *delegate) LocalState(join bool) []byte { + if join { + // Update all the local node/network state to a new time to + // force update on the node we are trying to rejoin, just in + // case that node has these in leaving state still. This is + // facilitate fast convergence after recovering from a gossip + // failure. + d.nDB.updateLocalNetworkTime() + } + d.nDB.RLock() defer d.nDB.RUnlock() @@ -408,10 +438,6 @@ func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) { return } - if pp.LTime > 0 { - d.nDB.networkClock.Witness(pp.LTime) - } - nodeEvent := &NodeEvent{ LTime: pp.LTime, NodeName: pp.NodeName, diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 1502d7300e..a8c942c9cc 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -524,7 +524,7 @@ func (nDB *NetworkDB) findCommonNetworks(nodeName string) []string { return networks } -func (nDB *NetworkDB) updateLocalStateTime() { +func (nDB *NetworkDB) updateLocalNetworkTime() { nDB.Lock() defer nDB.Unlock() @@ -532,8 +532,13 @@ func (nDB *NetworkDB) updateLocalStateTime() { for _, n := range nDB.networks[nDB.config.NodeName] { n.ltime = ltime } +} + +func (nDB *NetworkDB) updateLocalTableTime() { + nDB.Lock() + defer nDB.Unlock() - ltime = nDB.tableClock.Increment() + ltime := nDB.tableClock.Increment() nDB.indexes[byTable].Walk(func(path string, v interface{}) bool { entry := v.(*entry) if entry.node != nDB.config.NodeName { From d43e87ed3c50f07e0fedcd928c0d947d684ff9be Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Sun, 25 Sep 2016 17:43:27 +0200 Subject: [PATCH 090/799] bridge,portmapper: custom docker-proxy path Signed-off-by: Antonio Murdaca --- drivers/bridge/bridge.go | 3 ++- drivers/bridge/setup_ip_tables_test.go | 2 +- portmapper/mapper.go | 13 ++++++++----- portmapper/mapper_test.go | 12 ++++++------ portmapper/mock_proxy.go | 2 +- portmapper/proxy.go | 17 ++++++++++------- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index 0b93eb60b0..777f7b162e 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -50,6 +50,7 @@ type configuration struct { EnableIPForwarding bool EnableIPTables bool EnableUserlandProxy bool + UserlandProxyPath string } // networkConfiguration for network specific configuration @@ -638,7 +639,7 @@ func (d *driver) createNetwork(config *networkConfiguration) error { id: config.ID, endpoints: make(map[string]*bridgeEndpoint), config: config, - portMapper: portmapper.New(), + portMapper: portmapper.New(d.config.UserlandProxyPath), driver: d, } diff --git a/drivers/bridge/setup_ip_tables_test.go b/drivers/bridge/setup_ip_tables_test.go index 20c70734ae..edfb2907fc 100644 --- a/drivers/bridge/setup_ip_tables_test.go +++ b/drivers/bridge/setup_ip_tables_test.go @@ -124,7 +124,7 @@ func assertChainConfig(d *driver, t *testing.T) { // Assert function which pushes chains based on bridge config parameters. func assertBridgeConfig(config *networkConfiguration, br *bridgeInterface, d *driver, t *testing.T) { - nw := bridgeNetwork{portMapper: portmapper.New(), + nw := bridgeNetwork{portMapper: portmapper.New(""), config: config} nw.driver = d diff --git a/portmapper/mapper.go b/portmapper/mapper.go index 6a1bb08ffb..7f2a67c89f 100644 --- a/portmapper/mapper.go +++ b/portmapper/mapper.go @@ -38,19 +38,22 @@ type PortMapper struct { currentMappings map[string]*mapping lock sync.Mutex + proxyPath string + Allocator *portallocator.PortAllocator } // New returns a new instance of PortMapper -func New() *PortMapper { - return NewWithPortAllocator(portallocator.Get()) +func New(proxyPath string) *PortMapper { + return NewWithPortAllocator(portallocator.Get(), proxyPath) } // NewWithPortAllocator returns a new instance of PortMapper which will use the specified PortAllocator -func NewWithPortAllocator(allocator *portallocator.PortAllocator) *PortMapper { +func NewWithPortAllocator(allocator *portallocator.PortAllocator, proxyPath string) *PortMapper { return &PortMapper{ currentMappings: make(map[string]*mapping), Allocator: allocator, + proxyPath: proxyPath, } } @@ -90,7 +93,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart, } if useProxy { - m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port) + m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port, pm.proxyPath) if err != nil { return nil, err } @@ -110,7 +113,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart, } if useProxy { - m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port) + m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port, pm.proxyPath) if err != nil { return nil, err } diff --git a/portmapper/mapper_test.go b/portmapper/mapper_test.go index 510a4291dc..7c93f8c8e8 100644 --- a/portmapper/mapper_test.go +++ b/portmapper/mapper_test.go @@ -15,7 +15,7 @@ func init() { } func TestSetIptablesChain(t *testing.T) { - pm := New() + pm := New("") c := &iptables.ChainInfo{ Name: "TEST", @@ -32,7 +32,7 @@ func TestSetIptablesChain(t *testing.T) { } func TestMapTCPPorts(t *testing.T) { - pm := New() + pm := New("") dstIP1 := net.ParseIP("192.168.0.1") dstIP2 := net.ParseIP("192.168.0.2") dstAddr1 := &net.TCPAddr{IP: dstIP1, Port: 80} @@ -111,7 +111,7 @@ func TestGetUDPIPAndPort(t *testing.T) { } func TestMapUDPPorts(t *testing.T) { - pm := New() + pm := New("") dstIP1 := net.ParseIP("192.168.0.1") dstIP2 := net.ParseIP("192.168.0.2") dstAddr1 := &net.UDPAddr{IP: dstIP1, Port: 80} @@ -157,7 +157,7 @@ func TestMapUDPPorts(t *testing.T) { } func TestMapAllPortsSingleInterface(t *testing.T) { - pm := New() + pm := New("") dstIP1 := net.ParseIP("0.0.0.0") srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")} @@ -196,7 +196,7 @@ func TestMapAllPortsSingleInterface(t *testing.T) { } func TestMapTCPDummyListen(t *testing.T) { - pm := New() + pm := New("") dstIP := net.ParseIP("0.0.0.0") dstAddr := &net.TCPAddr{IP: dstIP, Port: 80} @@ -233,7 +233,7 @@ func TestMapTCPDummyListen(t *testing.T) { } func TestMapUDPDummyListen(t *testing.T) { - pm := New() + pm := New("") dstIP := net.ParseIP("0.0.0.0") dstAddr := &net.UDPAddr{IP: dstIP, Port: 80} diff --git a/portmapper/mock_proxy.go b/portmapper/mock_proxy.go index 587026f9ce..ceb7b02926 100644 --- a/portmapper/mock_proxy.go +++ b/portmapper/mock_proxy.go @@ -2,7 +2,7 @@ package portmapper import "net" -func newMockProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) (userlandProxy, error) { +func newMockProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, userlandProxyPath string) (userlandProxy, error) { return &mockProxyCommand{}, nil } diff --git a/portmapper/proxy.go b/portmapper/proxy.go index 25a341a98f..6a4adbb872 100644 --- a/portmapper/proxy.go +++ b/portmapper/proxy.go @@ -25,15 +25,18 @@ type proxyCommand struct { cmd *exec.Cmd } -func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) (userlandProxy, error) { - cmd, err := exec.LookPath(userlandProxyCommandName) - - if err != nil { - return nil, err +func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) { + path := proxyPath + if proxyPath == "" { + cmd, err := exec.LookPath(userlandProxyCommandName) + if err != nil { + return nil, err + } + path = cmd } args := []string{ - cmd, + path, "-proto", proto, "-host-ip", hostIP.String(), "-host-port", strconv.Itoa(hostPort), @@ -43,7 +46,7 @@ func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net. return &proxyCommand{ cmd: &exec.Cmd{ - Path: cmd, + Path: path, Args: args, SysProcAttr: &syscall.SysProcAttr{ Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies From 23a782bb92d5b62990ee1b0fc3f5b47a94d609ce Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Tue, 27 Sep 2016 00:12:07 -0700 Subject: [PATCH 091/799] Avoid returning early on agent join failures When a gossip join failure happens do not return early in the call chain because a join failure is most likely transient and the retry logic built in the networkdb is going to retry and succeed. Returning early makes the initialization of ingress network/sandbox to not happen which causes a problem even after the gossip join on retry is successful. Signed-off-by: Jana Radhakrishnan --- agent.go | 3 +-- networkdb/cluster.go | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/agent.go b/agent.go index fb0c342257..4c8980b2e1 100644 --- a/agent.go +++ b/agent.go @@ -191,8 +191,7 @@ func (c *controller) agentSetup() error { if remoteAddr != "" { if err := c.agentJoin(remoteAddr); err != nil { - logrus.Errorf("Error in agentJoin : %v", err) - return nil + logrus.Errorf("Error in joining gossip cluster : %v(join will be retried in background)", err) } } diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 3b624c9a27..c3bfdd4051 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -161,6 +161,10 @@ func (nDB *NetworkDB) retryJoin(members []string, stop <-chan struct{}) { logrus.Errorf("Failed to join memberlist %s on retry: %v", members, err) continue } + if err := nDB.sendNodeEvent(NodeEventTypeJoin); err != nil { + logrus.Errorf("failed to send node join on retry: %v", err) + continue + } return case <-stop: return From 25df2211be76870da004d1a2d649ee22e76a9416 Mon Sep 17 00:00:00 2001 From: Anusha Ragunathan Date: Tue, 27 Sep 2016 13:53:58 -0700 Subject: [PATCH 092/799] Godep changes. Signed-off-by: Anusha Ragunathan --- Godeps/Godeps.json | 110 ++--- .../github.com/Microsoft/go-winio/.gitignore | 1 + .../github.com/Microsoft/go-winio/README.md | 15 +- .../docker/docker/pkg/ioutils/fswriters.go | 80 ++++ .../docker/docker/pkg/plugins/plugins.go | 4 +- .../docker/docker/pkg/signal/signal_unix.go | 2 +- .../docker/pkg/signal/signal_windows.go | 2 +- .../docker/docker/pkg/symlink/fs.go | 7 +- .../docker/docker/pkg/symlink/fs_unix.go | 4 + .../docker/docker/pkg/symlink/fs_windows.go | 14 + .../docker/docker/pkg/term/term_windows.go | 1 + .../docker/docker/plugin/getter/interface.go | 26 ++ .../golang.org/x/sys/windows/registry/key.go | 178 -------- .../x/sys/windows/registry/syscall.go | 33 -- .../x/sys/windows/registry/value.go | 384 ------------------ .../sys/windows/registry/zsyscall_windows.go | 82 ---- .../golang.org/x/sys/windows/svc/debug/log.go | 56 --- .../x/sys/windows/svc/debug/service.go | 45 -- .../src/golang.org/x/sys/windows/svc/event.go | 48 --- .../x/sys/windows/svc/eventlog/install.go | 80 ---- .../x/sys/windows/svc/eventlog/log.go | 70 ---- .../x/sys/windows/svc/example/beep.go | 22 - .../x/sys/windows/svc/example/install.go | 92 ----- .../x/sys/windows/svc/example/main.go | 76 ---- .../x/sys/windows/svc/example/manage.go | 62 --- .../x/sys/windows/svc/example/service.go | 82 ---- .../src/golang.org/x/sys/windows/svc/go12.c | 24 -- .../src/golang.org/x/sys/windows/svc/go12.go | 11 - .../src/golang.org/x/sys/windows/svc/go13.go | 31 -- .../x/sys/windows/svc/mgr/config.go | 139 ------- .../golang.org/x/sys/windows/svc/mgr/mgr.go | 119 ------ .../x/sys/windows/svc/mgr/service.go | 74 ---- .../golang.org/x/sys/windows/svc/security.go | 62 --- .../golang.org/x/sys/windows/svc/service.go | 316 -------------- .../golang.org/x/sys/windows/svc/sys_386.s | 67 --- .../golang.org/x/sys/windows/svc/sys_amd64.s | 41 -- .../src/golang.org/x/sys/windows/syscall.go | 2 +- 37 files changed, 205 insertions(+), 2257 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/Microsoft/go-winio/.gitignore create mode 100644 Godeps/_workspace/src/github.com/docker/docker/plugin/getter/interface.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/registry/key.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/registry/syscall.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/registry/value.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/registry/zsyscall_windows.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/log.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/service.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/event.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/install.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/log.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/beep.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/install.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/main.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/manage.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/service.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.c delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/go13.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/config.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/mgr.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/service.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/security.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/service.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_386.s delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_amd64.s diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index de85ed333b..57b67187ab 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,7 @@ { "ImportPath": "github.com/docker/libnetwork", "GoVersion": "go1.5", + "GodepVersion": "v74", "Packages": [ "./..." ], @@ -20,10 +21,12 @@ }, { "ImportPath": "github.com/Microsoft/go-winio", + "Comment": "v0.3.5-2-gce2922f", "Rev": "ce2922f643c8fd76b46cadc7f404a06282678b34" }, { "ImportPath": "github.com/Microsoft/hcsshim", + "Comment": "v0.4.3", "Rev": "6611816fb4c1693b429ada0f358102119a0b1466" }, { @@ -81,113 +84,118 @@ }, { "ImportPath": "github.com/docker/docker/api/types/filters", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/api/types/network", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/api/types/versions", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/opts", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/discovery", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/discovery/kv", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/homedir", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/ioutils", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/locker", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/longpath", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/mount", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/parsers/kernel", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/plugins", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/plugins/transport", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/random", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/reexec", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/signal", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/stringid", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/symlink", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/system", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/term", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/docker/pkg/term/windows", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1316-g426a0af", - "Rev": "426a0af0759798d8e3332b38236ee40df6d14798" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + }, + { + "ImportPath": "github.com/docker/docker/plugin/getter", + "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", + "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" }, { "ImportPath": "github.com/docker/go-connections/sockets", @@ -210,32 +218,32 @@ }, { "ImportPath": "github.com/docker/libkv", - "Comment": "v0.1.0-35-g7283ef2", + "Comment": "v0.2.0-1-g7283ef2", "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" }, { "ImportPath": "github.com/docker/libkv/store", - "Comment": "v0.1.0-35-g7283ef2", + "Comment": "v0.2.0-1-g7283ef2", "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" }, { "ImportPath": "github.com/docker/libkv/store/boltdb", - "Comment": "v0.1.0-35-g7283ef2", + "Comment": "v0.2.0-1-g7283ef2", "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" }, { "ImportPath": "github.com/docker/libkv/store/consul", - "Comment": "v0.1.0-35-g7283ef2", + "Comment": "v0.2.0-1-g7283ef2", "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" }, { "ImportPath": "github.com/docker/libkv/store/etcd", - "Comment": "v0.1.0-35-g7283ef2", + "Comment": "v0.2.0-1-g7283ef2", "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" }, { "ImportPath": "github.com/docker/libkv/store/zookeeper", - "Comment": "v0.1.0-35-g7283ef2", + "Comment": "v0.2.0-1-g7283ef2", "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" }, { @@ -432,6 +440,6 @@ { "ImportPath": "golang.org/x/sys/windows", "Rev": "5eaf0df67e70d6997a9fe0ed24383fa1b01638d3" - } + } ] } diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/.gitignore b/Godeps/_workspace/src/github.com/Microsoft/go-winio/.gitignore new file mode 100644 index 0000000000..b883f1fdc6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Microsoft/go-winio/.gitignore @@ -0,0 +1 @@ +*.exe diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md b/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md index 478862a8b9..5680010575 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md +++ b/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md @@ -1,15 +1,22 @@ # go-winio -This repository contains utilities for efficiently performing Win32 IO operations in +This repository contains utilities for efficiently performing Win32 IO operations in Go. Currently, this is focused on accessing named pipes and other file handles, and for using named pipes as a net transport. -This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go -to reuse the thread to schedule another goroutine. This limits support to Windows Vista and +This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go +to reuse the thread to schedule another goroutine. This limits support to Windows Vista and newer operating systems. This is similar to the implementation of network sockets in Go's net package. Please see the LICENSE file for licensing information. -Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe +This project has adopted the [Microsoft Open Source Code of +Conduct](https://opensource.microsoft.com/codeofconduct/). For more information +see the [Code of Conduct +FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact +[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional +questions or comments. + +Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe for another named pipe implementation. diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go index 6dc50a03dc..a56c462651 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fswriters.go @@ -80,3 +80,83 @@ func (w *atomicFileWriter) Close() (retErr error) { } return nil } + +// AtomicWriteSet is used to atomically write a set +// of files and ensure they are visible at the same time. +// Must be committed to a new directory. +type AtomicWriteSet struct { + root string +} + +// NewAtomicWriteSet creates a new atomic write set to +// atomically create a set of files. The given directory +// is used as the base directory for storing files before +// commit. If no temporary directory is given the system +// default is used. +func NewAtomicWriteSet(tmpDir string) (*AtomicWriteSet, error) { + td, err := ioutil.TempDir(tmpDir, "write-set-") + if err != nil { + return nil, err + } + + return &AtomicWriteSet{ + root: td, + }, nil +} + +// WriteFile writes a file to the set, guaranteeing the file +// has been synced. +func (ws *AtomicWriteSet) WriteFile(filename string, data []byte, perm os.FileMode) error { + f, err := ws.FileWriter(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil { + return err + } + n, err := f.Write(data) + if err == nil && n < len(data) { + err = io.ErrShortWrite + } + if err1 := f.Close(); err == nil { + err = err1 + } + return err +} + +type syncFileCloser struct { + *os.File +} + +func (w syncFileCloser) Close() error { + err := w.File.Sync() + if err1 := w.File.Close(); err == nil { + err = err1 + } + return err +} + +// FileWriter opens a file writer inside the set. The file +// should be synced and closed before calling commit. +func (ws *AtomicWriteSet) FileWriter(name string, flag int, perm os.FileMode) (io.WriteCloser, error) { + f, err := os.OpenFile(filepath.Join(ws.root, name), flag, perm) + if err != nil { + return nil, err + } + return syncFileCloser{f}, nil +} + +// Cancel cancels the set and removes all temporary data +// created in the set. +func (ws *AtomicWriteSet) Cancel() error { + return os.RemoveAll(ws.root) +} + +// Commit moves all created files to the target directory. The +// target directory must not exist and the parent of the target +// directory must exist. +func (ws *AtomicWriteSet) Commit(target string) error { + return os.Rename(ws.root, target) +} + +// String returns the location the set is writing to. +func (ws *AtomicWriteSet) String() string { + return ws.root +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go index debcd087c9..9385b9b1bc 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go @@ -83,8 +83,8 @@ func (p *Plugin) Client() *Client { return p.client } -// IsLegacy returns true for legacy plugins and false otherwise. -func (p *Plugin) IsLegacy() bool { +// IsV1 returns true for V1 plugins and false otherwise. +func (p *Plugin) IsV1() bool { return true } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_unix.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_unix.go index 6621d37184..5d058fd56b 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_unix.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_unix.go @@ -6,7 +6,7 @@ import ( "syscall" ) -// Signals used in api/client (no windows equivalent, use +// Signals used in cli/command (no windows equivalent, use // invalid signals so they don't get handled) const ( diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_windows.go index 698cbf2dc8..440f2700e2 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/signal_windows.go @@ -6,7 +6,7 @@ import ( "syscall" ) -// Signals used in api/client (no windows equivalent, use +// Signals used in cli/command (no windows equivalent, use // invalid signals so they don't get handled) const ( SIGCHLD = syscall.Signal(0xff) diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs.go index dcf707f426..f6bc2231f6 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs.go @@ -95,8 +95,8 @@ func evalSymlinksInScope(path, root string) (string, error) { // root gets prepended and we Clean again (to remove any trailing slash // if the first Clean gave us just "/") cleanP := filepath.Clean(string(filepath.Separator) + b.String() + p) - if cleanP == string(filepath.Separator) { - // never Lstat "/" itself + if isDriveOrRoot(cleanP) { + // never Lstat "/" itself, or drive letters on Windows b.Reset() continue } @@ -113,7 +113,8 @@ func evalSymlinksInScope(path, root string) (string, error) { return "", err } if fi.Mode()&os.ModeSymlink == 0 { - b.WriteString(p + string(filepath.Separator)) + b.WriteString(p) + b.WriteRune(filepath.Separator) continue } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs_unix.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs_unix.go index 818004f26c..22708273d6 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs_unix.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs_unix.go @@ -9,3 +9,7 @@ import ( func evalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) } + +func isDriveOrRoot(p string) bool { + return p == string(filepath.Separator) +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs_windows.go index 449fe56483..241e531f9d 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs_windows.go @@ -153,3 +153,17 @@ func walkSymlinks(path string) (string, error) { } return filepath.Clean(b.String()), nil } + +func isDriveOrRoot(p string) bool { + if p == string(filepath.Separator) { + return true + } + + length := len(p) + if length >= 2 { + if p[length-1] == ':' && (('a' <= p[length-2] && p[length-2] <= 'z') || ('A' <= p[length-2] && p[length-2] <= 'Z')) { + return true + } + } + return false +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go index dc50da4577..11a16fdea8 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go @@ -73,6 +73,7 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { if os.Getenv("ConEmuANSI") == "ON" { // The ConEmu terminal emulates ANSI on output streams well. + emulateStdin = true emulateStdout = false emulateStderr = false } diff --git a/Godeps/_workspace/src/github.com/docker/docker/plugin/getter/interface.go b/Godeps/_workspace/src/github.com/docker/docker/plugin/getter/interface.go new file mode 100644 index 0000000000..12558437e6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/plugin/getter/interface.go @@ -0,0 +1,26 @@ +package getter + +import "github.com/docker/docker/pkg/plugins" + +const ( + // LOOKUP doesn't update RefCount + LOOKUP = 0 + // CREATE increments RefCount + CREATE = 1 + // REMOVE decrements RefCount + REMOVE = -1 +) + +// CompatPlugin is a abstraction to handle both v2(new) and v1(legacy) plugins. +type CompatPlugin interface { + Client() *plugins.Client + Name() string + IsV1() bool +} + +// PluginGetter is the interface implemented by Store +type PluginGetter interface { + Get(name, capability string, mode int) (CompatPlugin, error) + GetAllByCap(capability string) ([]CompatPlugin, error) + Handle(capability string, callback func(string, *plugins.Client)) +} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/key.go b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/key.go deleted file mode 100644 index f087ce5ada..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/key.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// Package registry provides access to the Windows registry. -// -// Here is a simple example, opening a registry key and reading a string value from it. -// -// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) -// if err != nil { -// log.Fatal(err) -// } -// defer k.Close() -// -// s, _, err := k.GetStringValue("SystemRoot") -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("Windows system root is %q\n", s) -// -package registry - -import ( - "io" - "syscall" - "time" -) - -const ( - // Registry key security and access rights. - // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx - // for details. - ALL_ACCESS = 0xf003f - CREATE_LINK = 0x00020 - CREATE_SUB_KEY = 0x00004 - ENUMERATE_SUB_KEYS = 0x00008 - EXECUTE = 0x20019 - NOTIFY = 0x00010 - QUERY_VALUE = 0x00001 - READ = 0x20019 - SET_VALUE = 0x00002 - WOW64_32KEY = 0x00200 - WOW64_64KEY = 0x00100 - WRITE = 0x20006 -) - -// Key is a handle to an open Windows registry key. -// Keys can be obtained by calling OpenKey; there are -// also some predefined root keys such as CURRENT_USER. -// Keys can be used directly in the Windows API. -type Key syscall.Handle - -const ( - // Windows defines some predefined root keys that are always open. - // An application can use these keys as entry points to the registry. - // Normally these keys are used in OpenKey to open new keys, - // but they can also be used anywhere a Key is required. - CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT) - CURRENT_USER = Key(syscall.HKEY_CURRENT_USER) - LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE) - USERS = Key(syscall.HKEY_USERS) - CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG) -) - -// Close closes open key k. -func (k Key) Close() error { - return syscall.RegCloseKey(syscall.Handle(k)) -} - -// OpenKey opens a new key with path name relative to key k. -// It accepts any open key, including CURRENT_USER and others, -// and returns the new key and an error. -// The access parameter specifies desired access rights to the -// key to be opened. -func OpenKey(k Key, path string, access uint32) (Key, error) { - p, err := syscall.UTF16PtrFromString(path) - if err != nil { - return 0, err - } - var subkey syscall.Handle - err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey) - if err != nil { - return 0, err - } - return Key(subkey), nil -} - -// ReadSubKeyNames returns the names of subkeys of key k. -// The parameter n controls the number of returned names, -// analogous to the way os.File.Readdirnames works. -func (k Key) ReadSubKeyNames(n int) ([]string, error) { - ki, err := k.Stat() - if err != nil { - return nil, err - } - names := make([]string, 0, ki.SubKeyCount) - buf := make([]uint16, ki.MaxSubKeyLen+1) // extra room for terminating zero byte -loopItems: - for i := uint32(0); ; i++ { - if n > 0 { - if len(names) == n { - return names, nil - } - } - l := uint32(len(buf)) - for { - err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) - if err == nil { - break - } - if err == syscall.ERROR_MORE_DATA { - // Double buffer size and try again. - l = uint32(2 * len(buf)) - buf = make([]uint16, l) - continue - } - if err == _ERROR_NO_MORE_ITEMS { - break loopItems - } - return names, err - } - names = append(names, syscall.UTF16ToString(buf[:l])) - } - if n > len(names) { - return names, io.EOF - } - return names, nil -} - -// CreateKey creates a key named path under open key k. -// CreateKey returns the new key and a boolean flag that reports -// whether the key already existed. -// The access parameter specifies the access rights for the key -// to be created. -func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) { - var h syscall.Handle - var d uint32 - err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path), - 0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d) - if err != nil { - return 0, false, err - } - return Key(h), d == _REG_OPENED_EXISTING_KEY, nil -} - -// DeleteKey deletes the subkey path of key k and its values. -func DeleteKey(k Key, path string) error { - return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path)) -} - -// A KeyInfo describes the statistics of a key. It is returned by Stat. -type KeyInfo struct { - SubKeyCount uint32 - MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte - ValueCount uint32 - MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte - MaxValueLen uint32 // longest data component among the key's values, in bytes - lastWriteTime syscall.Filetime -} - -// ModTime returns the key's last write time. -func (ki *KeyInfo) ModTime() time.Time { - return time.Unix(0, ki.lastWriteTime.Nanoseconds()) -} - -// Stat retrieves information about the open key k. -func (k Key) Stat() (*KeyInfo, error) { - var ki KeyInfo - err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil, - &ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount, - &ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime) - if err != nil { - return nil, err - } - return &ki, nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/syscall.go b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/syscall.go deleted file mode 100644 index 5426cae909..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/syscall.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package registry - -import "syscall" - -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go - -const ( - _REG_OPTION_NON_VOLATILE = 0 - - _REG_CREATED_NEW_KEY = 1 - _REG_OPENED_EXISTING_KEY = 2 - - _ERROR_NO_MORE_ITEMS syscall.Errno = 259 -) - -func LoadRegLoadMUIString() error { - return procRegLoadMUIStringW.Find() -} - -//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW -//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW -//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW -//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW -//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW -//sys regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW - -//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/value.go b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/value.go deleted file mode 100644 index 71d4e15bab..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/value.go +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package registry - -import ( - "errors" - "io" - "syscall" - "unicode/utf16" - "unsafe" -) - -const ( - // Registry value types. - NONE = 0 - SZ = 1 - EXPAND_SZ = 2 - BINARY = 3 - DWORD = 4 - DWORD_BIG_ENDIAN = 5 - LINK = 6 - MULTI_SZ = 7 - RESOURCE_LIST = 8 - FULL_RESOURCE_DESCRIPTOR = 9 - RESOURCE_REQUIREMENTS_LIST = 10 - QWORD = 11 -) - -var ( - // ErrShortBuffer is returned when the buffer was too short for the operation. - ErrShortBuffer = syscall.ERROR_MORE_DATA - - // ErrNotExist is returned when a registry key or value does not exist. - ErrNotExist = syscall.ERROR_FILE_NOT_FOUND - - // ErrUnexpectedType is returned by Get*Value when the value's type was unexpected. - ErrUnexpectedType = errors.New("unexpected key value type") -) - -// GetValue retrieves the type and data for the specified value associated -// with an open key k. It fills up buffer buf and returns the retrieved -// byte count n. If buf is too small to fit the stored value it returns -// ErrShortBuffer error along with the required buffer size n. -// If no buffer is provided, it returns true and actual buffer size n. -// If no buffer is provided, GetValue returns the value's type only. -// If the value does not exist, the error returned is ErrNotExist. -// -// GetValue is a low level function. If value's type is known, use the appropriate -// Get*Value function instead. -func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) { - pname, err := syscall.UTF16PtrFromString(name) - if err != nil { - return 0, 0, err - } - var pbuf *byte - if len(buf) > 0 { - pbuf = (*byte)(unsafe.Pointer(&buf[0])) - } - l := uint32(len(buf)) - err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l) - if err != nil { - return int(l), valtype, err - } - return int(l), valtype, nil -} - -func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) { - p, err := syscall.UTF16PtrFromString(name) - if err != nil { - return nil, 0, err - } - var t uint32 - n := uint32(len(buf)) - for { - err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n) - if err == nil { - return buf[:n], t, nil - } - if err != syscall.ERROR_MORE_DATA { - return nil, 0, err - } - if n <= uint32(len(buf)) { - return nil, 0, err - } - buf = make([]byte, n) - } -} - -// GetStringValue retrieves the string value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetStringValue returns ErrNotExist. -// If value is not SZ or EXPAND_SZ, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return "", typ, err2 - } - switch typ { - case SZ, EXPAND_SZ: - default: - return "", typ, ErrUnexpectedType - } - if len(data) == 0 { - return "", typ, nil - } - u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:] - return syscall.UTF16ToString(u), typ, nil -} - -// GetMUIStringValue retrieves the localized string value for -// the specified value name associated with an open key k. -// If the value name doesn't exist or the localized string value -// can't be resolved, GetMUIStringValue returns ErrNotExist. -// GetMUIStringValue panics if the system doesn't support -// regLoadMUIString; use LoadRegLoadMUIString to check if -// regLoadMUIString is supported before calling this function. -func (k Key) GetMUIStringValue(name string) (string, error) { - pname, err := syscall.UTF16PtrFromString(name) - if err != nil { - return "", err - } - - buf := make([]uint16, 1024) - var buflen uint32 - var pdir *uint16 - - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path - - // Try to resolve the string value using the system directory as - // a DLL search path; this assumes the string value is of the form - // @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320. - - // This approach works with tzres.dll but may have to be revised - // in the future to allow callers to provide custom search paths. - - var s string - s, err = ExpandString("%SystemRoot%\\system32\\") - if err != nil { - return "", err - } - pdir, err = syscall.UTF16PtrFromString(s) - if err != nil { - return "", err - } - - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - } - - for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed - if buflen <= uint32(len(buf)) { - break // Buffer not growing, assume race; break - } - buf = make([]uint16, buflen) - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - } - - if err != nil { - return "", err - } - - return syscall.UTF16ToString(buf), nil -} - -// ExpandString expands environment-variable strings and replaces -// them with the values defined for the current user. -// Use ExpandString to expand EXPAND_SZ strings. -func ExpandString(value string) (string, error) { - if value == "" { - return "", nil - } - p, err := syscall.UTF16PtrFromString(value) - if err != nil { - return "", err - } - r := make([]uint16, 100) - for { - n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r))) - if err != nil { - return "", err - } - if n <= uint32(len(r)) { - u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:] - return syscall.UTF16ToString(u), nil - } - r = make([]uint16, n) - } -} - -// GetStringsValue retrieves the []string value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetStringsValue returns ErrNotExist. -// If value is not MULTI_SZ, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return nil, typ, err2 - } - if typ != MULTI_SZ { - return nil, typ, ErrUnexpectedType - } - if len(data) == 0 { - return nil, typ, nil - } - p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2] - if len(p) == 0 { - return nil, typ, nil - } - if p[len(p)-1] == 0 { - p = p[:len(p)-1] // remove terminating null - } - val = make([]string, 0, 5) - from := 0 - for i, c := range p { - if c == 0 { - val = append(val, string(utf16.Decode(p[from:i]))) - from = i + 1 - } - } - return val, typ, nil -} - -// GetIntegerValue retrieves the integer value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetIntegerValue returns ErrNotExist. -// If value is not DWORD or QWORD, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 8)) - if err2 != nil { - return 0, typ, err2 - } - switch typ { - case DWORD: - if len(data) != 4 { - return 0, typ, errors.New("DWORD value is not 4 bytes long") - } - return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil - case QWORD: - if len(data) != 8 { - return 0, typ, errors.New("QWORD value is not 8 bytes long") - } - return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil - default: - return 0, typ, ErrUnexpectedType - } -} - -// GetBinaryValue retrieves the binary value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetBinaryValue returns ErrNotExist. -// If value is not BINARY, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return nil, typ, err2 - } - if typ != BINARY { - return nil, typ, ErrUnexpectedType - } - return data, typ, nil -} - -func (k Key) setValue(name string, valtype uint32, data []byte) error { - p, err := syscall.UTF16PtrFromString(name) - if err != nil { - return err - } - if len(data) == 0 { - return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0) - } - return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data))) -} - -// SetDWordValue sets the data and type of a name value -// under key k to value and DWORD. -func (k Key) SetDWordValue(name string, value uint32) error { - return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:]) -} - -// SetQWordValue sets the data and type of a name value -// under key k to value and QWORD. -func (k Key) SetQWordValue(name string, value uint64) error { - return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:]) -} - -func (k Key) setStringValue(name string, valtype uint32, value string) error { - v, err := syscall.UTF16FromString(value) - if err != nil { - return err - } - buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2] - return k.setValue(name, valtype, buf) -} - -// SetStringValue sets the data and type of a name value -// under key k to value and SZ. The value must not contain a zero byte. -func (k Key) SetStringValue(name, value string) error { - return k.setStringValue(name, SZ, value) -} - -// SetExpandStringValue sets the data and type of a name value -// under key k to value and EXPAND_SZ. The value must not contain a zero byte. -func (k Key) SetExpandStringValue(name, value string) error { - return k.setStringValue(name, EXPAND_SZ, value) -} - -// SetStringsValue sets the data and type of a name value -// under key k to value and MULTI_SZ. The value strings -// must not contain a zero byte. -func (k Key) SetStringsValue(name string, value []string) error { - ss := "" - for _, s := range value { - for i := 0; i < len(s); i++ { - if s[i] == 0 { - return errors.New("string cannot have 0 inside") - } - } - ss += s + "\x00" - } - v := utf16.Encode([]rune(ss + "\x00")) - buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2] - return k.setValue(name, MULTI_SZ, buf) -} - -// SetBinaryValue sets the data and type of a name value -// under key k to value and BINARY. -func (k Key) SetBinaryValue(name string, value []byte) error { - return k.setValue(name, BINARY, value) -} - -// DeleteValue removes a named value from the key k. -func (k Key) DeleteValue(name string) error { - return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name)) -} - -// ReadValueNames returns the value names of key k. -// The parameter n controls the number of returned names, -// analogous to the way os.File.Readdirnames works. -func (k Key) ReadValueNames(n int) ([]string, error) { - ki, err := k.Stat() - if err != nil { - return nil, err - } - names := make([]string, 0, ki.ValueCount) - buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character -loopItems: - for i := uint32(0); ; i++ { - if n > 0 { - if len(names) == n { - return names, nil - } - } - l := uint32(len(buf)) - for { - err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) - if err == nil { - break - } - if err == syscall.ERROR_MORE_DATA { - // Double buffer size and try again. - l = uint32(2 * len(buf)) - buf = make([]uint16, l) - continue - } - if err == _ERROR_NO_MORE_ITEMS { - break loopItems - } - return names, err - } - names = append(names, syscall.UTF16ToString(buf[:l])) - } - if n > len(names) { - return names, io.EOF - } - return names, nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/zsyscall_windows.go b/Godeps/_workspace/src/golang.org/x/sys/windows/registry/zsyscall_windows.go deleted file mode 100644 index 9c17675a24..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/registry/zsyscall_windows.go +++ /dev/null @@ -1,82 +0,0 @@ -// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT - -package registry - -import "unsafe" -import "syscall" - -var _ unsafe.Pointer - -var ( - modadvapi32 = syscall.NewLazyDLL("advapi32.dll") - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - - procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW") - procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW") - procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW") - procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") - procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW") - procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW") - procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") -) - -func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition))) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) { - r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize)) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size)) - n = uint32(r0) - if n == 0 { - if e1 != 0 { - err = error(e1) - } else { - err = syscall.EINVAL - } - } - return -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/log.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/log.go deleted file mode 100644 index e51ab42a1a..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/log.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package debug - -import ( - "os" - "strconv" -) - -// Log interface allows different log implementations to be used. -type Log interface { - Close() error - Info(eid uint32, msg string) error - Warning(eid uint32, msg string) error - Error(eid uint32, msg string) error -} - -// ConsoleLog provides access to the console. -type ConsoleLog struct { - Name string -} - -// New creates new ConsoleLog. -func New(source string) *ConsoleLog { - return &ConsoleLog{Name: source} -} - -// Close closes console log l. -func (l *ConsoleLog) Close() error { - return nil -} - -func (l *ConsoleLog) report(kind string, eid uint32, msg string) error { - s := l.Name + "." + kind + "(" + strconv.Itoa(int(eid)) + "): " + msg + "\n" - _, err := os.Stdout.Write([]byte(s)) - return err -} - -// Info writes an information event msg with event id eid to the console l. -func (l *ConsoleLog) Info(eid uint32, msg string) error { - return l.report("info", eid, msg) -} - -// Warning writes an warning event msg with event id eid to the console l. -func (l *ConsoleLog) Warning(eid uint32, msg string) error { - return l.report("warn", eid, msg) -} - -// Error writes an error event msg with event id eid to the console l. -func (l *ConsoleLog) Error(eid uint32, msg string) error { - return l.report("error", eid, msg) -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/service.go deleted file mode 100644 index d5ab94b2c7..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/debug/service.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// Package debug provides facilities to execute svc.Handler on console. -// -package debug - -import ( - "os" - "os/signal" - "syscall" - - "golang.org/x/sys/windows/svc" -) - -// Run executes service name by calling appropriate handler function. -// The process is running on console, unlike real service. Use Ctrl+C to -// send "Stop" command to your service. -func Run(name string, handler svc.Handler) error { - cmds := make(chan svc.ChangeRequest) - changes := make(chan svc.Status) - - sig := make(chan os.Signal) - signal.Notify(sig) - - go func() { - status := svc.Status{State: svc.Stopped} - for { - select { - case <-sig: - cmds <- svc.ChangeRequest{svc.Stop, status} - case status = <-changes: - } - } - }() - - _, errno := handler.Execute([]string{name}, cmds, changes) - if errno != 0 { - return syscall.Errno(errno) - } - return nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/event.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/event.go deleted file mode 100644 index 0508e22881..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/event.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package svc - -import ( - "errors" - - "golang.org/x/sys/windows" -) - -// event represents auto-reset, initially non-signaled Windows event. -// It is used to communicate between go and asm parts of this package. -type event struct { - h windows.Handle -} - -func newEvent() (*event, error) { - h, err := windows.CreateEvent(nil, 0, 0, nil) - if err != nil { - return nil, err - } - return &event{h: h}, nil -} - -func (e *event) Close() error { - return windows.CloseHandle(e.h) -} - -func (e *event) Set() error { - return windows.SetEvent(e.h) -} - -func (e *event) Wait() error { - s, err := windows.WaitForSingleObject(e.h, windows.INFINITE) - switch s { - case windows.WAIT_OBJECT_0: - break - case windows.WAIT_FAILED: - return err - default: - return errors.New("unexpected result from WaitForSingleObject") - } - return nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/install.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/install.go deleted file mode 100644 index c76a3760a4..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/install.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package eventlog - -import ( - "errors" - - "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" -) - -const ( - // Log levels. - Info = windows.EVENTLOG_INFORMATION_TYPE - Warning = windows.EVENTLOG_WARNING_TYPE - Error = windows.EVENTLOG_ERROR_TYPE -) - -const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application` - -// Install modifies PC registry to allow logging with an event source src. -// It adds all required keys and values to the event log registry key. -// Install uses msgFile as the event message file. If useExpandKey is true, -// the event message file is installed as REG_EXPAND_SZ value, -// otherwise as REG_SZ. Use bitwise of log.Error, log.Warning and -// log.Info to specify events supported by the new event source. -func Install(src, msgFile string, useExpandKey bool, eventsSupported uint32) error { - appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.CREATE_SUB_KEY) - if err != nil { - return err - } - defer appkey.Close() - - sk, alreadyExist, err := registry.CreateKey(appkey, src, registry.SET_VALUE) - if err != nil { - return err - } - defer sk.Close() - if alreadyExist { - return errors.New(addKeyName + `\` + src + " registry key already exists") - } - - err = sk.SetDWordValue("CustomSource", 1) - if err != nil { - return err - } - if useExpandKey { - err = sk.SetExpandStringValue("EventMessageFile", msgFile) - } else { - err = sk.SetStringValue("EventMessageFile", msgFile) - } - if err != nil { - return err - } - err = sk.SetDWordValue("TypesSupported", eventsSupported) - if err != nil { - return err - } - return nil -} - -// InstallAsEventCreate is the same as Install, but uses -// %SystemRoot%\System32\EventCreate.exe as the event message file. -func InstallAsEventCreate(src string, eventsSupported uint32) error { - return Install(src, "%SystemRoot%\\System32\\EventCreate.exe", true, eventsSupported) -} - -// Remove deletes all registry elements installed by the correspondent Install. -func Remove(src string) error { - appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.SET_VALUE) - if err != nil { - return err - } - defer appkey.Close() - return registry.DeleteKey(appkey, src) -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/log.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/log.go deleted file mode 100644 index 46e5153d02..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/eventlog/log.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// Package eventlog implements access to Windows event log. -// -package eventlog - -import ( - "errors" - "syscall" - - "golang.org/x/sys/windows" -) - -// Log provides access to the system log. -type Log struct { - Handle windows.Handle -} - -// Open retrieves a handle to the specified event log. -func Open(source string) (*Log, error) { - return OpenRemote("", source) -} - -// OpenRemote does the same as Open, but on different computer host. -func OpenRemote(host, source string) (*Log, error) { - if source == "" { - return nil, errors.New("Specify event log source") - } - var s *uint16 - if host != "" { - s = syscall.StringToUTF16Ptr(host) - } - h, err := windows.RegisterEventSource(s, syscall.StringToUTF16Ptr(source)) - if err != nil { - return nil, err - } - return &Log{Handle: h}, nil -} - -// Close closes event log l. -func (l *Log) Close() error { - return windows.DeregisterEventSource(l.Handle) -} - -func (l *Log) report(etype uint16, eid uint32, msg string) error { - ss := []*uint16{syscall.StringToUTF16Ptr(msg)} - return windows.ReportEvent(l.Handle, etype, 0, eid, 0, 1, 0, &ss[0], nil) -} - -// Info writes an information event msg with event id eid to the end of event log l. -// When EventCreate.exe is used, eid must be between 1 and 1000. -func (l *Log) Info(eid uint32, msg string) error { - return l.report(windows.EVENTLOG_INFORMATION_TYPE, eid, msg) -} - -// Warning writes an warning event msg with event id eid to the end of event log l. -// When EventCreate.exe is used, eid must be between 1 and 1000. -func (l *Log) Warning(eid uint32, msg string) error { - return l.report(windows.EVENTLOG_WARNING_TYPE, eid, msg) -} - -// Error writes an error event msg with event id eid to the end of event log l. -// When EventCreate.exe is used, eid must be between 1 and 1000. -func (l *Log) Error(eid uint32, msg string) error { - return l.report(windows.EVENTLOG_ERROR_TYPE, eid, msg) -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/beep.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/beep.go deleted file mode 100644 index dcf23408d3..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/beep.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package main - -import ( - "syscall" -) - -// BUG(brainman): MessageBeep Windows api is broken on Windows 7, -// so this example does not beep when runs as service on Windows 7. - -var ( - beepFunc = syscall.MustLoadDLL("user32.dll").MustFindProc("MessageBeep") -) - -func beep() { - beepFunc.Call(0xffffffff) -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/install.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/install.go deleted file mode 100644 index 39cb00d2ad..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/install.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package main - -import ( - "fmt" - "os" - "path/filepath" - - "golang.org/x/sys/windows/svc/eventlog" - "golang.org/x/sys/windows/svc/mgr" -) - -func exePath() (string, error) { - prog := os.Args[0] - p, err := filepath.Abs(prog) - if err != nil { - return "", err - } - fi, err := os.Stat(p) - if err == nil { - if !fi.Mode().IsDir() { - return p, nil - } - err = fmt.Errorf("%s is directory", p) - } - if filepath.Ext(p) == "" { - p += ".exe" - fi, err := os.Stat(p) - if err == nil { - if !fi.Mode().IsDir() { - return p, nil - } - err = fmt.Errorf("%s is directory", p) - } - } - return "", err -} - -func installService(name, desc string) error { - exepath, err := exePath() - if err != nil { - return err - } - m, err := mgr.Connect() - if err != nil { - return err - } - defer m.Disconnect() - s, err := m.OpenService(name) - if err == nil { - s.Close() - return fmt.Errorf("service %s already exists", name) - } - s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: desc}, "is", "auto-started") - if err != nil { - return err - } - defer s.Close() - err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info) - if err != nil { - s.Delete() - return fmt.Errorf("SetupEventLogSource() failed: %s", err) - } - return nil -} - -func removeService(name string) error { - m, err := mgr.Connect() - if err != nil { - return err - } - defer m.Disconnect() - s, err := m.OpenService(name) - if err != nil { - return fmt.Errorf("service %s is not installed", name) - } - defer s.Close() - err = s.Delete() - if err != nil { - return err - } - err = eventlog.Remove(name) - if err != nil { - return fmt.Errorf("RemoveEventLogSource() failed: %s", err) - } - return nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/main.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/main.go deleted file mode 100644 index dc96c081af..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/main.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// Example service program that beeps. -// -// The program demonstrates how to create Windows service and -// install / remove it on a computer. It also shows how to -// stop / start / pause / continue any service, and how to -// write to event log. It also shows how to use debug -// facilities available in debug package. -// -package main - -import ( - "fmt" - "log" - "os" - "strings" - - "golang.org/x/sys/windows/svc" -) - -func usage(errmsg string) { - fmt.Fprintf(os.Stderr, - "%s\n\n"+ - "usage: %s \n"+ - " where is one of\n"+ - " install, remove, debug, start, stop, pause or continue.\n", - errmsg, os.Args[0]) - os.Exit(2) -} - -func main() { - const svcName = "myservice" - - isIntSess, err := svc.IsAnInteractiveSession() - if err != nil { - log.Fatalf("failed to determine if we are running in an interactive session: %v", err) - } - if !isIntSess { - runService(svcName, false) - return - } - - if len(os.Args) < 2 { - usage("no command specified") - } - - cmd := strings.ToLower(os.Args[1]) - switch cmd { - case "debug": - runService(svcName, true) - return - case "install": - err = installService(svcName, "my service") - case "remove": - err = removeService(svcName) - case "start": - err = startService(svcName) - case "stop": - err = controlService(svcName, svc.Stop, svc.Stopped) - case "pause": - err = controlService(svcName, svc.Pause, svc.Paused) - case "continue": - err = controlService(svcName, svc.Continue, svc.Running) - default: - usage(fmt.Sprintf("invalid command %s", cmd)) - } - if err != nil { - log.Fatalf("failed to %s %s: %v", cmd, svcName, err) - } - return -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/manage.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/manage.go deleted file mode 100644 index 782dbd96ca..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/manage.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package main - -import ( - "fmt" - "time" - - "golang.org/x/sys/windows/svc" - "golang.org/x/sys/windows/svc/mgr" -) - -func startService(name string) error { - m, err := mgr.Connect() - if err != nil { - return err - } - defer m.Disconnect() - s, err := m.OpenService(name) - if err != nil { - return fmt.Errorf("could not access service: %v", err) - } - defer s.Close() - err = s.Start("is", "manual-started") - if err != nil { - return fmt.Errorf("could not start service: %v", err) - } - return nil -} - -func controlService(name string, c svc.Cmd, to svc.State) error { - m, err := mgr.Connect() - if err != nil { - return err - } - defer m.Disconnect() - s, err := m.OpenService(name) - if err != nil { - return fmt.Errorf("could not access service: %v", err) - } - defer s.Close() - status, err := s.Control(c) - if err != nil { - return fmt.Errorf("could not send control=%d: %v", c, err) - } - timeout := time.Now().Add(10 * time.Second) - for status.State != to { - if timeout.Before(time.Now()) { - return fmt.Errorf("timeout waiting for service to go to state=%d", to) - } - time.Sleep(300 * time.Millisecond) - status, err = s.Query() - if err != nil { - return fmt.Errorf("could not retrieve service status: %v", err) - } - } - return nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/service.go deleted file mode 100644 index 237e80984d..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/example/service.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package main - -import ( - "fmt" - "time" - - "golang.org/x/sys/windows/svc" - "golang.org/x/sys/windows/svc/debug" - "golang.org/x/sys/windows/svc/eventlog" -) - -var elog debug.Log - -type myservice struct{} - -func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) { - const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue - changes <- svc.Status{State: svc.StartPending} - fasttick := time.Tick(500 * time.Millisecond) - slowtick := time.Tick(2 * time.Second) - tick := fasttick - changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} -loop: - for { - select { - case <-tick: - beep() - elog.Info(1, "beep") - case c := <-r: - switch c.Cmd { - case svc.Interrogate: - changes <- c.CurrentStatus - // Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4 - time.Sleep(100 * time.Millisecond) - changes <- c.CurrentStatus - case svc.Stop, svc.Shutdown: - break loop - case svc.Pause: - changes <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted} - tick = slowtick - case svc.Continue: - changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} - tick = fasttick - default: - elog.Error(1, fmt.Sprintf("unexpected control request #%d", c)) - } - } - } - changes <- svc.Status{State: svc.StopPending} - return -} - -func runService(name string, isDebug bool) { - var err error - if isDebug { - elog = debug.New(name) - } else { - elog, err = eventlog.Open(name) - if err != nil { - return - } - } - defer elog.Close() - - elog.Info(1, fmt.Sprintf("starting %s service", name)) - run := svc.Run - if isDebug { - run = debug.Run - } - err = run(name, &myservice{}) - if err != nil { - elog.Error(1, fmt.Sprintf("%s service failed: %v", name, err)) - return - } - elog.Info(1, fmt.Sprintf("%s service stopped", name)) -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.c b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.c deleted file mode 100644 index 6f1be1fa3b..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.c +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows -// +build !go1.3 - -// copied from pkg/runtime -typedef unsigned int uint32; -typedef unsigned long long int uint64; -#ifdef _64BIT -typedef uint64 uintptr; -#else -typedef uint32 uintptr; -#endif - -// from sys_386.s or sys_amd64.s -void ·servicemain(void); - -void -·getServiceMain(uintptr *r) -{ - *r = (uintptr)·servicemain; -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.go deleted file mode 100644 index 6f0a924eaf..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go12.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows -// +build !go1.3 - -package svc - -// from go12.c -func getServiceMain(r *uintptr) diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go13.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go13.go deleted file mode 100644 index 432a9e796a..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/go13.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows -// +build go1.3 - -package svc - -import "unsafe" - -const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const - -// Should be a built-in for unsafe.Pointer? -func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { - return unsafe.Pointer(uintptr(p) + x) -} - -// funcPC returns the entry PC of the function f. -// It assumes that f is a func value. Otherwise the behavior is undefined. -func funcPC(f interface{}) uintptr { - return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize)) -} - -// from sys_386.s and sys_amd64.s -func servicectlhandler(ctl uint32) uintptr -func servicemain(argc uint32, argv **uint16) - -func getServiceMain(r *uintptr) { - *r = funcPC(servicemain) -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/config.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/config.go deleted file mode 100644 index 0a6edba4f5..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/config.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package mgr - -import ( - "syscall" - "unicode/utf16" - "unsafe" - - "golang.org/x/sys/windows" -) - -const ( - // Service start types. - StartManual = windows.SERVICE_DEMAND_START // the service must be started manually - StartAutomatic = windows.SERVICE_AUTO_START // the service will start by itself whenever the computer reboots - StartDisabled = windows.SERVICE_DISABLED // the service cannot be started - - // The severity of the error, and action taken, - // if this service fails to start. - ErrorCritical = windows.SERVICE_ERROR_CRITICAL - ErrorIgnore = windows.SERVICE_ERROR_IGNORE - ErrorNormal = windows.SERVICE_ERROR_NORMAL - ErrorSevere = windows.SERVICE_ERROR_SEVERE -) - -// TODO(brainman): Password is not returned by windows.QueryServiceConfig, not sure how to get it. - -type Config struct { - ServiceType uint32 - StartType uint32 - ErrorControl uint32 - BinaryPathName string // fully qualified path to the service binary file, can also include arguments for an auto-start service - LoadOrderGroup string - TagId uint32 - Dependencies []string - ServiceStartName string // name of the account under which the service should run - DisplayName string - Password string - Description string -} - -func toString(p *uint16) string { - if p == nil { - return "" - } - return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:]) -} - -func toStringSlice(ps *uint16) []string { - if ps == nil { - return nil - } - r := make([]string, 0) - for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ { - if p[i] == 0 { - // empty string marks the end - if i <= from { - break - } - r = append(r, string(utf16.Decode(p[from:i]))) - from = i + 1 - } - } - return r -} - -// Config retrieves service s configuration paramteres. -func (s *Service) Config() (Config, error) { - var p *windows.QUERY_SERVICE_CONFIG - n := uint32(1024) - for { - b := make([]byte, n) - p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0])) - err := windows.QueryServiceConfig(s.Handle, p, n, &n) - if err == nil { - break - } - if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER { - return Config{}, err - } - if n <= uint32(len(b)) { - return Config{}, err - } - } - - var p2 *windows.SERVICE_DESCRIPTION - n = uint32(1024) - for { - b := make([]byte, n) - p2 = (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0])) - err := windows.QueryServiceConfig2(s.Handle, - windows.SERVICE_CONFIG_DESCRIPTION, &b[0], n, &n) - if err == nil { - break - } - if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER { - return Config{}, err - } - if n <= uint32(len(b)) { - return Config{}, err - } - } - - return Config{ - ServiceType: p.ServiceType, - StartType: p.StartType, - ErrorControl: p.ErrorControl, - BinaryPathName: toString(p.BinaryPathName), - LoadOrderGroup: toString(p.LoadOrderGroup), - TagId: p.TagId, - Dependencies: toStringSlice(p.Dependencies), - ServiceStartName: toString(p.ServiceStartName), - DisplayName: toString(p.DisplayName), - Description: toString(p2.Description), - }, nil -} - -func updateDescription(handle windows.Handle, desc string) error { - d := windows.SERVICE_DESCRIPTION{toPtr(desc)} - return windows.ChangeServiceConfig2(handle, - windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d))) -} - -// UpdateConfig updates service s configuration parameters. -func (s *Service) UpdateConfig(c Config) error { - err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType, - c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup), - nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), - toPtr(c.Password), toPtr(c.DisplayName)) - if err != nil { - return err - } - return updateDescription(s.Handle, c.Description) -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/mgr.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/mgr.go deleted file mode 100644 index da8ceb6ed8..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/mgr.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// Package mgr can be used to manage Windows service programs. -// It can be used to install and remove them. It can also start, -// stop and pause them. The package can query / change current -// service state and config parameters. -// -package mgr - -import ( - "syscall" - "unicode/utf16" - - "golang.org/x/sys/windows" -) - -// Mgr is used to manage Windows service. -type Mgr struct { - Handle windows.Handle -} - -// Connect establishes a connection to the service control manager. -func Connect() (*Mgr, error) { - return ConnectRemote("") -} - -// ConnectRemote establishes a connection to the -// service control manager on computer named host. -func ConnectRemote(host string) (*Mgr, error) { - var s *uint16 - if host != "" { - s = syscall.StringToUTF16Ptr(host) - } - h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS) - if err != nil { - return nil, err - } - return &Mgr{Handle: h}, nil -} - -// Disconnect closes connection to the service control manager m. -func (m *Mgr) Disconnect() error { - return windows.CloseServiceHandle(m.Handle) -} - -func toPtr(s string) *uint16 { - if len(s) == 0 { - return nil - } - return syscall.StringToUTF16Ptr(s) -} - -// toStringBlock terminates strings in ss with 0, and then -// concatenates them together. It also adds extra 0 at the end. -func toStringBlock(ss []string) *uint16 { - if len(ss) == 0 { - return nil - } - t := "" - for _, s := range ss { - if s != "" { - t += s + "\x00" - } - } - if t == "" { - return nil - } - t += "\x00" - return &utf16.Encode([]rune(t))[0] -} - -// CreateService installs new service name on the system. -// The service will be executed by running exepath binary. -// Use config c to specify service parameters. -// If service StartType is set to StartAutomatic, -// args will be passed to svc.Handle.Execute. -func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) { - if c.StartType == 0 { - c.StartType = StartManual - } - if c.ErrorControl == 0 { - c.ErrorControl = ErrorNormal - } - if c.ServiceType == 0 { - c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS - } - s := syscall.EscapeArg(exepath) - for _, v := range args { - s += " " + syscall.EscapeArg(v) - } - h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName), - windows.SERVICE_ALL_ACCESS, c.ServiceType, - c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup), - nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password)) - if err != nil { - return nil, err - } - if c.Description != "" { - err = updateDescription(h, c.Description) - if err != nil { - return nil, err - } - } - return &Service{Name: name, Handle: h}, nil -} - -// OpenService retrieves access to service name, so it can -// be interrogated and controlled. -func (m *Mgr) OpenService(name string) (*Service, error) { - h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS) - if err != nil { - return nil, err - } - return &Service{Name: name, Handle: h}, nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/service.go deleted file mode 100644 index 465f3c3d23..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/mgr/service.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package mgr - -import ( - "syscall" - - "golang.org/x/sys/windows" - "golang.org/x/sys/windows/svc" -) - -// TODO(brainman): Use EnumDependentServices to enumerate dependent services. - -// TODO(brainman): Use EnumServicesStatus to enumerate services in the specified service control manager database. - -// Service is used to access Windows service. -type Service struct { - Name string - Handle windows.Handle -} - -// Delete marks service s for deletion from the service control manager database. -func (s *Service) Delete() error { - return windows.DeleteService(s.Handle) -} - -// Close relinquish access to the service s. -func (s *Service) Close() error { - return windows.CloseServiceHandle(s.Handle) -} - -// Start starts service s. -// args will be passed to svc.Handler.Execute. -func (s *Service) Start(args ...string) error { - var p **uint16 - if len(args) > 0 { - vs := make([]*uint16, len(args)) - for i, _ := range vs { - vs[i] = syscall.StringToUTF16Ptr(args[i]) - } - p = &vs[0] - } - return windows.StartService(s.Handle, uint32(len(args)), p) -} - -// Control sends state change request c to the servce s. -func (s *Service) Control(c svc.Cmd) (svc.Status, error) { - var t windows.SERVICE_STATUS - err := windows.ControlService(s.Handle, uint32(c), &t) - if err != nil { - return svc.Status{}, err - } - return svc.Status{ - State: svc.State(t.CurrentState), - Accepts: svc.Accepted(t.ControlsAccepted), - }, nil -} - -// Query returns current status of service s. -func (s *Service) Query() (svc.Status, error) { - var t windows.SERVICE_STATUS - err := windows.QueryServiceStatus(s.Handle, &t) - if err != nil { - return svc.Status{}, err - } - return svc.Status{ - State: svc.State(t.CurrentState), - Accepts: svc.Accepted(t.ControlsAccepted), - }, nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/security.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/security.go deleted file mode 100644 index 6fbc9236ed..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/security.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package svc - -import ( - "unsafe" - - "golang.org/x/sys/windows" -) - -func allocSid(subAuth0 uint32) (*windows.SID, error) { - var sid *windows.SID - err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY, - 1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid) - if err != nil { - return nil, err - } - return sid, nil -} - -// IsAnInteractiveSession determines if calling process is running interactively. -// It queries the process token for membership in the Interactive group. -// http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s -func IsAnInteractiveSession() (bool, error) { - interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID) - if err != nil { - return false, err - } - defer windows.FreeSid(interSid) - - serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID) - if err != nil { - return false, err - } - defer windows.FreeSid(serviceSid) - - t, err := windows.OpenCurrentProcessToken() - if err != nil { - return false, err - } - defer t.Close() - - gs, err := t.GetTokenGroups() - if err != nil { - return false, err - } - p := unsafe.Pointer(&gs.Groups[0]) - groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount] - for _, g := range groups { - if windows.EqualSid(g.Sid, interSid) { - return true, nil - } - if windows.EqualSid(g.Sid, serviceSid) { - return false, nil - } - } - return false, nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/service.go b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/service.go deleted file mode 100644 index 9864f7a72f..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/service.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// Package svc provides everything required to build Windows service. -// -package svc - -import ( - "errors" - "runtime" - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -// State describes service execution state (Stopped, Running and so on). -type State uint32 - -const ( - Stopped = State(windows.SERVICE_STOPPED) - StartPending = State(windows.SERVICE_START_PENDING) - StopPending = State(windows.SERVICE_STOP_PENDING) - Running = State(windows.SERVICE_RUNNING) - ContinuePending = State(windows.SERVICE_CONTINUE_PENDING) - PausePending = State(windows.SERVICE_PAUSE_PENDING) - Paused = State(windows.SERVICE_PAUSED) -) - -// Cmd represents service state change request. It is sent to a service -// by the service manager, and should be actioned upon by the service. -type Cmd uint32 - -const ( - Stop = Cmd(windows.SERVICE_CONTROL_STOP) - Pause = Cmd(windows.SERVICE_CONTROL_PAUSE) - Continue = Cmd(windows.SERVICE_CONTROL_CONTINUE) - Interrogate = Cmd(windows.SERVICE_CONTROL_INTERROGATE) - Shutdown = Cmd(windows.SERVICE_CONTROL_SHUTDOWN) -) - -// Accepted is used to describe commands accepted by the service. -// Note that Interrogate is always accepted. -type Accepted uint32 - -const ( - AcceptStop = Accepted(windows.SERVICE_ACCEPT_STOP) - AcceptShutdown = Accepted(windows.SERVICE_ACCEPT_SHUTDOWN) - AcceptPauseAndContinue = Accepted(windows.SERVICE_ACCEPT_PAUSE_CONTINUE) -) - -// Status combines State and Accepted commands to fully describe running service. -type Status struct { - State State - Accepts Accepted - CheckPoint uint32 // used to report progress during a lengthy operation - WaitHint uint32 // estimated time required for a pending operation, in milliseconds -} - -// ChangeRequest is sent to the service Handler to request service status change. -type ChangeRequest struct { - Cmd Cmd - CurrentStatus Status -} - -// Handler is the interface that must be implemented to build Windows service. -type Handler interface { - - // Execute will be called by the package code at the start of - // the service, and the service will exit once Execute completes. - // Inside Execute you must read service change requests from r and - // act accordingly. You must keep service control manager up to date - // about state of your service by writing into s as required. - // args contains service name followed by argument strings passed - // to the service. - // You can provide service exit code in exitCode return parameter, - // with 0 being "no error". You can also indicate if exit code, - // if any, is service specific or not by using svcSpecificEC - // parameter. - Execute(args []string, r <-chan ChangeRequest, s chan<- Status) (svcSpecificEC bool, exitCode uint32) -} - -var ( - // These are used by asm code. - goWaitsH uintptr - cWaitsH uintptr - ssHandle uintptr - sName *uint16 - sArgc uintptr - sArgv **uint16 - ctlHandlerProc uintptr - cSetEvent uintptr - cWaitForSingleObject uintptr - cRegisterServiceCtrlHandlerW uintptr -) - -func init() { - k := syscall.MustLoadDLL("kernel32.dll") - cSetEvent = k.MustFindProc("SetEvent").Addr() - cWaitForSingleObject = k.MustFindProc("WaitForSingleObject").Addr() - a := syscall.MustLoadDLL("advapi32.dll") - cRegisterServiceCtrlHandlerW = a.MustFindProc("RegisterServiceCtrlHandlerW").Addr() -} - -type ctlEvent struct { - cmd Cmd - errno uint32 -} - -// service provides access to windows service api. -type service struct { - name string - h windows.Handle - cWaits *event - goWaits *event - c chan ctlEvent - handler Handler -} - -func newService(name string, handler Handler) (*service, error) { - var s service - var err error - s.name = name - s.c = make(chan ctlEvent) - s.handler = handler - s.cWaits, err = newEvent() - if err != nil { - return nil, err - } - s.goWaits, err = newEvent() - if err != nil { - s.cWaits.Close() - return nil, err - } - return &s, nil -} - -func (s *service) close() error { - s.cWaits.Close() - s.goWaits.Close() - return nil -} - -type exitCode struct { - isSvcSpecific bool - errno uint32 -} - -func (s *service) updateStatus(status *Status, ec *exitCode) error { - if s.h == 0 { - return errors.New("updateStatus with no service status handle") - } - var t windows.SERVICE_STATUS - t.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS - t.CurrentState = uint32(status.State) - if status.Accepts&AcceptStop != 0 { - t.ControlsAccepted |= windows.SERVICE_ACCEPT_STOP - } - if status.Accepts&AcceptShutdown != 0 { - t.ControlsAccepted |= windows.SERVICE_ACCEPT_SHUTDOWN - } - if status.Accepts&AcceptPauseAndContinue != 0 { - t.ControlsAccepted |= windows.SERVICE_ACCEPT_PAUSE_CONTINUE - } - if ec.errno == 0 { - t.Win32ExitCode = windows.NO_ERROR - t.ServiceSpecificExitCode = windows.NO_ERROR - } else if ec.isSvcSpecific { - t.Win32ExitCode = uint32(windows.ERROR_SERVICE_SPECIFIC_ERROR) - t.ServiceSpecificExitCode = ec.errno - } else { - t.Win32ExitCode = ec.errno - t.ServiceSpecificExitCode = windows.NO_ERROR - } - t.CheckPoint = status.CheckPoint - t.WaitHint = status.WaitHint - return windows.SetServiceStatus(s.h, &t) -} - -const ( - sysErrSetServiceStatusFailed = uint32(syscall.APPLICATION_ERROR) + iota - sysErrNewThreadInCallback -) - -func (s *service) run() { - s.goWaits.Wait() - s.h = windows.Handle(ssHandle) - argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc] - args := make([]string, len(argv)) - for i, a := range argv { - args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:]) - } - - cmdsToHandler := make(chan ChangeRequest) - changesFromHandler := make(chan Status) - exitFromHandler := make(chan exitCode) - - go func() { - ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler) - exitFromHandler <- exitCode{ss, errno} - }() - - status := Status{State: Stopped} - ec := exitCode{isSvcSpecific: true, errno: 0} - var outch chan ChangeRequest - inch := s.c - var cmd Cmd -loop: - for { - select { - case r := <-inch: - if r.errno != 0 { - ec.errno = r.errno - break loop - } - inch = nil - outch = cmdsToHandler - cmd = r.cmd - case outch <- ChangeRequest{cmd, status}: - inch = s.c - outch = nil - case c := <-changesFromHandler: - err := s.updateStatus(&c, &ec) - if err != nil { - // best suitable error number - ec.errno = sysErrSetServiceStatusFailed - if err2, ok := err.(syscall.Errno); ok { - ec.errno = uint32(err2) - } - break loop - } - status = c - case ec = <-exitFromHandler: - break loop - } - } - - s.updateStatus(&Status{State: Stopped}, &ec) - s.cWaits.Set() -} - -func newCallback(fn interface{}) (cb uintptr, err error) { - defer func() { - r := recover() - if r == nil { - return - } - cb = 0 - switch v := r.(type) { - case string: - err = errors.New(v) - case error: - err = v - default: - err = errors.New("unexpected panic in syscall.NewCallback") - } - }() - return syscall.NewCallback(fn), nil -} - -// BUG(brainman): There is no mechanism to run multiple services -// inside one single executable. Perhaps, it can be overcome by -// using RegisterServiceCtrlHandlerEx Windows api. - -// Run executes service name by calling appropriate handler function. -func Run(name string, handler Handler) error { - runtime.LockOSThread() - - tid := windows.GetCurrentThreadId() - - s, err := newService(name, handler) - if err != nil { - return err - } - - ctlHandler := func(ctl uint32) uintptr { - e := ctlEvent{cmd: Cmd(ctl)} - // We assume that this callback function is running on - // the same thread as Run. Nowhere in MS documentation - // I could find statement to guarantee that. So putting - // check here to verify, otherwise things will go bad - // quickly, if ignored. - i := windows.GetCurrentThreadId() - if i != tid { - e.errno = sysErrNewThreadInCallback - } - s.c <- e - return 0 - } - - var svcmain uintptr - getServiceMain(&svcmain) - t := []windows.SERVICE_TABLE_ENTRY{ - {syscall.StringToUTF16Ptr(s.name), svcmain}, - {nil, 0}, - } - - goWaitsH = uintptr(s.goWaits.h) - cWaitsH = uintptr(s.cWaits.h) - sName = t[0].ServiceName - ctlHandlerProc, err = newCallback(ctlHandler) - if err != nil { - return err - } - - go s.run() - - err = windows.StartServiceCtrlDispatcher(&t[0]) - if err != nil { - return err - } - return nil -} diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_386.s b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_386.s deleted file mode 100644 index 5e11bfadb5..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_386.s +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// func servicemain(argc uint32, argv **uint16) -TEXT ·servicemain(SB),7,$0 - MOVL argc+0(FP), AX - MOVL AX, ·sArgc(SB) - MOVL argv+4(FP), AX - MOVL AX, ·sArgv(SB) - - PUSHL BP - PUSHL BX - PUSHL SI - PUSHL DI - - SUBL $12, SP - - MOVL ·sName(SB), AX - MOVL AX, (SP) - MOVL $·servicectlhandler(SB), AX - MOVL AX, 4(SP) - MOVL ·cRegisterServiceCtrlHandlerW(SB), AX - MOVL SP, BP - CALL AX - MOVL BP, SP - CMPL AX, $0 - JE exit - MOVL AX, ·ssHandle(SB) - - MOVL ·goWaitsH(SB), AX - MOVL AX, (SP) - MOVL ·cSetEvent(SB), AX - MOVL SP, BP - CALL AX - MOVL BP, SP - - MOVL ·cWaitsH(SB), AX - MOVL AX, (SP) - MOVL $-1, AX - MOVL AX, 4(SP) - MOVL ·cWaitForSingleObject(SB), AX - MOVL SP, BP - CALL AX - MOVL BP, SP - -exit: - ADDL $12, SP - - POPL DI - POPL SI - POPL BX - POPL BP - - MOVL 0(SP), CX - ADDL $12, SP - JMP CX - -// I do not know why, but this seems to be the only way to call -// ctlHandlerProc on Windows 7. - -// func servicectlhandler(ctl uint32) uintptr -TEXT ·servicectlhandler(SB),7,$0 - MOVL ·ctlHandlerProc(SB), CX - JMP CX diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_amd64.s b/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_amd64.s deleted file mode 100644 index 87dbec8395..0000000000 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/svc/sys_amd64.s +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// func servicemain(argc uint32, argv **uint16) -TEXT ·servicemain(SB),7,$0 - MOVL CX, ·sArgc(SB) - MOVL DX, ·sArgv(SB) - - SUBQ $32, SP // stack for the first 4 syscall params - - MOVQ ·sName(SB), CX - MOVQ $·servicectlhandler(SB), DX - MOVQ ·cRegisterServiceCtrlHandlerW(SB), AX - CALL AX - CMPQ AX, $0 - JE exit - MOVQ AX, ·ssHandle(SB) - - MOVQ ·goWaitsH(SB), CX - MOVQ ·cSetEvent(SB), AX - CALL AX - - MOVQ ·cWaitsH(SB), CX - MOVQ $4294967295, DX - MOVQ ·cWaitForSingleObject(SB), AX - CALL AX - -exit: - ADDQ $32, SP - RET - -// I do not know why, but this seems to be the only way to call -// ctlHandlerProc on Windows 7. - -// func servicectlhandler(ctl uint32) uintptr -TEXT ·servicectlhandler(SB),7,$0 - MOVQ ·ctlHandlerProc(SB), AX - JMP AX diff --git a/Godeps/_workspace/src/golang.org/x/sys/windows/syscall.go b/Godeps/_workspace/src/golang.org/x/sys/windows/syscall.go index a8cc609b32..281cd669f9 100644 --- a/Godeps/_workspace/src/golang.org/x/sys/windows/syscall.go +++ b/Godeps/_workspace/src/golang.org/x/sys/windows/syscall.go @@ -19,7 +19,7 @@ // These calls return err == nil to indicate success; otherwise // err represents an operating system error describing the failure and // holds a value of type syscall.Errno. -package windows // import "golang.org/x/sys/windows" +package windows import ( "syscall" From 7b26d7e3009f57409cbd15b5cd42e240c1a13510 Mon Sep 17 00:00:00 2001 From: Anusha Ragunathan Date: Tue, 27 Sep 2016 13:54:25 -0700 Subject: [PATCH 093/799] Make libnetwork understand pluginv2. As part of daemon init, network and ipam drivers are passed a pluginstore object that implements the plugin/getter interface. Use this interface methods in libnetwork to interact with network plugins. This interface provides the new and improved pluginv2 functionality and falls back to pluginv1 (legacy) if necessary. Signed-off-by: Anusha Ragunathan --- cmd/ovrouter/ovrouter.go | 5 +++++ config/config.go | 9 +++++++++ controller.go | 9 +++++++-- driverapi/driverapi.go | 3 +++ drivers/ipvlan/ipvlan_test.go | 5 +++++ drivers/macvlan/macvlan_test.go | 5 +++++ drivers/overlay/overlay_test.go | 5 +++++ drivers/remote/driver.go | 7 ++++++- drvregistry/drvregistry.go | 26 +++++++++++++++++--------- drvregistry/drvregistry_test.go | 2 +- ipamapi/contract.go | 3 +++ ipams/remote/remote.go | 8 +++++++- 12 files changed, 73 insertions(+), 14 deletions(-) diff --git a/cmd/ovrouter/ovrouter.go b/cmd/ovrouter/ovrouter.go index 8e286d0729..538e28aaf4 100644 --- a/cmd/ovrouter/ovrouter.go +++ b/cmd/ovrouter/ovrouter.go @@ -7,6 +7,7 @@ import ( "os/signal" "github.com/docker/docker/pkg/reexec" + "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/drivers/overlay" "github.com/docker/libnetwork/netlabel" @@ -24,6 +25,10 @@ type endpoint struct { name string } +func (r *router) GetPluginGetter() getter.PluginGetter { + return nil +} + func (r *router) RegisterDriver(name string, driver driverapi.Driver, c driverapi.Capability) error { r.d = driver return nil diff --git a/config/config.go b/config/config.go index 832412ec74..0e4780e489 100644 --- a/config/config.go +++ b/config/config.go @@ -6,6 +6,7 @@ import ( "github.com/BurntSushi/toml" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" + "github.com/docker/docker/plugin/getter" "github.com/docker/go-connections/tlsconfig" "github.com/docker/libkv/store" "github.com/docker/libnetwork/cluster" @@ -20,6 +21,7 @@ type Config struct { Cluster ClusterCfg Scopes map[string]*datastore.ScopeCfg ActiveSandboxes map[string]interface{} + PluginGetter getter.PluginGetter } // DaemonCfg represents libnetwork core configuration @@ -205,6 +207,13 @@ func OptionExecRoot(execRoot string) Option { } } +// OptionPluginGetter returns a plugingetter for remote drivers. +func OptionPluginGetter(pg getter.PluginGetter) Option { + return func(c *Config) { + c.PluginGetter = pg + } +} + // ProcessOptions processes options and stores it in config func (c *Config) ProcessOptions(options ...Option) { for _, opt := range options { diff --git a/controller.go b/controller.go index a1906da322..50ff1195a9 100644 --- a/controller.go +++ b/controller.go @@ -55,6 +55,7 @@ import ( "github.com/docker/docker/pkg/locker" "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/stringid" + "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/cluster" "github.com/docker/libnetwork/config" "github.com/docker/libnetwork/datastore" @@ -178,7 +179,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) { return nil, err } - drvRegistry, err := drvregistry.New(c.getStore(datastore.LocalScope), c.getStore(datastore.GlobalScope), c.RegisterDriver, nil) + drvRegistry, err := drvregistry.New(c.getStore(datastore.LocalScope), c.getStore(datastore.GlobalScope), c.RegisterDriver, nil, c.cfg.PluginGetter) if err != nil { return nil, err } @@ -601,6 +602,10 @@ func (c *controller) isDistributedControl() bool { return !c.isManager() && !c.isAgent() } +func (c *controller) GetPluginGetter() getter.PluginGetter { + return c.drvRegistry.GetPluginGetter() +} + func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error { c.Lock() hd := c.discovery @@ -1074,7 +1079,7 @@ func (c *controller) loadDriver(networkType string) error { } func (c *controller) loadIPAMDriver(name string) error { - if _, err := plugins.Get(name, ipamapi.PluginEndpointType); err != nil { + if _, err := c.GetPluginGetter().Get(name, ipamapi.PluginEndpointType, getter.LOOKUP); err != nil { if err == plugins.ErrNotFound { return types.NotFoundErrorf(err.Error()) } diff --git a/driverapi/driverapi.go b/driverapi/driverapi.go index ccb7936e2a..51a43e780b 100644 --- a/driverapi/driverapi.go +++ b/driverapi/driverapi.go @@ -3,6 +3,7 @@ package driverapi import ( "net" + "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/discoverapi" ) @@ -139,6 +140,8 @@ type JoinInfo interface { // DriverCallback provides a Callback interface for Drivers into LibNetwork type DriverCallback interface { + // GetPluginGetter returns the pluginv2 getter. + GetPluginGetter() getter.PluginGetter // RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance RegisterDriver(name string, driver Driver, capability Capability) error } diff --git a/drivers/ipvlan/ipvlan_test.go b/drivers/ipvlan/ipvlan_test.go index 6d4ee218fc..b4650f469a 100644 --- a/drivers/ipvlan/ipvlan_test.go +++ b/drivers/ipvlan/ipvlan_test.go @@ -3,6 +3,7 @@ package ipvlan import ( "testing" + "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/driverapi" _ "github.com/docker/libnetwork/testutils" ) @@ -14,6 +15,10 @@ type driverTester struct { d *driver } +func (dt *driverTester) GetPluginGetter() getter.PluginGetter { + return nil +} + func (dt *driverTester) RegisterDriver(name string, drv driverapi.Driver, cap driverapi.Capability) error { if name != testNetworkType { diff --git a/drivers/macvlan/macvlan_test.go b/drivers/macvlan/macvlan_test.go index 243df5fc0b..76d73f65f2 100644 --- a/drivers/macvlan/macvlan_test.go +++ b/drivers/macvlan/macvlan_test.go @@ -3,6 +3,7 @@ package macvlan import ( "testing" + "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/driverapi" _ "github.com/docker/libnetwork/testutils" ) @@ -14,6 +15,10 @@ type driverTester struct { d *driver } +func (dt *driverTester) GetPluginGetter() getter.PluginGetter { + return nil +} + func (dt *driverTester) RegisterDriver(name string, drv driverapi.Driver, cap driverapi.Capability) error { if name != testNetworkType { diff --git a/drivers/overlay/overlay_test.go b/drivers/overlay/overlay_test.go index 1d6012904f..c15886be7f 100644 --- a/drivers/overlay/overlay_test.go +++ b/drivers/overlay/overlay_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/docker/docker/plugin/getter" "github.com/docker/libkv/store/consul" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" @@ -67,6 +68,10 @@ func cleanupDriver(t *testing.T, dt *driverTester) { } } +func (dt *driverTester) GetPluginGetter() getter.PluginGetter { + return nil +} + func (dt *driverTester) RegisterDriver(name string, drv driverapi.Driver, cap driverapi.Capability) error { if name != testNetworkType { diff --git a/drivers/remote/driver.go b/drivers/remote/driver.go index 9fa253bb29..7794d1964f 100644 --- a/drivers/remote/driver.go +++ b/drivers/remote/driver.go @@ -29,7 +29,12 @@ func newDriver(name string, client *plugins.Client) driverapi.Driver { // Init makes sure a remote driver is registered when a network driver // plugin is activated. func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { - plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) { + // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. + handleFunc := plugins.Handle + if pg := dc.GetPluginGetter(); pg != nil { + handleFunc = pg.Handle + } + handleFunc(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) { // negotiate driver capability with client d := newDriver(name, client) c, err := d.(*driver).getCapabilities() diff --git a/drvregistry/drvregistry.go b/drvregistry/drvregistry.go index d2cf781193..af4dee4264 100644 --- a/drvregistry/drvregistry.go +++ b/drvregistry/drvregistry.go @@ -5,6 +5,7 @@ import ( "strings" "sync" + "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/types" @@ -28,10 +29,11 @@ type ipamTable map[string]*ipamData // DrvRegistry holds the registry of all network drivers and IPAM drivers that it knows about. type DrvRegistry struct { sync.Mutex - drivers driverTable - ipamDrivers ipamTable - dfn DriverNotifyFunc - ifn IPAMNotifyFunc + drivers driverTable + ipamDrivers ipamTable + dfn DriverNotifyFunc + ifn IPAMNotifyFunc + pluginGetter getter.PluginGetter } // Functors definition @@ -52,12 +54,13 @@ type IPAMNotifyFunc func(name string, driver ipamapi.Ipam, cap *ipamapi.Capabili type DriverNotifyFunc func(name string, driver driverapi.Driver, capability driverapi.Capability) error // New retruns a new driver registry handle. -func New(lDs, gDs interface{}, dfn DriverNotifyFunc, ifn IPAMNotifyFunc) (*DrvRegistry, error) { +func New(lDs, gDs interface{}, dfn DriverNotifyFunc, ifn IPAMNotifyFunc, pg getter.PluginGetter) (*DrvRegistry, error) { r := &DrvRegistry{ - drivers: make(driverTable), - ipamDrivers: make(ipamTable), - dfn: dfn, - ifn: ifn, + drivers: make(driverTable), + ipamDrivers: make(ipamTable), + dfn: dfn, + ifn: ifn, + pluginGetter: pg, } return r, nil @@ -149,6 +152,11 @@ func (r *DrvRegistry) IPAMDefaultAddressSpaces(name string) (string, string, err return i.defaultLocalAddressSpace, i.defaultGlobalAddressSpace, nil } +// GetPluginGetter returns the plugingetter +func (r *DrvRegistry) GetPluginGetter() getter.PluginGetter { + return r.pluginGetter +} + // RegisterDriver registers the network driver when it gets discovered. func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capability driverapi.Capability) error { if strings.TrimSpace(ntype) == "" { diff --git a/drvregistry/drvregistry_test.go b/drvregistry/drvregistry_test.go index 0b1f7a6843..e52e28c28b 100644 --- a/drvregistry/drvregistry_test.go +++ b/drvregistry/drvregistry_test.go @@ -88,7 +88,7 @@ func (m *mockDriver) EventNotify(etype driverapi.EventType, nid, tableName, key } func getNew(t *testing.T) *DrvRegistry { - reg, err := New(nil, nil, nil, nil) + reg, err := New(nil, nil, nil, nil, nil) if err != nil { t.Fatal(err) } diff --git a/ipamapi/contract.go b/ipamapi/contract.go index a34d4a5c85..2800282ee0 100644 --- a/ipamapi/contract.go +++ b/ipamapi/contract.go @@ -4,6 +4,7 @@ package ipamapi import ( "net" + "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/discoverapi" "github.com/docker/libnetwork/types" ) @@ -25,6 +26,8 @@ const ( // Callback provides a Callback interface for registering an IPAM instance into LibNetwork type Callback interface { + // GetPluginGetter returns the pluginv2 getter. + GetPluginGetter() getter.PluginGetter // RegisterIpamDriver provides a way for Remote drivers to dynamically register with libnetwork RegisterIpamDriver(name string, driver Ipam) error // RegisterIpamDriverWithCapabilities provides a way for Remote drivers to dynamically register with libnetwork and specify capabilities diff --git a/ipams/remote/remote.go b/ipams/remote/remote.go index 4ad3287e66..ab00fc6fe7 100644 --- a/ipams/remote/remote.go +++ b/ipams/remote/remote.go @@ -30,7 +30,13 @@ func newAllocator(name string, client *plugins.Client) ipamapi.Ipam { // Init registers a remote ipam when its plugin is activated func Init(cb ipamapi.Callback, l, g interface{}) error { - plugins.Handle(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) { + + // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. + handleFunc := plugins.Handle + if pg := cb.GetPluginGetter(); pg != nil { + handleFunc = pg.Handle + } + handleFunc(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) { a := newAllocator(name, client) if cps, err := a.(*allocator).getCapabilities(); err == nil { if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil { From 81757138e2eeb79242a607c54ba51c4f0a85d5ad Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Thu, 29 Sep 2016 15:01:44 -0700 Subject: [PATCH 094/799] Clear ingress resources on graceful shutdown Signed-off-by: Alessandro Boch --- controller.go | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/controller.go b/controller.go index 50ff1195a9..8c3c3a1eae 100644 --- a/controller.go +++ b/controller.go @@ -324,27 +324,7 @@ func (c *controller) clusterAgentInit() { c.agentClose() c.cleanupServiceBindings("") - c.Lock() - ingressSandbox := c.ingressSandbox - c.ingressSandbox = nil - c.Unlock() - - if ingressSandbox != nil { - if err := ingressSandbox.Delete(); err != nil { - log.Warnf("Could not delete ingress sandbox while leaving: %v", err) - } - } - - n, err := c.NetworkByName("ingress") - if err != nil { - log.Warnf("Could not find ingress network while leaving: %v", err) - } - - if n != nil { - if err := n.Delete(); err != nil { - log.Warnf("Could not delete ingress network while leaving: %v", err) - } - } + c.clearIngress(true) return } @@ -1108,7 +1088,32 @@ func (c *controller) getIPAMDriver(name string) (ipamapi.Ipam, *ipamapi.Capabili } func (c *controller) Stop() { + c.clearIngress(false) c.closeStores() c.stopExternalKeyListener() osl.GC() } + +func (c *controller) clearIngress(clusterLeave bool) { + c.Lock() + ingressSandbox := c.ingressSandbox + c.ingressSandbox = nil + c.Unlock() + + if ingressSandbox != nil { + if err := ingressSandbox.Delete(); err != nil { + log.Warnf("Could not delete ingress sandbox while leaving: %v", err) + } + } + + n, err := c.NetworkByName("ingress") + if err != nil && clusterLeave { + log.Warnf("Could not find ingress network while leaving: %v", err) + } + + if n != nil { + if err := n.Delete(); err != nil { + log.Warnf("Could not delete ingress network while leaving: %v", err) + } + } +} From 149be9f9687593a21851321ab90f11aebbde7ee7 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 3 Oct 2016 09:50:02 -0700 Subject: [PATCH 095/799] Do not hold ack channel in ack table after closing Once the bulksync ack channel is closed remove it from the ack table right away. There is no reason to keep it in the ack table and later delete it in the ack waiter. Ack waiter anyways has reference to the channel on which it is waiting. Signed-off-by: Jana Radhakrishnan --- networkdb/cluster.go | 4 ---- networkdb/delegate.go | 5 +++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index c3bfdd4051..37bb3536f4 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -559,10 +559,6 @@ func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited b case <-t.C: logrus.Errorf("Bulk sync to node %s timed out", node) case <-ch: - nDB.Lock() - delete(nDB.bulkSyncAckTbl, node) - nDB.Unlock() - logrus.Debugf("%s: Bulk sync to node %s took %s", nDB.config.NodeName, node, time.Now().Sub(startTime)) } t.Stop() diff --git a/networkdb/delegate.go b/networkdb/delegate.go index eb8d18557d..e886cfcab2 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -318,12 +318,13 @@ func (nDB *NetworkDB) handleBulkSync(buf []byte) { // Don't respond to a bulk sync which was not unsolicited if !bsm.Unsolicited { - nDB.RLock() + nDB.Lock() ch, ok := nDB.bulkSyncAckTbl[bsm.NodeName] - nDB.RUnlock() if ok { close(ch) + delete(nDB.bulkSyncAckTbl, bsm.NodeName) } + nDB.Unlock() return } From adb4e0e1bee7910e07e127aab41f85f68fb97c90 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 3 Oct 2016 16:48:43 -0700 Subject: [PATCH 096/799] WIP: Update golang version to 1.7.1 Signed-off-by: Jana Radhakrishnan --- Dockerfile.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.build b/Dockerfile.build index cabcefe0ef..08947575ae 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -1,4 +1,4 @@ -FROM golang:1.5.4 +FROM golang:1.7.1 RUN apt-get update && apt-get -y install iptables RUN go get github.com/tools/godep \ From 8dd6270f208ce449ec69140a2b7103d8190189cc Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 3 Oct 2016 15:15:09 -0700 Subject: [PATCH 097/799] Do not add names to ingress network Do not add service discovery names to ingress network as this is a routing only network and no intra-cluster discovery should happen in that network. This fixes the ambiguity and resolving names between services which are both publishing ports and also attached to same another network. Signed-off-by: Jana Radhakrishnan --- network.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/network.go b/network.go index 6b35bc628b..4901c91bc7 100644 --- a/network.go +++ b/network.go @@ -1059,6 +1059,12 @@ func delNameToIP(svcMap map[string][]net.IP, name string, epIP net.IP) { } func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool) { + // Do not add service names for ingress network as this is a + // routing only network + if n.ingress { + return + } + c := n.getController() c.Lock() defer c.Unlock() @@ -1086,6 +1092,12 @@ func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUp } func (n *network) deleteSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool) { + // Do not delete service names from ingress network as this is a + // routing only network + if n.ingress { + return + } + c := n.getController() c.Lock() defer c.Unlock() From 8ff6817b8b18fd509235773193eefa0db6f39b7a Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Tue, 4 Oct 2016 09:35:45 -0700 Subject: [PATCH 098/799] networkdb: fix race in access to nodes len Signed-off-by: Alexander Morozov --- networkdb/cluster.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 37bb3536f4..fc6ac698d8 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -112,14 +112,20 @@ func (nDB *NetworkDB) clusterInit() error { nDB.networkBroadcasts = &memberlist.TransmitLimitedQueue{ NumNodes: func() int { - return len(nDB.nodes) + nDB.RLock() + num := len(nDB.nodes) + nDB.RUnlock() + return num }, RetransmitMult: config.RetransmitMult, } nDB.nodeBroadcasts = &memberlist.TransmitLimitedQueue{ NumNodes: func() int { - return len(nDB.nodes) + nDB.RLock() + num := len(nDB.nodes) + nDB.RUnlock() + return num }, RetransmitMult: config.RetransmitMult, } From 6b6d230a1922ae1a53b4c474ea7b565419f29b67 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 30 Jun 2016 05:48:14 -0700 Subject: [PATCH 099/799] Add support for NetworkAllocate and NetworkFree in remote driver Also added an API to return list of builtin network drivers Signed-off-by: Madhu Venugopal --- controller.go | 14 ++++++++++++++ drivers/remote/api/api.go | 32 ++++++++++++++++++++++++++++++++ drivers/remote/driver.go | 15 ++++++++++++--- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/controller.go b/controller.go index 8c3c3a1eae..d37e136636 100644 --- a/controller.go +++ b/controller.go @@ -75,6 +75,9 @@ type NetworkController interface { // ID provides a unique identity for the controller ID() string + // BuiltinDrivers returns list of builtin drivers + BuiltinDrivers() []string + // Config method returns the bootup configuration for the controller Config() config.Config @@ -463,6 +466,17 @@ func (c *controller) ID() string { return c.id } +func (c *controller) BuiltinDrivers() []string { + drivers := []string{} + for _, i := range getInitializers() { + if i.ntype == "remote" { + continue + } + drivers = append(drivers, i.ntype) + } + return drivers +} + func (c *controller) validateHostDiscoveryConfig() bool { if c.cfg == nil || c.cfg.Cluster.Discovery == "" || c.cfg.Cluster.Address == "" { return false diff --git a/drivers/remote/api/api.go b/drivers/remote/api/api.go index c40a80bb87..f9a341c540 100644 --- a/drivers/remote/api/api.go +++ b/drivers/remote/api/api.go @@ -27,6 +27,38 @@ type GetCapabilityResponse struct { Scope string } +// AllocateNetworkRequest requests allocation of new network by manager +type AllocateNetworkRequest struct { + // A network ID that remote plugins are expected to store for future + // reference. + NetworkID string + + // A free form map->object interface for communication of options. + Options map[string]string + + // IPAMData contains the address pool information for this network + IPv4Data, IPv6Data []driverapi.IPAMData +} + +// AllocateNetworkResponse is the response to the AllocateNetworkRequest. +type AllocateNetworkResponse struct { + Response + // A free form plugin specific string->string object to be sent in + // CreateNetworkRequest call in the libnetwork agents + Options map[string]string +} + +// FreeNetworkRequest is the request to free allocated network in the manager +type FreeNetworkRequest struct { + // The ID of the network to be freed. + NetworkID string +} + +// FreeNetworkResponse is the response to a request for freeing a network. +type FreeNetworkResponse struct { + Response +} + // CreateNetworkRequest requests a new network. type CreateNetworkRequest struct { // A network ID that remote plugins are expected to store for future diff --git a/drivers/remote/driver.go b/drivers/remote/driver.go index 7794d1964f..3452eb9db1 100644 --- a/drivers/remote/driver.go +++ b/drivers/remote/driver.go @@ -88,12 +88,21 @@ func (d *driver) call(methodName string, arg interface{}, retVal maybeError) err return nil } -func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { - return nil, types.NotImplementedErrorf("not implemented") +func (d *driver) NetworkAllocate(id string, options map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { + create := &api.AllocateNetworkRequest{ + NetworkID: id, + Options: options, + IPv4Data: ipV4Data, + IPv6Data: ipV6Data, + } + retVal := api.AllocateNetworkResponse{} + err := d.call("AllocateNetwork", create, &retVal) + return retVal.Options, err } func (d *driver) NetworkFree(id string) error { - return types.NotImplementedErrorf("not implemented") + fr := &api.FreeNetworkRequest{NetworkID: id} + return d.call("FreeNetwork", fr, &api.FreeNetworkResponse{}) } func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { From 1ed278f68c079fa8886442de54785642003e6de4 Mon Sep 17 00:00:00 2001 From: Shayan Pooya Date: Wed, 28 Sep 2016 19:41:14 -0700 Subject: [PATCH 100/799] Handle containers with different network drivers There is no guarantees that the ep and extEp are using the same driver. If they are not using the same drivers, the driver for ep will not know about the networks of extEp and fails the RevokeExternalConnectivity call. Signed-off-by: Shayan Pooya --- endpoint.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/endpoint.go b/endpoint.go index 1c75b6fea5..65a7295424 100644 --- a/endpoint.go +++ b/endpoint.go @@ -513,14 +513,22 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { if moveExtConn { if extEp != nil { log.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) - if err = d.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil { + extN, err := extEp.getNetworkFromStore() + if err != nil { + return fmt.Errorf("failed to get network from store during join: %v", err) + } + extD, err := extN.driver(true) + if err != nil { + return fmt.Errorf("failed to join endpoint: %v", err) + } + if err = extD.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil { return types.InternalErrorf( "driver failed revoking external connectivity on endpoint %s (%s): %v", extEp.Name(), extEp.ID(), err) } defer func() { if err != nil { - if e := d.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil { + if e := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil { log.Warnf("Failed to roll-back external connectivity on endpoint %s (%s): %v", extEp.Name(), extEp.ID(), e) } @@ -699,7 +707,15 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) extEp = sb.getGatewayEndpoint() if moveExtConn && extEp != nil { log.Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) - if err := d.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil { + extN, err := extEp.getNetworkFromStore() + if err != nil { + return fmt.Errorf("failed to get network from store during leave: %v", err) + } + extD, err := extN.driver(true) + if err != nil { + return fmt.Errorf("failed to leave endpoint: %v", err) + } + if err := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil { log.Warnf("driver failed programming external connectivity on endpoint %s: (%s) %v", extEp.Name(), extEp.ID(), err) } From a9a4aaf382589902d0bda9ef0af3034f2b926812 Mon Sep 17 00:00:00 2001 From: Anusha Ragunathan Date: Fri, 7 Oct 2016 11:58:10 -0700 Subject: [PATCH 101/799] Update plugingetter import path. Signed-off-by: Anusha Ragunathan --- Godeps/Godeps.json | 98 +++++++++---------- .../plugingetter/getter.go} | 2 +- .../docker/docker/pkg/term/term_windows.go | 4 +- cmd/ovrouter/ovrouter.go | 4 +- config/config.go | 6 +- controller.go | 6 +- driverapi/driverapi.go | 4 +- drivers/ipvlan/ipvlan_test.go | 4 +- drivers/macvlan/macvlan_test.go | 4 +- drivers/overlay/overlay_test.go | 4 +- drvregistry/drvregistry.go | 8 +- ipamapi/contract.go | 4 +- 12 files changed, 74 insertions(+), 74 deletions(-) rename Godeps/_workspace/src/github.com/docker/docker/{plugin/getter/interface.go => pkg/plugingetter/getter.go} (96%) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 57b67187ab..c3fe20f234 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -84,118 +84,118 @@ }, { "ImportPath": "github.com/docker/docker/api/types/filters", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/api/types/network", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/api/types/versions", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/opts", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/discovery", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/discovery/kv", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/homedir", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/ioutils", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/locker", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/longpath", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/mount", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/parsers/kernel", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" + }, + { + "ImportPath": "github.com/docker/docker/pkg/plugingetter", + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/plugins", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/plugins/transport", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/random", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/reexec", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/signal", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/stringid", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/symlink", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/system", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/term", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/docker/pkg/term/windows", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" - }, - { - "ImportPath": "github.com/docker/docker/plugin/getter", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1792-g1de5043", - "Rev": "1de5043f4e7f4283909eac0f2268e701395d7ad9" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", + "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" }, { "ImportPath": "github.com/docker/go-connections/sockets", diff --git a/Godeps/_workspace/src/github.com/docker/docker/plugin/getter/interface.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go similarity index 96% rename from Godeps/_workspace/src/github.com/docker/docker/plugin/getter/interface.go rename to Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go index 12558437e6..cd8214cae9 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/plugin/getter/interface.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go @@ -1,4 +1,4 @@ -package getter +package plugingetter import "github.com/docker/docker/pkg/plugins" diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go index 11a16fdea8..a91f07e482 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go @@ -71,8 +71,8 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { } } - if os.Getenv("ConEmuANSI") == "ON" { - // The ConEmu terminal emulates ANSI on output streams well. + if os.Getenv("ConEmuANSI") == "ON" || os.Getenv("ConsoleZVersion") != "" { + // The ConEmu and ConsoleZ terminals emulate ANSI on output streams well. emulateStdin = true emulateStdout = false emulateStderr = false diff --git a/cmd/ovrouter/ovrouter.go b/cmd/ovrouter/ovrouter.go index 538e28aaf4..0a4673c8af 100644 --- a/cmd/ovrouter/ovrouter.go +++ b/cmd/ovrouter/ovrouter.go @@ -6,8 +6,8 @@ import ( "os" "os/signal" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/reexec" - "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/drivers/overlay" "github.com/docker/libnetwork/netlabel" @@ -25,7 +25,7 @@ type endpoint struct { name string } -func (r *router) GetPluginGetter() getter.PluginGetter { +func (r *router) GetPluginGetter() plugingetter.PluginGetter { return nil } diff --git a/config/config.go b/config/config.go index 0e4780e489..8c3af13b22 100644 --- a/config/config.go +++ b/config/config.go @@ -6,7 +6,7 @@ import ( "github.com/BurntSushi/toml" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" - "github.com/docker/docker/plugin/getter" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/go-connections/tlsconfig" "github.com/docker/libkv/store" "github.com/docker/libnetwork/cluster" @@ -21,7 +21,7 @@ type Config struct { Cluster ClusterCfg Scopes map[string]*datastore.ScopeCfg ActiveSandboxes map[string]interface{} - PluginGetter getter.PluginGetter + PluginGetter plugingetter.PluginGetter } // DaemonCfg represents libnetwork core configuration @@ -208,7 +208,7 @@ func OptionExecRoot(execRoot string) Option { } // OptionPluginGetter returns a plugingetter for remote drivers. -func OptionPluginGetter(pg getter.PluginGetter) Option { +func OptionPluginGetter(pg plugingetter.PluginGetter) Option { return func(c *Config) { c.PluginGetter = pg } diff --git a/controller.go b/controller.go index 8c3c3a1eae..f7b527e3b5 100644 --- a/controller.go +++ b/controller.go @@ -53,9 +53,9 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" "github.com/docker/docker/pkg/locker" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/stringid" - "github.com/docker/docker/plugin/getter" "github.com/docker/libnetwork/cluster" "github.com/docker/libnetwork/config" "github.com/docker/libnetwork/datastore" @@ -582,7 +582,7 @@ func (c *controller) isDistributedControl() bool { return !c.isManager() && !c.isAgent() } -func (c *controller) GetPluginGetter() getter.PluginGetter { +func (c *controller) GetPluginGetter() plugingetter.PluginGetter { return c.drvRegistry.GetPluginGetter() } @@ -1059,7 +1059,7 @@ func (c *controller) loadDriver(networkType string) error { } func (c *controller) loadIPAMDriver(name string) error { - if _, err := c.GetPluginGetter().Get(name, ipamapi.PluginEndpointType, getter.LOOKUP); err != nil { + if _, err := c.GetPluginGetter().Get(name, ipamapi.PluginEndpointType, plugingetter.LOOKUP); err != nil { if err == plugins.ErrNotFound { return types.NotFoundErrorf(err.Error()) } diff --git a/driverapi/driverapi.go b/driverapi/driverapi.go index 51a43e780b..98bc60ac9d 100644 --- a/driverapi/driverapi.go +++ b/driverapi/driverapi.go @@ -3,7 +3,7 @@ package driverapi import ( "net" - "github.com/docker/docker/plugin/getter" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/libnetwork/discoverapi" ) @@ -141,7 +141,7 @@ type JoinInfo interface { // DriverCallback provides a Callback interface for Drivers into LibNetwork type DriverCallback interface { // GetPluginGetter returns the pluginv2 getter. - GetPluginGetter() getter.PluginGetter + GetPluginGetter() plugingetter.PluginGetter // RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance RegisterDriver(name string, driver Driver, capability Capability) error } diff --git a/drivers/ipvlan/ipvlan_test.go b/drivers/ipvlan/ipvlan_test.go index b4650f469a..207bfd2ab8 100644 --- a/drivers/ipvlan/ipvlan_test.go +++ b/drivers/ipvlan/ipvlan_test.go @@ -3,7 +3,7 @@ package ipvlan import ( "testing" - "github.com/docker/docker/plugin/getter" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/libnetwork/driverapi" _ "github.com/docker/libnetwork/testutils" ) @@ -15,7 +15,7 @@ type driverTester struct { d *driver } -func (dt *driverTester) GetPluginGetter() getter.PluginGetter { +func (dt *driverTester) GetPluginGetter() plugingetter.PluginGetter { return nil } diff --git a/drivers/macvlan/macvlan_test.go b/drivers/macvlan/macvlan_test.go index 76d73f65f2..f9a18d5b47 100644 --- a/drivers/macvlan/macvlan_test.go +++ b/drivers/macvlan/macvlan_test.go @@ -3,7 +3,7 @@ package macvlan import ( "testing" - "github.com/docker/docker/plugin/getter" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/libnetwork/driverapi" _ "github.com/docker/libnetwork/testutils" ) @@ -15,7 +15,7 @@ type driverTester struct { d *driver } -func (dt *driverTester) GetPluginGetter() getter.PluginGetter { +func (dt *driverTester) GetPluginGetter() plugingetter.PluginGetter { return nil } diff --git a/drivers/overlay/overlay_test.go b/drivers/overlay/overlay_test.go index c15886be7f..6d2127311d 100644 --- a/drivers/overlay/overlay_test.go +++ b/drivers/overlay/overlay_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/docker/docker/plugin/getter" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/libkv/store/consul" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" @@ -68,7 +68,7 @@ func cleanupDriver(t *testing.T, dt *driverTester) { } } -func (dt *driverTester) GetPluginGetter() getter.PluginGetter { +func (dt *driverTester) GetPluginGetter() plugingetter.PluginGetter { return nil } diff --git a/drvregistry/drvregistry.go b/drvregistry/drvregistry.go index af4dee4264..a9a7368025 100644 --- a/drvregistry/drvregistry.go +++ b/drvregistry/drvregistry.go @@ -5,7 +5,7 @@ import ( "strings" "sync" - "github.com/docker/docker/plugin/getter" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/types" @@ -33,7 +33,7 @@ type DrvRegistry struct { ipamDrivers ipamTable dfn DriverNotifyFunc ifn IPAMNotifyFunc - pluginGetter getter.PluginGetter + pluginGetter plugingetter.PluginGetter } // Functors definition @@ -54,7 +54,7 @@ type IPAMNotifyFunc func(name string, driver ipamapi.Ipam, cap *ipamapi.Capabili type DriverNotifyFunc func(name string, driver driverapi.Driver, capability driverapi.Capability) error // New retruns a new driver registry handle. -func New(lDs, gDs interface{}, dfn DriverNotifyFunc, ifn IPAMNotifyFunc, pg getter.PluginGetter) (*DrvRegistry, error) { +func New(lDs, gDs interface{}, dfn DriverNotifyFunc, ifn IPAMNotifyFunc, pg plugingetter.PluginGetter) (*DrvRegistry, error) { r := &DrvRegistry{ drivers: make(driverTable), ipamDrivers: make(ipamTable), @@ -153,7 +153,7 @@ func (r *DrvRegistry) IPAMDefaultAddressSpaces(name string) (string, string, err } // GetPluginGetter returns the plugingetter -func (r *DrvRegistry) GetPluginGetter() getter.PluginGetter { +func (r *DrvRegistry) GetPluginGetter() plugingetter.PluginGetter { return r.pluginGetter } diff --git a/ipamapi/contract.go b/ipamapi/contract.go index 2800282ee0..090205e11f 100644 --- a/ipamapi/contract.go +++ b/ipamapi/contract.go @@ -4,7 +4,7 @@ package ipamapi import ( "net" - "github.com/docker/docker/plugin/getter" + "github.com/docker/docker/pkg/plugingetter" "github.com/docker/libnetwork/discoverapi" "github.com/docker/libnetwork/types" ) @@ -27,7 +27,7 @@ const ( // Callback provides a Callback interface for registering an IPAM instance into LibNetwork type Callback interface { // GetPluginGetter returns the pluginv2 getter. - GetPluginGetter() getter.PluginGetter + GetPluginGetter() plugingetter.PluginGetter // RegisterIpamDriver provides a way for Remote drivers to dynamically register with libnetwork RegisterIpamDriver(name string, driver Ipam) error // RegisterIpamDriverWithCapabilities provides a way for Remote drivers to dynamically register with libnetwork and specify capabilities From 93eead6d2242732b6c2ce85d746adef3cc907443 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Tue, 4 Oct 2016 15:40:47 -0700 Subject: [PATCH 102/799] fix race in serializing sandbox to string Signed-off-by: Alexander Morozov --- controller.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/controller.go b/controller.go index 8c3c3a1eae..b8b4c8e0ff 100644 --- a/controller.go +++ b/controller.go @@ -868,8 +868,9 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s if s.containerID == containerID { // If not a stub, then we already have a complete sandbox. if !s.isStub { + sbID := s.ID() c.Unlock() - return nil, types.ForbiddenErrorf("container %s is already present: %v", containerID, s) + return nil, types.ForbiddenErrorf("container %s is already present in sandbox %s", containerID, sbID) } // We already have a stub sandbox from the From 8f68ca8bdc6c6abc8c149a9d3d967714cea2b464 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 10 Oct 2016 11:56:03 -0700 Subject: [PATCH 103/799] Run API check to assert xfrm modules - When docker is run inside a container, the infrastructure needed by modprobe is not always available, causing the xfrm module load to fail even when these modules are already loaded or builtin in the kernel. - In case of probe failure, before declaring the failure, run an API check by attempting the creation of a NETLINK_XFRM socket. Signed-off-by: Alessandro Boch --- ns/init_linux.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ns/init_linux.go b/ns/init_linux.go index 78529c7fbe..dd31f3e7e7 100644 --- a/ns/init_linux.go +++ b/ns/init_linux.go @@ -69,8 +69,10 @@ func NlHandle() *netlink.Handle { func getSupportedNlFamilies() []int { fams := []int{syscall.NETLINK_ROUTE} if err := loadXfrmModules(); err != nil { - log.Warnf("Could not load necessary modules for IPSEC rules: %v", err) - return fams + if checkXfrmSocket() != nil { + log.Warnf("Could not load necessary modules for IPSEC rules: %v", err) + return fams + } } return append(fams, syscall.NETLINK_XFRM) } @@ -84,3 +86,13 @@ func loadXfrmModules() error { } return nil } + +// API check on required xfrm modules (xfrm_user, xfrm_algo) +func checkXfrmSocket() error { + fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_XFRM) + if err != nil { + return err + } + syscall.Close(fd) + return nil +} From eacb25db31d7b5c541efa4b2ec7ffdfc1f6860fc Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Tue, 11 Oct 2016 15:20:15 -0700 Subject: [PATCH 104/799] networkdb: fix race in deleteNetwork There are multiple places which reads from that slice(i.e. bulkSync). Signed-off-by: Alexander Morozov --- networkdb/networkdb.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index a8c942c9cc..816a07ce71 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -496,14 +496,14 @@ func (nDB *NetworkDB) addNetworkNode(nid string, nodeName string) { // this func (nDB *NetworkDB) deleteNetworkNode(nid string, nodeName string) { nodes := nDB.networkNodes[nid] - for i, name := range nodes { + newNodes := make([]string, 0, len(nodes)-1) + for _, name := range nodes { if name == nodeName { - nodes[i] = nodes[len(nodes)-1] - nodes = nodes[:len(nodes)-1] - break + continue } + newNodes = append(newNodes, name) } - nDB.networkNodes[nid] = nodes + nDB.networkNodes[nid] = newNodes } // findCommonnetworks find the networks that both this node and the From c0271afdc465b3a43553aebdd3c9b358c86e529a Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 25 May 2016 11:41:36 -0700 Subject: [PATCH 105/799] Reset endpoint port info on connectivity revoke in bridge driver - and update it to store. Otherwise after an ungraceful shutdown, at next boot there will be in store two bridge endpoints with same port-mapping data. When bridge driver will try to restore the endpoints, there will be conflicts and a container with restart policy could fail to start. Signed-off-by: Alessandro Boch --- drivers/bridge/bridge.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index 777f7b162e..64492eddc2 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -1318,6 +1318,12 @@ func (d *driver) RevokeExternalConnectivity(nid, eid string) error { logrus.Warn(err) } + endpoint.portMapping = nil + + if err = d.storeUpdate(endpoint); err != nil { + return fmt.Errorf("failed to update bridge endpoint %s to store: %v", endpoint.id[0:7], err) + } + return nil } From 529a4c3506bb34b8aaca1a3c2452a6a3d0e6d721 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 12 Oct 2016 12:01:18 -0700 Subject: [PATCH 106/799] Force go 1.7.1 in circle.yml to resolve failure to get golint Signed-off-by: Alessandro Boch --- circle.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/circle.yml b/circle.yml index a5db509c67..bd34a8f19b 100644 --- a/circle.yml +++ b/circle.yml @@ -1,4 +1,6 @@ machine: + environment: + GODIST: "go1.7.1.linux-amd64.tar.gz" services: - docker From 2c921bab71357c84de6f7795f3a0b2df521e79c0 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Fri, 30 Sep 2016 11:08:38 -0700 Subject: [PATCH 107/799] Check for presence before installing forward rules - same for links rules Signed-off-by: Alessandro Boch --- iptables/iptables.go | 55 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/iptables/iptables.go b/iptables/iptables.go index f6ddaed775..340bba6b0b 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -206,7 +206,8 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr // value" by both iptables and ip6tables. daddr = "0/0" } - args := []string{"-t", string(Nat), string(action), c.Name, + + args := []string{ "-p", proto, "-d", daddr, "--dport", strconv.Itoa(port), @@ -215,33 +216,31 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr if !c.HairpinMode { args = append(args, "!", "-i", bridgeName) } - if output, err := Raw(args...); err != nil { + if err := ProgramRule(Nat, c.Name, action, args); err != nil { return err - } else if len(output) != 0 { - return ChainError{Chain: "FORWARD", Output: output} } - if output, err := Raw("-t", string(Filter), string(action), c.Name, + args = []string{ "!", "-i", bridgeName, "-o", bridgeName, "-p", proto, "-d", destAddr, "--dport", strconv.Itoa(destPort), - "-j", "ACCEPT"); err != nil { + "-j", "ACCEPT", + } + if err := ProgramRule(Filter, c.Name, action, args); err != nil { return err - } else if len(output) != 0 { - return ChainError{Chain: "FORWARD", Output: output} } - if output, err := Raw("-t", string(Nat), string(action), "POSTROUTING", + args = []string{ "-p", proto, "-s", destAddr, "-d", destAddr, "--dport", strconv.Itoa(destPort), - "-j", "MASQUERADE"); err != nil { + "-j", "MASQUERADE", + } + if err := ProgramRule(Nat, "POSTROUTING", action, args); err != nil { return err - } else if len(output) != 0 { - return ChainError{Chain: "FORWARD", Output: output} } return nil @@ -250,31 +249,37 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr // Link adds reciprocal ACCEPT rule for two supplied IP addresses. // Traffic is allowed from ip1 to ip2 and vice-versa func (c *ChainInfo) Link(action Action, ip1, ip2 net.IP, port int, proto string, bridgeName string) error { - if output, err := Raw("-t", string(Filter), string(action), c.Name, + // forward + args := []string{ "-i", bridgeName, "-o", bridgeName, "-p", proto, "-s", ip1.String(), "-d", ip2.String(), "--dport", strconv.Itoa(port), - "-j", "ACCEPT"); err != nil { + "-j", "ACCEPT", + } + if err := ProgramRule(Filter, c.Name, action, args); err != nil { return err - } else if len(output) != 0 { - return fmt.Errorf("Error iptables forward: %s", output) } - if output, err := Raw("-t", string(Filter), string(action), c.Name, - "-i", bridgeName, "-o", bridgeName, - "-p", proto, - "-s", ip2.String(), - "-d", ip1.String(), - "--sport", strconv.Itoa(port), - "-j", "ACCEPT"); err != nil { + // reverse + args[7], args[9] = args[9], args[7] + args[10] = "--sport" + if err := ProgramRule(Filter, c.Name, action, args); err != nil { return err - } else if len(output) != 0 { - return fmt.Errorf("Error iptables forward: %s", output) } return nil } +// ProgramRule adds the rule specified by args only if the +// rule is not already present in the chain. Reciprocally, +// it removes the rule only if present. +func ProgramRule(table Table, chain string, action Action, args []string) error { + if Exists(table, chain, args...) != (action == Delete) { + return nil + } + return RawCombinedOutput(append([]string{"-t", string(table), string(action), chain}, args...)...) +} + // Prerouting adds linking rule to nat/PREROUTING chain. func (c *ChainInfo) Prerouting(action Action, args ...string) error { a := []string{"-t", string(Nat), string(action), "PREROUTING"} From b757f57c5a93e7b99dc1fd38b8c0c56e56b7056f Mon Sep 17 00:00:00 2001 From: Lei Jitang Date: Thu, 13 Oct 2016 22:15:20 -0400 Subject: [PATCH 108/799] Remove driver endpoints on network deleting Signed-off-by: Lei Jitang --- drivers/bridge/bridge.go | 14 ++++++++++++++ drivers/ipvlan/ipvlan_network.go | 10 ++++++++++ drivers/macvlan/macvlan_network.go | 10 ++++++++++ drivers/overlay/ov_network.go | 12 ++++++++++++ 4 files changed, 46 insertions(+) diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index 64492eddc2..a30140feae 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -779,6 +779,20 @@ func (d *driver) DeleteNetwork(nid string) error { config := n.config n.Unlock() + // delele endpoints belong to this network + for _, ep := range n.endpoints { + if err := n.releasePorts(ep); err != nil { + logrus.Warn(err) + } + if link, err := d.nlh.LinkByName(ep.srcName); err == nil { + d.nlh.LinkDel(link) + } + + if err := d.storeDelete(ep); err != nil { + logrus.Warnf("Failed to remove bridge endpoint %s from store: %v", ep.id[0:7], err) + } + } + d.Lock() delete(d.networks, nid) d.Unlock() diff --git a/drivers/ipvlan/ipvlan_network.go b/drivers/ipvlan/ipvlan_network.go index 7a58a382d0..801fc20a7e 100644 --- a/drivers/ipvlan/ipvlan_network.go +++ b/drivers/ipvlan/ipvlan_network.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/pkg/stringid" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/ns" "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/osl" "github.com/docker/libnetwork/types" @@ -147,6 +148,15 @@ func (d *driver) DeleteNetwork(nid string) error { } } } + for _, ep := range n.endpoints { + if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil { + ns.NlHandle().LinkDel(link) + } + + if err := d.storeDelete(ep); err != nil { + logrus.Warnf("Failed to remove ipvlan endpoint %s from store: %v", ep.id[0:7], err) + } + } // delete the *network d.deleteNetwork(nid) // delete the network record from persistent cache diff --git a/drivers/macvlan/macvlan_network.go b/drivers/macvlan/macvlan_network.go index 2975596593..fcc6ccc9e1 100644 --- a/drivers/macvlan/macvlan_network.go +++ b/drivers/macvlan/macvlan_network.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/pkg/stringid" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/ns" "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/osl" "github.com/docker/libnetwork/types" @@ -151,6 +152,15 @@ func (d *driver) DeleteNetwork(nid string) error { } } } + for _, ep := range n.endpoints { + if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil { + ns.NlHandle().LinkDel(link) + } + + if err := d.storeDelete(ep); err != nil { + logrus.Warnf("Failed to remove macvlan endpoint %s from store: %v", ep.id[0:7], err) + } + } // delete the *network d.deleteNetwork(nid) // delete the network record from persistent cache diff --git a/drivers/overlay/ov_network.go b/drivers/overlay/ov_network.go index b5af0f4b04..c6bc67cab5 100644 --- a/drivers/overlay/ov_network.go +++ b/drivers/overlay/ov_network.go @@ -182,6 +182,18 @@ func (d *driver) DeleteNetwork(nid string) error { return fmt.Errorf("could not find network with id %s", nid) } + for _, ep := range n.endpoints { + if ep.ifName != "" { + if link, err := ns.NlHandle().LinkByName(ep.ifName); err != nil { + ns.NlHandle().LinkDel(link) + } + } + + if err := d.deleteEndpointFromStore(ep); err != nil { + logrus.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err) + } + + } d.deleteNetwork(nid) vnis, err := n.releaseVxlanID() From e9fe159e208f106223cce4686c9fc25f1971fe73 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 20 Sep 2016 15:59:32 +0000 Subject: [PATCH 109/799] add Created to NetworkInfo Signed-off-by: Akihiro Suda --- controller.go | 2 ++ libnetwork_internal_test.go | 5 ++++- network.go | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/controller.go b/controller.go index 351e0acccc..914287a5be 100644 --- a/controller.go +++ b/controller.go @@ -49,6 +49,7 @@ import ( "net" "strings" "sync" + "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" @@ -640,6 +641,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... generic: map[string]interface{}{netlabel.GenericData: make(map[string]string)}, ipamType: ipamapi.DefaultIPAM, id: id, + created: time.Now(), ctrlr: c, persist: true, drvOnce: &sync.Once{}, diff --git a/libnetwork_internal_test.go b/libnetwork_internal_test.go index 8bb4881cc6..8adee2a4d8 100644 --- a/libnetwork_internal_test.go +++ b/libnetwork_internal_test.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "testing" + "time" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" @@ -114,6 +115,7 @@ func TestNetworkMarshalling(t *testing.T) { "color": "blue", "superimposed": "", }, + created: time.Now(), } b, err := json.Marshal(n) @@ -133,7 +135,8 @@ func TestNetworkMarshalling(t *testing.T) { !compareIpamInfoList(n.ipamV4Info, nn.ipamV4Info) || !compareIpamConfList(n.ipamV6Config, nn.ipamV6Config) || !compareIpamInfoList(n.ipamV6Info, nn.ipamV6Info) || !compareStringMaps(n.ipamOptions, nn.ipamOptions) || - !compareStringMaps(n.labels, nn.labels) { + !compareStringMaps(n.labels, nn.labels) || + !n.created.Equal(nn.created) { t.Fatalf("JSON marsh/unmarsh failed."+ "\nOriginal:\n%#v\nDecoded:\n%#v"+ "\nOriginal ipamV4Conf: %#v\n\nDecoded ipamV4Conf: %#v"+ diff --git a/network.go b/network.go index 4901c91bc7..8a068d22e9 100644 --- a/network.go +++ b/network.go @@ -6,6 +6,7 @@ import ( "net" "strings" "sync" + "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/stringid" @@ -65,6 +66,7 @@ type NetworkInfo interface { Internal() bool Labels() map[string]string Dynamic() bool + Created() time.Time } // EndpointWalker is a client provided function which will be used to walk the Endpoints. @@ -166,6 +168,7 @@ type network struct { name string networkType string id string + created time.Time scope string labels map[string]string ipamType string @@ -208,6 +211,13 @@ func (n *network) ID() string { return n.id } +func (n *network) Created() time.Time { + n.Lock() + defer n.Unlock() + + return n.created +} + func (n *network) Type() string { n.Lock() defer n.Unlock() @@ -320,6 +330,7 @@ func (n *network) CopyTo(o datastore.KVObject) error { dstN := o.(*network) dstN.name = n.name dstN.id = n.id + dstN.created = n.created dstN.networkType = n.networkType dstN.scope = n.scope dstN.dynamic = n.dynamic @@ -397,6 +408,7 @@ func (n *network) MarshalJSON() ([]byte, error) { netMap := make(map[string]interface{}) netMap["name"] = n.name netMap["id"] = n.id + netMap["created"] = n.created netMap["networkType"] = n.networkType netMap["scope"] = n.scope netMap["labels"] = n.labels @@ -451,6 +463,14 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { } n.name = netMap["name"].(string) n.id = netMap["id"].(string) + // "created" is not available in older versions + if v, ok := netMap["created"]; ok { + // n.created is time.Time but marshalled as string + if err = n.created.UnmarshalText([]byte(v.(string))); err != nil { + log.Warnf("failed to unmarshal creation time %v: %v", v, err) + n.created = time.Time{} + } + } n.networkType = netMap["networkType"].(string) n.enableIPv6 = netMap["enableIPv6"].(bool) From b8ef8c2bab148427d911b98b48a5cdcfdc0abec3 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Fri, 14 Oct 2016 10:17:24 -0700 Subject: [PATCH 110/799] Avoid controller/service lock AB/BA situation Currently there is an instance of controller and service lock being obtained in different order which causes the AB/BA deadlock. Do not ever wrap controller lock around service lock. Signed-off-by: Jana Radhakrishnan --- service_linux.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/service_linux.go b/service_linux.go index 5e3802a823..158411d140 100644 --- a/service_linux.go +++ b/service_linux.go @@ -41,8 +41,15 @@ func newService(name string, id string, ingressPorts []*PortConfig, aliases []st func (c *controller) cleanupServiceBindings(cleanupNID string) { var cleanupFuncs []func() + c.Lock() + services := make([]*service, 0, len(c.serviceBindings)) for _, s := range c.serviceBindings { + services = append(services, s) + } + c.Unlock() + + for _, s := range services { s.Lock() for nid, lb := range s.loadBalancers { if cleanupNID != "" && nid != cleanupNID { @@ -67,7 +74,6 @@ func (c *controller) cleanupServiceBindings(cleanupNID string) { } s.Unlock() } - c.Unlock() for _, f := range cleanupFuncs { f() From 566903dd7b05cf93c309c3eb630d0a17721d347d Mon Sep 17 00:00:00 2001 From: Puneet Pruthi Date: Fri, 20 May 2016 13:23:53 -0700 Subject: [PATCH 111/799] libnetwork support for Solaris Signed-off-by: Puneet Pruthi --- Makefile | 45 +- api/api_linux_test.go | 18 + api/api_solaris_test.go | 18 + api/api_test.go | 16 +- drivers/solaris/bridge/bridge.go | 1254 ++++++++++++++++++++++++ drivers/solaris/bridge/bridge_store.go | 384 ++++++++ drivers/solaris/bridge/bridge_test.go | 675 +++++++++++++ drivers/solaris/bridge/errors.go | 119 +++ drivers/solaris/bridge/port_mapping.go | 225 +++++ drivers_solaris.go | 10 +- libnetwork_linux_test.go | 995 +++++++++++++++++++ libnetwork_test.go | 990 +------------------ netutils/utils_solaris.go | 80 +- netutils/utils_test.go | 2 + osl/sandbox_solaris.go | 24 + osl/sandbox_test.go | 2 + osl/sandbox_unsupported.go | 2 +- osl/sandbox_unsupported_test.go | 2 +- portallocator/portallocator.go | 22 - portallocator/portallocator_linux.go | 27 + portallocator/portallocator_solaris.go | 5 + portmapper/proxy.go | 32 - portmapper/proxy_linux.go | 38 + portmapper/proxy_solaris.go | 34 + store_linux_test.go | 45 + store_test.go | 37 - testutils/context_solaris.go | 25 + 27 files changed, 4030 insertions(+), 1096 deletions(-) create mode 100644 api/api_linux_test.go create mode 100644 api/api_solaris_test.go create mode 100644 drivers/solaris/bridge/bridge.go create mode 100644 drivers/solaris/bridge/bridge_store.go create mode 100644 drivers/solaris/bridge/bridge_test.go create mode 100644 drivers/solaris/bridge/errors.go create mode 100644 drivers/solaris/bridge/port_mapping.go create mode 100644 libnetwork_linux_test.go create mode 100644 osl/sandbox_solaris.go create mode 100644 portallocator/portallocator_linux.go create mode 100644 portallocator/portallocator_solaris.go create mode 100644 portmapper/proxy_linux.go create mode 100644 portmapper/proxy_solaris.go create mode 100644 store_linux_test.go create mode 100644 testutils/context_solaris.go diff --git a/Makefile b/Makefile index a130dc656d..f1d25ff339 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,14 @@ ciargs = -e CIRCLECI -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER= cidocker = docker run ${dockerargs} ${ciargs} $$EXTRA_ARGS ${container_env} ${build_image} CROSS_PLATFORMS = linux/amd64 linux/386 linux/arm windows/amd64 export PATH := $(CURDIR)/bin:$(PATH) +hostOS = ${shell go env GOHOSTOS} +ifeq (${hostOS}, solaris) + gnufind=gfind + gnutail=gtail +else + gnufind=find + gnutail=tail +endif all: ${build_image}.created build check integration-tests clean @@ -62,7 +70,40 @@ check-format: run-tests: @echo "Running tests... " @echo "mode: count" > coverage.coverprofile - @for dir in $$(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); do \ + @for dir in $$( ${gnufind} . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); do \ + if [ ${hostOS} == solaris ]; then \ + case "$$dir" in \ + "./cmd/dnet" ) \ + ;& \ + "./cmd/ovrouter" ) \ + ;& \ + "./ns" ) \ + ;& \ + "./iptables" ) \ + ;& \ + "./ipvs" ) \ + ;& \ + "./drivers/bridge" ) \ + ;& \ + "./drivers/host" ) \ + ;& \ + "./drivers/ipvlan" ) \ + ;& \ + "./drivers/macvlan" ) \ + ;& \ + "./drivers/overlay" ) \ + ;& \ + "./drivers/remote" ) \ + ;& \ + "./drivers/windows" ) \ + echo "Skipping $$dir on solaris host... "; \ + continue; \ + ;; \ + * )\ + echo "Entering $$dir ... "; \ + ;; \ + esac; \ + fi; \ if ls $$dir/*.go &> /dev/null; then \ pushd . &> /dev/null ; \ cd $$dir ; \ @@ -71,7 +112,7 @@ run-tests: if [ $$ret -ne 0 ]; then exit $$ret; fi ;\ popd &> /dev/null; \ if [ -f $$dir/profile.tmp ]; then \ - cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \ + cat $$dir/profile.tmp | ${gnutail} -n +2 >> coverage.coverprofile ; \ rm $$dir/profile.tmp ; \ fi ; \ fi ; \ diff --git a/api/api_linux_test.go b/api/api_linux_test.go new file mode 100644 index 0000000000..2e5ced023b --- /dev/null +++ b/api/api_linux_test.go @@ -0,0 +1,18 @@ +package api + +import ( + "github.com/docker/libnetwork/drivers/bridge" + "github.com/docker/libnetwork/netlabel" +) + +func GetOpsMap(bridgeName, defaultMTU string) map[string]string { + if defaultMTU == "" { + return map[string]string{ + bridge.BridgeName: bridgeName, + } + } + return map[string]string{ + bridge.BridgeName: bridgeName, + netlabel.DriverMTU: defaultMTU, + } +} diff --git a/api/api_solaris_test.go b/api/api_solaris_test.go new file mode 100644 index 0000000000..d667443e0b --- /dev/null +++ b/api/api_solaris_test.go @@ -0,0 +1,18 @@ +package api + +import ( + "github.com/docker/libnetwork/drivers/solaris/bridge" + "github.com/docker/libnetwork/netlabel" +) + +func GetOpsMap(bridgeName, defaultMTU string) map[string]string { + if defaultMTU == "" { + return map[string]string{ + bridge.BridgeName: bridgeName, + } + } + return map[string]string{ + bridge.BridgeName: bridgeName, + netlabel.DriverMTU: defaultMTU, + } +} diff --git a/api/api_test.go b/api/api_test.go index b1241188aa..ab83761239 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -15,7 +15,6 @@ import ( "github.com/docker/docker/pkg/reexec" "github.com/docker/libnetwork" "github.com/docker/libnetwork/datastore" - "github.com/docker/libnetwork/drivers/bridge" "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/testutils" @@ -225,9 +224,7 @@ func TestCreateDeleteNetwork(t *testing.T) { t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp) } - dops := map[string]string{ - bridge.BridgeName: "abc", - } + dops := GetOpsMap("abc", "") nops := map[string]string{ netlabel.EnableIPv6: "true", } @@ -273,9 +270,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) { } defer c.Stop() - ops := map[string]string{ - bridge.BridgeName: "api_test_nw", - } + ops := GetOpsMap("api_test_nw", "") nc := networkCreate{Name: "sh", NetworkType: bridgeNetType, DriverOpts: ops} body, err := json.Marshal(nc) if err != nil { @@ -544,7 +539,7 @@ func TestProcGetServices(t *testing.T) { t.Fatal(err) } - netName2 := "work-dev" + netName2 := "workdev" netOption = options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": netName2, @@ -1811,10 +1806,7 @@ func TestEndToEnd(t *testing.T) { handleRequest := NewHTTPHandler(c) - dops := map[string]string{ - bridge.BridgeName: "cdef", - netlabel.DriverMTU: "1460", - } + dops := GetOpsMap("cdef", "1460") nops := map[string]string{ netlabel.EnableIPv6: "true", } diff --git a/drivers/solaris/bridge/bridge.go b/drivers/solaris/bridge/bridge.go new file mode 100644 index 0000000000..c3a87de042 --- /dev/null +++ b/drivers/solaris/bridge/bridge.go @@ -0,0 +1,1254 @@ +// +build solaris + +package bridge + +import ( + "bufio" + "errors" + "fmt" + "net" + "os" + "os/exec" + "strconv" + "strings" + "sync" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/iptables" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/options" + "github.com/docker/libnetwork/portmapper" + "github.com/docker/libnetwork/types" +) + +const ( + networkType = "bridge" + + // DefaultBridgeName is the default name for the bridge interface managed + // by the driver when unspecified by the caller. + DefaultBridgeName = "docker0" + + // BridgeName label for bridge driver + BridgeName = "com.docker.network.bridge.name" + + // EnableIPMasquerade label for bridge driver + EnableIPMasquerade = "com.docker.network.bridge.enable_ip_masquerade" + + // EnableICC label + EnableICC = "com.docker.network.bridge.enable_icc" + + // DefaultBindingIP label + DefaultBindingIP = "com.docker.network.bridge.host_binding_ipv4" + + // DefaultBridge label + DefaultBridge = "com.docker.network.bridge.default_bridge" + + // DefaultGatewayV4AuxKey represents the default-gateway configured by the user + DefaultGatewayV4AuxKey = "DefaultGatewayIPv4" + + // DefaultGatewayV6AuxKey represents the ipv6 default-gateway configured by the user + DefaultGatewayV6AuxKey = "DefaultGatewayIPv6" +) + +// configuration info for the "bridge" driver. +type configuration struct { + EnableIPForwarding bool + EnableIPTables bool + EnableUserlandProxy bool +} + +// networkConfiguration for network specific configuration +type networkConfiguration struct { + ID string + BridgeName string + BridgeNameInternal string + EnableIPv6 bool + EnableIPMasquerade bool + EnableICC bool + Mtu int + DefaultBindingIntf string + DefaultBindingIP net.IP + DefaultBridge bool + // Internal fields set after ipam data parsing + AddressIPv4 *net.IPNet + AddressIPv6 *net.IPNet + DefaultGatewayIPv4 net.IP + DefaultGatewayIPv6 net.IP + dbIndex uint64 + dbExists bool + Internal bool +} + +// endpointConfiguration represents the user specified configuration for the sandbox endpoint +type endpointConfiguration struct { + MacAddress net.HardwareAddr + PortBindings []types.PortBinding + ExposedPorts []types.TransportPort +} + +// containerConfiguration represents the user specified configuration for a container +type containerConfiguration struct { + ParentEndpoints []string + ChildEndpoints []string +} + +// cnnectivityConfiguration represents the user specified configuration regarding the external connectivity +type connectivityConfiguration struct { + PortBindings []types.PortBinding + ExposedPorts []types.TransportPort +} + +type bridgeEndpoint struct { + id string + nid string + srcName string + addr *net.IPNet + addrv6 *net.IPNet + macAddress net.HardwareAddr + config *endpointConfiguration // User specified parameters + containerConfig *containerConfiguration + extConnConfig *connectivityConfiguration + portMapping []types.PortBinding // Operation port bindings + dbIndex uint64 + dbExists bool +} + +type bridgeInterface struct { + bridgeIPv4 *net.IPNet + bridgeIPv6 *net.IPNet + gatewayIPv4 net.IP + gatewayIPv6 net.IP +} + +type bridgeNetwork struct { + id string + bridge *bridgeInterface + config *networkConfiguration + endpoints map[string]*bridgeEndpoint // key: endpoint id + portMapper *portmapper.PortMapper + driver *driver // The network's driver + sync.Mutex +} + +type driver struct { + config *configuration + network *bridgeNetwork + natChain *iptables.ChainInfo + filterChain *iptables.ChainInfo + isolationChain *iptables.ChainInfo + networks map[string]*bridgeNetwork + store datastore.DataStore + sync.Mutex + defrouteIP net.IP +} + +// New constructs a new bridge driver +func newDriver() *driver { + return &driver{networks: map[string]*bridgeNetwork{}} +} + +// Init registers a new instance of bridge driver +func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { + d := newDriver() + if err := d.configure(config); err != nil { + return err + } + + c := driverapi.Capability{ + DataScope: datastore.LocalScope, + } + return dc.RegisterDriver(networkType, d, c) +} + +func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { + return nil, types.NotImplementedErrorf("not implemented") +} + +func (d *driver) NetworkFree(id string) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { +} + +func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { + if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" { + return types.BadRequestErrorf("ipv4 pool is empty") + } + // Sanity checks + d.Lock() + if _, ok := d.networks[id]; ok { + d.Unlock() + return types.ForbiddenErrorf("network %s exists", id) + } + d.Unlock() + + // Parse and validate the config. It should not conflict with existing networks' config + config, err := parseNetworkOptions(d, id, option) + if err != nil { + return err + } + + err = config.processIPAM(id, ipV4Data, ipV6Data) + if err != nil { + return err + } + + if err = d.createNetwork(config); err != nil { + return err + } + + return d.storeUpdate(config) +} + +func newInterface(config *networkConfiguration) *bridgeInterface { + i := &bridgeInterface{} + + i.bridgeIPv4 = config.AddressIPv4 + i.gatewayIPv4 = config.AddressIPv4.IP + if config.BridgeName == "" { + config.BridgeName = DefaultBridgeName + } + return i +} + +// This function prunes the pf.conf for the firewall +// that enable the service successfully. +func fixPFConf() error { + conf := "/etc/firewall/pf.conf" + f, err := os.Open("/etc/firewall/pf.conf") + if err != nil { + return fmt.Errorf("cannot open %s: %v", conf, err) + } + defer f.Close() + + // Look for line beginning with "REMOVE THIS LINE" + modify := false + lines := []string{} + scanner := bufio.NewScanner(f) + for scanner.Scan() { + l := scanner.Text() + if strings.Contains(l, "REMOVE THIS LINE") { + modify = true + continue + } + lines = append(lines, fmt.Sprintf("%s\n", l)) + } + if err = scanner.Err(); err != nil { + return fmt.Errorf("cannot open %s: %v", conf, err) + } + + // No changes needed to fix pf.conf + if !modify { + return nil + } + + // Write back the file removing the line found above + tmpname := "/etc/firewall/pf.conf.tmp." + strconv.Itoa(os.Getpid()) + tmp, err := os.OpenFile(tmpname, + os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return fmt.Errorf("cannot open %s: %v", tmpname, err) + } + defer tmp.Close() + for _, l := range lines { + _, err = tmp.WriteString(l) + if err != nil { + return fmt.Errorf("cannot write to %s: %v", + tmpname, err) + } + } + if err = tmp.Sync(); err != nil { + return fmt.Errorf("cannot sync %s: %v", tmpname, err) + } + if err = os.Rename(tmpname, conf); err != nil { + return fmt.Errorf("cannot rename %s to %s: %v", + tmpname, conf, err) + } + return nil +} + +func (d *driver) initFirewall() error { + out, err := exec.Command("/usr/bin/svcs", "-Ho", "state", + "firewall").Output() + if err != nil { + return fmt.Errorf("cannot check firewall state: %v", err) + } + state := strings.TrimSpace(string(out)) + if state != "online" { + if state != "disabled" { + return fmt.Errorf("firewall service is in %s state. "+ + "please enable service manually.", state) + } + if err = fixPFConf(); err != nil { + return fmt.Errorf("cannot verify pf.conf: %v", err) + } + err = exec.Command("/usr/sbin/svcadm", "enable", "-ts", + "firewall").Run() + if err != nil { + return fmt.Errorf("cannot enable firewall service: %v", err) + } + } + out, err = exec.Command("/usr/sbin/pfctl", "-sr").Output() + if err != nil { + return fmt.Errorf("failed to list firewall rules: %v", err) + } + if strings.Contains(string(out), "anchor \"_auto/docker/*\" all") { + return nil + } + pfctlCmd := "(/usr/sbin/pfctl -sr; " + + "/usr/bin/echo \"anchor \\\"_auto/docker/*\\\"\") |" + + "/usr/sbin/pfctl -f -" + err = exec.Command("/usr/bin/bash", "-c", pfctlCmd).Run() + if err != nil { + return fmt.Errorf("failed to add docker firewall rules: %v", err) + } + return nil +} + +func (d *driver) initRouting() error { + err := exec.Command("/usr/sbin/ipadm", "set-prop", "-t", + "-p", "forwarding=on", "ipv4").Run() + if err != nil { + return fmt.Errorf("cannot switch-on IP forwarding: %v", err) + } + routeCmd := "/usr/sbin/ipadm show-addr -p -o addr " + + "`/usr/sbin/route get default | /usr/bin/grep interface | " + + "/usr/bin/awk '{print $2}'`" + out, err := exec.Command("/usr/bin/bash", "-c", routeCmd).Output() + if err != nil { + return fmt.Errorf("cannot get default route: %v", err) + } + defroute := strings.SplitN(string(out), "/", 2) + d.defrouteIP = net.ParseIP(defroute[0]) + if d.defrouteIP == nil { + return &ErrNoIPAddr{} + } + return nil +} + +func (d *driver) configure(option map[string]interface{}) error { + var err error + + if err = d.initFirewall(); err != nil { + return fmt.Errorf("failed to configure firewall: %v", err) + } + if err = d.initRouting(); err != nil { + return fmt.Errorf("failed to configure routing: %v", err) + } + if err = d.initStore(option); err != nil { + return fmt.Errorf("failed to initialize datastore: %v", err) + } + + return nil +} + +func (d *driver) getNetwork(id string) (*bridgeNetwork, error) { + d.Lock() + defer d.Unlock() + + if id == "" { + return nil, types.BadRequestErrorf("invalid network id: %s", id) + } + + if nw, ok := d.networks[id]; ok { + return nw, nil + } + + return nil, types.NotFoundErrorf("network not found: %s", id) +} + +// Return a slice of networks over which caller can iterate safely +func (d *driver) getNetworks() []*bridgeNetwork { + d.Lock() + defer d.Unlock() + + ls := make([]*bridgeNetwork, 0, len(d.networks)) + for _, nw := range d.networks { + ls = append(ls, nw) + } + return ls +} + +func bridgeSetup(config *networkConfiguration) error { + var err error + var bindingIntf string + + bridgeName := config.BridgeName + gwName := fmt.Sprintf("%s_gw0", bridgeName) + gwIP := config.AddressIPv4.String() + + if config.DefaultBindingIP == nil { + // Default to net0 if bindingIP is not provided. + bindingIntf = "net0" + } else { + ipadmCmd := "/usr/sbin/ipadm show-addr -p -o addrobj,addr |" + + "/usr/bin/grep " + config.DefaultBindingIP.String() + out, err := exec.Command("/usr/bin/bash", "-c", ipadmCmd).Output() + if err != nil { + logrus.Warnf("cannot find binding interface") + return err + } + bindingIntf = strings.SplitN(string(out), "/", 2)[0] + if bindingIntf == "" { + logrus.Warnf("cannot parse binding interface %s", string(out)) + return &ErrNoIPAddr{} + } + } + config.DefaultBindingIntf = bindingIntf + + err = exec.Command("/usr/sbin/dladm", "create-etherstub", + "-t", config.BridgeNameInternal).Run() + if err != nil { + logrus.Warnf("cannot create etherstub %s: %+v", config.BridgeNameInternal, err) + return err + } + err = exec.Command("/usr/sbin/dladm", "create-vnic", + "-t", "-l", config.BridgeNameInternal, gwName).Run() + if err != nil { + logrus.Warnf("cannot create vnic %s", gwName) + return err + } + err = exec.Command("/usr/sbin/ifconfig", gwName, + "plumb", gwIP, "up").Run() + if err != nil { + logrus.Warnf("cannot create gateway interface %s on %s", + gwIP, gwName) + return err + } + + tableName := "bridge_nw_subnets" + pfAnchor := fmt.Sprintf("_auto/docker/%s", tableName) + err = exec.Command("/usr/sbin/pfctl", "-a", pfAnchor, "-t", tableName, "-T", "add", gwIP).Run() + if err != nil { + logrus.Warnf("cannot add bridge network '%s' to PF table", bridgeName) + } + + pfCmd := fmt.Sprintf( + "/usr/bin/echo \"pass out on %s from %s:network to any nat-to (%s)\n"+ + "block in quick from { <%s>, ! %s } to %s\" |"+ + "/usr/sbin/pfctl -a _auto/docker/%s -f -", + bindingIntf, gwName, bindingIntf, + tableName, gwIP, gwIP, + bridgeName) + err = exec.Command("/usr/bin/bash", "-c", pfCmd).Run() + if err != nil { + logrus.Warnf("cannot add pf rule using: %s", pfCmd) + return err + } + + return nil +} + +func bridgeCleanup(config *networkConfiguration, logErr bool) { + var err error + + bridgeName := config.BridgeName + tableName := "bridge_nw_subnets" + gwName := fmt.Sprintf("%s_gw0", bridgeName) + gwIP := config.AddressIPv4.String() + pfAnchor := fmt.Sprintf("_auto/docker/%s", bridgeName) + tableAnchor := fmt.Sprintf("_auto/docker/%s", tableName) + + err = exec.Command("/usr/sbin/pfctl", "-a", pfAnchor, "-F", "all").Run() + if err != nil && logErr { + logrus.Warnf("cannot flush firewall rules") + } + err = exec.Command("/usr/sbin/ifconfig", gwName, "unplumb").Run() + if err != nil && logErr { + logrus.Warnf("cannot remove gateway interface") + } + err = exec.Command("/usr/sbin/dladm", "delete-vnic", + "-t", gwName).Run() + if err != nil && logErr { + logrus.Warnf("cannot delete vnic") + } + err = exec.Command("/usr/sbin/dladm", "delete-etherstub", + "-t", config.BridgeNameInternal).Run() + if err != nil && logErr { + logrus.Warnf("cannot delete etherstub") + } + err = exec.Command("/usr/sbin/pfctl", "-a", tableAnchor, "-t", tableName, "-T", "delete", gwIP).Run() + if err != nil && logErr { + logrus.Warnf("cannot remove bridge network '%s' from PF table", bridgeName) + } +} + +func (d *driver) createNetwork(config *networkConfiguration) error { + var err error + + logrus.Infof("Creating bridge network: %s %s %s", config.ID, + config.BridgeName, config.AddressIPv4) + + networkList := d.getNetworks() + for i, nw := range networkList { + nw.Lock() + nwConfig := nw.config + nw.Unlock() + if err := nwConfig.Conflicts(config); err != nil { + if config.DefaultBridge { + // We encountered and identified a stale default network + // We must delete it as libnetwork is the source of thruth + // The default network being created must be the only one + // This can happen only from docker 1.12 on ward + logrus.Infof("Removing stale default bridge network %s (%s)", nwConfig.ID, nwConfig.BridgeName) + if err := d.DeleteNetwork(nwConfig.ID); err != nil { + logrus.Warnf("Failed to remove stale default network: %s (%s): %v. Will remove from store.", nwConfig.ID, nwConfig.BridgeName, err) + d.storeDelete(nwConfig) + } + networkList = append(networkList[:i], networkList[i+1:]...) + } else { + return types.ForbiddenErrorf( + "cannot create network %s (%s): "+ + "conflicts with network %s (%s): %s", + nwConfig.BridgeName, config.ID, nw.id, + nw.config.BridgeName, err.Error()) + } + } + } + if config.DefaultBindingIP == nil || + config.DefaultBindingIP.IsUnspecified() { + config.DefaultBindingIP = d.defrouteIP + } + + // Create and set network handler in driver + network := &bridgeNetwork{ + id: config.ID, + endpoints: make(map[string]*bridgeEndpoint), + config: config, + portMapper: portmapper.New(""), + driver: d, + } + + d.Lock() + d.networks[config.ID] = network + d.Unlock() + + // On failure make sure to reset driver network handler to nil + defer func() { + if err != nil { + d.Lock() + delete(d.networks, config.ID) + d.Unlock() + } + }() + + // Create or retrieve the bridge L3 interface + bridgeIface := newInterface(config) + network.bridge = bridgeIface + + // Verify the network configuration does not conflict with previously installed + // networks. This step is needed now because driver might have now set the bridge + // name on this config struct. And because we need to check for possible address + // conflicts, so we need to check against operational networks. + if err = config.conflictsWithNetworks(config.ID, networkList); err != nil { + return err + } + + // We only attempt to create the bridge when the requested device name is + // the default one. + if config.BridgeName != DefaultBridgeName && config.DefaultBridge { + return NonDefaultBridgeExistError(config.BridgeName) + } + + bridgeCleanup(config, false) + err = bridgeSetup(config) + if err != nil { + return err + } + return nil +} + +func (d *driver) DeleteNetwork(nid string) error { + var err error + // Get network handler and remove it from driver + d.Lock() + n, ok := d.networks[nid] + d.Unlock() + + if !ok { + return types.InternalMaskableErrorf("network %s does not exist", nid) + } + d.Lock() + delete(d.networks, nid) + d.Unlock() + + // On failure set network handler back in driver, but + // only if is not already taken over by some other thread + defer func() { + if err != nil { + d.Lock() + if _, ok := d.networks[nid]; !ok { + d.networks[nid] = n + } + d.Unlock() + } + }() + + // Sanity check + if n == nil { + err = driverapi.ErrNoNetwork(nid) + return err + } + + // Cannot remove network if endpoints are still present + if len(n.endpoints) != 0 { + err = ActiveEndpointsError(n.id) + return err + } + bridgeCleanup(n.config, true) + logrus.Infof("Deleting bridge network: %s", nid[:12]) + return d.storeDelete(n.config) +} + +func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { + if ifInfo == nil { + return errors.New("invalid interface passed") + } + + // Get the network handler and make sure it exists + d.Lock() + n, ok := d.networks[nid] + d.Unlock() + + if !ok { + return types.NotFoundErrorf("network %s does not exist", nid) + } + if n == nil { + return driverapi.ErrNoNetwork(nid) + } + + // Sanity check + n.Lock() + if n.id != nid { + n.Unlock() + return InvalidNetworkIDError(nid) + } + n.Unlock() + + // Check if endpoint id is good and retrieve correspondent endpoint + ep, err := n.getEndpoint(eid) + if err != nil { + return err + } + + // Endpoint with that id exists either on desired or other sandbox + if ep != nil { + return driverapi.ErrEndpointExists(eid) + } + + // Try to convert the options to endpoint configuration + epConfig, err := parseEndpointOptions(epOptions) + if err != nil { + return err + } + + // Create and add the endpoint + n.Lock() + endpoint := &bridgeEndpoint{id: eid, config: epConfig} + n.endpoints[eid] = endpoint + n.Unlock() + + // On failure make sure to remove the endpoint + defer func() { + if err != nil { + n.Lock() + delete(n.endpoints, eid) + n.Unlock() + } + }() + + // Create the sandbox side pipe interface + if ifInfo.MacAddress() == nil { + // No MAC address assigned to interface. Generate a random MAC to assign + endpoint.macAddress = netutils.GenerateRandomMAC() + if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil { + logrus.Warnf("Unable to set mac address: %s to endpoint: %s", + endpoint.macAddress.String(), endpoint.id) + return err + } + } else { + endpoint.macAddress = ifInfo.MacAddress() + } + endpoint.addr = ifInfo.Address() + endpoint.addrv6 = ifInfo.AddressIPv6() + c := n.config + + // Program any required port mapping and store them in the endpoint + endpoint.portMapping, err = n.allocatePorts(endpoint, c.DefaultBindingIntf, c.DefaultBindingIP, true) + if err != nil { + return err + } + + return nil +} + +func (d *driver) DeleteEndpoint(nid, eid string) error { + var err error + + // Get the network handler and make sure it exists + d.Lock() + n, ok := d.networks[nid] + d.Unlock() + + if !ok { + return types.InternalMaskableErrorf("network %s does not exist", nid) + } + if n == nil { + return driverapi.ErrNoNetwork(nid) + } + + // Sanity Check + n.Lock() + if n.id != nid { + n.Unlock() + return InvalidNetworkIDError(nid) + } + n.Unlock() + + // Check endpoint id and if an endpoint is actually there + ep, err := n.getEndpoint(eid) + if err != nil { + return err + } + if ep == nil { + return EndpointNotFoundError(eid) + } + + // Remove it + n.Lock() + delete(n.endpoints, eid) + n.Unlock() + + // On failure make sure to set back ep in n.endpoints, but only + // if it hasn't been taken over already by some other thread. + defer func() { + if err != nil { + n.Lock() + if _, ok := n.endpoints[eid]; !ok { + n.endpoints[eid] = ep + } + n.Unlock() + } + }() + + err = n.releasePorts(ep) + if err != nil { + logrus.Warn(err) + } + + return nil +} + +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { + // Get the network handler and make sure it exists + d.Lock() + n, ok := d.networks[nid] + d.Unlock() + if !ok { + return nil, types.NotFoundErrorf("network %s does not exist", nid) + } + if n == nil { + return nil, driverapi.ErrNoNetwork(nid) + } + + // Sanity check + n.Lock() + if n.id != nid { + n.Unlock() + return nil, InvalidNetworkIDError(nid) + } + n.Unlock() + + // Check if endpoint id is good and retrieve correspondent endpoint + ep, err := n.getEndpoint(eid) + if err != nil { + return nil, err + } + if ep == nil { + return nil, driverapi.ErrNoEndpoint(eid) + } + + m := make(map[string]interface{}) + + if ep.extConnConfig != nil && ep.extConnConfig.ExposedPorts != nil { + // Return a copy of the config data + epc := make([]types.TransportPort, 0, len(ep.extConnConfig.ExposedPorts)) + for _, tp := range ep.extConnConfig.ExposedPorts { + epc = append(epc, tp.GetCopy()) + } + m[netlabel.ExposedPorts] = epc + } + + if ep.portMapping != nil { + // Return a copy of the operational data + pmc := make([]types.PortBinding, 0, len(ep.portMapping)) + for _, pm := range ep.portMapping { + pmc = append(pmc, pm.GetCopy()) + } + m[netlabel.PortMap] = pmc + } + + if len(ep.macAddress) != 0 { + m[netlabel.MacAddress] = ep.macAddress + } + return m, nil +} + +// Join method is invoked when a Sandbox is attached to an endpoint. +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { + network, err := d.getNetwork(nid) + if err != nil { + return err + } + + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + if endpoint == nil { + return EndpointNotFoundError(eid) + } + + endpoint.containerConfig, err = parseContainerOptions(options) + if err != nil { + return err + } + + err = jinfo.SetGateway(network.bridge.gatewayIPv4) + if err != nil { + return err + } + + err = jinfo.SetGatewayIPv6(network.bridge.gatewayIPv6) + if err != nil { + return err + } + + return nil +} + +func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, enable bool) error { + return nil +} + +// Leave method is invoked when a Sandbox detaches from an endpoint. +func (d *driver) Leave(nid, eid string) error { + network, err := d.getNetwork(nid) + if err != nil { + return types.InternalMaskableErrorf("%s", err) + } + + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + if endpoint == nil { + return EndpointNotFoundError(eid) + } + + return nil +} + +func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { + network, err := d.getNetwork(nid) + if err != nil { + return err + } + + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + if endpoint == nil { + return EndpointNotFoundError(eid) + } + + endpoint.extConnConfig, err = parseConnectivityOptions(options) + if err != nil { + return err + } + + // Program any required port mapping and store them in the endpoint + endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIntf, network.config.DefaultBindingIP, true) + if err != nil { + return err + } + + if !network.config.EnableICC { + return d.link(network, endpoint, true) + } + + return nil +} + +func (d *driver) RevokeExternalConnectivity(nid, eid string) error { + network, err := d.getNetwork(nid) + if err != nil { + return err + } + + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + if endpoint == nil { + return EndpointNotFoundError(eid) + } + + err = network.releasePorts(endpoint) + if err != nil { + logrus.Warn(err) + } + + return nil +} + +func (d *driver) Type() string { + return networkType +} + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { + return nil +} + +// Validate performs a static validation on the network configuration parameters. +// Whatever can be assessed a priori before attempting any programming. +func (c *networkConfiguration) Validate() error { + if c.Mtu < 0 { + return ErrInvalidMtu(c.Mtu) + } + + // If bridge v4 subnet is specified + if c.AddressIPv4 != nil { + // If default gw is specified, it must be part of bridge subnet + if c.DefaultGatewayIPv4 != nil { + if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) { + return &ErrInvalidGateway{} + } + } + } + + // If default v6 gw is specified, AddressIPv6 must be specified and gw must belong to AddressIPv6 subnet + if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil { + if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) { + return &ErrInvalidGateway{} + } + } + return nil +} + +// Checks whether this network's configuration for the network with this id conflicts with any of the passed networks +func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridgeNetwork) error { + for _, nw := range others { + + nw.Lock() + nwID := nw.id + nwConfig := nw.config + nwBridge := nw.bridge + nw.Unlock() + + if nwID == id { + continue + } + // Verify the name (which may have been set by newInterface()) does not conflict with + // existing bridge interfaces. Ironically the system chosen name gets stored in the config... + // Basically we are checking if the two original configs were both empty. + if nwConfig.BridgeName == c.BridgeName { + return types.ForbiddenErrorf("conflicts with network %s (%s) by bridge name", nwID, nwConfig.BridgeName) + } + // If this network config specifies the AddressIPv4, we need + // to make sure it does not conflict with any previously allocated + // bridges. This could not be completely caught by the config conflict + // check, because networks which config does not specify the AddressIPv4 + // get their address and subnet selected by the driver (see electBridgeIPv4()) + if c.AddressIPv4 != nil { + if nwBridge.bridgeIPv4.Contains(c.AddressIPv4.IP) || + c.AddressIPv4.Contains(nwBridge.bridgeIPv4.IP) { + return types.ForbiddenErrorf("conflicts with network %s (%s) by ip network", nwID, nwConfig.BridgeName) + } + } + } + + return nil +} + +// Conflicts check if two NetworkConfiguration objects overlap +func (c *networkConfiguration) Conflicts(o *networkConfiguration) error { + if o == nil { + return fmt.Errorf("same configuration") + } + + // Also empty, becasue only one network with empty name is allowed + if c.BridgeName == o.BridgeName { + return fmt.Errorf("networks have same bridge name") + } + + // They must be in different subnets + if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) && + (c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) { + return fmt.Errorf("networks have overlapping IPv4") + } + + // They must be in different v6 subnets + if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) && + (c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) { + return fmt.Errorf("networks have overlapping IPv6") + } + + return nil +} + +func (c *networkConfiguration) fromLabels(labels map[string]string) error { + var err error + for label, value := range labels { + switch label { + case BridgeName: + c.BridgeName = value + case netlabel.DriverMTU: + if c.Mtu, err = strconv.Atoi(value); err != nil { + return parseErr(label, value, err.Error()) + } + case netlabel.EnableIPv6: + if c.EnableIPv6, err = strconv.ParseBool(value); err != nil { + return parseErr(label, value, err.Error()) + } + case EnableIPMasquerade: + if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil { + return parseErr(label, value, err.Error()) + } + case EnableICC: + if c.EnableICC, err = strconv.ParseBool(value); err != nil { + return parseErr(label, value, err.Error()) + } + case DefaultBridge: + if c.DefaultBridge, err = strconv.ParseBool(value); err != nil { + return parseErr(label, value, err.Error()) + } + case DefaultBindingIP: + if c.DefaultBindingIP = net.ParseIP(value); c.DefaultBindingIP == nil { + return parseErr(label, value, "nil ip") + } + } + } + + return nil +} + +func parseErr(label, value, errString string) error { + return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString) +} + +func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) { + var ( + err error + config *networkConfiguration + ) + + switch opt := data.(type) { + case *networkConfiguration: + config = opt + case map[string]string: + config = &networkConfiguration{ + EnableICC: true, + EnableIPMasquerade: true, + } + err = config.fromLabels(opt) + case options.Generic: + var opaqueConfig interface{} + if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil { + config = opaqueConfig.(*networkConfiguration) + } + default: + err = types.BadRequestErrorf("do not recognize network configuration format: %T", opt) + } + + return config, err +} + +func parseNetworkOptions(d *driver, id string, option options.Generic) (*networkConfiguration, error) { + var ( + err error + config = &networkConfiguration{} + ) + + // Parse generic label first, config will be re-assigned + if genData, ok := option[netlabel.GenericData]; ok && genData != nil { + if config, err = parseNetworkGenericOptions(genData); err != nil { + return nil, err + } + } + + // Process well-known labels next + if val, ok := option[netlabel.EnableIPv6]; ok { + config.EnableIPv6 = val.(bool) + } + + if val, ok := option[netlabel.Internal]; ok { + if internal, ok := val.(bool); ok && internal { + config.Internal = true + } + } + + // Finally validate the configuration + if err = config.Validate(); err != nil { + return nil, err + } + + if config.BridgeName == "" && config.DefaultBridge == false { + config.BridgeName = "br_" + id[:12] + "_0" + } + + lastChar := config.BridgeName[len(config.BridgeName)-1:] + if _, err = strconv.Atoi(lastChar); err != nil { + config.BridgeNameInternal = config.BridgeName + "_0" + } else { + config.BridgeNameInternal = config.BridgeName + } + + config.ID = id + return config, nil +} + +func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error { + if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 { + return types.ForbiddenErrorf("bridge driver doesnt support multiple subnets") + } + + if len(ipamV4Data) == 0 { + return types.BadRequestErrorf("bridge network %s requires ipv4 configuration", id) + } + + if ipamV4Data[0].Gateway != nil { + c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway) + } + + if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok { + c.DefaultGatewayIPv4 = gw.IP + } + + if len(ipamV6Data) > 0 { + c.AddressIPv6 = ipamV6Data[0].Pool + + if ipamV6Data[0].Gateway != nil { + c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway) + } + + if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok { + c.DefaultGatewayIPv6 = gw.IP + } + } + + return nil +} + +func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) { + n.Lock() + defer n.Unlock() + + if eid == "" { + return nil, InvalidEndpointIDError(eid) + } + + if ep, ok := n.endpoints[eid]; ok { + return ep, nil + } + + return nil, nil +} + +func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) { + if epOptions == nil { + return nil, nil + } + + ec := &endpointConfiguration{} + + if opt, ok := epOptions[netlabel.MacAddress]; ok { + if mac, ok := opt.(net.HardwareAddr); ok { + ec.MacAddress = mac + } else { + return nil, &ErrInvalidEndpointConfig{} + } + } + + if opt, ok := epOptions[netlabel.PortMap]; ok { + if bs, ok := opt.([]types.PortBinding); ok { + ec.PortBindings = bs + } else { + return nil, &ErrInvalidEndpointConfig{} + } + } + + if opt, ok := epOptions[netlabel.ExposedPorts]; ok { + if ports, ok := opt.([]types.TransportPort); ok { + ec.ExposedPorts = ports + } else { + return nil, &ErrInvalidEndpointConfig{} + } + } + + return ec, nil +} + +func parseContainerOptions(cOptions map[string]interface{}) (*containerConfiguration, error) { + if cOptions == nil { + return nil, nil + } + genericData := cOptions[netlabel.GenericData] + if genericData == nil { + return nil, nil + } + switch opt := genericData.(type) { + case options.Generic: + opaqueConfig, err := options.GenerateFromModel(opt, &containerConfiguration{}) + if err != nil { + return nil, err + } + return opaqueConfig.(*containerConfiguration), nil + case *containerConfiguration: + return opt, nil + default: + return nil, nil + } +} + +func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) { + if cOptions == nil { + return nil, nil + } + + cc := &connectivityConfiguration{} + + if opt, ok := cOptions[netlabel.PortMap]; ok { + if pb, ok := opt.([]types.PortBinding); ok { + cc.PortBindings = pb + } else { + return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt) + } + } + + if opt, ok := cOptions[netlabel.ExposedPorts]; ok { + if ports, ok := opt.([]types.TransportPort); ok { + cc.ExposedPorts = ports + } else { + return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt) + } + } + + return cc, nil +} diff --git a/drivers/solaris/bridge/bridge_store.go b/drivers/solaris/bridge/bridge_store.go new file mode 100644 index 0000000000..956e82902f --- /dev/null +++ b/drivers/solaris/bridge/bridge_store.go @@ -0,0 +1,384 @@ +// +build solaris + +package bridge + +import ( + "encoding/json" + "fmt" + "net" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/types" +) + +const ( + // network config prefix was not specific enough. + // To be backward compatible, need custom endpoint + // prefix with different root + bridgePrefix = "bridge" + bridgeEndpointPrefix = "bridge-endpoint" +) + +func (d *driver) initStore(option map[string]interface{}) error { + if data, ok := option[netlabel.LocalKVClient]; ok { + var err error + dsc, ok := data.(discoverapi.DatastoreConfigData) + if !ok { + return types.InternalErrorf("incorrect data in datastore configuration: %v", data) + } + d.store, err = datastore.NewDataStoreFromConfig(dsc) + if err != nil { + return types.InternalErrorf("bridge driver failed to initialize data store: %v", err) + } + + err = d.populateNetworks() + if err != nil { + return err + } + + err = d.populateEndpoints() + if err != nil { + return err + } + } + + return nil +} + +func (d *driver) populateNetworks() error { + kvol, err := d.store.List(datastore.Key(bridgePrefix), &networkConfiguration{}) + if err != nil && err != datastore.ErrKeyNotFound { + return fmt.Errorf("failed to get bridge network configurations from store: %v", err) + } + + // It's normal for network configuration state to be empty. Just return. + if err == datastore.ErrKeyNotFound { + return nil + } + + for _, kvo := range kvol { + ncfg := kvo.(*networkConfiguration) + if err = d.createNetwork(ncfg); err != nil { + logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state: %v", ncfg.ID, ncfg.BridgeName, err) + } + logrus.Debugf("Network (%s) restored", ncfg.ID[0:7]) + } + + return nil +} + +func (d *driver) populateEndpoints() error { + kvol, err := d.store.List(datastore.Key(bridgeEndpointPrefix), &bridgeEndpoint{}) + if err != nil && err != datastore.ErrKeyNotFound { + return fmt.Errorf("failed to get bridge endpoints from store: %v", err) + } + + if err == datastore.ErrKeyNotFound { + return nil + } + + for _, kvo := range kvol { + ep := kvo.(*bridgeEndpoint) + n, ok := d.networks[ep.nid] + if !ok { + logrus.Debugf("Network (%s) not found for restored bridge endpoint (%s)", ep.nid[0:7], ep.id[0:7]) + logrus.Debugf("Deleting stale bridge endpoint (%s) from store", ep.nid[0:7]) + if err := d.storeDelete(ep); err != nil { + logrus.Debugf("Failed to delete stale bridge endpoint (%s) from store", ep.nid[0:7]) + } + continue + } + n.endpoints[ep.id] = ep + n.restorePortAllocations(ep) + logrus.Debugf("Endpoint (%s) restored to network (%s)", ep.id[0:7], ep.nid[0:7]) + } + + return nil +} + +func (d *driver) storeUpdate(kvObject datastore.KVObject) error { + if d.store == nil { + logrus.Warnf("bridge store not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...)) + return nil + } + + if err := d.store.PutObjectAtomic(kvObject); err != nil { + return fmt.Errorf("failed to update bridge store for object type %T: %v", kvObject, err) + } + + return nil +} + +func (d *driver) storeDelete(kvObject datastore.KVObject) error { + if d.store == nil { + logrus.Debugf("bridge store not initialized. kv object %s is not deleted from store", datastore.Key(kvObject.Key()...)) + return nil + } + +retry: + if err := d.store.DeleteObjectAtomic(kvObject); err != nil { + if err == datastore.ErrKeyModified { + if err := d.store.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil { + return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err) + } + goto retry + } + return err + } + + return nil +} + +func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) { + nMap := make(map[string]interface{}) + nMap["ID"] = ncfg.ID + nMap["BridgeName"] = ncfg.BridgeName + nMap["BridgeNameInternal"] = ncfg.BridgeNameInternal + nMap["EnableIPv6"] = ncfg.EnableIPv6 + nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade + nMap["EnableICC"] = ncfg.EnableICC + nMap["Mtu"] = ncfg.Mtu + nMap["Internal"] = ncfg.Internal + nMap["DefaultBridge"] = ncfg.DefaultBridge + nMap["DefaultBindingIP"] = ncfg.DefaultBindingIP.String() + nMap["DefaultBindingIntf"] = ncfg.DefaultBindingIntf + nMap["DefaultGatewayIPv4"] = ncfg.DefaultGatewayIPv4.String() + nMap["DefaultGatewayIPv6"] = ncfg.DefaultGatewayIPv6.String() + + if ncfg.AddressIPv4 != nil { + nMap["AddressIPv4"] = ncfg.AddressIPv4.String() + } + + if ncfg.AddressIPv6 != nil { + nMap["AddressIPv6"] = ncfg.AddressIPv6.String() + } + + return json.Marshal(nMap) +} + +func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error { + var ( + err error + nMap map[string]interface{} + ) + + if err = json.Unmarshal(b, &nMap); err != nil { + return err + } + + if v, ok := nMap["AddressIPv4"]; ok { + if ncfg.AddressIPv4, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge network address IPv4 after json unmarshal: %s", v.(string)) + } + } + + if v, ok := nMap["AddressIPv6"]; ok { + if ncfg.AddressIPv6, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge network address IPv6 after json unmarshal: %s", v.(string)) + } + } + + ncfg.DefaultBridge = nMap["DefaultBridge"].(bool) + ncfg.DefaultBindingIP = net.ParseIP(nMap["DefaultBindingIP"].(string)) + ncfg.DefaultBindingIntf = nMap["DefaultBindingIntf"].(string) + ncfg.DefaultGatewayIPv4 = net.ParseIP(nMap["DefaultGatewayIPv4"].(string)) + ncfg.DefaultGatewayIPv6 = net.ParseIP(nMap["DefaultGatewayIPv6"].(string)) + ncfg.ID = nMap["ID"].(string) + ncfg.BridgeName = nMap["BridgeName"].(string) + ncfg.BridgeNameInternal = nMap["BridgeNameInternal"].(string) + ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool) + ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool) + ncfg.EnableICC = nMap["EnableICC"].(bool) + ncfg.Mtu = int(nMap["Mtu"].(float64)) + if v, ok := nMap["Internal"]; ok { + ncfg.Internal = v.(bool) + } + + return nil +} + +func (ncfg *networkConfiguration) Key() []string { + return []string{bridgePrefix, ncfg.ID} +} + +func (ncfg *networkConfiguration) KeyPrefix() []string { + return []string{bridgePrefix} +} + +func (ncfg *networkConfiguration) Value() []byte { + b, err := json.Marshal(ncfg) + if err != nil { + return nil + } + return b +} + +func (ncfg *networkConfiguration) SetValue(value []byte) error { + return json.Unmarshal(value, ncfg) +} + +func (ncfg *networkConfiguration) Index() uint64 { + return ncfg.dbIndex +} + +func (ncfg *networkConfiguration) SetIndex(index uint64) { + ncfg.dbIndex = index + ncfg.dbExists = true +} + +func (ncfg *networkConfiguration) Exists() bool { + return ncfg.dbExists +} + +func (ncfg *networkConfiguration) Skip() bool { + return false +} + +func (ncfg *networkConfiguration) New() datastore.KVObject { + return &networkConfiguration{} +} + +func (ncfg *networkConfiguration) CopyTo(o datastore.KVObject) error { + dstNcfg := o.(*networkConfiguration) + *dstNcfg = *ncfg + return nil +} + +func (ncfg *networkConfiguration) DataScope() string { + return datastore.LocalScope +} + +func (ep *bridgeEndpoint) MarshalJSON() ([]byte, error) { + epMap := make(map[string]interface{}) + epMap["id"] = ep.id + epMap["nid"] = ep.nid + epMap["SrcName"] = ep.srcName + epMap["MacAddress"] = ep.macAddress.String() + epMap["Addr"] = ep.addr.String() + if ep.addrv6 != nil { + epMap["Addrv6"] = ep.addrv6.String() + } + epMap["Config"] = ep.config + epMap["ContainerConfig"] = ep.containerConfig + epMap["ExternalConnConfig"] = ep.extConnConfig + epMap["PortMapping"] = ep.portMapping + + return json.Marshal(epMap) +} + +func (ep *bridgeEndpoint) UnmarshalJSON(b []byte) error { + var ( + err error + epMap map[string]interface{} + ) + + if err = json.Unmarshal(b, &epMap); err != nil { + return fmt.Errorf("Failed to unmarshal to bridge endpoint: %v", err) + } + + if v, ok := epMap["MacAddress"]; ok { + if ep.macAddress, err = net.ParseMAC(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge endpoint MAC address (%s) after json unmarshal: %v", v.(string), err) + } + } + if v, ok := epMap["Addr"]; ok { + if ep.addr, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err) + } + } + if v, ok := epMap["Addrv6"]; ok { + if ep.addrv6, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge endpoint IPv6 address (%s) after json unmarshal: %v", v.(string), err) + } + } + ep.id = epMap["id"].(string) + ep.nid = epMap["nid"].(string) + ep.srcName = epMap["SrcName"].(string) + d, _ := json.Marshal(epMap["Config"]) + if err := json.Unmarshal(d, &ep.config); err != nil { + logrus.Warnf("Failed to decode endpoint config %v", err) + } + d, _ = json.Marshal(epMap["ContainerConfig"]) + if err := json.Unmarshal(d, &ep.containerConfig); err != nil { + logrus.Warnf("Failed to decode endpoint container config %v", err) + } + d, _ = json.Marshal(epMap["ExternalConnConfig"]) + if err := json.Unmarshal(d, &ep.extConnConfig); err != nil { + logrus.Warnf("Failed to decode endpoint external connectivity configuration %v", err) + } + d, _ = json.Marshal(epMap["PortMapping"]) + if err := json.Unmarshal(d, &ep.portMapping); err != nil { + logrus.Warnf("Failed to decode endpoint port mapping %v", err) + } + + return nil +} + +func (ep *bridgeEndpoint) Key() []string { + return []string{bridgeEndpointPrefix, ep.id} +} + +func (ep *bridgeEndpoint) KeyPrefix() []string { + return []string{bridgeEndpointPrefix} +} + +func (ep *bridgeEndpoint) Value() []byte { + b, err := json.Marshal(ep) + if err != nil { + return nil + } + return b +} + +func (ep *bridgeEndpoint) SetValue(value []byte) error { + return json.Unmarshal(value, ep) +} + +func (ep *bridgeEndpoint) Index() uint64 { + return ep.dbIndex +} + +func (ep *bridgeEndpoint) SetIndex(index uint64) { + ep.dbIndex = index + ep.dbExists = true +} + +func (ep *bridgeEndpoint) Exists() bool { + return ep.dbExists +} + +func (ep *bridgeEndpoint) Skip() bool { + return false +} + +func (ep *bridgeEndpoint) New() datastore.KVObject { + return &bridgeEndpoint{} +} + +func (ep *bridgeEndpoint) CopyTo(o datastore.KVObject) error { + dstEp := o.(*bridgeEndpoint) + *dstEp = *ep + return nil +} + +func (ep *bridgeEndpoint) DataScope() string { + return datastore.LocalScope +} + +func (n *bridgeNetwork) restorePortAllocations(ep *bridgeEndpoint) { + if ep.extConnConfig == nil || + ep.extConnConfig.ExposedPorts == nil || + ep.extConnConfig.PortBindings == nil { + return + } + tmp := ep.extConnConfig.PortBindings + ep.extConnConfig.PortBindings = ep.portMapping + _, err := n.allocatePorts(ep, n.config.DefaultBindingIntf, n.config.DefaultBindingIP, n.driver.config.EnableUserlandProxy) + if err != nil { + logrus.Warnf("Failed to reserve existing port mapping for endpoint %s:%v", ep.id[0:7], err) + } + ep.extConnConfig.PortBindings = tmp +} diff --git a/drivers/solaris/bridge/bridge_test.go b/drivers/solaris/bridge/bridge_test.go new file mode 100644 index 0000000000..e27264a6e7 --- /dev/null +++ b/drivers/solaris/bridge/bridge_test.go @@ -0,0 +1,675 @@ +// +build solaris + +package bridge + +import ( + "bytes" + "encoding/json" + "net" + "testing" + + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/ipamutils" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/testutils" + "github.com/docker/libnetwork/types" +) + +func init() { + ipamutils.InitNetworks() +} + +func TestEndpointMarshalling(t *testing.T) { + ip1, _ := types.ParseCIDR("172.22.0.9/16") + ip2, _ := types.ParseCIDR("2001:db8::9") + mac, _ := net.ParseMAC("ac:bd:24:57:66:77") + e := &bridgeEndpoint{ + id: "d2c015a1fe5930650cbcd50493efba0500bcebd8ee1f4401a16319f8a567de33", + nid: "ee33fbb43c323f1920b6b35a0101552ac22ede960d0e5245e9738bccc68b2415", + addr: ip1, + addrv6: ip2, + macAddress: mac, + srcName: "veth123456", + config: &endpointConfiguration{MacAddress: mac}, + containerConfig: &containerConfiguration{ + ParentEndpoints: []string{"one", "due", "three"}, + ChildEndpoints: []string{"four", "five", "six"}, + }, + extConnConfig: &connectivityConfiguration{ + ExposedPorts: []types.TransportPort{ + { + Proto: 6, + Port: uint16(18), + }, + }, + PortBindings: []types.PortBinding{ + { + Proto: 6, + IP: net.ParseIP("17210.33.9.56"), + Port: uint16(18), + HostPort: uint16(3000), + HostPortEnd: uint16(14000), + }, + }, + }, + portMapping: []types.PortBinding{ + { + Proto: 17, + IP: net.ParseIP("172.33.9.56"), + Port: uint16(99), + HostIP: net.ParseIP("10.10.100.2"), + HostPort: uint16(9900), + HostPortEnd: uint16(10000), + }, + { + Proto: 6, + IP: net.ParseIP("171.33.9.56"), + Port: uint16(55), + HostIP: net.ParseIP("10.11.100.2"), + HostPort: uint16(5500), + HostPortEnd: uint16(55000), + }, + }, + } + + b, err := json.Marshal(e) + if err != nil { + t.Fatal(err) + } + + ee := &bridgeEndpoint{} + err = json.Unmarshal(b, ee) + if err != nil { + t.Fatal(err) + } + + if e.id != ee.id || e.nid != ee.nid || e.srcName != ee.srcName || !bytes.Equal(e.macAddress, ee.macAddress) || + !types.CompareIPNet(e.addr, ee.addr) || !types.CompareIPNet(e.addrv6, ee.addrv6) || + !compareEpConfig(e.config, ee.config) || + !compareContainerConfig(e.containerConfig, ee.containerConfig) || + !compareConnConfig(e.extConnConfig, ee.extConnConfig) || + !compareBindings(e.portMapping, ee.portMapping) { + t.Fatalf("JSON marsh/unmarsh failed.\nOriginal:\n%#v\nDecoded:\n%#v", e, ee) + } +} + +func compareEpConfig(a, b *endpointConfiguration) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + return bytes.Equal(a.MacAddress, b.MacAddress) +} + +func compareContainerConfig(a, b *containerConfiguration) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + if len(a.ParentEndpoints) != len(b.ParentEndpoints) || + len(a.ChildEndpoints) != len(b.ChildEndpoints) { + return false + } + for i := 0; i < len(a.ParentEndpoints); i++ { + if a.ParentEndpoints[i] != b.ParentEndpoints[i] { + return false + } + } + for i := 0; i < len(a.ChildEndpoints); i++ { + if a.ChildEndpoints[i] != b.ChildEndpoints[i] { + return false + } + } + return true +} + +func compareConnConfig(a, b *connectivityConfiguration) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + if len(a.ExposedPorts) != len(b.ExposedPorts) || + len(a.PortBindings) != len(b.PortBindings) { + return false + } + for i := 0; i < len(a.ExposedPorts); i++ { + if !a.ExposedPorts[i].Equal(&b.ExposedPorts[i]) { + return false + } + } + for i := 0; i < len(a.PortBindings); i++ { + if !a.PortBindings[i].Equal(&b.PortBindings[i]) { + return false + } + } + return true +} + +func compareBindings(a, b []types.PortBinding) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if !a[i].Equal(&b[i]) { + return false + } + } + return true +} + +func getIPv4Data(t *testing.T) []driverapi.IPAMData { + ipd := driverapi.IPAMData{AddressSpace: "full"} + nw, _, err := netutils.ElectInterfaceAddresses("") + if err != nil { + t.Fatal(err) + } + ipd.Pool = nw + // Set network gateway to X.X.X.1 + ipd.Gateway = types.GetIPNetCopy(nw) + ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1 + return []driverapi.IPAMData{ipd} +} + +func TestCreateFullOptions(t *testing.T) { + defer testutils.SetupTestOSContext(t)() + d := newDriver() + + config := &configuration{ + EnableIPForwarding: true, + EnableIPTables: true, + } + + // Test this scenario: Default gw address does not belong to + // container network and it's greater than bridge address + cnw, _ := types.ParseCIDR("172.16.122.0/24") + bnw, _ := types.ParseCIDR("172.16.0.0/24") + br, _ := types.ParseCIDR("172.16.0.1/16") + defgw, _ := types.ParseCIDR("172.16.0.100/16") + + genericOption := make(map[string]interface{}) + genericOption[netlabel.GenericData] = config + + if err := d.configure(genericOption); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + netOption := make(map[string]interface{}) + netOption[netlabel.EnableIPv6] = true + netOption[netlabel.GenericData] = &networkConfiguration{ + BridgeName: DefaultBridgeName, + } + + ipdList := []driverapi.IPAMData{ + { + Pool: bnw, + Gateway: br, + AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw}, + }, + } + err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil) + if err != nil { + t.Fatalf("Failed to create bridge: %v", err) + } + + // Verify the IP address allocated for the endpoint belongs to the container network + epOptions := make(map[string]interface{}) + te := newTestEndpoint(cnw, 10) + err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions) + if err != nil { + t.Fatalf("Failed to create an endpoint : %s", err.Error()) + } + + if !cnw.Contains(te.Interface().Address().IP) { + t.Fatalf("endpoint got assigned address outside of container network(%s): %s", cnw.String(), te.Interface().Address()) + } +} + +func TestCreateNoConfig(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + d := newDriver() + + netconfig := &networkConfiguration{BridgeName: DefaultBridgeName} + genericOption := make(map[string]interface{}) + genericOption[netlabel.GenericData] = netconfig + + if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil { + t.Fatalf("Failed to create bridge: %v", err) + } +} + +func TestCreateFullOptionsLabels(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + d := newDriver() + + config := &configuration{ + EnableIPForwarding: true, + } + genericOption := make(map[string]interface{}) + genericOption[netlabel.GenericData] = config + + if err := d.configure(genericOption); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + bndIPs := "127.0.0.1" + nwV6s := "2001:db8:2600:2700:2800::/80" + gwV6s := "2001:db8:2600:2700:2800::25/80" + nwV6, _ := types.ParseCIDR(nwV6s) + gwV6, _ := types.ParseCIDR(gwV6s) + + labels := map[string]string{ + BridgeName: DefaultBridgeName, + DefaultBridge: "true", + EnableICC: "true", + EnableIPMasquerade: "true", + DefaultBindingIP: bndIPs, + } + + netOption := make(map[string]interface{}) + netOption[netlabel.EnableIPv6] = true + netOption[netlabel.GenericData] = labels + + ipdList := getIPv4Data(t) + ipd6List := []driverapi.IPAMData{ + { + Pool: nwV6, + AuxAddresses: map[string]*net.IPNet{ + DefaultGatewayV6AuxKey: gwV6, + }, + }, + } + + err := d.CreateNetwork("dummy", netOption, nil, ipdList, ipd6List) + if err != nil { + t.Fatalf("Failed to create bridge: %v", err) + } + + nw, ok := d.networks["dummy"] + if !ok { + t.Fatalf("Cannot find dummy network in bridge driver") + } + + if nw.config.BridgeName != DefaultBridgeName { + t.Fatalf("incongruent name in bridge network") + } + + if !nw.config.EnableIPv6 { + t.Fatalf("incongruent EnableIPv6 in bridge network") + } + + if !nw.config.EnableICC { + t.Fatalf("incongruent EnableICC in bridge network") + } + + if !nw.config.EnableIPMasquerade { + t.Fatalf("incongruent EnableIPMasquerade in bridge network") + } + + bndIP := net.ParseIP(bndIPs) + if !bndIP.Equal(nw.config.DefaultBindingIP) { + t.Fatalf("Unexpected: %v", nw.config.DefaultBindingIP) + } + + if !types.CompareIPNet(nw.config.AddressIPv6, nwV6) { + t.Fatalf("Unexpected: %v", nw.config.AddressIPv6) + } + + if !gwV6.IP.Equal(nw.config.DefaultGatewayIPv6) { + t.Fatalf("Unexpected: %v", nw.config.DefaultGatewayIPv6) + } + + // In short here we are testing --fixed-cidr-v6 daemon option + // plus --mac-address run option + mac, _ := net.ParseMAC("aa:bb:cc:dd:ee:ff") + epOptions := map[string]interface{}{netlabel.MacAddress: mac} + te := newTestEndpoint(ipdList[0].Pool, 20) + err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions) + if err != nil { + t.Fatal(err) + } +} + +func TestCreate(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + d := newDriver() + + if err := d.configure(nil); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + netconfig := &networkConfiguration{BridgeName: DefaultBridgeName} + genericOption := make(map[string]interface{}) + genericOption[netlabel.GenericData] = netconfig + + if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil { + t.Fatalf("Failed to create bridge: %v", err) + } + + err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil) + if err == nil { + t.Fatalf("Expected bridge driver to refuse creation of second network with default name") + } + if _, ok := err.(types.ForbiddenError); !ok { + t.Fatalf("Creation of second network with default name failed with unexpected error type") + } +} + +func TestCreateFail(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + d := newDriver() + + if err := d.configure(nil); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + netconfig := &networkConfiguration{BridgeName: "dummy0", DefaultBridge: true} + genericOption := make(map[string]interface{}) + genericOption[netlabel.GenericData] = netconfig + + if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err == nil { + t.Fatal("Bridge creation was expected to fail") + } +} + +type testInterface struct { + mac net.HardwareAddr + addr *net.IPNet + addrv6 *net.IPNet + srcName string + dstName string +} + +type testEndpoint struct { + iface *testInterface + gw net.IP + gw6 net.IP + hostsPath string + resolvConfPath string + routes []types.StaticRoute +} + +func newTestEndpoint(nw *net.IPNet, ordinal byte) *testEndpoint { + addr := types.GetIPNetCopy(nw) + addr.IP[len(addr.IP)-1] = ordinal + return &testEndpoint{iface: &testInterface{addr: addr}} +} + +func (te *testEndpoint) Interface() driverapi.InterfaceInfo { + if te.iface != nil { + return te.iface + } + + return nil +} + +func (i *testInterface) MacAddress() net.HardwareAddr { + return i.mac +} + +func (i *testInterface) Address() *net.IPNet { + return i.addr +} + +func (i *testInterface) AddressIPv6() *net.IPNet { + return i.addrv6 +} + +func (i *testInterface) SetMacAddress(mac net.HardwareAddr) error { + if i.mac != nil { + return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", i.mac, mac) + } + if mac == nil { + return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface") + } + i.mac = types.GetMacCopy(mac) + return nil +} + +func (i *testInterface) SetIPAddress(address *net.IPNet) error { + if address.IP == nil { + return types.BadRequestErrorf("tried to set nil IP address to endpoint interface") + } + if address.IP.To4() == nil { + return setAddress(&i.addrv6, address) + } + return setAddress(&i.addr, address) +} + +func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error { + if *ifaceAddr != nil { + return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address) + } + *ifaceAddr = types.GetIPNetCopy(address) + return nil +} + +func (i *testInterface) SetNames(srcName string, dstName string) error { + i.srcName = srcName + i.dstName = dstName + return nil +} + +func (te *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo { + if te.iface != nil { + return te.iface + } + + return nil +} + +func (te *testEndpoint) SetGateway(gw net.IP) error { + te.gw = gw + return nil +} + +func (te *testEndpoint) SetGatewayIPv6(gw6 net.IP) error { + te.gw6 = gw6 + return nil +} + +func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error { + te.routes = append(te.routes, types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop}) + return nil +} + +func (te *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error { + return nil +} + +func (te *testEndpoint) DisableGatewayService() {} + +func TestQueryEndpointInfo(t *testing.T) { + testQueryEndpointInfo(t, true) +} + +func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) { + defer testutils.SetupTestOSContext(t)() + + d := newDriver() + + config := &configuration{ + EnableIPTables: true, + EnableUserlandProxy: ulPxyEnabled, + } + genericOption := make(map[string]interface{}) + genericOption[netlabel.GenericData] = config + + if err := d.configure(genericOption); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + netconfig := &networkConfiguration{ + BridgeName: DefaultBridgeName, + EnableICC: false, + } + genericOption = make(map[string]interface{}) + genericOption[netlabel.GenericData] = netconfig + + ipdList := getIPv4Data(t) + err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil) + if err != nil { + t.Fatalf("Failed to create bridge: %v", err) + } + + sbOptions := make(map[string]interface{}) + sbOptions[netlabel.PortMap] = getPortMapping() + + te := newTestEndpoint(ipdList[0].Pool, 11) + err = d.CreateEndpoint("net1", "ep1", te.Interface(), nil) + if err != nil { + t.Fatalf("Failed to create an endpoint : %s", err.Error()) + } + + err = d.Join("net1", "ep1", "sbox", te, sbOptions) + if err != nil { + t.Fatalf("Failed to join the endpoint: %v", err) + } + + err = d.ProgramExternalConnectivity("net1", "ep1", sbOptions) + if err != nil { + t.Fatalf("Failed to program external connectivity: %v", err) + } + + network, ok := d.networks["net1"] + if !ok { + t.Fatalf("Cannot find network %s inside driver", "net1") + } + ep, _ := network.endpoints["ep1"] + data, err := d.EndpointOperInfo(network.id, ep.id) + if err != nil { + t.Fatalf("Failed to ask for endpoint operational data: %v", err) + } + pmd, ok := data[netlabel.PortMap] + if !ok { + t.Fatalf("Endpoint operational data does not contain port mapping data") + } + pm, ok := pmd.([]types.PortBinding) + if !ok { + t.Fatalf("Unexpected format for port mapping in endpoint operational data") + } + if len(ep.portMapping) != len(pm) { + t.Fatalf("Incomplete data for port mapping in endpoint operational data") + } + for i, pb := range ep.portMapping { + if !pb.Equal(&pm[i]) { + t.Fatalf("Unexpected data for port mapping in endpoint operational data") + } + } + + err = d.RevokeExternalConnectivity("net1", "ep1") + if err != nil { + t.Fatal(err) + } + + // release host mapped ports + err = d.Leave("net1", "ep1") + if err != nil { + t.Fatal(err) + } +} + +func getExposedPorts() []types.TransportPort { + return []types.TransportPort{ + {Proto: types.TCP, Port: uint16(5000)}, + {Proto: types.UDP, Port: uint16(400)}, + {Proto: types.TCP, Port: uint16(600)}, + } +} + +func getPortMapping() []types.PortBinding { + return []types.PortBinding{ + {Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)}, + {Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)}, + {Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)}, + } +} + +func TestValidateConfig(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + // Test mtu + c := networkConfiguration{Mtu: -2} + err := c.Validate() + if err == nil { + t.Fatalf("Failed to detect invalid MTU number") + } + + c.Mtu = 9000 + err = c.Validate() + if err != nil { + t.Fatalf("unexpected validation error on MTU number") + } + + // Bridge network + _, network, _ := net.ParseCIDR("172.28.0.0/16") + c = networkConfiguration{ + AddressIPv4: network, + } + + err = c.Validate() + if err != nil { + t.Fatal(err) + } + + // Test v4 gw + c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234") + err = c.Validate() + if err == nil { + t.Fatalf("Failed to detect invalid default gateway") + } + + c.DefaultGatewayIPv4 = net.ParseIP("172.28.30.234") + err = c.Validate() + if err != nil { + t.Fatalf("Unexpected validation error on default gateway") + } + + // Test v6 gw + _, v6nw, _ := net.ParseCIDR("2001:db8:ae:b004::/64") + c = networkConfiguration{ + EnableIPv6: true, + AddressIPv6: v6nw, + DefaultGatewayIPv6: net.ParseIP("2001:db8:ac:b004::bad:a55"), + } + err = c.Validate() + if err == nil { + t.Fatalf("Failed to detect invalid v6 default gateway") + } + + c.DefaultGatewayIPv6 = net.ParseIP("2001:db8:ae:b004::bad:a55") + err = c.Validate() + if err != nil { + t.Fatalf("Unexpected validation error on v6 default gateway") + } + + c.AddressIPv6 = nil + err = c.Validate() + if err == nil { + t.Fatalf("Failed to detect invalid v6 default gateway") + } + + c.AddressIPv6 = nil + err = c.Validate() + if err == nil { + t.Fatalf("Failed to detect invalid v6 default gateway") + } +} diff --git a/drivers/solaris/bridge/errors.go b/drivers/solaris/bridge/errors.go new file mode 100644 index 0000000000..ceb238895f --- /dev/null +++ b/drivers/solaris/bridge/errors.go @@ -0,0 +1,119 @@ +package bridge + +import "fmt" + +// ErrInvalidEndpointConfig error is returned when an endpoint create is attempted with an invalid endpoint configuration. +type ErrInvalidEndpointConfig struct{} + +func (eiec *ErrInvalidEndpointConfig) Error() string { + return "trying to create an endpoint with an invalid endpoint configuration" +} + +// BadRequest denotes the type of this error +func (eiec *ErrInvalidEndpointConfig) BadRequest() {} + +// ErrNoIPAddr error is returned when bridge has no IPv4 address configured. +type ErrNoIPAddr struct{} + +func (enip *ErrNoIPAddr) Error() string { + return "bridge has no IPv4 address configured" +} + +// InternalError denotes the type of this error +func (enip *ErrNoIPAddr) InternalError() {} + +// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid. +type ErrInvalidGateway struct{} + +func (eig *ErrInvalidGateway) Error() string { + return "default gateway ip must be part of the network" +} + +// BadRequest denotes the type of this error +func (eig *ErrInvalidGateway) BadRequest() {} + +// ErrInvalidMtu is returned when the user provided MTU is not valid. +type ErrInvalidMtu int + +func (eim ErrInvalidMtu) Error() string { + return fmt.Sprintf("invalid MTU number: %d", int(eim)) +} + +// BadRequest denotes the type of this error +func (eim ErrInvalidMtu) BadRequest() {} + +// ErrUnsupportedAddressType is returned when the specified address type is not supported. +type ErrUnsupportedAddressType string + +func (uat ErrUnsupportedAddressType) Error() string { + return fmt.Sprintf("unsupported address type: %s", string(uat)) +} + +// BadRequest denotes the type of this error +func (uat ErrUnsupportedAddressType) BadRequest() {} + +// ActiveEndpointsError is returned when there are +// still active endpoints in the network being deleted. +type ActiveEndpointsError string + +func (aee ActiveEndpointsError) Error() string { + return fmt.Sprintf("network %s has active endpoint", string(aee)) +} + +// Forbidden denotes the type of this error +func (aee ActiveEndpointsError) Forbidden() {} + +// InvalidNetworkIDError is returned when the passed +// network id for an existing network is not a known id. +type InvalidNetworkIDError string + +func (inie InvalidNetworkIDError) Error() string { + return fmt.Sprintf("invalid network id %s", string(inie)) +} + +// NotFound denotes the type of this error +func (inie InvalidNetworkIDError) NotFound() {} + +// InvalidEndpointIDError is returned when the passed +// endpoint id is not valid. +type InvalidEndpointIDError string + +func (ieie InvalidEndpointIDError) Error() string { + return fmt.Sprintf("invalid endpoint id: %s", string(ieie)) +} + +// BadRequest denotes the type of this error +func (ieie InvalidEndpointIDError) BadRequest() {} + +// EndpointNotFoundError is returned when the no endpoint +// with the passed endpoint id is found. +type EndpointNotFoundError string + +func (enfe EndpointNotFoundError) Error() string { + return fmt.Sprintf("endpoint not found: %s", string(enfe)) +} + +// NotFound denotes the type of this error +func (enfe EndpointNotFoundError) NotFound() {} + +// NonDefaultBridgeExistError is returned when a non-default +// bridge config is passed but it does not already exist. +type NonDefaultBridgeExistError string + +func (ndbee NonDefaultBridgeExistError) Error() string { + return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee)) +} + +// Forbidden denotes the type of this error +func (ndbee NonDefaultBridgeExistError) Forbidden() {} + +// NonDefaultBridgeNeedsIPError is returned when a non-default +// bridge config is passed but it has no ip configured +type NonDefaultBridgeNeedsIPError string + +func (ndbee NonDefaultBridgeNeedsIPError) Error() string { + return fmt.Sprintf("bridge device with non default name %s must have a valid IP address", string(ndbee)) +} + +// Forbidden denotes the type of this error +func (ndbee NonDefaultBridgeNeedsIPError) Forbidden() {} diff --git a/drivers/solaris/bridge/port_mapping.go b/drivers/solaris/bridge/port_mapping.go new file mode 100644 index 0000000000..38162c7592 --- /dev/null +++ b/drivers/solaris/bridge/port_mapping.go @@ -0,0 +1,225 @@ +// +build solaris + +package bridge + +import ( + "bytes" + "errors" + "fmt" + "net" + "os" + "os/exec" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/types" +) + +var ( + defaultBindingIP = net.IPv4(0, 0, 0, 0) +) + +const ( + maxAllocatePortAttempts = 10 +) + +func addPFRules(epid, bindIntf string, bs []types.PortBinding) { + var id string + + if len(epid) > 12 { + id = epid[:12] + } else { + id = epid + } + + fname := "/var/lib/docker/network/files/pf." + id + + f, err := os.OpenFile(fname, + os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if err != nil { + logrus.Warnf("cannot open temp pf file") + return + } + for _, b := range bs { + r := fmt.Sprintf( + "pass in on %s proto %s from any to (%s) "+ + "port %d rdr-to %s port %d\n", bindIntf, + b.Proto.String(), bindIntf, b.HostPort, + b.IP.String(), b.Port) + _, err = f.WriteString(r) + if err != nil { + logrus.Warnf("cannot write firewall rules to %s: %v", fname, err) + } + } + f.Close() + + anchor := fmt.Sprintf("_auto/docker/ep%s", id) + err = exec.Command("/usr/sbin/pfctl", "-a", anchor, "-f", fname).Run() + if err != nil { + logrus.Warnf("failed to add firewall rules: %v", err) + } + os.Remove(fname) +} + +func removePFRules(epid string) { + var id string + + if len(epid) > 12 { + id = epid[:12] + } else { + id = epid + } + + anchor := fmt.Sprintf("_auto/docker/ep%s", id) + err := exec.Command("/usr/sbin/pfctl", "-a", anchor, "-F", "all").Run() + if err != nil { + logrus.Warnf("failed to remove firewall rules: %v", err) + } +} + +func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, bindIntf string, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { + if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil { + return nil, nil + } + + defHostIP := defaultBindingIP + if reqDefBindIP != nil { + defHostIP = reqDefBindIP + } + + bs, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, bindIntf, ep.addr.IP, defHostIP, ulPxyEnabled) + if err != nil { + return nil, err + } + + // Add PF rules for port bindings, if any + if len(bs) > 0 { + addPFRules(ep.id, bindIntf, bs) + } + + return bs, err +} + +func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, bindIntf string, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { + bs := make([]types.PortBinding, 0, len(bindings)) + for _, c := range bindings { + b := c.GetCopy() + if err := n.allocatePort(&b, containerIP, defHostIP); err != nil { + // On allocation failure,release previously + // allocated ports. On cleanup error, just log + // a warning message + if cuErr := n.releasePortsInternal(bs); cuErr != nil { + logrus.Warnf("Upon allocation failure "+ + "for %v, failed to clear previously "+ + "allocated port bindings: %v", b, cuErr) + } + return nil, err + } + bs = append(bs, b) + } + return bs, nil +} + +func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP) error { + var ( + host net.Addr + err error + ) + + // Store the container interface address in the operational binding + bnd.IP = containerIP + + // Adjust the host address in the operational binding + if len(bnd.HostIP) == 0 { + bnd.HostIP = defHostIP + } + + // Adjust HostPortEnd if this is not a range. + if bnd.HostPortEnd == 0 { + bnd.HostPortEnd = bnd.HostPort + } + + // Construct the container side transport address + container, err := bnd.ContainerAddr() + if err != nil { + return err + } + + // Try up to maxAllocatePortAttempts times to get a port that's + // not already allocated. + for i := 0; i < maxAllocatePortAttempts; i++ { + if host, err = n.portMapper.MapRange(container, bnd.HostIP, + int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil { + break + } + // There is no point in immediately retrying to map an + // explicitly chosen port. + if bnd.HostPort != 0 { + logrus.Warnf( + "Failed to allocate and map port %d-%d: %s", + bnd.HostPort, bnd.HostPortEnd, err) + break + } + logrus.Warnf("Failed to allocate and map port: %s, retry: %d", + err, i+1) + } + if err != nil { + return err + } + + // Save the host port (regardless it was or not specified in the + // binding) + switch netAddr := host.(type) { + case *net.TCPAddr: + bnd.HostPort = uint16(host.(*net.TCPAddr).Port) + return nil + case *net.UDPAddr: + bnd.HostPort = uint16(host.(*net.UDPAddr).Port) + return nil + default: + // For completeness + return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr)) + } +} + +func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error { + err := n.releasePortsInternal(ep.portMapping) + if err != nil { + return nil + } + + // remove rules if there are any port mappings + if len(ep.portMapping) > 0 { + removePFRules(ep.id) + } + + return nil + +} + +func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error { + var errorBuf bytes.Buffer + + // Attempt to release all port bindings, do not stop on failure + for _, m := range bindings { + if err := n.releasePort(m); err != nil { + errorBuf.WriteString( + fmt.Sprintf( + "\ncould not release %v because of %v", + m, err)) + } + } + + if errorBuf.Len() != 0 { + return errors.New(errorBuf.String()) + } + return nil +} + +func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error { + // Construct the host side transport address + host, err := bnd.HostAddr() + if err != nil { + return err + } + return n.portMapper.Unmap(host) +} diff --git a/drivers_solaris.go b/drivers_solaris.go index 89ae42c58c..ba5d6a93e0 100644 --- a/drivers_solaris.go +++ b/drivers_solaris.go @@ -1,5 +1,13 @@ package libnetwork +import ( + "github.com/docker/libnetwork/drivers/null" + "github.com/docker/libnetwork/drivers/solaris/bridge" +) + func getInitializers() []initializer { - return []initializer{} + return []initializer{ + {bridge.Init, "bridge"}, + {null.Init, "null"}, + } } diff --git a/libnetwork_linux_test.go b/libnetwork_linux_test.go new file mode 100644 index 0000000000..37121bd8b0 --- /dev/null +++ b/libnetwork_linux_test.go @@ -0,0 +1,995 @@ +package libnetwork_test + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "net" + "os" + "os/exec" + "runtime" + "strconv" + "strings" + "testing" + + log "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/reexec" + "github.com/docker/libnetwork" + "github.com/docker/libnetwork/ipamapi" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/options" + "github.com/docker/libnetwork/osl" + "github.com/docker/libnetwork/testutils" + "github.com/docker/libnetwork/types" + "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" +) + +func TestHost(t *testing.T) { + sbx1, err := controller.NewSandbox("host_c1", + libnetwork.OptionHostname("test1"), + libnetwork.OptionDomainname("docker.io"), + libnetwork.OptionExtraHost("web", "192.168.0.1"), + libnetwork.OptionUseDefaultSandbox()) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := sbx1.Delete(); err != nil { + t.Fatal(err) + } + }() + + sbx2, err := controller.NewSandbox("host_c2", + libnetwork.OptionHostname("test2"), + libnetwork.OptionDomainname("docker.io"), + libnetwork.OptionExtraHost("web", "192.168.0.1"), + libnetwork.OptionUseDefaultSandbox()) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := sbx2.Delete(); err != nil { + t.Fatal(err) + } + }() + + network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil) + if err != nil { + t.Fatal(err) + } + + ep1, err := network.CreateEndpoint("testep1") + if err != nil { + t.Fatal(err) + } + + if err := ep1.Join(sbx1); err != nil { + t.Fatal(err) + } + + ep2, err := network.CreateEndpoint("testep2") + if err != nil { + t.Fatal(err) + } + + if err := ep2.Join(sbx2); err != nil { + t.Fatal(err) + } + + if err := ep1.Leave(sbx1); err != nil { + t.Fatal(err) + } + + if err := ep2.Leave(sbx2); err != nil { + t.Fatal(err) + } + + if err := ep1.Delete(false); err != nil { + t.Fatal(err) + } + + if err := ep2.Delete(false); err != nil { + t.Fatal(err) + } + + // Try to create another host endpoint and join/leave that. + cnt3, err := controller.NewSandbox("host_c3", + libnetwork.OptionHostname("test3"), + libnetwork.OptionDomainname("docker.io"), + libnetwork.OptionExtraHost("web", "192.168.0.1"), + libnetwork.OptionUseDefaultSandbox()) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := cnt3.Delete(); err != nil { + t.Fatal(err) + } + }() + + ep3, err := network.CreateEndpoint("testep3") + if err != nil { + t.Fatal(err) + } + + if err := ep3.Join(sbx2); err != nil { + t.Fatal(err) + } + + if err := ep3.Leave(sbx2); err != nil { + t.Fatal(err) + } + + if err := ep3.Delete(false); err != nil { + t.Fatal(err) + } +} + +// Testing IPV6 from MAC address +func TestBridgeIpv6FromMac(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + netOption := options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": "testipv6mac", + "EnableICC": true, + "EnableIPMasquerade": true, + }, + } + ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}} + ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}} + + network, err := controller.NewNetwork(bridgeNetType, "testipv6mac", "", + libnetwork.NetworkOptionGeneric(netOption), + libnetwork.NetworkOptionEnableIPv6(true), + libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4ConfList, ipamV6ConfList, nil), + libnetwork.NetworkOptionDeferIPv6Alloc(true)) + if err != nil { + t.Fatal(err) + } + + mac := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} + epOption := options.Generic{netlabel.MacAddress: mac} + + ep, err := network.CreateEndpoint("testep", libnetwork.EndpointOptionGeneric(epOption)) + if err != nil { + t.Fatal(err) + } + + iface := ep.Info().Iface() + if !bytes.Equal(iface.MacAddress(), mac) { + t.Fatalf("Unexpected mac address: %v", iface.MacAddress()) + } + + ip, expIP, _ := net.ParseCIDR("fe90::aabb:ccdd:eeff/64") + expIP.IP = ip + if !types.CompareIPNet(expIP, iface.AddressIPv6()) { + t.Fatalf("Expected %v. Got: %v", expIP, iface.AddressIPv6()) + } + + if err := ep.Delete(false); err != nil { + t.Fatal(err) + } + + if err := network.Delete(); err != nil { + t.Fatal(err) + } +} + +func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) { + key := info.Sandbox().Key() + sbNs, err := netns.GetFromPath(key) + if err != nil { + t.Fatalf("Failed to get network namespace path %q: %v", key, err) + } + defer sbNs.Close() + + nh, err := netlink.NewHandleAt(sbNs) + if err != nil { + t.Fatal(err) + } + + _, err = nh.LinkByName("eth0") + if err != nil { + t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err) + } + + _, err = nh.LinkByName("eth1") + if err != nil { + t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err) + } +} + +func TestEndpointJoin(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + // Create network 1 and add 2 endpoint: ep11, ep12 + netOption := options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": "testnetwork1", + "EnableICC": true, + "EnableIPMasquerade": true, + }, + } + ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}} + n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "", + libnetwork.NetworkOptionGeneric(netOption), + libnetwork.NetworkOptionEnableIPv6(true), + libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil), + libnetwork.NetworkOptionDeferIPv6Alloc(true)) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n1.Delete(); err != nil { + t.Fatal(err) + } + }() + + ep1, err := n1.CreateEndpoint("ep1") + if err != nil { + t.Fatal(err) + } + defer func() { + if err := ep1.Delete(false); err != nil { + t.Fatal(err) + } + }() + + // Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint() + info := ep1.Info() + iface := info.Iface() + if iface.Address() != nil && iface.Address().IP.To4() == nil { + t.Fatalf("Invalid IP address returned: %v", iface.Address()) + } + if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil { + t.Fatalf("Invalid IPv6 address returned: %v", iface.Address()) + } + + if len(info.Gateway()) != 0 { + t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway()) + } + if len(info.GatewayIPv6()) != 0 { + t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6()) + } + + if info.Sandbox() != nil { + t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key()) + } + + // test invalid joins + err = ep1.Join(nil) + if err == nil { + t.Fatalf("Expected to fail join with nil Sandbox") + } + if _, ok := err.(types.BadRequestError); !ok { + t.Fatalf("Unexpected error type returned: %T", err) + } + + fsbx := &fakeSandbox{} + if err = ep1.Join(fsbx); err == nil { + t.Fatalf("Expected to fail join with invalid Sandbox") + } + if _, ok := err.(types.BadRequestError); !ok { + t.Fatalf("Unexpected error type returned: %T", err) + } + + sb, err := controller.NewSandbox(containerID, + libnetwork.OptionHostname("test"), + libnetwork.OptionDomainname("docker.io"), + libnetwork.OptionExtraHost("web", "192.168.0.1")) + if err != nil { + t.Fatal(err) + } + + defer func() { + if err := sb.Delete(); err != nil { + t.Fatal(err) + } + }() + + err = ep1.Join(sb) + if err != nil { + t.Fatal(err) + } + defer func() { + err = ep1.Leave(sb) + if err != nil { + t.Fatal(err) + } + }() + + // Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined. + info = ep1.Info() + if len(info.Gateway()) == 0 { + t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway()) + } + if len(info.GatewayIPv6()) == 0 { + t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6()) + } + + if info.Sandbox() == nil { + t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key") + } + + // Check endpoint provided container information + if ep1.Info().Sandbox().Key() != sb.Key() { + t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key()) + } + + // Attempt retrieval of endpoint interfaces statistics + stats, err := sb.Statistics() + if err != nil { + t.Fatal(err) + } + if _, ok := stats["eth0"]; !ok { + t.Fatalf("Did not find eth0 statistics") + } + + // Now test the container joining another network + n2, err := createTestNetwork(bridgeNetType, "testnetwork2", + options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": "testnetwork2", + }, + }, nil, nil) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n2.Delete(); err != nil { + t.Fatal(err) + } + }() + + ep2, err := n2.CreateEndpoint("ep2") + if err != nil { + t.Fatal(err) + } + defer func() { + if err := ep2.Delete(false); err != nil { + t.Fatal(err) + } + }() + + err = ep2.Join(sb) + if err != nil { + t.Fatal(err) + } + defer func() { + err = ep2.Leave(sb) + if err != nil { + t.Fatal(err) + } + }() + + if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() { + t.Fatalf("ep1 and ep2 returned different container sandbox key") + } + + checkSandbox(t, info) +} + +func TestExternalKey(t *testing.T) { + externalKeyTest(t, false) +} + +func externalKeyTest(t *testing.T, reexec bool) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": "testnetwork", + }, + }, nil, nil) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n.Delete(); err != nil { + t.Fatal(err) + } + }() + + ep, err := n.CreateEndpoint("ep1") + if err != nil { + t.Fatal(err) + } + defer func() { + err = ep.Delete(false) + if err != nil { + t.Fatal(err) + } + }() + + ep2, err := n.CreateEndpoint("ep2") + if err != nil { + t.Fatal(err) + } + defer func() { + err = ep2.Delete(false) + if err != nil { + t.Fatal(err) + } + }() + + cnt, err := controller.NewSandbox(containerID, + libnetwork.OptionHostname("test"), + libnetwork.OptionDomainname("docker.io"), + libnetwork.OptionUseExternalKey(), + libnetwork.OptionExtraHost("web", "192.168.0.1")) + defer func() { + if err := cnt.Delete(); err != nil { + t.Fatal(err) + } + osl.GC() + }() + + // Join endpoint to sandbox before SetKey + err = ep.Join(cnt) + if err != nil { + t.Fatal(err) + } + defer func() { + err = ep.Leave(cnt) + if err != nil { + t.Fatal(err) + } + }() + + sbox := ep.Info().Sandbox() + if sbox == nil { + t.Fatalf("Expected to have a valid Sandbox") + } + + if reexec { + err := reexecSetKey("this-must-fail", containerID, controller.ID()) + if err == nil { + t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created") + } + } else { + // Setting an non-existing key (namespace) must fail + if err := sbox.SetKey("this-must-fail"); err == nil { + t.Fatalf("Setkey must fail if the corresponding namespace is not created") + } + } + + // Create a new OS sandbox using the osl API before using it in SetKey + if extOsBox, err := osl.NewSandbox("ValidKey", true, false); err != nil { + t.Fatalf("Failed to create new osl sandbox") + } else { + defer func() { + if err := extOsBox.Destroy(); err != nil { + log.Warnf("Failed to remove os sandbox: %v", err) + } + }() + } + + if reexec { + err := reexecSetKey("ValidKey", containerID, controller.ID()) + if err != nil { + t.Fatalf("SetExternalKey failed with %v", err) + } + } else { + if err := sbox.SetKey("ValidKey"); err != nil { + t.Fatalf("Setkey failed with %v", err) + } + } + + // Join endpoint to sandbox after SetKey + err = ep2.Join(sbox) + if err != nil { + t.Fatal(err) + } + defer func() { + err = ep2.Leave(sbox) + if err != nil { + t.Fatal(err) + } + }() + + if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() { + t.Fatalf("ep1 and ep2 returned different container sandbox key") + } + + checkSandbox(t, ep.Info()) +} + +func reexecSetKey(key string, containerID string, controllerID string) error { + var ( + state libcontainer.State + b []byte + err error + ) + + state.NamespacePaths = make(map[configs.NamespaceType]string) + state.NamespacePaths[configs.NamespaceType("NEWNET")] = key + if b, err = json.Marshal(state); err != nil { + return err + } + cmd := &exec.Cmd{ + Path: reexec.Self(), + Args: append([]string{"libnetwork-setkey"}, containerID, controllerID), + Stdin: strings.NewReader(string(b)), + Stdout: os.Stdout, + Stderr: os.Stderr, + } + return cmd.Run() +} + +func TestEnableIPv6(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n") + expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\noptions ndots:0\n") + //take a copy of resolv.conf for restoring after test completes + resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") + if err != nil { + t.Fatal(err) + } + //cleanup + defer func() { + if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { + t.Fatal(err) + } + }() + + netOption := options.Generic{ + netlabel.EnableIPv6: true, + netlabel.GenericData: options.Generic{ + "BridgeName": "testnetwork", + }, + } + ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe99::/64", Gateway: "fe99::9"}} + + n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, ipamV6ConfList) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n.Delete(); err != nil { + t.Fatal(err) + } + }() + + ep1, err := n.CreateEndpoint("ep1") + if err != nil { + t.Fatal(err) + } + + if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { + t.Fatal(err) + } + + resolvConfPath := "/tmp/libnetwork_test/resolv.conf" + defer os.Remove(resolvConfPath) + + sb, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath)) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := sb.Delete(); err != nil { + t.Fatal(err) + } + }() + + err = ep1.Join(sb) + if err != nil { + t.Fatal(err) + } + + content, err := ioutil.ReadFile(resolvConfPath) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(content, expectedResolvConf) { + t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf), string(content)) + } + + if err != nil { + t.Fatal(err) + } +} + +func TestResolvConfHost(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888\n") + + //take a copy of resolv.conf for restoring after test completes + resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") + if err != nil { + t.Fatal(err) + } + //cleanup + defer func() { + if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { + t.Fatal(err) + } + }() + + n, err := controller.NetworkByName("testhost") + if err != nil { + t.Fatal(err) + } + + ep1, err := n.CreateEndpoint("ep1", libnetwork.CreateOptionDisableResolution()) + if err != nil { + t.Fatal(err) + } + + if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { + t.Fatal(err) + } + + resolvConfPath := "/tmp/libnetwork_test/resolv.conf" + defer os.Remove(resolvConfPath) + + sb, err := controller.NewSandbox(containerID, + libnetwork.OptionResolvConfPath(resolvConfPath), + libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := sb.Delete(); err != nil { + t.Fatal(err) + } + }() + + err = ep1.Join(sb) + if err != nil { + t.Fatal(err) + } + defer func() { + err = ep1.Leave(sb) + if err != nil { + t.Fatal(err) + } + }() + + finfo, err := os.Stat(resolvConfPath) + if err != nil { + t.Fatal(err) + } + + fmode := (os.FileMode)(0644) + if finfo.Mode() != fmode { + t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String()) + } + + content, err := ioutil.ReadFile(resolvConfPath) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(content, tmpResolvConf) { + t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content)) + } +} + +func TestResolvConf(t *testing.T) { + if !testutils.IsRunningInContainer() { + defer testutils.SetupTestOSContext(t)() + } + + tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n") + tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888\n") + expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\noptions ndots:0\n") + tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n") + + //take a copy of resolv.conf for restoring after test completes + resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") + if err != nil { + t.Fatal(err) + } + //cleanup + defer func() { + if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { + t.Fatal(err) + } + }() + + netOption := options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": "testnetwork", + }, + } + n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, nil) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n.Delete(); err != nil { + t.Fatal(err) + } + }() + + ep, err := n.CreateEndpoint("ep") + if err != nil { + t.Fatal(err) + } + + if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf1, 0644); err != nil { + t.Fatal(err) + } + + resolvConfPath := "/tmp/libnetwork_test/resolv.conf" + defer os.Remove(resolvConfPath) + + sb1, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath)) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := sb1.Delete(); err != nil { + t.Fatal(err) + } + }() + + err = ep.Join(sb1) + if err != nil { + t.Fatal(err) + } + + finfo, err := os.Stat(resolvConfPath) + if err != nil { + t.Fatal(err) + } + + fmode := (os.FileMode)(0644) + if finfo.Mode() != fmode { + t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String()) + } + + content, err := ioutil.ReadFile(resolvConfPath) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(content, expectedResolvConf1) { + fmt.Printf("\n%v\n%v\n", expectedResolvConf1, content) + t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content)) + } + + err = ep.Leave(sb1) + if err != nil { + t.Fatal(err) + } + + if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf2, 0644); err != nil { + t.Fatal(err) + } + + sb2, err := controller.NewSandbox(containerID+"_2", libnetwork.OptionResolvConfPath(resolvConfPath)) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := sb2.Delete(); err != nil { + t.Fatal(err) + } + }() + + err = ep.Join(sb2) + if err != nil { + t.Fatal(err) + } + + content, err = ioutil.ReadFile(resolvConfPath) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(content, expectedResolvConf1) { + t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content)) + } + + if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil { + t.Fatal(err) + } + + err = ep.Leave(sb2) + if err != nil { + t.Fatal(err) + } + + err = ep.Join(sb2) + if err != nil { + t.Fatal(err) + } + + content, err = ioutil.ReadFile(resolvConfPath) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(content, tmpResolvConf3) { + t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf3), string(content)) + } +} + +func parallelJoin(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) { + debugf("J%d.", thrNumber) + var err error + + sb := sboxes[thrNumber-1] + err = ep.Join(sb) + + runtime.LockOSThread() + if err != nil { + if _, ok := err.(types.ForbiddenError); !ok { + t.Fatalf("thread %d: %v", thrNumber, err) + } + debugf("JE%d(%v).", thrNumber, err) + } + debugf("JD%d.", thrNumber) +} + +func parallelLeave(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) { + debugf("L%d.", thrNumber) + var err error + + sb := sboxes[thrNumber-1] + + err = ep.Leave(sb) + runtime.LockOSThread() + if err != nil { + if _, ok := err.(types.ForbiddenError); !ok { + t.Fatalf("thread %d: %v", thrNumber, err) + } + debugf("LE%d(%v).", thrNumber, err) + } + debugf("LD%d.", thrNumber) +} + +func runParallelTests(t *testing.T, thrNumber int) { + var ( + ep libnetwork.Endpoint + sb libnetwork.Sandbox + err error + ) + + t.Parallel() + + pTest := flag.Lookup("test.parallel") + if pTest == nil { + t.Skip("Skipped because test.parallel flag not set;") + } + numParallel, err := strconv.Atoi(pTest.Value.String()) + if err != nil { + t.Fatal(err) + } + if numParallel < numThreads { + t.Skip("Skipped because t.parallel was less than ", numThreads) + } + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if thrNumber == first { + createGlobalInstance(t) + } + + if thrNumber != first { + select { + case <-start: + } + + thrdone := make(chan struct{}) + done <- thrdone + defer close(thrdone) + + if thrNumber == last { + defer close(done) + } + + err = netns.Set(testns) + if err != nil { + t.Fatal(err) + } + } + defer netns.Set(origns) + + net1, err := controller.NetworkByName("testhost") + if err != nil { + t.Fatal(err) + } + if net1 == nil { + t.Fatal("Could not find testhost") + } + + net2, err := controller.NetworkByName("network2") + if err != nil { + t.Fatal(err) + } + if net2 == nil { + t.Fatal("Could not find network2") + } + + epName := fmt.Sprintf("pep%d", thrNumber) + + if thrNumber == first { + ep, err = net1.EndpointByName(epName) + } else { + ep, err = net2.EndpointByName(epName) + } + + if err != nil { + t.Fatal(err) + } + if ep == nil { + t.Fatal("Got nil ep with no error") + } + + cid := fmt.Sprintf("%drace", thrNumber) + controller.WalkSandboxes(libnetwork.SandboxContainerWalker(&sb, cid)) + if sb == nil { + t.Fatalf("Got nil sandbox for container: %s", cid) + } + + for i := 0; i < iterCnt; i++ { + parallelJoin(t, sb, ep, thrNumber) + parallelLeave(t, sb, ep, thrNumber) + } + + debugf("\n") + + err = sb.Delete() + if err != nil { + t.Fatal(err) + } + if thrNumber == first { + for thrdone := range done { + select { + case <-thrdone: + } + } + + testns.Close() + if err := net2.Delete(); err != nil { + t.Fatal(err) + } + } else { + err = ep.Delete(false) + if err != nil { + t.Fatal(err) + } + } +} + +func TestParallel1(t *testing.T) { + runParallelTests(t, 1) +} + +func TestParallel2(t *testing.T) { + runParallelTests(t, 2) +} + +func TestParallel3(t *testing.T) { + runParallelTests(t, 3) +} + +func TestNullIpam(t *testing.T) { + _, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", "", libnetwork.NetworkOptionIpam(ipamapi.NullIPAM, "", nil, nil, nil)) + if err == nil || err.Error() != "ipv4 pool is empty" { + t.Fatal("bridge network should complain empty pool") + } +} diff --git a/libnetwork_test.go b/libnetwork_test.go index d918a9c442..1eee7fa6b8 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -1,19 +1,12 @@ package libnetwork_test import ( - "bytes" - "encoding/json" - "flag" "fmt" "io/ioutil" "net" "net/http" "net/http/httptest" "os" - "os/exec" - "runtime" - "strconv" - "strings" "sync" "testing" @@ -27,12 +20,8 @@ import ( "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/options" - "github.com/docker/libnetwork/osl" "github.com/docker/libnetwork/testutils" "github.com/docker/libnetwork/types" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/vishvananda/netlink" "github.com/vishvananda/netns" ) @@ -151,107 +140,6 @@ func TestNull(t *testing.T) { } } -func TestHost(t *testing.T) { - sbx1, err := controller.NewSandbox("host_c1", - libnetwork.OptionHostname("test1"), - libnetwork.OptionDomainname("docker.io"), - libnetwork.OptionExtraHost("web", "192.168.0.1"), - libnetwork.OptionUseDefaultSandbox()) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := sbx1.Delete(); err != nil { - t.Fatal(err) - } - }() - - sbx2, err := controller.NewSandbox("host_c2", - libnetwork.OptionHostname("test2"), - libnetwork.OptionDomainname("docker.io"), - libnetwork.OptionExtraHost("web", "192.168.0.1"), - libnetwork.OptionUseDefaultSandbox()) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := sbx2.Delete(); err != nil { - t.Fatal(err) - } - }() - - network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil) - if err != nil { - t.Fatal(err) - } - - ep1, err := network.CreateEndpoint("testep1") - if err != nil { - t.Fatal(err) - } - - if err := ep1.Join(sbx1); err != nil { - t.Fatal(err) - } - - ep2, err := network.CreateEndpoint("testep2") - if err != nil { - t.Fatal(err) - } - - if err := ep2.Join(sbx2); err != nil { - t.Fatal(err) - } - - if err := ep1.Leave(sbx1); err != nil { - t.Fatal(err) - } - - if err := ep2.Leave(sbx2); err != nil { - t.Fatal(err) - } - - if err := ep1.Delete(false); err != nil { - t.Fatal(err) - } - - if err := ep2.Delete(false); err != nil { - t.Fatal(err) - } - - // Try to create another host endpoint and join/leave that. - cnt3, err := controller.NewSandbox("host_c3", - libnetwork.OptionHostname("test3"), - libnetwork.OptionDomainname("docker.io"), - libnetwork.OptionExtraHost("web", "192.168.0.1"), - libnetwork.OptionUseDefaultSandbox()) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := cnt3.Delete(); err != nil { - t.Fatal(err) - } - }() - - ep3, err := network.CreateEndpoint("testep3") - if err != nil { - t.Fatal(err) - } - - if err := ep3.Join(sbx2); err != nil { - t.Fatal(err) - } - - if err := ep3.Leave(sbx2); err != nil { - t.Fatal(err) - } - - if err := ep3.Delete(false); err != nil { - t.Fatal(err) - } -} - func TestBridge(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() @@ -315,59 +203,6 @@ func TestBridge(t *testing.T) { } } -// Testing IPV6 from MAC address -func TestBridgeIpv6FromMac(t *testing.T) { - if !testutils.IsRunningInContainer() { - defer testutils.SetupTestOSContext(t)() - } - - netOption := options.Generic{ - netlabel.GenericData: options.Generic{ - "BridgeName": "testipv6mac", - "EnableICC": true, - "EnableIPMasquerade": true, - }, - } - ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}} - ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}} - - network, err := controller.NewNetwork(bridgeNetType, "testipv6mac", "", - libnetwork.NetworkOptionGeneric(netOption), - libnetwork.NetworkOptionEnableIPv6(true), - libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4ConfList, ipamV6ConfList, nil), - libnetwork.NetworkOptionDeferIPv6Alloc(true)) - if err != nil { - t.Fatal(err) - } - - mac := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} - epOption := options.Generic{netlabel.MacAddress: mac} - - ep, err := network.CreateEndpoint("testep", libnetwork.EndpointOptionGeneric(epOption)) - if err != nil { - t.Fatal(err) - } - - iface := ep.Info().Iface() - if !bytes.Equal(iface.MacAddress(), mac) { - t.Fatalf("Unexpected mac address: %v", iface.MacAddress()) - } - - ip, expIP, _ := net.ParseCIDR("fe90::aabb:ccdd:eeff/64") - expIP.IP = ip - if !types.CompareIPNet(expIP, iface.AddressIPv6()) { - t.Fatalf("Expected %v. Got: %v", expIP, iface.AddressIPv6()) - } - - if err := ep.Delete(false); err != nil { - t.Fatal(err) - } - - if err := network.Delete(); err != nil { - t.Fatal(err) - } -} - func TestUnknownDriver(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() @@ -966,202 +801,6 @@ func TestNetworkQuery(t *testing.T) { const containerID = "valid_c" -func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) { - key := info.Sandbox().Key() - sbNs, err := netns.GetFromPath(key) - if err != nil { - t.Fatalf("Failed to get network namespace path %q: %v", key, err) - } - defer sbNs.Close() - - nh, err := netlink.NewHandleAt(sbNs) - if err != nil { - t.Fatal(err) - } - - _, err = nh.LinkByName("eth0") - if err != nil { - t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err) - } - - _, err = nh.LinkByName("eth1") - if err != nil { - t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err) - } -} - -func TestEndpointJoin(t *testing.T) { - if !testutils.IsRunningInContainer() { - defer testutils.SetupTestOSContext(t)() - } - - // Create network 1 and add 2 endpoint: ep11, ep12 - netOption := options.Generic{ - netlabel.GenericData: options.Generic{ - "BridgeName": "testnetwork1", - "EnableICC": true, - "EnableIPMasquerade": true, - }, - } - ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}} - n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "", - libnetwork.NetworkOptionGeneric(netOption), - libnetwork.NetworkOptionEnableIPv6(true), - libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil), - libnetwork.NetworkOptionDeferIPv6Alloc(true)) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := n1.Delete(); err != nil { - t.Fatal(err) - } - }() - - ep1, err := n1.CreateEndpoint("ep1") - if err != nil { - t.Fatal(err) - } - defer func() { - if err := ep1.Delete(false); err != nil { - t.Fatal(err) - } - }() - - // Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint() - info := ep1.Info() - iface := info.Iface() - if iface.Address() != nil && iface.Address().IP.To4() == nil { - t.Fatalf("Invalid IP address returned: %v", iface.Address()) - } - if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil { - t.Fatalf("Invalid IPv6 address returned: %v", iface.Address()) - } - - if len(info.Gateway()) != 0 { - t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway()) - } - if len(info.GatewayIPv6()) != 0 { - t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6()) - } - - if info.Sandbox() != nil { - t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key()) - } - - // test invalid joins - err = ep1.Join(nil) - if err == nil { - t.Fatalf("Expected to fail join with nil Sandbox") - } - if _, ok := err.(types.BadRequestError); !ok { - t.Fatalf("Unexpected error type returned: %T", err) - } - - fsbx := &fakeSandbox{} - if err = ep1.Join(fsbx); err == nil { - t.Fatalf("Expected to fail join with invalid Sandbox") - } - if _, ok := err.(types.BadRequestError); !ok { - t.Fatalf("Unexpected error type returned: %T", err) - } - - sb, err := controller.NewSandbox(containerID, - libnetwork.OptionHostname("test"), - libnetwork.OptionDomainname("docker.io"), - libnetwork.OptionExtraHost("web", "192.168.0.1")) - if err != nil { - t.Fatal(err) - } - - defer func() { - if err := sb.Delete(); err != nil { - t.Fatal(err) - } - }() - - err = ep1.Join(sb) - if err != nil { - t.Fatal(err) - } - defer func() { - err = ep1.Leave(sb) - if err != nil { - t.Fatal(err) - } - }() - - // Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined. - info = ep1.Info() - if len(info.Gateway()) == 0 { - t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway()) - } - if len(info.GatewayIPv6()) == 0 { - t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6()) - } - - if info.Sandbox() == nil { - t.Fatalf("Expected a non-empty sandbox key for a joined endpoint. Instead found an empty sandbox key") - } - - // Check endpoint provided container information - if ep1.Info().Sandbox().Key() != sb.Key() { - t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key()) - } - - // Attempt retrieval of endpoint interfaces statistics - stats, err := sb.Statistics() - if err != nil { - t.Fatal(err) - } - if _, ok := stats["eth0"]; !ok { - t.Fatalf("Did not find eth0 statistics") - } - - // Now test the container joining another network - n2, err := createTestNetwork(bridgeNetType, "testnetwork2", - options.Generic{ - netlabel.GenericData: options.Generic{ - "BridgeName": "testnetwork2", - }, - }, nil, nil) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := n2.Delete(); err != nil { - t.Fatal(err) - } - }() - - ep2, err := n2.CreateEndpoint("ep2") - if err != nil { - t.Fatal(err) - } - defer func() { - if err := ep2.Delete(false); err != nil { - t.Fatal(err) - } - }() - - err = ep2.Join(sb) - if err != nil { - t.Fatal(err) - } - defer func() { - err = ep2.Leave(sb) - if err != nil { - t.Fatal(err) - } - }() - - if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() { - t.Fatalf("ep1 and ep2 returned different container sandbox key") - } - - checkSandbox(t, info) -} - type fakeSandbox struct{} func (f *fakeSandbox) ID() string { @@ -1216,11 +855,7 @@ func (f *fakeSandbox) Endpoints() []libnetwork.Endpoint { return nil } -func TestExternalKey(t *testing.T) { - externalKeyTest(t, false) -} - -func externalKeyTest(t *testing.T, reexec bool) { +func TestEndpointDeleteWithActiveContainer(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() } @@ -1250,30 +885,16 @@ func externalKeyTest(t *testing.T, reexec bool) { } }() - ep2, err := n.CreateEndpoint("ep2") - if err != nil { - t.Fatal(err) - } - defer func() { - err = ep2.Delete(false) - if err != nil { - t.Fatal(err) - } - }() - cnt, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), - libnetwork.OptionUseExternalKey(), libnetwork.OptionExtraHost("web", "192.168.0.1")) defer func() { if err := cnt.Delete(); err != nil { t.Fatal(err) } - osl.GC() }() - // Join endpoint to sandbox before SetKey err = ep.Join(cnt) if err != nil { t.Fatal(err) @@ -1285,146 +906,15 @@ func externalKeyTest(t *testing.T, reexec bool) { } }() - sbox := ep.Info().Sandbox() - if sbox == nil { - t.Fatalf("Expected to have a valid Sandbox") + err = ep.Delete(false) + if err == nil { + t.Fatal("Expected to fail. But instead succeeded") } - if reexec { - err := reexecSetKey("this-must-fail", containerID, controller.ID()) - if err == nil { - t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created") - } - } else { - // Setting a non-existing key (namespace) must fail - if err := sbox.SetKey("this-must-fail"); err == nil { - t.Fatalf("Setkey must fail if the corresponding namespace is not created") - } + if _, ok := err.(*libnetwork.ActiveContainerError); !ok { + t.Fatalf("Did not fail with expected error. Actual error: %v", err) } - - // Create a new OS sandbox using the osl API before using it in SetKey - if extOsBox, err := osl.NewSandbox("ValidKey", true, false); err != nil { - t.Fatalf("Failed to create new osl sandbox") - } else { - defer func() { - if err := extOsBox.Destroy(); err != nil { - log.Warnf("Failed to remove os sandbox: %v", err) - } - }() - } - - if reexec { - err := reexecSetKey("ValidKey", containerID, controller.ID()) - if err != nil { - t.Fatalf("SetExternalKey failed with %v", err) - } - } else { - if err := sbox.SetKey("ValidKey"); err != nil { - t.Fatalf("Setkey failed with %v", err) - } - } - - // Join endpoint to sandbox after SetKey - err = ep2.Join(sbox) - if err != nil { - t.Fatal(err) - } - defer func() { - err = ep2.Leave(sbox) - if err != nil { - t.Fatal(err) - } - }() - - if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() { - t.Fatalf("ep1 and ep2 returned different container sandbox key") - } - - checkSandbox(t, ep.Info()) -} - -func reexecSetKey(key string, containerID string, controllerID string) error { - var ( - state libcontainer.State - b []byte - err error - ) - - state.NamespacePaths = make(map[configs.NamespaceType]string) - state.NamespacePaths[configs.NamespaceType("NEWNET")] = key - if b, err = json.Marshal(state); err != nil { - return err - } - cmd := &exec.Cmd{ - Path: reexec.Self(), - Args: append([]string{"libnetwork-setkey"}, containerID, controllerID), - Stdin: strings.NewReader(string(b)), - Stdout: os.Stdout, - Stderr: os.Stderr, - } - return cmd.Run() -} - -func TestEndpointDeleteWithActiveContainer(t *testing.T) { - if !testutils.IsRunningInContainer() { - defer testutils.SetupTestOSContext(t)() - } - - n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{ - netlabel.GenericData: options.Generic{ - "BridgeName": "testnetwork", - }, - }, nil, nil) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := n.Delete(); err != nil { - t.Fatal(err) - } - }() - - ep, err := n.CreateEndpoint("ep1") - if err != nil { - t.Fatal(err) - } - defer func() { - err = ep.Delete(false) - if err != nil { - t.Fatal(err) - } - }() - - cnt, err := controller.NewSandbox(containerID, - libnetwork.OptionHostname("test"), - libnetwork.OptionDomainname("docker.io"), - libnetwork.OptionExtraHost("web", "192.168.0.1")) - defer func() { - if err := cnt.Delete(); err != nil { - t.Fatal(err) - } - }() - - err = ep.Join(cnt) - if err != nil { - t.Fatal(err) - } - defer func() { - err = ep.Leave(cnt) - if err != nil { - t.Fatal(err) - } - }() - - err = ep.Delete(false) - if err == nil { - t.Fatal("Expected to fail. But instead succeeded") - } - - if _, ok := err.(*libnetwork.ActiveContainerError); !ok { - t.Fatalf("Did not fail with expected error. Actual error: %v", err) - } -} +} func TestEndpointMultipleJoins(t *testing.T) { if !testutils.IsRunningInContainer() { @@ -1678,304 +1168,6 @@ func TestEndpointUpdateParent(t *testing.T) { } } -func TestEnableIPv6(t *testing.T) { - if !testutils.IsRunningInContainer() { - defer testutils.SetupTestOSContext(t)() - } - - tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n") - expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\noptions ndots:0\n") - //take a copy of resolv.conf for restoring after test completes - resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") - if err != nil { - t.Fatal(err) - } - //cleanup - defer func() { - if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { - t.Fatal(err) - } - }() - - netOption := options.Generic{ - netlabel.EnableIPv6: true, - netlabel.GenericData: options.Generic{ - "BridgeName": "testnetwork", - }, - } - ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe99::/64", Gateway: "fe99::9"}} - - n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, ipamV6ConfList) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := n.Delete(); err != nil { - t.Fatal(err) - } - }() - - ep1, err := n.CreateEndpoint("ep1") - if err != nil { - t.Fatal(err) - } - - if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { - t.Fatal(err) - } - - resolvConfPath := "/tmp/libnetwork_test/resolv.conf" - defer os.Remove(resolvConfPath) - - sb, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath)) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := sb.Delete(); err != nil { - t.Fatal(err) - } - }() - - err = ep1.Join(sb) - if err != nil { - t.Fatal(err) - } - - content, err := ioutil.ReadFile(resolvConfPath) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(content, expectedResolvConf) { - t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf), string(content)) - } - - if err != nil { - t.Fatal(err) - } -} - -func TestResolvConfHost(t *testing.T) { - if !testutils.IsRunningInContainer() { - defer testutils.SetupTestOSContext(t)() - } - - tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888\n") - - //take a copy of resolv.conf for restoring after test completes - resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") - if err != nil { - t.Fatal(err) - } - //cleanup - defer func() { - if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { - t.Fatal(err) - } - }() - - n, err := controller.NetworkByName("testhost") - if err != nil { - t.Fatal(err) - } - - ep1, err := n.CreateEndpoint("ep1", libnetwork.CreateOptionDisableResolution()) - if err != nil { - t.Fatal(err) - } - - if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { - t.Fatal(err) - } - - resolvConfPath := "/tmp/libnetwork_test/resolv.conf" - defer os.Remove(resolvConfPath) - - sb, err := controller.NewSandbox(containerID, - libnetwork.OptionResolvConfPath(resolvConfPath), - libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := sb.Delete(); err != nil { - t.Fatal(err) - } - }() - - err = ep1.Join(sb) - if err != nil { - t.Fatal(err) - } - defer func() { - err = ep1.Leave(sb) - if err != nil { - t.Fatal(err) - } - }() - - finfo, err := os.Stat(resolvConfPath) - if err != nil { - t.Fatal(err) - } - - fmode := (os.FileMode)(0644) - if finfo.Mode() != fmode { - t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String()) - } - - content, err := ioutil.ReadFile(resolvConfPath) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(content, tmpResolvConf) { - t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content)) - } -} - -func TestResolvConf(t *testing.T) { - if !testutils.IsRunningInContainer() { - defer testutils.SetupTestOSContext(t)() - } - - tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n") - tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888\n") - expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\noptions ndots:0\n") - tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n") - - //take a copy of resolv.conf for restoring after test completes - resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") - if err != nil { - t.Fatal(err) - } - //cleanup - defer func() { - if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { - t.Fatal(err) - } - }() - - netOption := options.Generic{ - netlabel.GenericData: options.Generic{ - "BridgeName": "testnetwork", - }, - } - n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, nil) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := n.Delete(); err != nil { - t.Fatal(err) - } - }() - - ep, err := n.CreateEndpoint("ep") - if err != nil { - t.Fatal(err) - } - - if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf1, 0644); err != nil { - t.Fatal(err) - } - - resolvConfPath := "/tmp/libnetwork_test/resolv.conf" - defer os.Remove(resolvConfPath) - - sb1, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath)) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := sb1.Delete(); err != nil { - t.Fatal(err) - } - }() - - err = ep.Join(sb1) - if err != nil { - t.Fatal(err) - } - - finfo, err := os.Stat(resolvConfPath) - if err != nil { - t.Fatal(err) - } - - fmode := (os.FileMode)(0644) - if finfo.Mode() != fmode { - t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String()) - } - - content, err := ioutil.ReadFile(resolvConfPath) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(content, expectedResolvConf1) { - fmt.Printf("\n%v\n%v\n", expectedResolvConf1, content) - t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content)) - } - - err = ep.Leave(sb1) - if err != nil { - t.Fatal(err) - } - - if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf2, 0644); err != nil { - t.Fatal(err) - } - - sb2, err := controller.NewSandbox(containerID+"_2", libnetwork.OptionResolvConfPath(resolvConfPath)) - if err != nil { - t.Fatal(err) - } - defer func() { - if err := sb2.Delete(); err != nil { - t.Fatal(err) - } - }() - - err = ep.Join(sb2) - if err != nil { - t.Fatal(err) - } - - content, err = ioutil.ReadFile(resolvConfPath) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(content, expectedResolvConf1) { - t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content)) - } - - if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil { - t.Fatal(err) - } - - err = ep.Leave(sb2) - if err != nil { - t.Fatal(err) - } - - err = ep.Join(sb2) - if err != nil { - t.Fatal(err) - } - - content, err = ioutil.ReadFile(resolvConfPath) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(content, tmpResolvConf3) { - t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf3), string(content)) - } -} - func TestInvalidRemoteDriver(t *testing.T) { if !testutils.IsRunningInContainer() { t.Skip("Skipping test when not running inside a Container") @@ -2164,171 +1356,3 @@ func debugf(format string, a ...interface{}) (int, error) { return 0, nil } - -func parallelJoin(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) { - debugf("J%d.", thrNumber) - var err error - - sb := sboxes[thrNumber-1] - err = ep.Join(sb) - - runtime.LockOSThread() - if err != nil { - if _, ok := err.(types.ForbiddenError); !ok { - t.Fatalf("thread %d: %v", thrNumber, err) - } - debugf("JE%d(%v).", thrNumber, err) - } - debugf("JD%d.", thrNumber) -} - -func parallelLeave(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) { - debugf("L%d.", thrNumber) - var err error - - sb := sboxes[thrNumber-1] - - err = ep.Leave(sb) - runtime.LockOSThread() - if err != nil { - if _, ok := err.(types.ForbiddenError); !ok { - t.Fatalf("thread %d: %v", thrNumber, err) - } - debugf("LE%d(%v).", thrNumber, err) - } - debugf("LD%d.", thrNumber) -} - -func runParallelTests(t *testing.T, thrNumber int) { - var ( - ep libnetwork.Endpoint - sb libnetwork.Sandbox - err error - ) - - t.Parallel() - - pTest := flag.Lookup("test.parallel") - if pTest == nil { - t.Skip("Skipped because test.parallel flag not set;") - } - numParallel, err := strconv.Atoi(pTest.Value.String()) - if err != nil { - t.Fatal(err) - } - if numParallel < numThreads { - t.Skip("Skipped because t.parallel was less than ", numThreads) - } - - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - if thrNumber == first { - createGlobalInstance(t) - } - - if thrNumber != first { - select { - case <-start: - } - - thrdone := make(chan struct{}) - done <- thrdone - defer close(thrdone) - - if thrNumber == last { - defer close(done) - } - - err = netns.Set(testns) - if err != nil { - t.Fatal(err) - } - } - defer netns.Set(origns) - - net1, err := controller.NetworkByName("testhost") - if err != nil { - t.Fatal(err) - } - if net1 == nil { - t.Fatal("Could not find testhost") - } - - net2, err := controller.NetworkByName("network2") - if err != nil { - t.Fatal(err) - } - if net2 == nil { - t.Fatal("Could not find network2") - } - - epName := fmt.Sprintf("pep%d", thrNumber) - - if thrNumber == first { - ep, err = net1.EndpointByName(epName) - } else { - ep, err = net2.EndpointByName(epName) - } - - if err != nil { - t.Fatal(err) - } - if ep == nil { - t.Fatal("Got nil ep with no error") - } - - cid := fmt.Sprintf("%drace", thrNumber) - controller.WalkSandboxes(libnetwork.SandboxContainerWalker(&sb, cid)) - if sb == nil { - t.Fatalf("Got nil sandbox for container: %s", cid) - } - - for i := 0; i < iterCnt; i++ { - parallelJoin(t, sb, ep, thrNumber) - parallelLeave(t, sb, ep, thrNumber) - } - - debugf("\n") - - err = sb.Delete() - if err != nil { - t.Fatal(err) - } - if thrNumber == first { - for thrdone := range done { - select { - case <-thrdone: - } - } - - testns.Close() - if err := net2.Delete(); err != nil { - t.Fatal(err) - } - } else { - err = ep.Delete(false) - if err != nil { - t.Fatal(err) - } - } -} - -func TestParallel1(t *testing.T) { - runParallelTests(t, 1) -} - -func TestParallel2(t *testing.T) { - runParallelTests(t, 2) -} - -func TestParallel3(t *testing.T) { - runParallelTests(t, 3) -} - -func TestNullIpam(t *testing.T) { - _, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", "", libnetwork.NetworkOptionIpam(ipamapi.NullIPAM, "", nil, nil, nil)) - if err == nil || err.Error() != "ipv4 pool is empty" { - t.Fatal("bridge network should complain empty pool") - } -} diff --git a/netutils/utils_solaris.go b/netutils/utils_solaris.go index d0356f6262..12d453f7ce 100644 --- a/netutils/utils_solaris.go +++ b/netutils/utils_solaris.go @@ -1,13 +1,26 @@ -package netutils +// +build solaris -// Solaris: TODO +package netutils import ( + "fmt" "net" + "os/exec" + "strings" "github.com/docker/libnetwork/ipamutils" + "github.com/vishvananda/netlink" +) + +var ( + networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error) ) +// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes +func CheckRouteOverlaps(toCheck *net.IPNet) error { + return nil +} + // ElectInterfaceAddresses looks for an interface on the OS with the specified name // and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist, // it chooses from a predifined list the first IPv4 address which does not conflict @@ -15,18 +28,75 @@ import ( func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { var ( v4Net *net.IPNet - err error ) - v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) + out, err := exec.Command("/usr/sbin/ipadm", "show-addr", + "-p", "-o", "addrobj,addr").Output() if err != nil { + fmt.Println("failed to list interfaces on system") return nil, nil, err } + alist := strings.Fields(string(out)) + for _, a := range alist { + linkandaddr := strings.SplitN(a, ":", 2) + if len(linkandaddr) != 2 { + fmt.Println("failed to check interfaces on system: ", a) + continue + } + gw := fmt.Sprintf("%s_gw0", name) + link := strings.Split(linkandaddr[0], "/")[0] + addr := linkandaddr[1] + if gw != link { + continue + } + _, ipnet, err := net.ParseCIDR(addr) + if err != nil { + fmt.Println("failed to parse address: ", addr) + continue + } + v4Net = ipnet + break + } + if v4Net == nil { + v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) + if err != nil { + return nil, nil, err + } + } return v4Net, nil, nil } // FindAvailableNetwork returns a network from the passed list which does not // overlap with existing interfaces in the system func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) { - return list[0], nil + out, err := exec.Command("/usr/sbin/ipadm", "show-addr", + "-p", "-o", "addr").Output() + + if err != nil { + fmt.Println("failed to list interfaces on system") + return nil, err + } + ipaddrs := strings.Fields(string(out)) + inuse := []*net.IPNet{} + for _, ip := range ipaddrs { + _, ipnet, err := net.ParseCIDR(ip) + if err != nil { + fmt.Println("failed to check interfaces on system: ", ip) + continue + } + inuse = append(inuse, ipnet) + } + for _, avail := range list { + is_avail := true + for _, ipnet := range inuse { + if NetworkOverlaps(avail, ipnet) { + is_avail = false + break + } + } + if is_avail { + return avail, nil + } + } + return nil, fmt.Errorf("no available network") } diff --git a/netutils/utils_test.go b/netutils/utils_test.go index c051d6e0b1..87fbe6531f 100644 --- a/netutils/utils_test.go +++ b/netutils/utils_test.go @@ -1,3 +1,5 @@ +// +build !solaris + package netutils import ( diff --git a/osl/sandbox_solaris.go b/osl/sandbox_solaris.go new file mode 100644 index 0000000000..9de44e5a20 --- /dev/null +++ b/osl/sandbox_solaris.go @@ -0,0 +1,24 @@ +package osl + +// NewSandbox provides a new sandbox instance created in an os specific way +// provided a key which uniquely identifies the sandbox +func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) { + return nil, nil +} + +// GenerateKey generates a sandbox key based on the passed +// container id. +func GenerateKey(containerID string) string { + maxLen := 12 + + if len(containerID) < maxLen { + maxLen = len(containerID) + } + + return containerID[:maxLen] +} + +// InitOSContext initializes OS context while configuring network resources +func InitOSContext() func() { + return func() {} +} diff --git a/osl/sandbox_test.go b/osl/sandbox_test.go index d3bd1aceb8..f4830625b4 100644 --- a/osl/sandbox_test.go +++ b/osl/sandbox_test.go @@ -1,3 +1,5 @@ +// +build !solaris + package osl import ( diff --git a/osl/sandbox_unsupported.go b/osl/sandbox_unsupported.go index 51a656c806..49184d608d 100644 --- a/osl/sandbox_unsupported.go +++ b/osl/sandbox_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!freebsd +// +build !linux,!windows,!freebsd,!solaris package osl diff --git a/osl/sandbox_unsupported_test.go b/osl/sandbox_unsupported_test.go index 42dbb7c235..9ece5ae0c0 100644 --- a/osl/sandbox_unsupported_test.go +++ b/osl/sandbox_unsupported_test.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux,!solaris package osl diff --git a/portallocator/portallocator.go b/portallocator/portallocator.go index 240e94fc82..b7f790bed1 100644 --- a/portallocator/portallocator.go +++ b/portallocator/portallocator.go @@ -1,11 +1,9 @@ package portallocator import ( - "bufio" "errors" "fmt" "net" - "os" "sync" ) @@ -106,26 +104,6 @@ func newInstance() *PortAllocator { } } -func getDynamicPortRange() (start int, end int, err error) { - const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range" - portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd) - file, err := os.Open(portRangeKernelParam) - if err != nil { - return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err) - } - - defer file.Close() - - n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end) - if n != 2 || err != nil { - if err == nil { - err = fmt.Errorf("unexpected count of parsed numbers (%d)", n) - } - return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err) - } - return start, end, nil -} - // RequestPort requests new port from global ports pool for specified ip and proto. // If port is 0 it returns first free port. Otherwise it checks port availability // in proto's pool and returns that port or error if port is already busy. diff --git a/portallocator/portallocator_linux.go b/portallocator/portallocator_linux.go new file mode 100644 index 0000000000..687f6dabb7 --- /dev/null +++ b/portallocator/portallocator_linux.go @@ -0,0 +1,27 @@ +package portallocator + +import ( + "bufio" + "fmt" + "os" +) + +func getDynamicPortRange() (start int, end int, err error) { + const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range" + portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd) + file, err := os.Open(portRangeKernelParam) + if err != nil { + return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err) + } + + defer file.Close() + + n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end) + if n != 2 || err != nil { + if err == nil { + err = fmt.Errorf("unexpected count of parsed numbers (%d)", n) + } + return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err) + } + return start, end, nil +} diff --git a/portallocator/portallocator_solaris.go b/portallocator/portallocator_solaris.go new file mode 100644 index 0000000000..ccc20b1373 --- /dev/null +++ b/portallocator/portallocator_solaris.go @@ -0,0 +1,5 @@ +package portallocator + +func getDynamicPortRange() (start int, end int, err error) { + return 32768, 65535, nil +} diff --git a/portmapper/proxy.go b/portmapper/proxy.go index 6a4adbb872..a5bdc55348 100644 --- a/portmapper/proxy.go +++ b/portmapper/proxy.go @@ -7,8 +7,6 @@ import ( "net" "os" "os/exec" - "strconv" - "syscall" "time" ) @@ -25,36 +23,6 @@ type proxyCommand struct { cmd *exec.Cmd } -func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) { - path := proxyPath - if proxyPath == "" { - cmd, err := exec.LookPath(userlandProxyCommandName) - if err != nil { - return nil, err - } - path = cmd - } - - args := []string{ - path, - "-proto", proto, - "-host-ip", hostIP.String(), - "-host-port", strconv.Itoa(hostPort), - "-container-ip", containerIP.String(), - "-container-port", strconv.Itoa(containerPort), - } - - return &proxyCommand{ - cmd: &exec.Cmd{ - Path: path, - Args: args, - SysProcAttr: &syscall.SysProcAttr{ - Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies - }, - }, - }, nil -} - func (p *proxyCommand) Start() error { r, w, err := os.Pipe() if err != nil { diff --git a/portmapper/proxy_linux.go b/portmapper/proxy_linux.go new file mode 100644 index 0000000000..947cd0ba4b --- /dev/null +++ b/portmapper/proxy_linux.go @@ -0,0 +1,38 @@ +package portmapper + +import ( + "net" + "os/exec" + "strconv" + "syscall" +) + +func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) { + path := proxyPath + if proxyPath == "" { + cmd, err := exec.LookPath(userlandProxyCommandName) + if err != nil { + return nil, err + } + path = cmd + } + + args := []string{ + path, + "-proto", proto, + "-host-ip", hostIP.String(), + "-host-port", strconv.Itoa(hostPort), + "-container-ip", containerIP.String(), + "-container-port", strconv.Itoa(containerPort), + } + + return &proxyCommand{ + cmd: &exec.Cmd{ + Path: path, + Args: args, + SysProcAttr: &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies + }, + }, + }, nil +} diff --git a/portmapper/proxy_solaris.go b/portmapper/proxy_solaris.go new file mode 100644 index 0000000000..dc70b5edce --- /dev/null +++ b/portmapper/proxy_solaris.go @@ -0,0 +1,34 @@ +package portmapper + +import ( + "net" + "os/exec" + "strconv" +) + +func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) { + path := proxyPath + if proxyPath == "" { + cmd, err := exec.LookPath(userlandProxyCommandName) + if err != nil { + return nil, err + } + path = cmd + } + + args := []string{ + path, + "-proto", proto, + "-host-ip", hostIP.String(), + "-host-port", strconv.Itoa(hostPort), + "-container-ip", containerIP.String(), + "-container-port", strconv.Itoa(containerPort), + } + + return &proxyCommand{ + cmd: &exec.Cmd{ + Path: path, + Args: args, + }, + }, nil +} diff --git a/store_linux_test.go b/store_linux_test.go new file mode 100644 index 0000000000..a4cdd823e1 --- /dev/null +++ b/store_linux_test.go @@ -0,0 +1,45 @@ +package libnetwork + +import ( + "os" + "testing" + + "github.com/docker/libkv/store" + "github.com/docker/libnetwork/datastore" +) + +func TestBoltdbBackend(t *testing.T) { + defer os.Remove(datastore.DefaultScopes("")[datastore.LocalScope].Client.Address) + testLocalBackend(t, "", "", nil) + defer os.Remove("/tmp/boltdb.db") + config := &store.Config{Bucket: "testBackend"} + testLocalBackend(t, "boltdb", "/tmp/boltdb.db", config) + +} + +func TestNoPersist(t *testing.T) { + cfgOptions, err := OptionBoltdbWithRandomDBFile() + if err != nil { + t.Fatalf("Error creating random boltdb file : %v", err) + } + ctrl, err := New(cfgOptions...) + if err != nil { + t.Fatalf("Error new controller: %v", err) + } + nw, err := ctrl.NewNetwork("host", "host", "", NetworkOptionPersist(false)) + if err != nil { + t.Fatalf("Error creating default \"host\" network: %v", err) + } + ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...) + if err != nil { + t.Fatalf("Error creating endpoint: %v", err) + } + store := ctrl.(*controller).getStore(datastore.LocalScope).KVStore() + if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists { + t.Fatalf("Network with persist=false should not be stored in KV Store") + } + if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists { + t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store") + } + store.Close() +} diff --git a/store_test.go b/store_test.go index 9ef9fcef68..873660c074 100644 --- a/store_test.go +++ b/store_test.go @@ -3,7 +3,6 @@ package libnetwork import ( "fmt" "io/ioutil" - "os" "testing" "github.com/docker/libkv/store" @@ -31,15 +30,6 @@ func testNewController(t *testing.T, provider, url string) (NetworkController, e return New(cfgOptions...) } -func TestBoltdbBackend(t *testing.T) { - defer os.Remove(datastore.DefaultScopes("")[datastore.LocalScope].Client.Address) - testLocalBackend(t, "", "", nil) - defer os.Remove("/tmp/boltdb.db") - config := &store.Config{Bucket: "testBackend"} - testLocalBackend(t, "boltdb", "/tmp/boltdb.db", config) - -} - func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Config) { cfgOptions := []config.Option{} cfgOptions = append(cfgOptions, config.OptionLocalKVProvider(provider)) @@ -82,33 +72,6 @@ func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Con } } -func TestNoPersist(t *testing.T) { - cfgOptions, err := OptionBoltdbWithRandomDBFile() - if err != nil { - t.Fatalf("Error creating random boltdb file : %v", err) - } - ctrl, err := New(cfgOptions...) - if err != nil { - t.Fatalf("Error new controller: %v", err) - } - nw, err := ctrl.NewNetwork("host", "host", "", NetworkOptionPersist(false)) - if err != nil { - t.Fatalf("Error creating default \"host\" network: %v", err) - } - ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...) - if err != nil { - t.Fatalf("Error creating endpoint: %v", err) - } - store := ctrl.(*controller).getStore(datastore.LocalScope).KVStore() - if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists { - t.Fatalf("Network with persist=false should not be stored in KV Store") - } - if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists { - t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store") - } - store.Close() -} - // OptionBoltdbWithRandomDBFile function returns a random dir for local store backend func OptionBoltdbWithRandomDBFile() ([]config.Option, error) { tmp, err := ioutil.TempFile("", "libnetwork-") diff --git a/testutils/context_solaris.go b/testutils/context_solaris.go new file mode 100644 index 0000000000..2a9eee2cf2 --- /dev/null +++ b/testutils/context_solaris.go @@ -0,0 +1,25 @@ +// +build solaris + +package testutils + +import ( + "os" + "testing" +) + +// SetupTestOSContext joins a new network namespace, and returns its associated +// teardown function. +// +// Example usage: +// +// defer SetupTestOSContext(t)() +// +func SetupTestOSContext(t *testing.T) func() { + return func() { + } +} + +// RunningOnCircleCI returns true if being executed on libnetwork Circle CI setup +func RunningOnCircleCI() bool { + return os.Getenv("CIRCLECI") != "" +} From 5f99a7d85f6bad32afd86f3d86feacf6f9a9f3ce Mon Sep 17 00:00:00 2001 From: Anusha Ragunathan Date: Mon, 17 Oct 2016 14:35:38 -0700 Subject: [PATCH 112/799] Update loadDriver to use pluginv2. NetworkDrivers were still using v1 to Get plugins. Fix that. Signed-off-by: Anusha Ragunathan --- controller.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/controller.go b/controller.go index 2943c8c0a0..a4c0f160b0 100644 --- a/controller.go +++ b/controller.go @@ -1059,9 +1059,14 @@ func SandboxKeyWalker(out *Sandbox, key string) SandboxWalker { } func (c *controller) loadDriver(networkType string) error { - // Plugins pkg performs lazy loading of plugins that acts as remote drivers. - // As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available. - _, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType) + var err error + + if pg := c.GetPluginGetter(); pg != nil { + _, err = pg.Get(networkType, driverapi.NetworkPluginEndpointType, plugingetter.LOOKUP) + } else { + _, err = plugins.Get(networkType, driverapi.NetworkPluginEndpointType) + } + if err != nil { if err == plugins.ErrNotFound { return types.NotFoundErrorf(err.Error()) @@ -1073,7 +1078,15 @@ func (c *controller) loadDriver(networkType string) error { } func (c *controller) loadIPAMDriver(name string) error { - if _, err := c.GetPluginGetter().Get(name, ipamapi.PluginEndpointType, plugingetter.LOOKUP); err != nil { + var err error + + if pg := c.GetPluginGetter(); pg != nil { + _, err = pg.Get(name, ipamapi.PluginEndpointType, plugingetter.LOOKUP) + } else { + _, err = plugins.Get(name, ipamapi.PluginEndpointType) + } + + if err != nil { if err == plugins.ErrNotFound { return types.NotFoundErrorf(err.Error()) } From 1807951d7f02b89133e3e41d8aef72bd4ba0e673 Mon Sep 17 00:00:00 2001 From: allencloud Date: Mon, 17 Oct 2016 23:37:10 +0800 Subject: [PATCH 113/799] validate network and endpoint name more strictly Signed-off-by: allencloud --- config/config.go | 18 +++++++++++++----- config/config_test.go | 9 ++++++--- controller.go | 4 ++-- error.go | 2 +- network.go | 5 +++-- 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/config/config.go b/config/config.go index 8c3af13b22..a6ebd05284 100644 --- a/config/config.go +++ b/config/config.go @@ -1,6 +1,8 @@ package config import ( + "fmt" + "regexp" "strings" "github.com/BurntSushi/toml" @@ -15,6 +17,12 @@ import ( "github.com/docker/libnetwork/osl" ) +// RestrictedNameChars collects the characters allowed to represent a network or endpoint name. +const restrictedNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]` + +// RestrictedNamePattern is a regular expression to validate names against the collection of restricted characters. +var restrictedNamePattern = regexp.MustCompile(`^/?` + restrictedNameChars + `+$`) + // Config encapsulates configurations of various Libnetwork components type Config struct { Daemon DaemonCfg @@ -223,12 +231,12 @@ func (c *Config) ProcessOptions(options ...Option) { } } -// IsValidName validates configuration objects supported by libnetwork -func IsValidName(name string) bool { - if strings.TrimSpace(name) == "" { - return false +// ValidateName validates configuration objects supported by libnetwork +func ValidateName(name string) error { + if !restrictedNamePattern.MatchString(name) { + return fmt.Errorf("%s includes invalid characters, only %q are allowed", name, restrictedNameChars) } - return true + return nil } // OptionLocalKVProvider function returns an option setter for kvstore provider diff --git a/config/config_test.go b/config/config_test.go index ade9f746cd..a5feebac58 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -46,13 +46,16 @@ func TestOptionsLabels(t *testing.T) { } func TestValidName(t *testing.T) { - if !IsValidName("test") { + if err := ValidateName("test"); err != nil { t.Fatal("Name validation fails for a name that must be accepted") } - if IsValidName("") { + if err := ValidateName(""); err == nil { t.Fatal("Name validation succeeds for a case when it is expected to fail") } - if IsValidName(" ") { + if err := ValidateName(" "); err == nil { + t.Fatal("Name validation succeeds for a case when it is expected to fail") + } + if err := ValidateName("<>$$^"); err == nil { t.Fatal("Name validation succeeds for a case when it is expected to fail") } } diff --git a/controller.go b/controller.go index 914287a5be..c86df6686f 100644 --- a/controller.go +++ b/controller.go @@ -626,8 +626,8 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... } } - if !config.IsValidName(name) { - return nil, ErrInvalidName(name) + if err := config.ValidateName(name); err != nil { + return nil, ErrInvalidName(err.Error()) } if id == "" { diff --git a/error.go b/error.go index d1291f1db6..6c41bf166a 100644 --- a/error.go +++ b/error.go @@ -69,7 +69,7 @@ func (ii ErrInvalidID) Error() string { func (ii ErrInvalidID) BadRequest() {} // ErrInvalidName is returned when a query-by-name or resource create method is -// invoked with an empty name parameter +// invoked with an invalid name parameter type ErrInvalidName string func (in ErrInvalidName) Error() string { diff --git a/network.go b/network.go index 8a068d22e9..eebb46ffb2 100644 --- a/network.go +++ b/network.go @@ -848,8 +848,9 @@ func (n *network) addEndpoint(ep *endpoint) error { func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) { var err error - if !config.IsValidName(name) { - return nil, ErrInvalidName(name) + + if err = config.ValidateName(name); err != nil { + return nil, ErrInvalidName(err.Error()) } if _, err = n.EndpointByName(name); err == nil { From c254f3f59c2ee34f27ff09e9328196058ff38d23 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Tue, 18 Oct 2016 10:20:05 -0700 Subject: [PATCH 114/799] Fix map access race in populatedEndpoints Signed-off-by: Jana Radhakrishnan --- sandbox.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sandbox.go b/sandbox.go index f5d86ef20e..7d1eef5b73 100644 --- a/sandbox.go +++ b/sandbox.go @@ -848,8 +848,9 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error { releaseOSSboxResources(osSbox, ep) } - delete(sb.populatedEndpoints, ep.ID()) sb.Lock() + delete(sb.populatedEndpoints, ep.ID()) + if len(sb.endpoints) == 0 { // sb.endpoints should never be empty and this is unexpected error condition // We log an error message to note this down for debugging purposes. From 0a8b77fb8665c1eced7668b243f9078d8d8fdbc0 Mon Sep 17 00:00:00 2001 From: Justin Cormack Date: Wed, 19 Oct 2016 00:01:11 +0100 Subject: [PATCH 115/799] Do not use logrus for proxy This simplifies how we build it in docker/docker as no vendoring needed, and this does program not use any logrus features. Signed-off-by: Justin Cormack --- cmd/proxy/tcp_proxy.go | 7 +++---- cmd/proxy/udp_proxy.go | 9 ++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/cmd/proxy/tcp_proxy.go b/cmd/proxy/tcp_proxy.go index 514b778773..1c713105db 100644 --- a/cmd/proxy/tcp_proxy.go +++ b/cmd/proxy/tcp_proxy.go @@ -2,11 +2,10 @@ package main import ( "io" + "log" "net" "sync" "syscall" - - "github.com/Sirupsen/logrus" ) // TCPProxy is a proxy for TCP connections. It implements the Proxy interface to @@ -35,7 +34,7 @@ func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) { func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) { backend, err := net.DialTCP("tcp", nil, proxy.backendAddr) if err != nil { - logrus.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err) + log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err) client.Close() return } @@ -79,7 +78,7 @@ func (proxy *TCPProxy) Run() { for { client, err := proxy.listener.Accept() if err != nil { - logrus.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) + log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) return } go proxy.clientLoop(client.(*net.TCPConn), quit) diff --git a/cmd/proxy/udp_proxy.go b/cmd/proxy/udp_proxy.go index 2b895ae9d4..12b96db646 100644 --- a/cmd/proxy/udp_proxy.go +++ b/cmd/proxy/udp_proxy.go @@ -2,13 +2,12 @@ package main import ( "encoding/binary" + "log" "net" "strings" "sync" "syscall" "time" - - "github.com/Sirupsen/logrus" ) const ( @@ -112,7 +111,7 @@ func (proxy *UDPProxy) Run() { // ECONNREFUSED like Read do (see comment in // UDPProxy.replyLoop) if !isClosedError(err) { - logrus.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) + log.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) } break } @@ -123,7 +122,7 @@ func (proxy *UDPProxy) Run() { if !hit { proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr) if err != nil { - logrus.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) + log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) proxy.connTrackLock.Unlock() continue } @@ -134,7 +133,7 @@ func (proxy *UDPProxy) Run() { for i := 0; i != read; { written, err := proxyConn.Write(readBuf[i:read]) if err != nil { - logrus.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) + log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) break } i += written From 6d3db55103a4adef21dbb3111ccda9062450fdac Mon Sep 17 00:00:00 2001 From: Puneet Pruthi Date: Mon, 17 Oct 2016 13:29:10 -0700 Subject: [PATCH 116/799] overlay driver support for Solaris Signed-off-by: Puneet Pruthi --- default_gateway_solaris.go | 23 +- drivers/solaris/overlay/encryption.go | 274 ++++++ drivers/solaris/overlay/joinleave.go | 184 ++++ drivers/solaris/overlay/ov_endpoint.go | 249 ++++++ drivers/solaris/overlay/ov_network.go | 791 ++++++++++++++++++ drivers/solaris/overlay/ov_serf.go | 233 ++++++ drivers/solaris/overlay/ov_utils.go | 61 ++ drivers/solaris/overlay/overlay.go | 362 ++++++++ drivers/solaris/overlay/overlay.pb.go | 468 +++++++++++ drivers/solaris/overlay/overlay.proto | 27 + drivers/solaris/overlay/overlay_test.go | 138 +++ .../solaris/overlay/ovmanager/ovmanager.go | 248 ++++++ .../overlay/ovmanager/ovmanager_test.go | 89 ++ drivers/solaris/overlay/peerdb.go | 336 ++++++++ drivers_solaris.go | 2 + 15 files changed, 3483 insertions(+), 2 deletions(-) create mode 100644 drivers/solaris/overlay/encryption.go create mode 100644 drivers/solaris/overlay/joinleave.go create mode 100644 drivers/solaris/overlay/ov_endpoint.go create mode 100644 drivers/solaris/overlay/ov_network.go create mode 100644 drivers/solaris/overlay/ov_serf.go create mode 100644 drivers/solaris/overlay/ov_utils.go create mode 100644 drivers/solaris/overlay/overlay.go create mode 100644 drivers/solaris/overlay/overlay.pb.go create mode 100644 drivers/solaris/overlay/overlay.proto create mode 100644 drivers/solaris/overlay/overlay_test.go create mode 100644 drivers/solaris/overlay/ovmanager/ovmanager.go create mode 100644 drivers/solaris/overlay/ovmanager/ovmanager_test.go create mode 100644 drivers/solaris/overlay/peerdb.go diff --git a/default_gateway_solaris.go b/default_gateway_solaris.go index 104781aa34..42f4d5c630 100644 --- a/default_gateway_solaris.go +++ b/default_gateway_solaris.go @@ -1,7 +1,26 @@ package libnetwork -import "github.com/docker/libnetwork/types" +import ( + "fmt" + "strconv" + + "github.com/docker/libnetwork/drivers/solaris/bridge" +) func (c *controller) createGWNetwork() (Network, error) { - return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in solaris") + netOption := map[string]string{ + bridge.BridgeName: libnGWNetwork, + bridge.EnableICC: strconv.FormatBool(false), + bridge.EnableIPMasquerade: strconv.FormatBool(true), + } + + n, err := c.NewNetwork("bridge", libnGWNetwork, "", + NetworkOptionDriverOpts(netOption), + NetworkOptionEnableIPv6(false), + ) + + if err != nil { + return nil, fmt.Errorf("error creating external connectivity network: %v", err) + } + return n, err } diff --git a/drivers/solaris/overlay/encryption.go b/drivers/solaris/overlay/encryption.go new file mode 100644 index 0000000000..932fdbb000 --- /dev/null +++ b/drivers/solaris/overlay/encryption.go @@ -0,0 +1,274 @@ +package overlay + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "fmt" + "hash/fnv" + "net" + "sync" + + log "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/types" +) + +const ( + mark = uint32(0xD0C4E3) + timeout = 30 + pktExpansion = 26 // SPI(4) + SeqN(4) + IV(8) + PadLength(1) + NextHeader(1) + ICV(8) +) + +const ( + forward = iota + 1 + reverse + bidir +) + +type key struct { + value []byte + tag uint32 +} + +func (k *key) String() string { + if k != nil { + return fmt.Sprintf("(key: %s, tag: 0x%x)", hex.EncodeToString(k.value)[0:5], k.tag) + } + return "" +} + +type spi struct { + forward int + reverse int +} + +func (s *spi) String() string { + return fmt.Sprintf("SPI(FWD: 0x%x, REV: 0x%x)", uint32(s.forward), uint32(s.reverse)) +} + +type encrMap struct { + nodes map[string][]*spi + sync.Mutex +} + +func (e *encrMap) String() string { + e.Lock() + defer e.Unlock() + b := new(bytes.Buffer) + for k, v := range e.nodes { + b.WriteString("\n") + b.WriteString(k) + b.WriteString(":") + b.WriteString("[") + for _, s := range v { + b.WriteString(s.String()) + b.WriteString(",") + } + b.WriteString("]") + + } + return b.String() +} + +func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal, add bool) error { + log.Debugf("checkEncryption(%s, %v, %d, %t)", nid[0:7], rIP, vxlanID, isLocal) + + n := d.network(nid) + if n == nil || !n.secure { + return nil + } + + if len(d.keys) == 0 { + return types.ForbiddenErrorf("encryption key is not present") + } + + lIP := net.ParseIP(d.bindAddress) + aIP := net.ParseIP(d.advertiseAddress) + nodes := map[string]net.IP{} + + switch { + case isLocal: + if err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool { + if !aIP.Equal(pEntry.vtep) { + nodes[pEntry.vtep.String()] = pEntry.vtep + } + return false + }); err != nil { + log.Warnf("Failed to retrieve list of participating nodes in overlay network %s: %v", nid[0:5], err) + } + default: + if len(d.network(nid).endpoints) > 0 { + nodes[rIP.String()] = rIP + } + } + + log.Debugf("List of nodes: %s", nodes) + + if add { + for _, rIP := range nodes { + if err := setupEncryption(lIP, aIP, rIP, vxlanID, d.secMap, d.keys); err != nil { + log.Warnf("Failed to program network encryption between %s and %s: %v", lIP, rIP, err) + } + } + } else { + if len(nodes) == 0 { + if err := removeEncryption(lIP, rIP, d.secMap); err != nil { + log.Warnf("Failed to remove network encryption between %s and %s: %v", lIP, rIP, err) + } + } + } + + return nil +} + +func setupEncryption(localIP, advIP, remoteIP net.IP, vni uint32, em *encrMap, keys []*key) error { + log.Debugf("Programming encryption for vxlan %d between %s and %s", vni, localIP, remoteIP) + rIPs := remoteIP.String() + + indices := make([]*spi, 0, len(keys)) + + err := programMangle(vni, true) + if err != nil { + log.Warn(err) + } + + em.Lock() + em.nodes[rIPs] = indices + em.Unlock() + + return nil +} + +func removeEncryption(localIP, remoteIP net.IP, em *encrMap) error { + return nil +} + +func programMangle(vni uint32, add bool) (err error) { + return +} + +func buildSPI(src, dst net.IP, st uint32) int { + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, st) + h := fnv.New32a() + h.Write(src) + h.Write(b) + h.Write(dst) + return int(binary.BigEndian.Uint32(h.Sum(nil))) +} + +func (d *driver) secMapWalk(f func(string, []*spi) ([]*spi, bool)) error { + d.secMap.Lock() + for node, indices := range d.secMap.nodes { + idxs, stop := f(node, indices) + if idxs != nil { + d.secMap.nodes[node] = idxs + } + if stop { + break + } + } + d.secMap.Unlock() + return nil +} + +func (d *driver) setKeys(keys []*key) error { + if d.keys != nil { + return types.ForbiddenErrorf("initial keys are already present") + } + d.keys = keys + log.Debugf("Initial encryption keys: %v", d.keys) + return nil +} + +// updateKeys allows to add a new key and/or change the primary key and/or prune an existing key +// The primary key is the key used in transmission and will go in first position in the list. +func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { + log.Debugf("Updating Keys. New: %v, Primary: %v, Pruned: %v", newKey, primary, pruneKey) + + log.Debugf("Current: %v", d.keys) + + var ( + newIdx = -1 + priIdx = -1 + delIdx = -1 + lIP = net.ParseIP(d.bindAddress) + ) + + d.Lock() + // add new + if newKey != nil { + d.keys = append(d.keys, newKey) + newIdx += len(d.keys) + } + for i, k := range d.keys { + if primary != nil && k.tag == primary.tag { + priIdx = i + } + if pruneKey != nil && k.tag == pruneKey.tag { + delIdx = i + } + } + d.Unlock() + + if (newKey != nil && newIdx == -1) || + (primary != nil && priIdx == -1) || + (pruneKey != nil && delIdx == -1) { + err := types.BadRequestErrorf("cannot find proper key indices while processing key update:"+ + "(newIdx,priIdx,delIdx):(%d, %d, %d)", newIdx, priIdx, delIdx) + log.Warn(err) + return err + } + + d.secMapWalk(func(rIPs string, spis []*spi) ([]*spi, bool) { + rIP := net.ParseIP(rIPs) + return updateNodeKey(lIP, rIP, spis, d.keys, newIdx, priIdx, delIdx), false + }) + + d.Lock() + // swap primary + if priIdx != -1 { + swp := d.keys[0] + d.keys[0] = d.keys[priIdx] + d.keys[priIdx] = swp + } + // prune + if delIdx != -1 { + if delIdx == 0 { + delIdx = priIdx + } + d.keys = append(d.keys[:delIdx], d.keys[delIdx+1:]...) + } + d.Unlock() + + log.Debugf("Updated: %v", d.keys) + + return nil +} + +/******************************************************** + * Steady state: rSA0, rSA1, rSA2, fSA1, fSP1 + * Rotation --> -rSA0, +rSA3, +fSA2, +fSP2/-fSP1, -fSA1 + * Steady state: rSA1, rSA2, rSA3, fSA2, fSP2 + *********************************************************/ + +// Spis and keys are sorted in such away the one in position 0 is the primary +func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, delIdx int) []*spi { + log.Debugf("Updating keys for node: %s (%d,%d,%d)", rIP, newIdx, priIdx, delIdx) + return nil +} + +func (n *network) maxMTU() int { + mtu := 1500 + if n.mtu != 0 { + mtu = n.mtu + } + mtu -= vxlanEncap + if n.secure { + // In case of encryption account for the + // esp packet espansion and padding + mtu -= pktExpansion + mtu -= (mtu % 4) + } + return mtu +} diff --git a/drivers/solaris/overlay/joinleave.go b/drivers/solaris/overlay/joinleave.go new file mode 100644 index 0000000000..78656391a5 --- /dev/null +++ b/drivers/solaris/overlay/joinleave.go @@ -0,0 +1,184 @@ +package overlay + +import ( + "fmt" + "net" + + log "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/types" + "github.com/gogo/protobuf/proto" +) + +// Join method is invoked when a Sandbox is attached to an endpoint. +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { + if err := validateID(nid, eid); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("could not find network with id %s", nid) + } + + ep := n.endpoint(eid) + if ep == nil { + return fmt.Errorf("could not find endpoint with id %s", eid) + } + + if n.secure && len(d.keys) == 0 { + return fmt.Errorf("cannot join secure network: encryption keys not present") + } + + s := n.getSubnetforIP(ep.addr) + if s == nil { + return fmt.Errorf("could not find subnet for endpoint %s", eid) + } + + if err := n.obtainVxlanID(s); err != nil { + return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err) + } + + if err := n.joinSandbox(false); err != nil { + return fmt.Errorf("network sandbox join failed: %v", err) + } + + if err := n.joinSubnetSandbox(s, false); err != nil { + return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err) + } + + // joinSubnetSandbox gets called when an endpoint comes up on a new subnet in the + // overlay network. Hence the Endpoint count should be updated outside joinSubnetSandbox + n.incEndpointCount() + + // Add creating a veth Pair for Solaris + + containerIfName := "solaris-if" + ep.ifName = containerIfName + + if err := d.writeEndpointToStore(ep); err != nil { + return fmt.Errorf("failed to update overlay endpoint %s to local data store: %v", ep.id[0:7], err) + } + + // Add solaris plumbing to add veth (with ep mac addr) to sandbox + + for _, sub := range n.subnets { + if sub == s { + continue + } + if err := jinfo.AddStaticRoute(sub.subnetIP, types.NEXTHOP, s.gwIP.IP); err != nil { + log.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id) + } + } + + if iNames := jinfo.InterfaceName(); iNames != nil { + err := iNames.SetNames(containerIfName, "eth") + if err != nil { + return err + } + } + + d.peerDbAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac, + net.ParseIP(d.advertiseAddress), true) + + if err := d.checkEncryption(nid, nil, n.vxlanID(s), true, true); err != nil { + log.Warn(err) + } + + buf, err := proto.Marshal(&PeerRecord{ + EndpointIP: ep.addr.String(), + EndpointMAC: ep.mac.String(), + TunnelEndpointIP: d.advertiseAddress, + }) + if err != nil { + return err + } + + if err := jinfo.AddTableEntry(ovPeerTable, eid, buf); err != nil { + log.Errorf("overlay: Failed adding table entry to joininfo: %v", err) + } + + d.pushLocalEndpointEvent("join", nid, eid) + + return nil +} + +func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { + if tableName != ovPeerTable { + log.Errorf("Unexpected table notification for table %s received", tableName) + return + } + + eid := key + + var peer PeerRecord + if err := proto.Unmarshal(value, &peer); err != nil { + log.Errorf("Failed to unmarshal peer record: %v", err) + return + } + + // Ignore local peers. We already know about them and they + // should not be added to vxlan fdb. + if peer.TunnelEndpointIP == d.advertiseAddress { + return + } + + addr, err := types.ParseCIDR(peer.EndpointIP) + if err != nil { + log.Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP) + return + } + + mac, err := net.ParseMAC(peer.EndpointMAC) + if err != nil { + log.Errorf("Invalid mac %s received in event notify", peer.EndpointMAC) + return + } + + vtep := net.ParseIP(peer.TunnelEndpointIP) + if vtep == nil { + log.Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP) + return + } + + if etype == driverapi.Delete { + d.peerDelete(nid, eid, addr.IP, addr.Mask, mac, vtep, true) + return + } + + d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, true) +} + +// Leave method is invoked when a Sandbox detaches from an endpoint. +func (d *driver) Leave(nid, eid string) error { + if err := validateID(nid, eid); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("could not find network with id %s", nid) + } + + ep := n.endpoint(eid) + + if ep == nil { + return types.InternalMaskableErrorf("could not find endpoint with id %s", eid) + } + + if d.notifyCh != nil { + d.notifyCh <- ovNotify{ + action: "leave", + nw: n, + ep: ep, + } + } + + n.leaveSandbox() + + if err := d.checkEncryption(nid, nil, 0, true, false); err != nil { + log.Warn(err) + } + + return nil +} diff --git a/drivers/solaris/overlay/ov_endpoint.go b/drivers/solaris/overlay/ov_endpoint.go new file mode 100644 index 0000000000..4b2431dc71 --- /dev/null +++ b/drivers/solaris/overlay/ov_endpoint.go @@ -0,0 +1,249 @@ +package overlay + +import ( + "encoding/json" + "fmt" + "net" + + log "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" +) + +type endpointTable map[string]*endpoint + +const overlayEndpointPrefix = "overlay/endpoint" + +type endpoint struct { + id string + nid string + ifName string + mac net.HardwareAddr + addr *net.IPNet + dbExists bool + dbIndex uint64 +} + +func (n *network) endpoint(eid string) *endpoint { + n.Lock() + defer n.Unlock() + + return n.endpoints[eid] +} + +func (n *network) addEndpoint(ep *endpoint) { + n.Lock() + n.endpoints[ep.id] = ep + n.Unlock() +} + +func (n *network) deleteEndpoint(eid string) { + n.Lock() + delete(n.endpoints, eid) + n.Unlock() +} + +func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, + epOptions map[string]interface{}) error { + var err error + + if err = validateID(nid, eid); err != nil { + return err + } + + // Since we perform lazy configuration make sure we try + // configuring the driver when we enter CreateEndpoint since + // CreateNetwork may not be called in every node. + if err := d.configure(); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("network id %q not found", nid) + } + + ep := &endpoint{ + id: eid, + nid: n.id, + addr: ifInfo.Address(), + mac: ifInfo.MacAddress(), + } + if ep.addr == nil { + return fmt.Errorf("create endpoint was not passed interface IP address") + } + + if s := n.getSubnetforIP(ep.addr); s == nil { + return fmt.Errorf("no matching subnet for IP %q in network %q\n", ep.addr, nid) + } + + if ep.mac == nil { + ep.mac = netutils.GenerateMACFromIP(ep.addr.IP) + if err := ifInfo.SetMacAddress(ep.mac); err != nil { + return err + } + } + + n.addEndpoint(ep) + + if err := d.writeEndpointToStore(ep); err != nil { + return fmt.Errorf("failed to update overlay endpoint %s to local store: %v", ep.id[0:7], err) + } + + return nil +} + +func (d *driver) DeleteEndpoint(nid, eid string) error { + if err := validateID(nid, eid); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("network id %q not found", nid) + } + + ep := n.endpoint(eid) + if ep == nil { + return fmt.Errorf("endpoint id %q not found", eid) + } + + n.deleteEndpoint(eid) + + if err := d.deleteEndpointFromStore(ep); err != nil { + log.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err) + } + + if ep.ifName == "" { + return nil + } + + // OVERLAY_SOLARIS: Add Solaris unplumbing for removing the interface endpoint + + return nil +} + +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { + return make(map[string]interface{}, 0), nil +} + +func (d *driver) deleteEndpointFromStore(e *endpoint) error { + if d.localStore == nil { + return fmt.Errorf("overlay local store not initialized, ep not deleted") + } + + if err := d.localStore.DeleteObjectAtomic(e); err != nil { + return err + } + + return nil +} + +func (d *driver) writeEndpointToStore(e *endpoint) error { + if d.localStore == nil { + return fmt.Errorf("overlay local store not initialized, ep not added") + } + + if err := d.localStore.PutObjectAtomic(e); err != nil { + return err + } + return nil +} + +func (ep *endpoint) DataScope() string { + return datastore.LocalScope +} + +func (ep *endpoint) New() datastore.KVObject { + return &endpoint{} +} + +func (ep *endpoint) CopyTo(o datastore.KVObject) error { + dstep := o.(*endpoint) + *dstep = *ep + return nil +} + +func (ep *endpoint) Key() []string { + return []string{overlayEndpointPrefix, ep.id} +} + +func (ep *endpoint) KeyPrefix() []string { + return []string{overlayEndpointPrefix} +} + +func (ep *endpoint) Index() uint64 { + return ep.dbIndex +} + +func (ep *endpoint) SetIndex(index uint64) { + ep.dbIndex = index + ep.dbExists = true +} + +func (ep *endpoint) Exists() bool { + return ep.dbExists +} + +func (ep *endpoint) Skip() bool { + return false +} + +func (ep *endpoint) Value() []byte { + b, err := json.Marshal(ep) + if err != nil { + return nil + } + return b +} + +func (ep *endpoint) SetValue(value []byte) error { + return json.Unmarshal(value, ep) +} + +func (ep *endpoint) MarshalJSON() ([]byte, error) { + epMap := make(map[string]interface{}) + + epMap["id"] = ep.id + epMap["nid"] = ep.nid + if ep.ifName != "" { + epMap["ifName"] = ep.ifName + } + if ep.addr != nil { + epMap["addr"] = ep.addr.String() + } + if len(ep.mac) != 0 { + epMap["mac"] = ep.mac.String() + } + + return json.Marshal(epMap) +} + +func (ep *endpoint) UnmarshalJSON(value []byte) error { + var ( + err error + epMap map[string]interface{} + ) + + json.Unmarshal(value, &epMap) + + ep.id = epMap["id"].(string) + ep.nid = epMap["nid"].(string) + if v, ok := epMap["mac"]; ok { + if ep.mac, err = net.ParseMAC(v.(string)); err != nil { + return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string)) + } + } + if v, ok := epMap["addr"]; ok { + if ep.addr, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err) + } + } + if v, ok := epMap["ifName"]; ok { + ep.ifName = v.(string) + } + + return nil +} diff --git a/drivers/solaris/overlay/ov_network.go b/drivers/solaris/overlay/ov_network.go new file mode 100644 index 0000000000..e9b27ba5bd --- /dev/null +++ b/drivers/solaris/overlay/ov_network.go @@ -0,0 +1,791 @@ +package overlay + +import ( + "encoding/json" + "fmt" + "net" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/osl" + "github.com/docker/libnetwork/resolvconf" + "github.com/docker/libnetwork/types" +) + +var ( + hostMode bool + networkOnce sync.Once + networkMu sync.Mutex + vniTbl = make(map[uint32]string) +) + +type networkTable map[string]*network + +type subnet struct { + once *sync.Once + vxlanName string + brName string + vni uint32 + initErr error + subnetIP *net.IPNet + gwIP *net.IPNet +} + +type subnetJSON struct { + SubnetIP string + GwIP string + Vni uint32 +} + +type network struct { + id string + dbIndex uint64 + dbExists bool + sbox osl.Sandbox + endpoints endpointTable + driver *driver + joinCnt int + once *sync.Once + initEpoch int + initErr error + subnets []*subnet + secure bool + mtu int + sync.Mutex +} + +func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { + return nil, types.NotImplementedErrorf("not implemented") +} + +func (d *driver) NetworkFree(id string) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { + if id == "" { + return fmt.Errorf("invalid network id") + } + if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" { + return types.BadRequestErrorf("ipv4 pool is empty") + } + + // Since we perform lazy configuration make sure we try + // configuring the driver when we enter CreateNetwork + if err := d.configure(); err != nil { + return err + } + + n := &network{ + id: id, + driver: d, + endpoints: endpointTable{}, + once: &sync.Once{}, + subnets: []*subnet{}, + } + + vnis := make([]uint32, 0, len(ipV4Data)) + if gval, ok := option[netlabel.GenericData]; ok { + optMap := gval.(map[string]string) + if val, ok := optMap[netlabel.OverlayVxlanIDList]; ok { + logrus.Debugf("overlay: Received vxlan IDs: %s", val) + vniStrings := strings.Split(val, ",") + for _, vniStr := range vniStrings { + vni, err := strconv.Atoi(vniStr) + if err != nil { + return fmt.Errorf("invalid vxlan id value %q passed", vniStr) + } + + vnis = append(vnis, uint32(vni)) + } + } + if _, ok := optMap[secureOption]; ok { + n.secure = true + } + if val, ok := optMap[netlabel.DriverMTU]; ok { + var err error + if n.mtu, err = strconv.Atoi(val); err != nil { + return fmt.Errorf("failed to parse %v: %v", val, err) + } + if n.mtu < 0 { + return fmt.Errorf("invalid MTU value: %v", n.mtu) + } + } + } + + // If we are getting vnis from libnetwork, either we get for + // all subnets or none. + if len(vnis) != 0 && len(vnis) < len(ipV4Data) { + return fmt.Errorf("insufficient vnis(%d) passed to overlay", len(vnis)) + } + + for i, ipd := range ipV4Data { + s := &subnet{ + subnetIP: ipd.Pool, + gwIP: ipd.Gateway, + once: &sync.Once{}, + } + + if len(vnis) != 0 { + s.vni = vnis[i] + } + + n.subnets = append(n.subnets, s) + } + + if err := n.writeToStore(); err != nil { + return fmt.Errorf("failed to update data store for network %v: %v", n.id, err) + } + + // Make sure no rule is on the way from any stale secure network + if !n.secure { + for _, vni := range vnis { + programMangle(vni, false) + } + } + + if nInfo != nil { + if err := nInfo.TableEventRegister(ovPeerTable); err != nil { + return err + } + } + + d.addNetwork(n) + return nil +} + +func (d *driver) DeleteNetwork(nid string) error { + if nid == "" { + return fmt.Errorf("invalid network id") + } + + // Make sure driver resources are initialized before proceeding + if err := d.configure(); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("could not find network with id %s", nid) + } + + d.deleteNetwork(nid) + + vnis, err := n.releaseVxlanID() + if err != nil { + return err + } + + if n.secure { + for _, vni := range vnis { + programMangle(vni, false) + } + } + + return nil +} + +func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { + return nil +} + +func (d *driver) RevokeExternalConnectivity(nid, eid string) error { + return nil +} + +func (n *network) incEndpointCount() { + n.Lock() + defer n.Unlock() + n.joinCnt++ +} + +func (n *network) joinSandbox(restore bool) error { + // If there is a race between two go routines here only one will win + // the other will wait. + n.once.Do(func() { + // save the error status of initSandbox in n.initErr so that + // all the racing go routines are able to know the status. + n.initErr = n.initSandbox(restore) + }) + + return n.initErr +} + +func (n *network) joinSubnetSandbox(s *subnet, restore bool) error { + s.once.Do(func() { + s.initErr = n.initSubnetSandbox(s, restore) + }) + return s.initErr +} + +func (n *network) leaveSandbox() { + n.Lock() + defer n.Unlock() + n.joinCnt-- + if n.joinCnt != 0 { + return + } + + // We are about to destroy sandbox since the container is leaving the network + // Reinitialize the once variable so that we will be able to trigger one time + // sandbox initialization(again) when another container joins subsequently. + n.once = &sync.Once{} + for _, s := range n.subnets { + s.once = &sync.Once{} + } + + n.destroySandbox() +} + +// to be called while holding network lock +func (n *network) destroySandbox() { + if n.sbox != nil { + for _, iface := range n.sbox.Info().Interfaces() { + if err := iface.Remove(); err != nil { + logrus.Debugf("Remove interface %s failed: %v", iface.SrcName(), err) + } + } + + for _, s := range n.subnets { + if s.vxlanName != "" { + err := deleteInterface(s.vxlanName) + if err != nil { + logrus.Warnf("could not cleanup sandbox properly: %v", err) + } + } + } + + n.sbox.Destroy() + n.sbox = nil + } +} + +func networkOnceInit() { + if os.Getenv("_OVERLAY_HOST_MODE") != "" { + hostMode = true + return + } + + err := createVxlan("testvxlan1", 1, 0) + if err != nil { + logrus.Errorf("Failed to create testvxlan1 interface: %v", err) + return + } + + defer deleteInterface("testvxlan1") +} + +func (n *network) generateVxlanName(s *subnet) string { + id := n.id + if len(n.id) > 12 { + id = n.id[:12] + } + + return "vx_" + id + "_0" +} + +func (n *network) generateBridgeName(s *subnet) string { + id := n.id + if len(n.id) > 5 { + id = n.id[:5] + } + + return n.getBridgeNamePrefix(s) + "_" + id + "_0" +} + +func (n *network) getBridgeNamePrefix(s *subnet) string { + return "ov_" + fmt.Sprintf("%06x", n.vxlanID(s)) +} + +func isOverlap(nw *net.IPNet) bool { + var nameservers []string + + if rc, err := resolvconf.Get(); err == nil { + nameservers = resolvconf.GetNameserversAsCIDR(rc.Content) + } + + if err := netutils.CheckNameserverOverlaps(nameservers, nw); err != nil { + return true + } + + if err := netutils.CheckRouteOverlaps(nw); err != nil { + return true + } + + return false +} + +func (n *network) restoreSubnetSandbox(s *subnet, brName, vxlanName string) error { + sbox := n.sandbox() + + // restore overlay osl sandbox + Ifaces := make(map[string][]osl.IfaceOption) + brIfaceOption := make([]osl.IfaceOption, 2) + brIfaceOption = append(brIfaceOption, sbox.InterfaceOptions().Address(s.gwIP)) + brIfaceOption = append(brIfaceOption, sbox.InterfaceOptions().Bridge(true)) + Ifaces[fmt.Sprintf("%s+%s", brName, "br")] = brIfaceOption + + err := sbox.Restore(Ifaces, nil, nil, nil) + if err != nil { + return err + } + + Ifaces = make(map[string][]osl.IfaceOption) + vxlanIfaceOption := make([]osl.IfaceOption, 1) + vxlanIfaceOption = append(vxlanIfaceOption, sbox.InterfaceOptions().Master(brName)) + Ifaces[fmt.Sprintf("%s+%s", vxlanName, "vxlan")] = vxlanIfaceOption + err = sbox.Restore(Ifaces, nil, nil, nil) + if err != nil { + return err + } + return nil +} + +func (n *network) addInterface(srcName, dstPrefix, name string, isBridge bool) error { + return nil +} + +func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error { + + if hostMode { + // Try to delete stale bridge interface if it exists + if err := deleteInterface(brName); err != nil { + deleteInterfaceBySubnet(n.getBridgeNamePrefix(s), s) + } + + if isOverlap(s.subnetIP) { + return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String()) + } + } + + if !hostMode { + // Try to find this subnet's vni is being used in some + // other namespace by looking at vniTbl that we just + // populated in the once init. If a hit is found then + // it must a stale namespace from previous + // life. Destroy it completely and reclaim resourced. + networkMu.Lock() + path, ok := vniTbl[n.vxlanID(s)] + networkMu.Unlock() + + if ok { + os.Remove(path) + + networkMu.Lock() + delete(vniTbl, n.vxlanID(s)) + networkMu.Unlock() + } + } + + err := createVxlan(vxlanName, n.vxlanID(s), n.maxMTU()) + if err != nil { + return err + } + + return nil +} + +func (n *network) initSubnetSandbox(s *subnet, restore bool) error { + brName := n.generateBridgeName(s) + vxlanName := n.generateVxlanName(s) + + if restore { + n.restoreSubnetSandbox(s, brName, vxlanName) + } else { + n.setupSubnetSandbox(s, brName, vxlanName) + } + + n.Lock() + s.vxlanName = vxlanName + s.brName = brName + n.Unlock() + + return nil +} + +func (n *network) cleanupStaleSandboxes() { + filepath.Walk(filepath.Dir(osl.GenerateKey("walk")), + func(path string, info os.FileInfo, err error) error { + _, fname := filepath.Split(path) + + pList := strings.Split(fname, "-") + if len(pList) <= 1 { + return nil + } + + pattern := pList[1] + if strings.Contains(n.id, pattern) { + // Now that we have destroyed this + // sandbox, remove all references to + // it in vniTbl so that we don't + // inadvertently destroy the sandbox + // created in this life. + networkMu.Lock() + for vni, tblPath := range vniTbl { + if tblPath == path { + delete(vniTbl, vni) + } + } + networkMu.Unlock() + } + + return nil + }) +} + +func (n *network) initSandbox(restore bool) error { + n.Lock() + n.initEpoch++ + n.Unlock() + + networkOnce.Do(networkOnceInit) + + if !restore { + // If there are any stale sandboxes related to this network + // from previous daemon life clean it up here + n.cleanupStaleSandboxes() + } + + // In the restore case network sandbox already exist; but we don't know + // what epoch number it was created with. It has to be retrieved by + // searching the net namespaces. + key := "" + if restore { + key = osl.GenerateKey("-" + n.id) + } else { + key = osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch) + n.id) + } + + sbox, err := osl.NewSandbox(key, !hostMode, restore) + if err != nil { + return fmt.Errorf("could not get network sandbox (oper %t): %v", restore, err) + } + + n.setSandbox(sbox) + + if !restore { + n.driver.peerDbUpdateSandbox(n.id) + } + + return nil +} + +func (d *driver) addNetwork(n *network) { + d.Lock() + d.networks[n.id] = n + d.Unlock() +} + +func (d *driver) deleteNetwork(nid string) { + d.Lock() + delete(d.networks, nid) + d.Unlock() +} + +func (d *driver) network(nid string) *network { + d.Lock() + networks := d.networks + d.Unlock() + + n, ok := networks[nid] + if !ok { + n = d.getNetworkFromStore(nid) + if n != nil { + n.driver = d + n.endpoints = endpointTable{} + n.once = &sync.Once{} + networks[nid] = n + } + } + + return n +} + +func (d *driver) getNetworkFromStore(nid string) *network { + if d.store == nil { + return nil + } + + n := &network{id: nid} + if err := d.store.GetObject(datastore.Key(n.Key()...), n); err != nil { + return nil + } + + return n +} + +func (n *network) sandbox() osl.Sandbox { + n.Lock() + defer n.Unlock() + + return n.sbox +} + +func (n *network) setSandbox(sbox osl.Sandbox) { + n.Lock() + n.sbox = sbox + n.Unlock() +} + +func (n *network) vxlanID(s *subnet) uint32 { + n.Lock() + defer n.Unlock() + + return s.vni +} + +func (n *network) setVxlanID(s *subnet, vni uint32) { + n.Lock() + s.vni = vni + n.Unlock() +} + +func (n *network) Key() []string { + return []string{"overlay", "network", n.id} +} + +func (n *network) KeyPrefix() []string { + return []string{"overlay", "network"} +} + +func (n *network) Value() []byte { + m := map[string]interface{}{} + + netJSON := []*subnetJSON{} + + for _, s := range n.subnets { + sj := &subnetJSON{ + SubnetIP: s.subnetIP.String(), + GwIP: s.gwIP.String(), + Vni: s.vni, + } + netJSON = append(netJSON, sj) + } + + b, err := json.Marshal(netJSON) + if err != nil { + return []byte{} + } + + m["secure"] = n.secure + m["subnets"] = netJSON + m["mtu"] = n.mtu + b, err = json.Marshal(m) + if err != nil { + return []byte{} + } + + return b +} + +func (n *network) Index() uint64 { + return n.dbIndex +} + +func (n *network) SetIndex(index uint64) { + n.dbIndex = index + n.dbExists = true +} + +func (n *network) Exists() bool { + return n.dbExists +} + +func (n *network) Skip() bool { + return false +} + +func (n *network) SetValue(value []byte) error { + var ( + m map[string]interface{} + newNet bool + isMap = true + netJSON = []*subnetJSON{} + ) + + if err := json.Unmarshal(value, &m); err != nil { + err := json.Unmarshal(value, &netJSON) + if err != nil { + return err + } + isMap = false + } + + if len(n.subnets) == 0 { + newNet = true + } + + if isMap { + if val, ok := m["secure"]; ok { + n.secure = val.(bool) + } + if val, ok := m["mtu"]; ok { + n.mtu = int(val.(float64)) + } + bytes, err := json.Marshal(m["subnets"]) + if err != nil { + return err + } + if err := json.Unmarshal(bytes, &netJSON); err != nil { + return err + } + } + + for _, sj := range netJSON { + subnetIPstr := sj.SubnetIP + gwIPstr := sj.GwIP + vni := sj.Vni + + subnetIP, _ := types.ParseCIDR(subnetIPstr) + gwIP, _ := types.ParseCIDR(gwIPstr) + + if newNet { + s := &subnet{ + subnetIP: subnetIP, + gwIP: gwIP, + vni: vni, + once: &sync.Once{}, + } + n.subnets = append(n.subnets, s) + } else { + sNet := n.getMatchingSubnet(subnetIP) + if sNet != nil { + sNet.vni = vni + } + } + } + return nil +} + +func (n *network) DataScope() string { + return datastore.GlobalScope +} + +func (n *network) writeToStore() error { + if n.driver.store == nil { + return nil + } + + return n.driver.store.PutObjectAtomic(n) +} + +func (n *network) releaseVxlanID() ([]uint32, error) { + if len(n.subnets) == 0 { + return nil, nil + } + + if n.driver.store != nil { + if err := n.driver.store.DeleteObjectAtomic(n); err != nil { + if err == datastore.ErrKeyModified || err == datastore.ErrKeyNotFound { + // In both the above cases we can safely assume that the key has been removed by some other + // instance and so simply get out of here + return nil, nil + } + + return nil, fmt.Errorf("failed to delete network to vxlan id map: %v", err) + } + } + var vnis []uint32 + for _, s := range n.subnets { + if n.driver.vxlanIdm != nil { + vni := n.vxlanID(s) + vnis = append(vnis, vni) + n.driver.vxlanIdm.Release(uint64(vni)) + } + + n.setVxlanID(s, 0) + } + + return vnis, nil +} + +func (n *network) obtainVxlanID(s *subnet) error { + //return if the subnet already has a vxlan id assigned + if s.vni != 0 { + return nil + } + + if n.driver.store == nil { + return fmt.Errorf("no valid vxlan id and no datastore configured, cannot obtain vxlan id") + } + + for { + if err := n.driver.store.GetObject(datastore.Key(n.Key()...), n); err != nil { + return fmt.Errorf("getting network %q from datastore failed %v", n.id, err) + } + + if s.vni == 0 { + vxlanID, err := n.driver.vxlanIdm.GetID() + if err != nil { + return fmt.Errorf("failed to allocate vxlan id: %v", err) + } + + n.setVxlanID(s, uint32(vxlanID)) + if err := n.writeToStore(); err != nil { + n.driver.vxlanIdm.Release(uint64(n.vxlanID(s))) + n.setVxlanID(s, 0) + if err == datastore.ErrKeyModified { + continue + } + return fmt.Errorf("network %q failed to update data store: %v", n.id, err) + } + return nil + } + return nil + } +} + +// contains return true if the passed ip belongs to one the network's +// subnets +func (n *network) contains(ip net.IP) bool { + for _, s := range n.subnets { + if s.subnetIP.Contains(ip) { + return true + } + } + + return false +} + +// getSubnetforIP returns the subnet to which the given IP belongs +func (n *network) getSubnetforIP(ip *net.IPNet) *subnet { + for _, s := range n.subnets { + // first check if the mask lengths are the same + i, _ := s.subnetIP.Mask.Size() + j, _ := ip.Mask.Size() + if i != j { + continue + } + if s.subnetIP.Contains(ip.IP) { + return s + } + } + return nil +} + +// getMatchingSubnet return the network's subnet that matches the input +func (n *network) getMatchingSubnet(ip *net.IPNet) *subnet { + if ip == nil { + return nil + } + for _, s := range n.subnets { + // first check if the mask lengths are the same + i, _ := s.subnetIP.Mask.Size() + j, _ := ip.Mask.Size() + if i != j { + continue + } + if s.subnetIP.IP.Equal(ip.IP) { + return s + } + } + return nil +} diff --git a/drivers/solaris/overlay/ov_serf.go b/drivers/solaris/overlay/ov_serf.go new file mode 100644 index 0000000000..53c59b4df2 --- /dev/null +++ b/drivers/solaris/overlay/ov_serf.go @@ -0,0 +1,233 @@ +package overlay + +import ( + "fmt" + "net" + "strings" + "time" + + "github.com/Sirupsen/logrus" + "github.com/hashicorp/serf/serf" +) + +type ovNotify struct { + action string + ep *endpoint + nw *network +} + +type logWriter struct{} + +func (l *logWriter) Write(p []byte) (int, error) { + str := string(p) + + switch { + case strings.Contains(str, "[WARN]"): + logrus.Warn(str) + case strings.Contains(str, "[DEBUG]"): + logrus.Debug(str) + case strings.Contains(str, "[INFO]"): + logrus.Info(str) + case strings.Contains(str, "[ERR]"): + logrus.Error(str) + } + + return len(p), nil +} + +func (d *driver) serfInit() error { + var err error + + config := serf.DefaultConfig() + config.Init() + config.MemberlistConfig.BindAddr = d.advertiseAddress + + d.eventCh = make(chan serf.Event, 4) + config.EventCh = d.eventCh + config.UserCoalescePeriod = 1 * time.Second + config.UserQuiescentPeriod = 50 * time.Millisecond + + config.LogOutput = &logWriter{} + config.MemberlistConfig.LogOutput = config.LogOutput + + s, err := serf.Create(config) + if err != nil { + return fmt.Errorf("failed to create cluster node: %v", err) + } + defer func() { + if err != nil { + s.Shutdown() + } + }() + + d.serfInstance = s + + d.notifyCh = make(chan ovNotify) + d.exitCh = make(chan chan struct{}) + + go d.startSerfLoop(d.eventCh, d.notifyCh, d.exitCh) + return nil +} + +func (d *driver) serfJoin(neighIP string) error { + if neighIP == "" { + return fmt.Errorf("no neighbor to join") + } + if _, err := d.serfInstance.Join([]string{neighIP}, false); err != nil { + return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v", + neighIP, err) + } + return nil +} + +func (d *driver) notifyEvent(event ovNotify) { + ep := event.ep + + ePayload := fmt.Sprintf("%s %s %s %s", event.action, ep.addr.IP.String(), + net.IP(ep.addr.Mask).String(), ep.mac.String()) + eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(), + event.nw.id, ep.id) + + if err := d.serfInstance.UserEvent(eName, []byte(ePayload), true); err != nil { + logrus.Errorf("Sending user event failed: %v\n", err) + } +} + +func (d *driver) processEvent(u serf.UserEvent) { + logrus.Debugf("Received user event name:%s, payload:%s\n", u.Name, + string(u.Payload)) + + var dummy, action, vtepStr, nid, eid, ipStr, maskStr, macStr string + if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil { + fmt.Printf("Failed to scan name string: %v\n", err) + } + + if _, err := fmt.Sscan(string(u.Payload), &action, + &ipStr, &maskStr, &macStr); err != nil { + fmt.Printf("Failed to scan value string: %v\n", err) + } + + logrus.Debugf("Parsed data = %s/%s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, maskStr, macStr) + + mac, err := net.ParseMAC(macStr) + if err != nil { + logrus.Errorf("Failed to parse mac: %v\n", err) + } + + if d.serfInstance.LocalMember().Addr.String() == vtepStr { + return + } + + switch action { + case "join": + if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac, + net.ParseIP(vtepStr), true); err != nil { + logrus.Errorf("Peer add failed in the driver: %v\n", err) + } + case "leave": + if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac, + net.ParseIP(vtepStr), true); err != nil { + logrus.Errorf("Peer delete failed in the driver: %v\n", err) + } + } +} + +func (d *driver) processQuery(q *serf.Query) { + logrus.Debugf("Received query name:%s, payload:%s\n", q.Name, + string(q.Payload)) + + var nid, ipStr string + if _, err := fmt.Sscan(string(q.Payload), &nid, &ipStr); err != nil { + fmt.Printf("Failed to scan query payload string: %v\n", err) + } + + peerMac, peerIPMask, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr)) + if err != nil { + return + } + + q.Respond([]byte(fmt.Sprintf("%s %s %s", peerMac.String(), net.IP(peerIPMask).String(), vtep.String()))) +} + +func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) { + if d.serfInstance == nil { + return nil, nil, nil, fmt.Errorf("could not resolve peer: serf instance not initialized") + } + + qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String()) + resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil) + if err != nil { + return nil, nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err) + } + + respCh := resp.ResponseCh() + select { + case r := <-respCh: + var macStr, maskStr, vtepStr string + if _, err := fmt.Sscan(string(r.Payload), &macStr, &maskStr, &vtepStr); err != nil { + return nil, nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err) + } + + mac, err := net.ParseMAC(macStr) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to parse mac: %v", err) + } + + return mac, net.IPMask(net.ParseIP(maskStr).To4()), net.ParseIP(vtepStr), nil + + case <-time.After(time.Second): + return nil, nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster") + } +} + +func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify, + exitCh chan chan struct{}) { + + for { + select { + case notify, ok := <-notifyCh: + if !ok { + break + } + + d.notifyEvent(notify) + case ch, ok := <-exitCh: + if !ok { + break + } + + if err := d.serfInstance.Leave(); err != nil { + logrus.Errorf("failed leaving the cluster: %v\n", err) + } + + d.serfInstance.Shutdown() + close(ch) + return + case e, ok := <-eventCh: + if !ok { + break + } + + if e.EventType() == serf.EventQuery { + d.processQuery(e.(*serf.Query)) + break + } + + u, ok := e.(serf.UserEvent) + if !ok { + break + } + d.processEvent(u) + } + } +} + +func (d *driver) isSerfAlive() bool { + d.Lock() + serfInstance := d.serfInstance + d.Unlock() + if serfInstance == nil || serfInstance.State() != serf.SerfAlive { + return false + } + return true +} diff --git a/drivers/solaris/overlay/ov_utils.go b/drivers/solaris/overlay/ov_utils.go new file mode 100644 index 0000000000..5e315e798a --- /dev/null +++ b/drivers/solaris/overlay/ov_utils.go @@ -0,0 +1,61 @@ +package overlay + +import ( + "fmt" + "os/exec" + "strings" + + "github.com/docker/libnetwork/osl" +) + +func validateID(nid, eid string) error { + if nid == "" { + return fmt.Errorf("invalid network id") + } + + if eid == "" { + return fmt.Errorf("invalid endpoint id") + } + + return nil +} + +func createVxlan(name string, vni uint32, mtu int) error { + defer osl.InitOSContext()() + + // Get default interface to plumb the vxlan on + routeCmd := "/usr/sbin/ipadm show-addr -p -o addrobj " + + "`/usr/sbin/route get default | /usr/bin/grep interface | " + + "/usr/bin/awk '{print $2}'`" + out, err := exec.Command("/usr/bin/bash", "-c", routeCmd).Output() + if err != nil { + return fmt.Errorf("cannot get default route: %v", err) + } + + defaultInterface := strings.SplitN(string(out), "/", 2) + propList := fmt.Sprintf("interface=%s,vni=%d", defaultInterface[0], vni) + + out, err = exec.Command("/usr/sbin/dladm", "create-vxlan", "-t", "-p", propList, + name).Output() + if err != nil { + return fmt.Errorf("error creating vxlan interface: %v %s", err, out) + } + + return nil +} + +func deleteInterfaceBySubnet(brPrefix string, s *subnet) error { + return nil + +} + +func deleteInterface(name string) error { + defer osl.InitOSContext()() + + out, err := exec.Command("/usr/sbin/dladm", "delete-vxlan", name).Output() + if err != nil { + return fmt.Errorf("error creating vxlan interface: %v %s", err, out) + } + + return nil +} diff --git a/drivers/solaris/overlay/overlay.go b/drivers/solaris/overlay/overlay.go new file mode 100644 index 0000000000..b48cfe7e76 --- /dev/null +++ b/drivers/solaris/overlay/overlay.go @@ -0,0 +1,362 @@ +package overlay + +//go:generate protoc -I.:../../Godeps/_workspace/src/github.com/gogo/protobuf --gogo_out=import_path=github.com/docker/libnetwork/drivers/overlay,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto:. overlay.proto + +import ( + "fmt" + "net" + "sync" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/idm" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/osl" + "github.com/docker/libnetwork/types" + "github.com/hashicorp/serf/serf" +) + +// XXX OVERLAY_SOLARIS +// Might need changes for names/constant values in solaris +const ( + networkType = "overlay" + vethPrefix = "veth" + vethLen = 7 + vxlanIDStart = 256 + vxlanIDEnd = (1 << 24) - 1 + vxlanPort = 4789 + vxlanEncap = 50 + secureOption = "encrypted" +) + +var initVxlanIdm = make(chan (bool), 1) + +type driver struct { + eventCh chan serf.Event + notifyCh chan ovNotify + exitCh chan chan struct{} + bindAddress string + advertiseAddress string + neighIP string + config map[string]interface{} + peerDb peerNetworkMap + secMap *encrMap + serfInstance *serf.Serf + networks networkTable + store datastore.DataStore + localStore datastore.DataStore + vxlanIdm *idm.Idm + once sync.Once + joinOnce sync.Once + keys []*key + sync.Mutex +} + +// Init registers a new instance of overlay driver +func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { + c := driverapi.Capability{ + DataScope: datastore.GlobalScope, + } + d := &driver{ + networks: networkTable{}, + peerDb: peerNetworkMap{ + mp: map[string]*peerMap{}, + }, + secMap: &encrMap{nodes: map[string][]*spi{}}, + config: config, + } + + if data, ok := config[netlabel.GlobalKVClient]; ok { + var err error + dsc, ok := data.(discoverapi.DatastoreConfigData) + if !ok { + return types.InternalErrorf("incorrect data in datastore configuration: %v", data) + } + d.store, err = datastore.NewDataStoreFromConfig(dsc) + if err != nil { + return types.InternalErrorf("failed to initialize data store: %v", err) + } + } + + if data, ok := config[netlabel.LocalKVClient]; ok { + var err error + dsc, ok := data.(discoverapi.DatastoreConfigData) + if !ok { + return types.InternalErrorf("incorrect data in datastore configuration: %v", data) + } + d.localStore, err = datastore.NewDataStoreFromConfig(dsc) + if err != nil { + return types.InternalErrorf("failed to initialize local data store: %v", err) + } + } + + d.restoreEndpoints() + + return dc.RegisterDriver(networkType, d, c) +} + +// Endpoints are stored in the local store. Restore them and reconstruct the overlay sandbox +func (d *driver) restoreEndpoints() error { + if d.localStore == nil { + logrus.Warnf("Cannot restore overlay endpoints because local datastore is missing") + return nil + } + kvol, err := d.localStore.List(datastore.Key(overlayEndpointPrefix), &endpoint{}) + if err != nil && err != datastore.ErrKeyNotFound { + return fmt.Errorf("failed to read overlay endpoint from store: %v", err) + } + + if err == datastore.ErrKeyNotFound { + return nil + } + for _, kvo := range kvol { + ep := kvo.(*endpoint) + n := d.network(ep.nid) + if n == nil { + logrus.Debugf("Network (%s) not found for restored endpoint (%s)", ep.nid[0:7], ep.id[0:7]) + logrus.Debugf("Deleting stale overlay endpoint (%s) from store", ep.id[0:7]) + if err := d.deleteEndpointFromStore(ep); err != nil { + logrus.Debugf("Failed to delete stale overlay endpoint (%s) from store", ep.id[0:7]) + } + continue + } + n.addEndpoint(ep) + + s := n.getSubnetforIP(ep.addr) + if s == nil { + return fmt.Errorf("could not find subnet for endpoint %s", ep.id) + } + + if err := n.joinSandbox(true); err != nil { + return fmt.Errorf("restore network sandbox failed: %v", err) + } + + if err := n.joinSubnetSandbox(s, true); err != nil { + return fmt.Errorf("restore subnet sandbox failed for %q: %v", s.subnetIP.String(), err) + } + + Ifaces := make(map[string][]osl.IfaceOption) + vethIfaceOption := make([]osl.IfaceOption, 1) + vethIfaceOption = append(vethIfaceOption, n.sbox.InterfaceOptions().Master(s.brName)) + Ifaces[fmt.Sprintf("%s+%s", "veth", "veth")] = vethIfaceOption + + err := n.sbox.Restore(Ifaces, nil, nil, nil) + if err != nil { + return fmt.Errorf("failed to restore overlay sandbox: %v", err) + } + + n.incEndpointCount() + d.peerDbAdd(ep.nid, ep.id, ep.addr.IP, ep.addr.Mask, ep.mac, net.ParseIP(d.advertiseAddress), true) + } + return nil +} + +// Fini cleans up the driver resources +func Fini(drv driverapi.Driver) { + d := drv.(*driver) + + if d.exitCh != nil { + waitCh := make(chan struct{}) + + d.exitCh <- waitCh + + <-waitCh + } +} + +func (d *driver) configure() error { + if d.store == nil { + return nil + } + + if d.vxlanIdm == nil { + return d.initializeVxlanIdm() + } + + return nil +} + +func (d *driver) initializeVxlanIdm() error { + var err error + + initVxlanIdm <- true + defer func() { <-initVxlanIdm }() + + if d.vxlanIdm != nil { + return nil + } + + d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd) + if err != nil { + return fmt.Errorf("failed to initialize vxlan id manager: %v", err) + } + + return nil +} + +func (d *driver) Type() string { + return networkType +} + +func validateSelf(node string) error { + advIP := net.ParseIP(node) + if advIP == nil { + return fmt.Errorf("invalid self address (%s)", node) + } + + addrs, err := net.InterfaceAddrs() + if err != nil { + return fmt.Errorf("Unable to get interface addresses %v", err) + } + for _, addr := range addrs { + ip, _, err := net.ParseCIDR(addr.String()) + if err == nil && ip.Equal(advIP) { + return nil + } + } + return fmt.Errorf("Multi-Host overlay networking requires cluster-advertise(%s) to be configured with a local ip-address that is reachable within the cluster", advIP.String()) +} + +func (d *driver) nodeJoin(advertiseAddress, bindAddress string, self bool) { + if self && !d.isSerfAlive() { + d.Lock() + d.advertiseAddress = advertiseAddress + d.bindAddress = bindAddress + d.Unlock() + + // If there is no cluster store there is no need to start serf. + if d.store != nil { + if err := validateSelf(advertiseAddress); err != nil { + logrus.Warnf("%s", err.Error()) + } + err := d.serfInit() + if err != nil { + logrus.Errorf("initializing serf instance failed: %v", err) + d.Lock() + d.advertiseAddress = "" + d.bindAddress = "" + d.Unlock() + return + } + } + } + + d.Lock() + if !self { + d.neighIP = advertiseAddress + } + neighIP := d.neighIP + d.Unlock() + + if d.serfInstance != nil && neighIP != "" { + var err error + d.joinOnce.Do(func() { + err = d.serfJoin(neighIP) + if err == nil { + d.pushLocalDb() + } + }) + if err != nil { + logrus.Errorf("joining serf neighbor %s failed: %v", advertiseAddress, err) + d.Lock() + d.joinOnce = sync.Once{} + d.Unlock() + return + } + } +} + +func (d *driver) pushLocalEndpointEvent(action, nid, eid string) { + n := d.network(nid) + if n == nil { + logrus.Debugf("Error pushing local endpoint event for network %s", nid) + return + } + ep := n.endpoint(eid) + if ep == nil { + logrus.Debugf("Error pushing local endpoint event for ep %s / %s", nid, eid) + return + } + + if !d.isSerfAlive() { + return + } + d.notifyCh <- ovNotify{ + action: "join", + nw: n, + ep: ep, + } +} + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { + var err error + switch dType { + case discoverapi.NodeDiscovery: + nodeData, ok := data.(discoverapi.NodeDiscoveryData) + if !ok || nodeData.Address == "" { + return fmt.Errorf("invalid discovery data") + } + d.nodeJoin(nodeData.Address, nodeData.BindAddress, nodeData.Self) + case discoverapi.DatastoreConfig: + if d.store != nil { + return types.ForbiddenErrorf("cannot accept datastore configuration: Overlay driver has a datastore configured already") + } + dsc, ok := data.(discoverapi.DatastoreConfigData) + if !ok { + return types.InternalErrorf("incorrect data in datastore configuration: %v", data) + } + d.store, err = datastore.NewDataStoreFromConfig(dsc) + if err != nil { + return types.InternalErrorf("failed to initialize data store: %v", err) + } + case discoverapi.EncryptionKeysConfig: + encrData, ok := data.(discoverapi.DriverEncryptionConfig) + if !ok { + return fmt.Errorf("invalid encryption key notification data") + } + keys := make([]*key, 0, len(encrData.Keys)) + for i := 0; i < len(encrData.Keys); i++ { + k := &key{ + value: encrData.Keys[i], + tag: uint32(encrData.Tags[i]), + } + keys = append(keys, k) + } + d.setKeys(keys) + case discoverapi.EncryptionKeysUpdate: + var newKey, delKey, priKey *key + encrData, ok := data.(discoverapi.DriverEncryptionUpdate) + if !ok { + return fmt.Errorf("invalid encryption key notification data") + } + if encrData.Key != nil { + newKey = &key{ + value: encrData.Key, + tag: uint32(encrData.Tag), + } + } + if encrData.Primary != nil { + priKey = &key{ + value: encrData.Primary, + tag: uint32(encrData.PrimaryTag), + } + } + if encrData.Prune != nil { + delKey = &key{ + value: encrData.Prune, + tag: uint32(encrData.PruneTag), + } + } + d.updateKeys(newKey, priKey, delKey) + default: + } + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { + return nil +} diff --git a/drivers/solaris/overlay/overlay.pb.go b/drivers/solaris/overlay/overlay.pb.go new file mode 100644 index 0000000000..cfa0eeeae4 --- /dev/null +++ b/drivers/solaris/overlay/overlay.pb.go @@ -0,0 +1,468 @@ +// Code generated by protoc-gen-gogo. +// source: overlay.proto +// DO NOT EDIT! + +/* + Package overlay is a generated protocol buffer package. + + It is generated from these files: + overlay.proto + + It has these top-level messages: + PeerRecord +*/ +package overlay + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" +import _ "github.com/gogo/protobuf/gogoproto" + +import strings "strings" +import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" +import sort "sort" +import strconv "strconv" +import reflect "reflect" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +const _ = proto.GoGoProtoPackageIsVersion1 + +// PeerRecord defines the information corresponding to a peer +// container in the overlay network. +type PeerRecord struct { + // Endpoint IP is the IP of the container attachment on the + // given overlay network. + EndpointIP string `protobuf:"bytes,1,opt,name=endpoint_ip,json=endpointIp,proto3" json:"endpoint_ip,omitempty"` + // Endpoint MAC is the mac address of the container attachment + // on the given overlay network. + EndpointMAC string `protobuf:"bytes,2,opt,name=endpoint_mac,json=endpointMac,proto3" json:"endpoint_mac,omitempty"` + // Tunnel Endpoint IP defines the host IP for the host in + // which this container is running and can be reached by + // building a tunnel to that host IP. + TunnelEndpointIP string `protobuf:"bytes,3,opt,name=tunnel_endpoint_ip,json=tunnelEndpointIp,proto3" json:"tunnel_endpoint_ip,omitempty"` +} + +func (m *PeerRecord) Reset() { *m = PeerRecord{} } +func (*PeerRecord) ProtoMessage() {} +func (*PeerRecord) Descriptor() ([]byte, []int) { return fileDescriptorOverlay, []int{0} } + +func init() { + proto.RegisterType((*PeerRecord)(nil), "overlay.PeerRecord") +} +func (this *PeerRecord) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 7) + s = append(s, "&overlay.PeerRecord{") + s = append(s, "EndpointIP: "+fmt.Sprintf("%#v", this.EndpointIP)+",\n") + s = append(s, "EndpointMAC: "+fmt.Sprintf("%#v", this.EndpointMAC)+",\n") + s = append(s, "TunnelEndpointIP: "+fmt.Sprintf("%#v", this.TunnelEndpointIP)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} +func valueToGoStringOverlay(v interface{}, typ string) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv) +} +func extensionToGoStringOverlay(e map[int32]github_com_gogo_protobuf_proto.Extension) string { + if e == nil { + return "nil" + } + s := "map[int32]proto.Extension{" + keys := make([]int, 0, len(e)) + for k := range e { + keys = append(keys, int(k)) + } + sort.Ints(keys) + ss := []string{} + for _, k := range keys { + ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString()) + } + s += strings.Join(ss, ",") + "}" + return s +} +func (m *PeerRecord) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *PeerRecord) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.EndpointIP) > 0 { + data[i] = 0xa + i++ + i = encodeVarintOverlay(data, i, uint64(len(m.EndpointIP))) + i += copy(data[i:], m.EndpointIP) + } + if len(m.EndpointMAC) > 0 { + data[i] = 0x12 + i++ + i = encodeVarintOverlay(data, i, uint64(len(m.EndpointMAC))) + i += copy(data[i:], m.EndpointMAC) + } + if len(m.TunnelEndpointIP) > 0 { + data[i] = 0x1a + i++ + i = encodeVarintOverlay(data, i, uint64(len(m.TunnelEndpointIP))) + i += copy(data[i:], m.TunnelEndpointIP) + } + return i, nil +} + +func encodeFixed64Overlay(data []byte, offset int, v uint64) int { + data[offset] = uint8(v) + data[offset+1] = uint8(v >> 8) + data[offset+2] = uint8(v >> 16) + data[offset+3] = uint8(v >> 24) + data[offset+4] = uint8(v >> 32) + data[offset+5] = uint8(v >> 40) + data[offset+6] = uint8(v >> 48) + data[offset+7] = uint8(v >> 56) + return offset + 8 +} +func encodeFixed32Overlay(data []byte, offset int, v uint32) int { + data[offset] = uint8(v) + data[offset+1] = uint8(v >> 8) + data[offset+2] = uint8(v >> 16) + data[offset+3] = uint8(v >> 24) + return offset + 4 +} +func encodeVarintOverlay(data []byte, offset int, v uint64) int { + for v >= 1<<7 { + data[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + data[offset] = uint8(v) + return offset + 1 +} +func (m *PeerRecord) Size() (n int) { + var l int + _ = l + l = len(m.EndpointIP) + if l > 0 { + n += 1 + l + sovOverlay(uint64(l)) + } + l = len(m.EndpointMAC) + if l > 0 { + n += 1 + l + sovOverlay(uint64(l)) + } + l = len(m.TunnelEndpointIP) + if l > 0 { + n += 1 + l + sovOverlay(uint64(l)) + } + return n +} + +func sovOverlay(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozOverlay(x uint64) (n int) { + return sovOverlay(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *PeerRecord) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PeerRecord{`, + `EndpointIP:` + fmt.Sprintf("%v", this.EndpointIP) + `,`, + `EndpointMAC:` + fmt.Sprintf("%v", this.EndpointMAC) + `,`, + `TunnelEndpointIP:` + fmt.Sprintf("%v", this.TunnelEndpointIP) + `,`, + `}`, + }, "") + return s +} +func valueToStringOverlay(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *PeerRecord) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOverlay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PeerRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PeerRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndpointIP", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOverlay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthOverlay + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndpointIP = string(data[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndpointMAC", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOverlay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthOverlay + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndpointMAC = string(data[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TunnelEndpointIP", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOverlay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthOverlay + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TunnelEndpointIP = string(data[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipOverlay(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthOverlay + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipOverlay(data []byte) (n int, err error) { + l := len(data) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOverlay + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOverlay + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if data[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOverlay + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthOverlay + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOverlay + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipOverlay(data[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthOverlay = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowOverlay = fmt.Errorf("proto: integer overflow") +) + +var fileDescriptorOverlay = []byte{ + // 195 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xcd, 0x2f, 0x4b, 0x2d, + 0xca, 0x49, 0xac, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x87, 0x72, 0xa5, 0x44, 0xd2, + 0xf3, 0xd3, 0xf3, 0xc1, 0x62, 0xfa, 0x20, 0x16, 0x44, 0x5a, 0x69, 0x2b, 0x23, 0x17, 0x57, 0x40, + 0x6a, 0x6a, 0x51, 0x50, 0x6a, 0x72, 0x7e, 0x51, 0x8a, 0x90, 0x3e, 0x17, 0x77, 0x6a, 0x5e, 0x4a, + 0x41, 0x7e, 0x66, 0x5e, 0x49, 0x7c, 0x66, 0x81, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xa7, 0x13, 0xdf, + 0xa3, 0x7b, 0xf2, 0x5c, 0xae, 0x50, 0x61, 0xcf, 0x80, 0x20, 0x2e, 0x98, 0x12, 0xcf, 0x02, 0x21, + 0x23, 0x2e, 0x1e, 0xb8, 0x86, 0xdc, 0xc4, 0x64, 0x09, 0x26, 0xb0, 0x0e, 0x7e, 0xa0, 0x0e, 0x6e, + 0x98, 0x0e, 0x5f, 0x47, 0xe7, 0x20, 0xb8, 0xa9, 0xbe, 0x89, 0xc9, 0x42, 0x4e, 0x5c, 0x42, 0x25, + 0xa5, 0x79, 0x79, 0xa9, 0x39, 0xf1, 0xc8, 0x76, 0x31, 0x83, 0x75, 0x8a, 0x00, 0x75, 0x0a, 0x84, + 0x80, 0x65, 0x91, 0x6c, 0x14, 0x28, 0x41, 0x15, 0x29, 0x70, 0x92, 0xb8, 0xf1, 0x50, 0x8e, 0xe1, + 0xc3, 0x43, 0x39, 0xc6, 0x86, 0x47, 0x72, 0x8c, 0x27, 0x80, 0xf8, 0x02, 0x10, 0x3f, 0x00, 0xe2, + 0x24, 0x36, 0xb0, 0xc7, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xd7, 0x7d, 0x7d, 0x08, + 0x01, 0x00, 0x00, +} diff --git a/drivers/solaris/overlay/overlay.proto b/drivers/solaris/overlay/overlay.proto new file mode 100644 index 0000000000..45b8c9de7e --- /dev/null +++ b/drivers/solaris/overlay/overlay.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +import "gogoproto/gogo.proto"; + +package overlay; + +option (gogoproto.marshaler_all) = true; +option (gogoproto.unmarshaler_all) = true; +option (gogoproto.stringer_all) = true; +option (gogoproto.gostring_all) = true; +option (gogoproto.sizer_all) = true; +option (gogoproto.goproto_stringer_all) = false; + +// PeerRecord defines the information corresponding to a peer +// container in the overlay network. +message PeerRecord { + // Endpoint IP is the IP of the container attachment on the + // given overlay network. + string endpoint_ip = 1 [(gogoproto.customname) = "EndpointIP"]; + // Endpoint MAC is the mac address of the container attachment + // on the given overlay network. + string endpoint_mac = 2 [(gogoproto.customname) = "EndpointMAC"]; + // Tunnel Endpoint IP defines the host IP for the host in + // which this container is running and can be reached by + // building a tunnel to that host IP. + string tunnel_endpoint_ip = 3 [(gogoproto.customname) = "TunnelEndpointIP"]; +} \ No newline at end of file diff --git a/drivers/solaris/overlay/overlay_test.go b/drivers/solaris/overlay/overlay_test.go new file mode 100644 index 0000000000..9e2b3807c7 --- /dev/null +++ b/drivers/solaris/overlay/overlay_test.go @@ -0,0 +1,138 @@ +// +build solaris + +package overlay + +import ( + "os/exec" + "testing" + "time" + + "github.com/docker/docker/pkg/plugingetter" + "github.com/docker/libkv/store/consul" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/netlabel" + _ "github.com/docker/libnetwork/testutils" +) + +func init() { + consul.Register() +} + +type driverTester struct { + t *testing.T + d *driver +} + +const testNetworkType = "overlay" + +func setupDriver(t *testing.T) *driverTester { + dt := &driverTester{t: t} + config := make(map[string]interface{}) + config[netlabel.GlobalKVClient] = discoverapi.DatastoreConfigData{ + Scope: datastore.GlobalScope, + Provider: "consul", + Address: "127.0.0.01:8500", + } + + if err := Init(dt, config); err != nil { + t.Fatal(err) + } + + // Use net0 as default interface + ifcfgCmd := "/usr/sbin/ifconfig net0 | grep inet | awk '{print $2}'" + out, err := exec.Command("/usr/bin/bash", "-c", ifcfgCmd).Output() + if err != nil { + t.Fatal(err) + } + + data := discoverapi.NodeDiscoveryData{ + Address: string(out), + Self: true, + } + dt.d.DiscoverNew(discoverapi.NodeDiscovery, data) + return dt +} + +func cleanupDriver(t *testing.T, dt *driverTester) { + ch := make(chan struct{}) + go func() { + Fini(dt.d) + close(ch) + }() + + select { + case <-ch: + case <-time.After(10 * time.Second): + t.Fatal("test timed out because Fini() did not return on time") + } +} + +func (dt *driverTester) GetPluginGetter() plugingetter.PluginGetter { + return nil +} + +func (dt *driverTester) RegisterDriver(name string, drv driverapi.Driver, + cap driverapi.Capability) error { + if name != testNetworkType { + dt.t.Fatalf("Expected driver register name to be %q. Instead got %q", + testNetworkType, name) + } + + if _, ok := drv.(*driver); !ok { + dt.t.Fatalf("Expected driver type to be %T. Instead got %T", + &driver{}, drv) + } + + dt.d = drv.(*driver) + return nil +} + +func TestOverlayInit(t *testing.T) { + if err := Init(&driverTester{t: t}, nil); err != nil { + t.Fatal(err) + } +} + +func TestOverlayFiniWithoutConfig(t *testing.T) { + dt := &driverTester{t: t} + if err := Init(dt, nil); err != nil { + t.Fatal(err) + } + + cleanupDriver(t, dt) +} + +func TestOverlayConfig(t *testing.T) { + dt := setupDriver(t) + + time.Sleep(1 * time.Second) + + d := dt.d + if d.notifyCh == nil { + t.Fatal("Driver notify channel wasn't initialzed after Config method") + } + + if d.exitCh == nil { + t.Fatal("Driver serfloop exit channel wasn't initialzed after Config method") + } + + if d.serfInstance == nil { + t.Fatal("Driver serfinstance hasn't been initialized after Config method") + } + + cleanupDriver(t, dt) +} + +func TestOverlayType(t *testing.T) { + dt := &driverTester{t: t} + if err := Init(dt, nil); err != nil { + t.Fatal(err) + } + + if dt.d.Type() != testNetworkType { + t.Fatalf("Expected Type() to return %q. Instead got %q", testNetworkType, + dt.d.Type()) + } +} diff --git a/drivers/solaris/overlay/ovmanager/ovmanager.go b/drivers/solaris/overlay/ovmanager/ovmanager.go new file mode 100644 index 0000000000..78a586e08e --- /dev/null +++ b/drivers/solaris/overlay/ovmanager/ovmanager.go @@ -0,0 +1,248 @@ +package ovmanager + +import ( + "fmt" + "net" + "strconv" + "strings" + "sync" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/idm" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/types" +) + +const ( + networkType = "overlay" + vxlanIDStart = 256 + vxlanIDEnd = (1 << 24) - 1 +) + +type networkTable map[string]*network + +type driver struct { + config map[string]interface{} + networks networkTable + store datastore.DataStore + vxlanIdm *idm.Idm + sync.Mutex +} + +type subnet struct { + subnetIP *net.IPNet + gwIP *net.IPNet + vni uint32 +} + +type network struct { + id string + driver *driver + subnets []*subnet + sync.Mutex +} + +// Init registers a new instance of overlay driver +func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { + var err error + c := driverapi.Capability{ + DataScope: datastore.GlobalScope, + } + + d := &driver{ + networks: networkTable{}, + config: config, + } + + d.vxlanIdm, err = idm.New(nil, "vxlan-id", vxlanIDStart, vxlanIDEnd) + if err != nil { + return fmt.Errorf("failed to initialize vxlan id manager: %v", err) + } + + return dc.RegisterDriver(networkType, d, c) +} + +func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { + if id == "" { + return nil, fmt.Errorf("invalid network id for overlay network") + } + + if ipV4Data == nil { + return nil, fmt.Errorf("empty ipv4 data passed during overlay network creation") + } + + n := &network{ + id: id, + driver: d, + subnets: []*subnet{}, + } + + opts := make(map[string]string) + vxlanIDList := make([]uint32, 0, len(ipV4Data)) + for key, val := range option { + if key == netlabel.OverlayVxlanIDList { + logrus.Debugf("overlay network option: %s", val) + valStrList := strings.Split(val, ",") + for _, idStr := range valStrList { + vni, err := strconv.Atoi(idStr) + if err != nil { + return nil, fmt.Errorf("invalid vxlan id value %q passed", idStr) + } + + vxlanIDList = append(vxlanIDList, uint32(vni)) + } + } else { + opts[key] = val + } + } + + for i, ipd := range ipV4Data { + s := &subnet{ + subnetIP: ipd.Pool, + gwIP: ipd.Gateway, + } + + if len(vxlanIDList) > i { + s.vni = vxlanIDList[i] + } + + if err := n.obtainVxlanID(s); err != nil { + n.releaseVxlanID() + return nil, fmt.Errorf("could not obtain vxlan id for pool %s: %v", s.subnetIP, err) + } + + n.subnets = append(n.subnets, s) + } + + val := fmt.Sprintf("%d", n.subnets[0].vni) + for _, s := range n.subnets[1:] { + val = val + fmt.Sprintf(",%d", s.vni) + } + opts[netlabel.OverlayVxlanIDList] = val + + d.Lock() + d.networks[id] = n + d.Unlock() + + return opts, nil +} + +func (d *driver) NetworkFree(id string) error { + if id == "" { + return fmt.Errorf("invalid network id passed while freeing overlay network") + } + + d.Lock() + n, ok := d.networks[id] + d.Unlock() + + if !ok { + return fmt.Errorf("overlay network with id %s not found", id) + } + + // Release all vxlan IDs in one shot. + n.releaseVxlanID() + + d.Lock() + delete(d.networks, id) + d.Unlock() + + return nil +} + +func (n *network) obtainVxlanID(s *subnet) error { + var ( + err error + vni uint64 + ) + + n.Lock() + vni = uint64(s.vni) + n.Unlock() + + if vni == 0 { + vni, err = n.driver.vxlanIdm.GetID() + if err != nil { + return err + } + + n.Lock() + s.vni = uint32(vni) + n.Unlock() + return nil + } + + return n.driver.vxlanIdm.GetSpecificID(vni) +} + +func (n *network) releaseVxlanID() { + n.Lock() + vnis := make([]uint32, 0, len(n.subnets)) + for _, s := range n.subnets { + vnis = append(vnis, s.vni) + s.vni = 0 + } + n.Unlock() + + for _, vni := range vnis { + n.driver.vxlanIdm.Release(uint64(vni)) + } +} + +func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { +} + +func (d *driver) DeleteNetwork(nid string) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) DeleteEndpoint(nid, eid string) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { + return nil, types.NotImplementedErrorf("not implemented") +} + +// Join method is invoked when a Sandbox is attached to an endpoint. +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { + return types.NotImplementedErrorf("not implemented") +} + +// Leave method is invoked when a Sandbox detaches from an endpoint. +func (d *driver) Leave(nid, eid string) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) Type() string { + return networkType +} + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { + return types.NotImplementedErrorf("not implemented") +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) RevokeExternalConnectivity(nid, eid string) error { + return types.NotImplementedErrorf("not implemented") +} diff --git a/drivers/solaris/overlay/ovmanager/ovmanager_test.go b/drivers/solaris/overlay/ovmanager/ovmanager_test.go new file mode 100644 index 0000000000..a4d08faef7 --- /dev/null +++ b/drivers/solaris/overlay/ovmanager/ovmanager_test.go @@ -0,0 +1,89 @@ +// +build solaris + +package ovmanager + +import ( + "fmt" + "net" + "strings" + "testing" + + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/idm" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func newDriver(t *testing.T) *driver { + d := &driver{ + networks: networkTable{}, + } + + vxlanIdm, err := idm.New(nil, "vxlan-id", vxlanIDStart, vxlanIDEnd) + require.NoError(t, err) + + d.vxlanIdm = vxlanIdm + return d +} + +func parseCIDR(t *testing.T, ipnet string) *net.IPNet { + subnet, err := types.ParseCIDR(ipnet) + require.NoError(t, err) + return subnet +} + +func TestNetworkAllocateFree(t *testing.T) { + d := newDriver(t) + + ipamData := []driverapi.IPAMData{ + { + Pool: parseCIDR(t, "10.1.1.0/24"), + }, + { + Pool: parseCIDR(t, "10.1.2.0/24"), + }, + } + + vals, err := d.NetworkAllocate("testnetwork", nil, ipamData, nil) + require.NoError(t, err) + + vxlanIDs, ok := vals[netlabel.OverlayVxlanIDList] + assert.Equal(t, true, ok) + assert.Equal(t, 2, len(strings.Split(vxlanIDs, ","))) + + err = d.NetworkFree("testnetwork") + require.NoError(t, err) +} + +func TestNetworkAllocateUserDefinedVNIs(t *testing.T) { + d := newDriver(t) + + ipamData := []driverapi.IPAMData{ + { + Pool: parseCIDR(t, "10.1.1.0/24"), + }, + { + Pool: parseCIDR(t, "10.1.2.0/24"), + }, + } + + options := make(map[string]string) + // Intentionally add mode vnis than subnets + options[netlabel.OverlayVxlanIDList] = fmt.Sprintf("%d,%d,%d", 256, 257, 258) + + vals, err := d.NetworkAllocate("testnetwork", options, ipamData, nil) + require.NoError(t, err) + + vxlanIDs, ok := vals[netlabel.OverlayVxlanIDList] + assert.Equal(t, true, ok) + + // We should only get exactly the same number of vnis as + // subnets. No more, no less, even if we passed more vnis. + assert.Equal(t, 2, len(strings.Split(vxlanIDs, ","))) + assert.Equal(t, fmt.Sprintf("%d,%d", 256, 257), vxlanIDs) + + err = d.NetworkFree("testnetwork") + require.NoError(t, err) +} diff --git a/drivers/solaris/overlay/peerdb.go b/drivers/solaris/overlay/peerdb.go new file mode 100644 index 0000000000..7c57517917 --- /dev/null +++ b/drivers/solaris/overlay/peerdb.go @@ -0,0 +1,336 @@ +package overlay + +import ( + "fmt" + "net" + "sync" + + log "github.com/Sirupsen/logrus" +) + +const ovPeerTable = "overlay_peer_table" + +type peerKey struct { + peerIP net.IP + peerMac net.HardwareAddr +} + +type peerEntry struct { + eid string + vtep net.IP + peerIPMask net.IPMask + inSandbox bool + isLocal bool +} + +type peerMap struct { + mp map[string]peerEntry + sync.Mutex +} + +type peerNetworkMap struct { + mp map[string]*peerMap + sync.Mutex +} + +func (pKey peerKey) String() string { + return fmt.Sprintf("%s %s", pKey.peerIP, pKey.peerMac) +} + +func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error { + ipB, err := state.Token(true, nil) + if err != nil { + return err + } + + pKey.peerIP = net.ParseIP(string(ipB)) + + macB, err := state.Token(true, nil) + if err != nil { + return err + } + + pKey.peerMac, err = net.ParseMAC(string(macB)) + if err != nil { + return err + } + + return nil +} + +var peerDbWg sync.WaitGroup + +func (d *driver) peerDbWalk(f func(string, *peerKey, *peerEntry) bool) error { + d.peerDb.Lock() + nids := []string{} + for nid := range d.peerDb.mp { + nids = append(nids, nid) + } + d.peerDb.Unlock() + + for _, nid := range nids { + d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool { + return f(nid, pKey, pEntry) + }) + } + return nil +} + +func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool) error { + d.peerDb.Lock() + pMap, ok := d.peerDb.mp[nid] + if !ok { + d.peerDb.Unlock() + return nil + } + d.peerDb.Unlock() + + pMap.Lock() + for pKeyStr, pEntry := range pMap.mp { + var pKey peerKey + if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil { + log.Warnf("Peer key scan on network %s failed: %v", nid, err) + } + + if f(&pKey, &pEntry) { + pMap.Unlock() + return nil + } + } + pMap.Unlock() + + return nil +} + +func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) { + var ( + peerMac net.HardwareAddr + vtep net.IP + peerIPMask net.IPMask + found bool + ) + + err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool { + if pKey.peerIP.Equal(peerIP) { + peerMac = pKey.peerMac + peerIPMask = pEntry.peerIPMask + vtep = pEntry.vtep + found = true + return found + } + + return found + }) + + if err != nil { + return nil, nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err) + } + + if !found { + return nil, nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP) + } + + return peerMac, peerIPMask, vtep, nil +} + +func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, + peerMac net.HardwareAddr, vtep net.IP, isLocal bool) { + + peerDbWg.Wait() + + d.peerDb.Lock() + pMap, ok := d.peerDb.mp[nid] + if !ok { + d.peerDb.mp[nid] = &peerMap{ + mp: make(map[string]peerEntry), + } + + pMap = d.peerDb.mp[nid] + } + d.peerDb.Unlock() + + pKey := peerKey{ + peerIP: peerIP, + peerMac: peerMac, + } + + pEntry := peerEntry{ + eid: eid, + vtep: vtep, + peerIPMask: peerIPMask, + isLocal: isLocal, + } + + pMap.Lock() + pMap.mp[pKey.String()] = pEntry + pMap.Unlock() +} + +func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, + peerMac net.HardwareAddr, vtep net.IP) { + peerDbWg.Wait() + + d.peerDb.Lock() + pMap, ok := d.peerDb.mp[nid] + if !ok { + d.peerDb.Unlock() + return + } + d.peerDb.Unlock() + + pKey := peerKey{ + peerIP: peerIP, + peerMac: peerMac, + } + + pMap.Lock() + delete(pMap.mp, pKey.String()) + pMap.Unlock() +} + +func (d *driver) peerDbUpdateSandbox(nid string) { + d.peerDb.Lock() + pMap, ok := d.peerDb.mp[nid] + if !ok { + d.peerDb.Unlock() + return + } + d.peerDb.Unlock() + + peerDbWg.Add(1) + + var peerOps []func() + pMap.Lock() + for pKeyStr, pEntry := range pMap.mp { + var pKey peerKey + if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil { + fmt.Printf("peer key scan failed: %v", err) + } + + if pEntry.isLocal { + continue + } + + // Go captures variables by reference. The pEntry could be + // pointing to the same memory location for every iteration. Make + // a copy of pEntry before capturing it in the following closure. + entry := pEntry + op := func() { + if err := d.peerAdd(nid, entry.eid, pKey.peerIP, entry.peerIPMask, + pKey.peerMac, entry.vtep, + false); err != nil { + fmt.Printf("peerdbupdate in sandbox failed for ip %s and mac %s: %v", + pKey.peerIP, pKey.peerMac, err) + } + } + + peerOps = append(peerOps, op) + } + pMap.Unlock() + + for _, op := range peerOps { + op() + } + + peerDbWg.Done() +} + +func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, + peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { + + if err := validateID(nid, eid); err != nil { + return err + } + + if updateDb { + d.peerDbAdd(nid, eid, peerIP, peerIPMask, peerMac, vtep, false) + } + + n := d.network(nid) + if n == nil { + return nil + } + + sbox := n.sandbox() + if sbox == nil { + return nil + } + + IP := &net.IPNet{ + IP: peerIP, + Mask: peerIPMask, + } + + s := n.getSubnetforIP(IP) + if s == nil { + return fmt.Errorf("couldn't find the subnet %q in network %q\n", IP.String(), n.id) + } + + if err := n.obtainVxlanID(s); err != nil { + return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err) + } + + if err := n.joinSubnetSandbox(s, false); err != nil { + return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err) + } + + if err := d.checkEncryption(nid, vtep, n.vxlanID(s), false, true); err != nil { + log.Warn(err) + } + + // Add neighbor entry for the peer IP + if err := sbox.AddNeighbor(peerIP, peerMac, sbox.NeighborOptions().LinkName(s.vxlanName)); err != nil { + return fmt.Errorf("could not add neigbor entry into the sandbox: %v", err) + } + + // XXX Add fdb entry to the bridge for the peer mac + + return nil +} + +func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, + peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { + + if err := validateID(nid, eid); err != nil { + return err + } + + if updateDb { + d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep) + } + + n := d.network(nid) + if n == nil { + return nil + } + + sbox := n.sandbox() + if sbox == nil { + return nil + } + + // Delete fdb entry to the bridge for the peer mac + if err := sbox.DeleteNeighbor(vtep, peerMac, true); err != nil { + return fmt.Errorf("could not delete fdb entry into the sandbox: %v", err) + } + + // Delete neighbor entry for the peer IP + if err := sbox.DeleteNeighbor(peerIP, peerMac, true); err != nil { + return fmt.Errorf("could not delete neigbor entry into the sandbox: %v", err) + } + + if err := d.checkEncryption(nid, vtep, 0, false, false); err != nil { + log.Warn(err) + } + + return nil +} + +func (d *driver) pushLocalDb() { + d.peerDbWalk(func(nid string, pKey *peerKey, pEntry *peerEntry) bool { + if pEntry.isLocal { + d.pushLocalEndpointEvent("join", nid, pEntry.eid) + } + return false + }) +} diff --git a/drivers_solaris.go b/drivers_solaris.go index ba5d6a93e0..ad5184a3fc 100644 --- a/drivers_solaris.go +++ b/drivers_solaris.go @@ -3,10 +3,12 @@ package libnetwork import ( "github.com/docker/libnetwork/drivers/null" "github.com/docker/libnetwork/drivers/solaris/bridge" + "github.com/docker/libnetwork/drivers/solaris/overlay" ) func getInitializers() []initializer { return []initializer{ + {overlay.Init, "overlay"}, {bridge.Init, "bridge"}, {null.Init, "null"}, } From 45762a5bfa2beb292f3c6048b5d00ef72ac31103 Mon Sep 17 00:00:00 2001 From: Ty Alexander Date: Wed, 19 Oct 2016 15:10:34 -0600 Subject: [PATCH 117/799] Updated vagrant box, ubuntu/vivid64 was remove from atlas.hasicorp.com Signed-off-by: Ty Alexander --- Vagrantfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vagrantfile b/Vagrantfile index da09602d9d..e09e704532 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -43,7 +43,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| num_nodes.times do |n| config.vm.define "net-#{n+1}" do |net| - net.vm.box = "ubuntu/vivid64" + net.vm.box = "ubuntu/xenial64" net_ip = net_ips[n] net_index = n+1 net.vm.hostname = "net-#{net_index}" From f4d61688aecf5888ca586a0d01075923af9f6e98 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 27 Sep 2016 16:38:47 -0700 Subject: [PATCH 118/799] Use monotonic clock for reaping networkDB entries Signed-off-by: Santhosh Manohar --- networkdb/cluster.go | 25 +++++++++++++++++-------- networkdb/delegate.go | 5 ++--- networkdb/networkdb.go | 30 ++++++++++++++++-------------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index fc6ac698d8..562f971af3 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -270,19 +270,27 @@ func (nDB *NetworkDB) reconnectNode() { nDB.bulkSync([]string{node.Name}, true) } +// For timing the entry deletion in the repaer APIs that doesn't use monotonic clock +// source (time.Now, Sub etc.) should be avoided. Hence we use reapTime in every +// entry which is set initially to reapInterval and decremented by reapPeriod every time +// the reaper runs. NOTE nDB.reapTableEntries updates the reapTime with a readlock. This +// is safe as long as no other concurrent path touches the reapTime field. func (nDB *NetworkDB) reapState() { nDB.reapNetworks() nDB.reapTableEntries() } func (nDB *NetworkDB) reapNetworks() { - now := time.Now() nDB.Lock() for name, nn := range nDB.networks { for id, n := range nn { - if n.leaving && now.Sub(n.leaveTime) > reapInterval { - delete(nn, id) - nDB.deleteNetworkNode(id, name) + if n.leaving { + if n.reapTime <= 0 { + delete(nn, id) + nDB.deleteNetworkNode(id, name) + continue + } + n.reapTime -= reapPeriod } } } @@ -292,8 +300,6 @@ func (nDB *NetworkDB) reapNetworks() { func (nDB *NetworkDB) reapTableEntries() { var paths []string - now := time.Now() - nDB.RLock() nDB.indexes[byTable].Walk(func(path string, v interface{}) bool { entry, ok := v.(*entry) @@ -301,10 +307,13 @@ func (nDB *NetworkDB) reapTableEntries() { return false } - if !entry.deleting || now.Sub(entry.deleteTime) <= reapInterval { + if !entry.deleting { + return false + } + if entry.reapTime > 0 { + entry.reapTime -= reapPeriod return false } - paths = append(paths, path) return false }) diff --git a/networkdb/delegate.go b/networkdb/delegate.go index e886cfcab2..2f8ca48686 100644 --- a/networkdb/delegate.go +++ b/networkdb/delegate.go @@ -4,7 +4,6 @@ import ( "fmt" "net" "strings" - "time" "github.com/Sirupsen/logrus" "github.com/gogo/protobuf/proto" @@ -121,7 +120,7 @@ func (nDB *NetworkDB) handleNetworkEvent(nEvent *NetworkEvent) bool { n.ltime = nEvent.LTime n.leaving = nEvent.Type == NetworkEventTypeLeave if n.leaving { - n.leaveTime = time.Now() + n.reapTime = reapInterval } nDB.addNetworkNode(nEvent.NetworkID, nEvent.NodeName) @@ -178,7 +177,7 @@ func (nDB *NetworkDB) handleTableEvent(tEvent *TableEvent) bool { } if e.deleting { - e.deleteTime = time.Now() + e.reapTime = reapInterval } nDB.Lock() diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index a8c942c9cc..7c125242bf 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -107,8 +107,9 @@ type network struct { // Node leave is in progress. leaving bool - // The time this node knew about the node's network leave. - leaveTime time.Time + // Number of seconds still left before a deleted network entry gets + // removed from networkDB + reapTime time.Duration // The broadcast queue for table event gossip. This is only // initialized for this node's network attachment entries. @@ -153,8 +154,9 @@ type entry struct { // the cluster for certain amount of time after deletion. deleting bool - // The wall clock time when this node learned about this deletion. - deleteTime time.Time + // Number of seconds still left before a deleted table entry gets + // removed from networkDB + reapTime time.Duration } // New creates a new instance of NetworkDB using the Config passed by @@ -286,11 +288,11 @@ func (nDB *NetworkDB) DeleteEntry(tname, nid, key string) error { } entry := &entry{ - ltime: nDB.tableClock.Increment(), - node: nDB.config.NodeName, - value: value, - deleting: true, - deleteTime: time.Now(), + ltime: nDB.tableClock.Increment(), + node: nDB.config.NodeName, + value: value, + deleting: true, + reapTime: reapInterval, } if err := nDB.sendTableEvent(TableEventTypeDelete, nid, tname, key, entry); err != nil { @@ -339,11 +341,11 @@ func (nDB *NetworkDB) deleteNodeTableEntries(node string) { key := params[2] entry := &entry{ - ltime: oldEntry.ltime, - node: node, - value: oldEntry.value, - deleting: true, - deleteTime: time.Now(), + ltime: oldEntry.ltime, + node: node, + value: oldEntry.value, + deleting: true, + reapTime: reapInterval, } nDB.indexes[byTable].Insert(fmt.Sprintf("/%s/%s/%s", tname, nid, key), entry) From caafbccb27d1962251dac353374ac494c0859d2e Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Fri, 30 Sep 2016 14:03:10 -0700 Subject: [PATCH 119/799] Reap failed nodes after 24 hours Signed-off-by: Santhosh Manohar --- networkdb/cluster.go | 22 +++++++++++++++++++--- networkdb/event_delegate.go | 2 ++ networkdb/networkdb.go | 2 ++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 562f971af3..1ba1b14b0d 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -16,9 +16,11 @@ import ( ) const ( - reapInterval = 60 * time.Second - reapPeriod = 5 * time.Second - retryInterval = 1 * time.Second + reapInterval = 60 * time.Second + reapPeriod = 5 * time.Second + retryInterval = 1 * time.Second + nodeReapInterval = 24 * time.Hour + nodeReapPeriod = 2 * time.Hour ) type logWriter struct{} @@ -147,6 +149,7 @@ func (nDB *NetworkDB) clusterInit() error { {config.GossipInterval, nDB.gossip}, {config.PushPullInterval, nDB.bulkSyncTables}, {retryInterval, nDB.reconnectNode}, + {nodeReapPeriod, nDB.reapDeadNode}, } { t := time.NewTicker(trigger.interval) go nDB.triggerFunc(trigger.interval, t.C, nDB.stopCh, trigger.fn) @@ -234,6 +237,19 @@ func (nDB *NetworkDB) triggerFunc(stagger time.Duration, C <-chan time.Time, sto } } +func (nDB *NetworkDB) reapDeadNode() { + nDB.Lock() + defer nDB.Unlock() + for id, n := range nDB.failedNodes { + if n.reapTime > 0 { + n.reapTime -= reapPeriod + continue + } + logrus.Debugf("Removing failed node %v from gossip cluster", n.Name) + delete(nDB.failedNodes, id) + } +} + func (nDB *NetworkDB) reconnectNode() { nDB.RLock() if len(nDB.failedNodes) == 0 { diff --git a/networkdb/event_delegate.go b/networkdb/event_delegate.go index 019cafbd06..c22d09eba3 100644 --- a/networkdb/event_delegate.go +++ b/networkdb/event_delegate.go @@ -29,6 +29,8 @@ func (e *eventDelegate) NotifyLeave(mn *memberlist.Node) { e.nDB.Lock() if n, ok := e.nDB.nodes[mn.Name]; ok { delete(e.nDB.nodes, mn.Name) + + n.reapTime = reapInterval e.nDB.failedNodes[mn.Name] = n } e.nDB.Unlock() diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 69fc4fe249..a79b4231d2 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -94,6 +94,8 @@ type NetworkDB struct { type node struct { memberlist.Node ltime serf.LamportTime + // Number of hours left before the reaper removes the node + reapTime time.Duration } // network describes the node/network attachment. From 55f35024463cbba4ef8f21386767c0617b66d3b0 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 4 Oct 2016 14:04:48 -0700 Subject: [PATCH 120/799] Do not update hosts file with internal networks endpoint IP Signed-off-by: Alessandro Boch --- endpoint.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/endpoint.go b/endpoint.go index 1c75b6fea5..529cfd5114 100644 --- a/endpoint.go +++ b/endpoint.go @@ -469,12 +469,14 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { n.getController().watchSvcRecord(ep) } - address := "" - if ip := ep.getFirstInterfaceAddress(); ip != nil { - address = ip.String() - } - if err = sb.updateHostsFile(address); err != nil { - return err + if doUpdateHostsFile(n, sb) { + address := "" + if ip := ep.getFirstInterfaceAddress(); ip != nil { + address = ip.String() + } + if err = sb.updateHostsFile(address); err != nil { + return err + } } if err = sb.updateDNS(n.enableIPv6); err != nil { return err @@ -548,6 +550,10 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { return nil } +func doUpdateHostsFile(n *network, sb *sandbox) bool { + return !n.ingress && n.Name() != libnGWNetwork +} + func (ep *endpoint) rename(name string) error { var err error n := ep.getNetwork() From e02f9e9a494d5f71a37cd631605dbcf18742a9c1 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Fri, 16 Sep 2016 22:40:44 -0700 Subject: [PATCH 121/799] Fix issue for `--fixed-cidr` when bridge has multiple addresses This fix tries to address the issue raised in: https://github.com/docker/docker/issues/26341 where multiple addresses in a bridge may cause `--fixed-cidr` to not have the correct addresses. The issue is that `netutils.ElectInterfaceAddresses(bridgeName)` only returns the first IPv4 address. This fix changes `ElectInterfaceAddresses()` and `addresses()` so that all IPv4 addresses are returned. This will allow the possibility of selectively choose the address needed. Signed-off-by: Yong Tang --- cmd/dnet/dnet.go | 8 ++-- drivers/bridge/bridge_test.go | 10 ++--- drivers/bridge/interface.go | 13 +++--- drivers/bridge/interface_test.go | 6 +-- drivers/bridge/setup_ipv4.go | 19 ++++++++- drivers/bridge/setup_verify.go | 6 ++- netutils/utils_freebsd.go | 10 +++-- netutils/utils_linux.go | 21 +++++----- netutils/utils_solaris.go | 12 +++--- netutils/utils_test.go | 68 ++++++++++++++++++++++++++------ netutils/utils_windows.go | 10 +++-- 11 files changed, 126 insertions(+), 57 deletions(-) diff --git a/cmd/dnet/dnet.go b/cmd/dnet/dnet.go index 2df69d5115..118ea80d3a 100644 --- a/cmd/dnet/dnet.go +++ b/cmd/dnet/dnet.go @@ -507,11 +507,11 @@ func encodeData(data interface{}) (*bytes.Buffer, error) { } func ipamOption(bridgeName string) libnetwork.NetworkOption { - if nw, _, err := netutils.ElectInterfaceAddresses(bridgeName); err == nil { - ipamV4Conf := &libnetwork.IpamConf{PreferredPool: nw.String()} - hip, _ := types.GetHostPartIP(nw.IP, nw.Mask) + if nws, _, err := netutils.ElectInterfaceAddresses(bridgeName); err == nil { + ipamV4Conf := &libnetwork.IpamConf{PreferredPool: nws[0].String()} + hip, _ := types.GetHostPartIP(nws[0].IP, nws[0].Mask) if hip.IsGlobalUnicast() { - ipamV4Conf.Gateway = nw.IP.String() + ipamV4Conf.Gateway = nws[0].IP.String() } return libnetwork.NetworkOptionIpam("default", "", []*libnetwork.IpamConf{ipamV4Conf}, nil, nil) } diff --git a/drivers/bridge/bridge_test.go b/drivers/bridge/bridge_test.go index 403bdcb286..a44a595968 100644 --- a/drivers/bridge/bridge_test.go +++ b/drivers/bridge/bridge_test.go @@ -169,13 +169,13 @@ func compareBindings(a, b []types.PortBinding) bool { func getIPv4Data(t *testing.T, iface string) []driverapi.IPAMData { ipd := driverapi.IPAMData{AddressSpace: "full"} - nw, _, err := netutils.ElectInterfaceAddresses(iface) + nws, _, err := netutils.ElectInterfaceAddresses(iface) if err != nil { t.Fatal(err) } - ipd.Pool = nw + ipd.Pool = nws[0] // Set network gateway to X.X.X.1 - ipd.Gateway = types.GetIPNetCopy(nw) + ipd.Gateway = types.GetIPNetCopy(nws[0]) ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1 return []driverapi.IPAMData{ipd} } @@ -1054,12 +1054,12 @@ func TestCreateWithExistingBridge(t *testing.T) { t.Fatalf("Failed to getNetwork(%s): %v", brName, err) } - addr4, _, err := nw.bridge.addresses() + addrs4, _, err := nw.bridge.addresses() if err != nil { t.Fatalf("Failed to get the bridge network's address: %v", err) } - if !addr4.IP.Equal(ip) { + if !addrs4[0].IP.Equal(ip) { t.Fatal("Creating bridge network with existing bridge interface unexpectedly modified the IP address of the bridge") } diff --git a/drivers/bridge/interface.go b/drivers/bridge/interface.go index 16a8c7722d..9b20900416 100644 --- a/drivers/bridge/interface.go +++ b/drivers/bridge/interface.go @@ -52,23 +52,22 @@ func (i *bridgeInterface) exists() bool { return i.Link != nil } -// addresses returns a single IPv4 address and all IPv6 addresses for the -// bridge interface. -func (i *bridgeInterface) addresses() (netlink.Addr, []netlink.Addr, error) { +// addresses returns all IPv4 addresses and all IPv6 addresses for the bridge interface. +func (i *bridgeInterface) addresses() ([]netlink.Addr, []netlink.Addr, error) { v4addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V4) if err != nil { - return netlink.Addr{}, nil, fmt.Errorf("Failed to retrieve V4 addresses: %v", err) + return nil, nil, fmt.Errorf("Failed to retrieve V4 addresses: %v", err) } v6addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V6) if err != nil { - return netlink.Addr{}, nil, fmt.Errorf("Failed to retrieve V6 addresses: %v", err) + return nil, nil, fmt.Errorf("Failed to retrieve V6 addresses: %v", err) } if len(v4addr) == 0 { - return netlink.Addr{}, v6addr, nil + return nil, v6addr, nil } - return v4addr[0], v6addr, nil + return v4addr, v6addr, nil } func (i *bridgeInterface) programIPv6Address() error { diff --git a/drivers/bridge/interface_test.go b/drivers/bridge/interface_test.go index 0e7dec3b5a..255a709478 100644 --- a/drivers/bridge/interface_test.go +++ b/drivers/bridge/interface_test.go @@ -37,12 +37,12 @@ func TestAddressesEmptyInterface(t *testing.T) { t.Fatalf("newInterface() failed: %v", err) } - addrv4, addrsv6, err := inf.addresses() + addrsv4, addrsv6, err := inf.addresses() if err != nil { t.Fatalf("Failed to get addresses of default interface: %v", err) } - if expected := (netlink.Addr{}); addrv4 != expected { - t.Fatalf("Default interface has unexpected IPv4: %s", addrv4) + if len(addrsv4) != 0 { + t.Fatalf("Default interface has unexpected IPv4: %s", addrsv4) } if len(addrsv6) != 0 { t.Fatalf("Default interface has unexpected IPv6: %v", addrsv6) diff --git a/drivers/bridge/setup_ipv4.go b/drivers/bridge/setup_ipv4.go index f11adc2cb1..3af5836d52 100644 --- a/drivers/bridge/setup_ipv4.go +++ b/drivers/bridge/setup_ipv4.go @@ -3,6 +3,7 @@ package bridge import ( "fmt" "io/ioutil" + "net" "path/filepath" log "github.com/Sirupsen/logrus" @@ -10,12 +11,28 @@ import ( "github.com/vishvananda/netlink" ) +func selectIPv4Address(addresses []netlink.Addr, selector *net.IPNet) (netlink.Addr, error) { + if len(addresses) == 0 { + return netlink.Addr{}, fmt.Errorf("unable to select an address as the address pool is empty") + } + if selector != nil { + for _, addr := range addresses { + if selector.Contains(addr.IP) { + return addr, nil + } + } + } + return addresses[0], nil +} + func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error { - addrv4, _, err := i.addresses() + addrv4List, _, err := i.addresses() if err != nil { return fmt.Errorf("failed to retrieve bridge interface addresses: %v", err) } + addrv4, _ := selectIPv4Address(addrv4List, config.AddressIPv4) + if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) { if addrv4.IPNet != nil { if err := i.nlh.AddrDel(i.Link, &addrv4); err != nil { diff --git a/drivers/bridge/setup_verify.go b/drivers/bridge/setup_verify.go index 0bafed6011..ec37d16d06 100644 --- a/drivers/bridge/setup_verify.go +++ b/drivers/bridge/setup_verify.go @@ -11,12 +11,14 @@ import ( ) func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) error { - // Fetch a single IPv4 and a slice of IPv6 addresses from the bridge. - addrv4, addrsv6, err := i.addresses() + // Fetch a slice of IPv4 addresses and a slice of IPv6 addresses from the bridge. + addrsv4, addrsv6, err := i.addresses() if err != nil { return fmt.Errorf("Failed to verify ip addresses: %v", err) } + addrv4, _ := selectIPv4Address(addrsv4, config.AddressIPv4) + // Verify that the bridge does have an IPv4 address. if addrv4.IPNet == nil { return &ErrNoIPAddr{} diff --git a/netutils/utils_freebsd.go b/netutils/utils_freebsd.go index f7a7ac75f5..02bcd32aa8 100644 --- a/netutils/utils_freebsd.go +++ b/netutils/utils_freebsd.go @@ -7,10 +7,12 @@ import ( ) // ElectInterfaceAddresses looks for an interface on the OS with the specified name -// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist, -// it chooses from a predifined list the first IPv4 address which does not conflict -// with other interfaces on the system. -func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { +// and returns returns all its IPv4 and IPv6 addresses in CIDR notation. +// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned. +// If the interface does not exist, it chooses from a predefined +// list the first IPv4 address which does not conflict with other +// interfaces on the system. +func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) { return nil, nil, types.NotImplementedErrorf("not supported on freebsd") } diff --git a/netutils/utils_linux.go b/netutils/utils_linux.go index 4a03a3a15a..870cc12855 100644 --- a/netutils/utils_linux.go +++ b/netutils/utils_linux.go @@ -62,15 +62,15 @@ func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, err } // ElectInterfaceAddresses looks for an interface on the OS with the -// specified name and returns its IPv4 and IPv6 addresses in CIDR -// form. If the interface does not exist, it chooses from a predefined +// specified name and returns returns all its IPv4 and IPv6 addresses in CIDR notation. +// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned. +// If the interface does not exist, it chooses from a predefined // list the first IPv4 address which does not conflict with other // interfaces on the system. -func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { +func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) { var ( - v4Net *net.IPNet + v4Nets []*net.IPNet v6Nets []*net.IPNet - err error ) defer osl.InitOSContext()() @@ -85,23 +85,24 @@ func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { if err != nil { return nil, nil, err } - if len(v4addr) > 0 { - v4Net = v4addr[0].IPNet + for _, nlAddr := range v4addr { + v4Nets = append(v4Nets, nlAddr.IPNet) } for _, nlAddr := range v6addr { v6Nets = append(v6Nets, nlAddr.IPNet) } } - if link == nil || v4Net == nil { + if link == nil || len(v4Nets) == 0 { // Choose from predefined broad networks - v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) + v4Net, err := FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) if err != nil { return nil, nil, err } + v4Nets = append(v4Nets, v4Net) } - return v4Net, v6Nets, nil + return v4Nets, v6Nets, nil } // FindAvailableNetwork returns a network from the passed list which does not diff --git a/netutils/utils_solaris.go b/netutils/utils_solaris.go index 12d453f7ce..dc67101f4b 100644 --- a/netutils/utils_solaris.go +++ b/netutils/utils_solaris.go @@ -22,10 +22,12 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error { } // ElectInterfaceAddresses looks for an interface on the OS with the specified name -// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist, -// it chooses from a predifined list the first IPv4 address which does not conflict -// with other interfaces on the system. -func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { +// and returns returns all its IPv4 and IPv6 addresses in CIDR notation. +// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned. +// If the interface does not exist, it chooses from a predefined +// list the first IPv4 address which does not conflict with other +// interfaces on the system. +func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) { var ( v4Net *net.IPNet ) @@ -63,7 +65,7 @@ func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { return nil, nil, err } } - return v4Net, nil, nil + return []*net.IPNet{v4Net}, nil, nil } // FindAvailableNetwork returns a network from the passed list which does not diff --git a/netutils/utils_test.go b/netutils/utils_test.go index 87fbe6531f..272c53e1f7 100644 --- a/netutils/utils_test.go +++ b/netutils/utils_test.go @@ -5,6 +5,7 @@ package netutils import ( "bytes" "net" + "sort" "testing" "github.com/docker/libnetwork/ipamutils" @@ -265,6 +266,43 @@ func TestNetworkRequest(t *testing.T) { } } +func TestElectInterfaceAddressMultipleAddresses(t *testing.T) { + defer testutils.SetupTestOSContext(t)() + ipamutils.InitNetworks() + + nws := []string{"172.101.202.254/16", "172.102.202.254/16"} + createInterface(t, "test", nws...) + + ipv4NwList, ipv6NwList, err := ElectInterfaceAddresses("test") + if err != nil { + t.Fatal(err) + } + + if len(ipv4NwList) == 0 { + t.Fatalf("unexpected empty ipv4 network addresses") + } + + if len(ipv6NwList) == 0 { + t.Fatalf("unexpected empty ipv6 network addresses") + } + + nwList := []string{} + for _, ipv4Nw := range ipv4NwList { + nwList = append(nwList, ipv4Nw.String()) + } + sort.Strings(nws) + sort.Strings(nwList) + + if len(nws) != len(nwList) { + t.Fatalf("expected %v. got %v", nws, nwList) + } + for i, nw := range nws { + if nw != nwList[i] { + t.Fatalf("expected %v. got %v", nw, nwList[i]) + } + } +} + func TestElectInterfaceAddress(t *testing.T) { defer testutils.SetupTestOSContext(t)() ipamutils.InitNetworks() @@ -277,37 +315,43 @@ func TestElectInterfaceAddress(t *testing.T) { t.Fatal(err) } - if ipv4Nw == nil { + if len(ipv4Nw) == 0 { t.Fatalf("unexpected empty ipv4 network addresses") } if len(ipv6Nw) == 0 { - t.Fatalf("unexpected empty ipv4 network addresses") + t.Fatalf("unexpected empty ipv6 network addresses") } - if nws != ipv4Nw.String() { - t.Fatalf("expected %s. got %s", nws, ipv4Nw) + if nws != ipv4Nw[0].String() { + t.Fatalf("expected %s. got %s", nws, ipv4Nw[0]) } } -func createInterface(t *testing.T, name, nw string) { +func createInterface(t *testing.T, name string, nws ...string) { // Add interface link := &netlink.Bridge{ LinkAttrs: netlink.LinkAttrs{ Name: "test", }, } - bip, err := types.ParseCIDR(nw) - if err != nil { - t.Fatal(err) + bips := []*net.IPNet{} + for _, nw := range nws { + bip, err := types.ParseCIDR(nw) + if err != nil { + t.Fatal(err) + } + bips = append(bips, bip) } - if err = netlink.LinkAdd(link); err != nil { + if err := netlink.LinkAdd(link); err != nil { t.Fatalf("Failed to create interface via netlink: %v", err) } - if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: bip}); err != nil { - t.Fatal(err) + for _, bip := range bips { + if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: bip}); err != nil { + t.Fatal(err) + } } - if err = netlink.LinkSetUp(link); err != nil { + if err := netlink.LinkSetUp(link); err != nil { t.Fatal(err) } } diff --git a/netutils/utils_windows.go b/netutils/utils_windows.go index 3b4bb9d909..b6e79c7538 100644 --- a/netutils/utils_windows.go +++ b/netutils/utils_windows.go @@ -7,10 +7,12 @@ import ( ) // ElectInterfaceAddresses looks for an interface on the OS with the specified name -// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist, -// it chooses from a predifined list the first IPv4 address which does not conflict -// with other interfaces on the system. -func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { +// and returns returns all its IPv4 and IPv6 addresses in CIDR notation. +// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned. +// If the interface does not exist, it chooses from a predefined +// list the first IPv4 address which does not conflict with other +// interfaces on the system. +func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) { return nil, nil, types.NotImplementedErrorf("not supported on windows") } From 16df588f51a9a1c73951f0a63ca08bc353995bc8 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Sat, 20 Aug 2016 22:55:00 -0700 Subject: [PATCH 122/799] Add sandbox API for task insertion to service LB and service discovery Signed-off-by: Santhosh Manohar --- endpoint.go | 17 +++++++++++++---- libnetwork_test.go | 8 ++++++++ networkdb/networkdb.go | 15 +++++++++++---- sandbox.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/endpoint.go b/endpoint.go index 1c75b6fea5..ee849bb12d 100644 --- a/endpoint.go +++ b/endpoint.go @@ -74,6 +74,7 @@ type endpoint struct { ingressPorts []*PortConfig dbIndex uint64 dbExists bool + serviceEnabled bool sync.Mutex } @@ -303,6 +304,18 @@ func (ep *endpoint) isAnonymous() bool { return ep.anonymous } +// enableService sets ep's serviceEnabled to the passed value if it's not in the +// current state and returns true; false otherwise. +func (ep *endpoint) enableService(state bool) bool { + ep.Lock() + defer ep.Unlock() + if ep.serviceEnabled != state { + ep.serviceEnabled = state + return true + } + return false +} + func (ep *endpoint) needResolver() bool { ep.Lock() defer ep.Unlock() @@ -500,10 +513,6 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { return err } - if e := ep.addToCluster(); e != nil { - log.Errorf("Could not update state for endpoint %s into cluster: %v", ep.Name(), e) - } - if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil { return sb.setupDefaultGW() } diff --git a/libnetwork_test.go b/libnetwork_test.go index 1eee7fa6b8..4510174d8b 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -855,6 +855,14 @@ func (f *fakeSandbox) Endpoints() []libnetwork.Endpoint { return nil } +func (f *fakeSandbox) EnableService() error { + return nil +} + +func (f *fakeSandbox) DisableService() error { + return nil +} + func TestEndpointDeleteWithActiveContainer(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index a79b4231d2..2074edb92b 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -11,6 +11,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/armon/go-radix" "github.com/docker/go-events" + "github.com/docker/libnetwork/types" "github.com/hashicorp/memberlist" "github.com/hashicorp/serf/serf" ) @@ -217,7 +218,7 @@ func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) { e, ok := nDB.indexes[byTable].Get(fmt.Sprintf("/%s/%s/%s", tname, nid, key)) if !ok { - return nil, fmt.Errorf("could not get entry in table %s with network id %s and key %s", tname, nid, key) + return nil, types.NotFoundErrorf("could not get entry in table %s with network id %s and key %s", tname, nid, key) } return e.(*entry), nil @@ -227,10 +228,16 @@ func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) { // table, key) tuple and if the NetworkDB is part of the cluster // propogates this event to the cluster. It is an error to create an // entry for the same tuple for which there is already an existing -// entry. +// entry unless the current entry is deleting state. func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error { - if _, err := nDB.GetEntry(tname, nid, key); err == nil { - return fmt.Errorf("cannot create entry as the entry in table %s with network id %s and key %s already exists", tname, nid, key) + oldEntry, err := nDB.getEntry(tname, nid, key) + if err != nil { + if _, ok := err.(types.NotFoundError); !ok { + return fmt.Errorf("cannot create entry in table %s with network id %s and key %s: %v", tname, nid, key, err) + } + } + if oldEntry != nil && !oldEntry.deleting { + return fmt.Errorf("cannot create entry in table %s with network id %s and key %s, already exists", tname, nid, key) } entry := &entry{ diff --git a/sandbox.go b/sandbox.go index 7d1eef5b73..49121f351e 100644 --- a/sandbox.go +++ b/sandbox.go @@ -42,6 +42,12 @@ type Sandbox interface { // ResolveService returns all the backend details about the containers or hosts // backing a service. Its purpose is to satisfy an SRV query ResolveService(name string) ([]*net.SRV, []net.IP) + // EnableService makes a managed container's service available by adding the + // endpoint to the service load balancer and service discovery + EnableService() error + // DisableService removes a managed contianer's endpoints from the load balancer + // and service discovery + DisableService() error } // SandboxOption is an option setter function type used to pass various options to @@ -655,6 +661,30 @@ func (sb *sandbox) SetKey(basePath string) error { return nil } +func (sb *sandbox) EnableService() error { + for _, ep := range sb.getConnectedEndpoints() { + if ep.enableService(true) { + if err := ep.addToCluster(); err != nil { + ep.enableService(false) + return fmt.Errorf("could not update state for endpoint %s into cluster: %v", ep.Name(), err) + } + } + } + return nil +} + +func (sb *sandbox) DisableService() error { + for _, ep := range sb.getConnectedEndpoints() { + if ep.enableService(false) { + if err := ep.deleteFromCluster(); err != nil { + ep.enableService(true) + return fmt.Errorf("could not delete state for endpoint %s from cluster: %v", ep.Name(), err) + } + } + } + return nil +} + func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) { for _, i := range osSbox.Info().Interfaces() { // Only remove the interfaces owned by this endpoint from the sandbox. From 185fd8d362f0c71b54f62d75a31a26a63234d97f Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Fri, 7 Oct 2016 12:41:15 -0700 Subject: [PATCH 123/799] Enable ping for service vip address Signed-off-by: Santhosh Manohar --- endpoint.go | 17 +++++++++++++++++ osl/interface_linux.go | 41 ++++++++++++++++++++++------------------- osl/options_linux.go | 6 ------ osl/sandbox.go | 10 ++++------ sandbox.go | 8 -------- service_linux.go | 28 ++++++++++++++++++++++++++-- 6 files changed, 69 insertions(+), 41 deletions(-) diff --git a/endpoint.go b/endpoint.go index 1c75b6fea5..97cb6f502c 100644 --- a/endpoint.go +++ b/endpoint.go @@ -1109,3 +1109,20 @@ func (c *controller) cleanupLocalEndpoints() { } } } + +func (ep *endpoint) setAliasIP(sb *sandbox, ip net.IP, add bool) error { + sb.Lock() + sbox := sb.osSbox + sb.Unlock() + + for _, i := range sbox.Info().Interfaces() { + if ep.hasInterface(i.SrcName()) { + ipNet := &net.IPNet{IP: ip, Mask: []byte{255, 255, 255, 255}} + if err := i.SetAliasIP(ipNet, add); err != nil { + return err + } + break + } + } + return nil +} diff --git a/osl/interface_linux.go b/osl/interface_linux.go index 72b1b13b6a..643939322e 100644 --- a/osl/interface_linux.go +++ b/osl/interface_linux.go @@ -26,7 +26,6 @@ type nwIface struct { mac net.HardwareAddr address *net.IPNet addressIPv6 *net.IPNet - ipAliases []*net.IPNet llAddrs []*net.IPNet routes []*net.IPNet bridge bool @@ -97,13 +96,6 @@ func (i *nwIface) LinkLocalAddresses() []*net.IPNet { return i.llAddrs } -func (i *nwIface) IPAliases() []*net.IPNet { - i.Lock() - defer i.Unlock() - - return i.ipAliases -} - func (i *nwIface) Routes() []*net.IPNet { i.Lock() defer i.Unlock() @@ -130,6 +122,28 @@ func (n *networkNamespace) Interfaces() []Interface { return ifaces } +func (i *nwIface) SetAliasIP(ip *net.IPNet, add bool) error { + i.Lock() + n := i.ns + i.Unlock() + + n.Lock() + nlh := n.nlHandle + n.Unlock() + + // Find the network interface identified by the DstName attribute. + iface, err := nlh.LinkByName(i.DstName()) + if err != nil { + return err + } + + ipAddr := &netlink.Addr{IPNet: ip, Label: ""} + if add { + return nlh.AddrAdd(iface, ipAddr) + } + return nlh.AddrDel(iface, ipAddr) +} + func (i *nwIface) Remove() error { i.Lock() n := i.ns @@ -333,7 +347,6 @@ func configureInterface(nlh *netlink.Handle, iface netlink.Link, i *nwIface) err {setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %v", ifaceName, i.AddressIPv6())}, {setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())}, {setInterfaceLinkLocalIPs, fmt.Sprintf("error setting interface %q link local IPs to %v", ifaceName, i.LinkLocalAddresses())}, - {setInterfaceIPAliases, fmt.Sprintf("error setting interface %q IP Aliases to %v", ifaceName, i.IPAliases())}, } for _, config := range ifaceConfigurators { @@ -387,16 +400,6 @@ func setInterfaceLinkLocalIPs(nlh *netlink.Handle, iface netlink.Link, i *nwIfac return nil } -func setInterfaceIPAliases(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { - for _, si := range i.IPAliases() { - ipAddr := &netlink.Addr{IPNet: si} - if err := nlh.AddrAdd(iface, ipAddr); err != nil { - return err - } - } - return nil -} - func setInterfaceName(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { return nlh.LinkSetName(iface, i.DstName()) } diff --git a/osl/options_linux.go b/osl/options_linux.go index 64309d0506..818669647f 100644 --- a/osl/options_linux.go +++ b/osl/options_linux.go @@ -66,12 +66,6 @@ func (n *networkNamespace) LinkLocalAddresses(list []*net.IPNet) IfaceOption { } } -func (n *networkNamespace) IPAliases(list []*net.IPNet) IfaceOption { - return func(i *nwIface) { - i.ipAliases = list - } -} - func (n *networkNamespace) Routes(routes []*net.IPNet) IfaceOption { return func(i *nwIface) { i.routes = routes diff --git a/osl/sandbox.go b/osl/sandbox.go index 18085c9082..051a7facc2 100644 --- a/osl/sandbox.go +++ b/osl/sandbox.go @@ -91,9 +91,6 @@ type IfaceOptionSetter interface { // LinkLocalAddresses returns an option setter to set the link-local IP addresses. LinkLocalAddresses([]*net.IPNet) IfaceOption - // IPAliases returns an option setter to set IP address Aliases - IPAliases([]*net.IPNet) IfaceOption - // Master returns an option setter to set the master interface if any for this // interface. The master interface name should refer to the srcname of a // previously added interface of type bridge. @@ -150,9 +147,6 @@ type Interface interface { // LinkLocalAddresses returns the link-local IP addresses assigned to the interface. LinkLocalAddresses() []*net.IPNet - // IPAliases returns the IP address aliases assigned to the interface. - IPAliases() []*net.IPNet - // IP routes for the interface. Routes() []*net.IPNet @@ -166,6 +160,10 @@ type Interface interface { // and moving it out of the sandbox. Remove() error + // SetAliasIP adds or deletes the passed IP as an alias on the interface. + // ex: set the vip of services in the same network as secondary IP. + SetAliasIP(ip *net.IPNet, add bool) error + // Statistics returns the statistics for this interface Statistics() (*types.InterfaceStatistics, error) } diff --git a/sandbox.go b/sandbox.go index f5d86ef20e..d9fdf98f2f 100644 --- a/sandbox.go +++ b/sandbox.go @@ -725,10 +725,6 @@ func (sb *sandbox) restoreOslSandbox() error { if len(i.llAddrs) != 0 { ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs)) } - if len(ep.virtualIP) != 0 { - vipAlias := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)} - ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().IPAliases([]*net.IPNet{vipAlias})) - } Ifaces[fmt.Sprintf("%s+%s", i.srcName, i.dstPrefix)] = ifaceOptions if joinInfo != nil { for _, r := range joinInfo.StaticRoutes { @@ -782,10 +778,6 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error { if len(i.llAddrs) != 0 { ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs)) } - if len(ep.virtualIP) != 0 { - vipAlias := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)} - ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().IPAliases([]*net.IPNet{vipAlias})) - } if i.mac != nil { ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac)) } diff --git a/service_linux.go b/service_linux.go index 5e3802a823..f919c09b5a 100644 --- a/service_linux.go +++ b/service_linux.go @@ -311,6 +311,14 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) { for _, ip := range lb.backEnds { sb.addLBBackend(ip, lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, gwIP, addService, n.ingress) + // For a new service program the vip as an alias on the task's sandbox interface + // connected to this network. + if !addService { + continue + } + if err := ep.setAliasIP(sb, lb.vip, true); err != nil { + logrus.Errorf("Adding Service VIP %v to ep %v(%v) failed: %v", lb.vip, ep.ID(), ep.Name(), err) + } addService = false } lb.service.Unlock() @@ -334,8 +342,16 @@ func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po } sb.addLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, addService, n.ingress) - } + // For a new service program the vip as an alias on the task's sandbox interface + // connected to this network. + if !addService { + return false + } + if err := ep.setAliasIP(sb, vip, true); err != nil { + logrus.Errorf("Adding Service VIP %v to ep %v(%v) failed: %v", vip, ep.ID(), ep.Name(), err) + } + } return false }) } @@ -357,8 +373,16 @@ func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Por } sb.rmLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, rmService, n.ingress) - } + // If the service is being remove its vip alias on on the task's sandbox interface + // has to be removed as well. + if !rmService { + return false + } + if err := ep.setAliasIP(sb, vip, false); err != nil { + logrus.Errorf("Removing Service VIP %v from ep %v(%v) failed: %v", vip, ep.ID(), ep.Name(), err) + } + } return false }) } From 83c9261d1a738f96ba612ac4cc8c0470b22e76dd Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 5 Oct 2016 00:04:05 -0700 Subject: [PATCH 124/799] Block non exposed port traffic on ingress nw interfaces Signed-off-by: Alessandro Boch --- iptables/iptables.go | 17 ++++++++++++++++- service_linux.go | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/iptables/iptables.go b/iptables/iptables.go index 340bba6b0b..b7fe816261 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -326,6 +326,21 @@ func (c *ChainInfo) Remove() error { // Exists checks if a rule exists func Exists(table Table, chain string, rule ...string) bool { + return exists(false, table, chain, rule...) +} + +// ExistsNative behaves as Exists with the difference it +// will always invoke `iptables` binary. +func ExistsNative(table Table, chain string, rule ...string) bool { + return exists(true, table, chain, rule...) +} + +func exists(native bool, table Table, chain string, rule ...string) bool { + f := Raw + if native { + f = raw + } + if string(table) == "" { table = Filter } @@ -334,7 +349,7 @@ func Exists(table Table, chain string, rule ...string) bool { if supportsCOpt { // if exit status is 0 then return true, the rule exists - _, err := Raw(append([]string{"-t", string(table), "-C", chain}, rule...)...) + _, err := f(append([]string{"-t", string(table), "-C", chain}, rule...)...) return err == nil } diff --git a/service_linux.go b/service_linux.go index 158411d140..a3f49c28f8 100644 --- a/service_linux.go +++ b/service_linux.go @@ -935,6 +935,14 @@ func redirecter() { rule := strings.Fields(fmt.Sprintf("-t nat -A PREROUTING -d %s -p %s --dport %d -j REDIRECT --to-port %d", eIP.String(), strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, iPort.TargetPort)) rules = append(rules, rule) + // Allow only incoming connections to exposed ports + iRule := strings.Fields(fmt.Sprintf("-I INPUT -d %s -p %s --dport %d -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT", + eIP.String(), strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.TargetPort)) + rules = append(rules, iRule) + // Allow only outgoing connections from exposed ports + oRule := strings.Fields(fmt.Sprintf("-I OUTPUT -s %s -p %s --sport %d -m conntrack --ctstate ESTABLISHED -j ACCEPT", + eIP.String(), strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.TargetPort)) + rules = append(rules, oRule) } ns, err := netns.GetFromPath(os.Args[1]) @@ -952,7 +960,31 @@ func redirecter() { for _, rule := range rules { if err := iptables.RawCombinedOutputNative(rule...); err != nil { logrus.Errorf("setting up rule failed, %v: %v", rule, err) - os.Exit(5) + os.Exit(6) + } + } + + if len(ingressPorts) == 0 { + return + } + + // Ensure blocking rules for anything else in/to ingress network + for _, rule := range [][]string{ + {"-d", eIP.String(), "-p", "udp", "-j", "DROP"}, + {"-d", eIP.String(), "-p", "tcp", "-j", "DROP"}, + } { + if !iptables.ExistsNative(iptables.Filter, "INPUT", rule...) { + if err := iptables.RawCombinedOutputNative(append([]string{"-A", "INPUT"}, rule...)...); err != nil { + logrus.Errorf("setting up rule failed, %v: %v", rule, err) + os.Exit(7) + } + } + rule[0] = "-s" + if !iptables.ExistsNative(iptables.Filter, "OUTPUT", rule...) { + if err := iptables.RawCombinedOutputNative(append([]string{"-A", "OUTPUT"}, rule...)...); err != nil { + logrus.Errorf("setting up rule failed, %v: %v", rule, err) + os.Exit(8) + } } } } From d588bb1fa6ef47bbd631373d6f854a07f3b2e80e Mon Sep 17 00:00:00 2001 From: yuexiao-wang Date: Sat, 29 Oct 2016 01:04:22 +0800 Subject: [PATCH 125/799] Fix some typos Signed-off-by: yuexiao-wang --- error.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/error.go b/error.go index d1291f1db6..c0054ce70c 100644 --- a/error.go +++ b/error.go @@ -107,7 +107,7 @@ func (nnr NetworkNameError) Error() string { // Forbidden denotes the type of this error func (nnr NetworkNameError) Forbidden() {} -// UnknownNetworkError is returned when libnetwork could not find in it's database +// UnknownNetworkError is returned when libnetwork could not find in its database // a network with the same name and id. type UnknownNetworkError struct { name string @@ -135,7 +135,7 @@ func (aee *ActiveEndpointsError) Error() string { // Forbidden denotes the type of this error func (aee *ActiveEndpointsError) Forbidden() {} -// UnknownEndpointError is returned when libnetwork could not find in it's database +// UnknownEndpointError is returned when libnetwork could not find in its database // an endpoint with the same name and id. type UnknownEndpointError struct { name string From 59d91e52216418abb7632c9e68054707c97e6826 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Fri, 28 Oct 2016 11:42:50 -0700 Subject: [PATCH 126/799] Respect icc option for internal networks Signed-off-by: Alessandro Boch --- drivers/bridge/setup_ip_tables.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/bridge/setup_ip_tables.go b/drivers/bridge/setup_ip_tables.go index 78ab10f053..862d9e4491 100644 --- a/drivers/bridge/setup_ip_tables.go +++ b/drivers/bridge/setup_ip_tables.go @@ -79,11 +79,11 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt Mask: i.bridgeIPv4.Mask, } if config.Internal { - if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, true); err != nil { + if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, config.EnableICC, true); err != nil { return fmt.Errorf("Failed to Setup IP tables: %s", err.Error()) } n.registerIptCleanFunc(func() error { - return setupInternalNetworkRules(config.BridgeName, maskedAddrv4, false) + return setupInternalNetworkRules(config.BridgeName, maskedAddrv4, config.EnableICC, false) }) } else { if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil { @@ -333,7 +333,7 @@ func removeIPChains() { } } -func setupInternalNetworkRules(bridgeIface string, addr net.Addr, insert bool) error { +func setupInternalNetworkRules(bridgeIface string, addr net.Addr, icc, insert bool) error { var ( inDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}} outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}} @@ -344,5 +344,9 @@ func setupInternalNetworkRules(bridgeIface string, addr net.Addr, insert bool) e if err := programChainRule(outDropRule, "DROP OUTGOING", insert); err != nil { return err } + // Set Inter Container Communication. + if err := setIcc(bridgeIface, icc, insert); err != nil { + return err + } return nil } From a1a0bb1d9f7aff95f304cfc0d3e205e22f4c6050 Mon Sep 17 00:00:00 2001 From: allencloud Date: Sun, 18 Sep 2016 17:57:49 +0800 Subject: [PATCH 127/799] fix nits in comments and log Signed-off-by: allencloud --- datastore/datastore.go | 2 +- discoverapi/discoverapi.go | 2 +- docs/macvlan.md | 10 +++++----- drivers/macvlan/macvlan_endpoint.go | 2 +- drivers/macvlan/macvlan_network.go | 6 +++--- drivers/macvlan/macvlan_setup.go | 2 +- endpoint.go | 2 +- error.go | 2 +- network.go | 2 +- resolvconf/resolvconf.go | 4 ++-- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/datastore/datastore.go b/datastore/datastore.go index b045eab28a..fa6942d837 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -145,7 +145,7 @@ func makeDefaultScopes() map[string]*ScopeCfg { var defaultRootChain = []string{"docker", "network", "v1.0"} var rootChain = defaultRootChain -// DefaultScopes returns a map of default scopes and it's config for clients to use. +// DefaultScopes returns a map of default scopes and its config for clients to use. func DefaultScopes(dataDir string) map[string]*ScopeCfg { if dataDir != "" { defaultScopes[LocalScope].Client.Address = dataDir + "/network/files/local-kv.db" diff --git a/discoverapi/discoverapi.go b/discoverapi/discoverapi.go index 3710ea447e..7ac36155db 100644 --- a/discoverapi/discoverapi.go +++ b/discoverapi/discoverapi.go @@ -1,6 +1,6 @@ package discoverapi -// Discover is an interface to be implemented by the componenet interested in receiving discover events +// Discover is an interface to be implemented by the component interested in receiving discover events // like new node joining the cluster or datastore updates type Discover interface { // DiscoverNew is a notification for a new discovery event, Example:a new node joining a cluster diff --git a/docs/macvlan.md b/docs/macvlan.md index 34477ff336..9193220e5e 100644 --- a/docs/macvlan.md +++ b/docs/macvlan.md @@ -11,7 +11,7 @@ Instead of attaching container network interfaces to a Docker host Linux bridge When using traditional Linux bridges there are two common techniques to get traffic out of a container and into the physical network and vice versa. The first method to connect containers to the underlying network is to use Iptable rules which perform a NAT translation from a bridge that represents the Docker network to the physical Ethernet connection such as `eth0`. The upside of Iptables using the Docker built-in bridge driver is that the NIC does not have to be in promiscuous mode. The second bridge driver method is to move a host's external Ethernet connection into the bridge. Moving the host Ethernet connection can at times be unforgiving. Common mistakes such as cutting oneself off from the host, or worse, creating bridging loops that can cripple a VLAN throughout a data center can open a network design up to potential risks as the infrastructure grows. -Connecting containers without any NATing is where the VLAN drivers accel. Rather then having to manage a bridge for each Docker network containers are connected directly to a `parent` interface such as `eth0` that attaches the container to the same broadcast domain as the parent interface. A simple example is if a host's `eth0` is on the network `192.168.1.0/24` with a gateway of `192.168.1.1` then a Macvlan Docker network can start containers on the addresses `192.168.1.2 - 192.168.1.254`. Containers use the same network as the parent `-o parent` that is specified in the `docker network create` command. +Connecting containers without any NATing is where the VLAN drivers accel. Rather than having to manage a bridge for each Docker network containers are connected directly to a `parent` interface such as `eth0` that attaches the container to the same broadcast domain as the parent interface. A simple example is if a host's `eth0` is on the network `192.168.1.0/24` with a gateway of `192.168.1.1` then a Macvlan Docker network can start containers on the addresses `192.168.1.2 - 192.168.1.254`. Containers use the same network as the parent `-o parent` that is specified in the `docker network create` command. There are positive performance implication as a result of bypassing the Linux bridge, along with the simplicity of less moving parts, which is also attractive. Macvlan containers are easy to troubleshoot. The actual MAC and IP address of the container is bridged into the upstream network making a problematic application easy for operators to trace from the network. Existing underlay network management and monitoring tools remain relevant. @@ -138,7 +138,7 @@ For more on Docker networking commands see: [Working with Docker network command VLANs have long been a primary means of virtualizing data center networks and are still in virtually all existing networks today. VLANs work by tagging a Layer-2 isolation domain with a 12-bit identifier ranging from 1-4094. The VLAN tag is inserted into a packet header that enables a logical grouping of a single subnet or multiple subnets of IPv4 and/or IPv6. It is very common for network operators to separate traffic using VLANs based on a subnet(s) function or security profile such as `web`, `db` or any other isolation requirements. -It is very common to have a compute host requirement of running multiple virtual networks concurrently on a host. Linux networking has long supported VLAN tagging, also known by it's standard 802.1Q, for maintaining datapath isolation between networks. The Ethernet link connected to a Docker host can be configured to support the 802.1q VLAN IDs by creating Linux sub-interfaces, each sub-interface being allocated a unique VLAN ID. +It is very common to have a compute host requirement of running multiple virtual networks concurrently on a host. Linux networking has long supported VLAN tagging, also known by its standard 802.1Q, for maintaining datapath isolation between networks. The Ethernet link connected to a Docker host can be configured to support the 802.1q VLAN IDs by creating Linux sub-interfaces, each sub-interface being allocated a unique VLAN ID. ![Simple Macvlan Mode Example](images/multi_tenant_8021q_vlans.png) @@ -164,7 +164,7 @@ In the next example, the network is tagged and isolated by the Docker host. A pa ``` # now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged -docker network create -d macvlan \ +docker network create -d macvlan \ --subnet=192.168.50.0/24 \ --gateway=192.168.50.1 \ -o parent=eth0.50 macvlan50 @@ -180,7 +180,7 @@ In the second network, tagged and isolated by the Docker host, `eth0.60` is the ``` # now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged. -docker network create -d macvlan \ +docker network create -d macvlan \ --subnet=192.168.60.0/24 \ --gateway=192.168.60.1 \ -o parent=eth0.60 -o \ @@ -197,7 +197,7 @@ The same as the example before except there is an additional subnet bound to the ``` -docker network create -d macvlan \ +docker network create -d macvlan \ --subnet=10.1.20.0/24 --subnet=10.1.10.0/24 \ --gateway=10.1.20.1 --gateway=10.1.10.1 \ -o parent=eth0.101 mcv101 diff --git a/drivers/macvlan/macvlan_endpoint.go b/drivers/macvlan/macvlan_endpoint.go index d76858ea36..3e5ccb29f8 100644 --- a/drivers/macvlan/macvlan_endpoint.go +++ b/drivers/macvlan/macvlan_endpoint.go @@ -66,7 +66,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, return nil } -// DeleteEndpoint remove the endpoint and associated netlink interface +// DeleteEndpoint removes the endpoint and associated netlink interface func (d *driver) DeleteEndpoint(nid, eid string) error { defer osl.InitOSContext()() if err := validateID(nid, eid); err != nil { diff --git a/drivers/macvlan/macvlan_network.go b/drivers/macvlan/macvlan_network.go index 2975596593..c7d3b1466d 100644 --- a/drivers/macvlan/macvlan_network.go +++ b/drivers/macvlan/macvlan_network.go @@ -123,7 +123,7 @@ func (d *driver) createNetwork(config *configuration) error { return nil } -// DeleteNetwork the network for the specified driver type +// DeleteNetwork deletes the network for the specified driver type func (d *driver) DeleteNetwork(nid string) error { defer osl.InitOSContext()() n := d.network(nid) @@ -161,7 +161,7 @@ func (d *driver) DeleteNetwork(nid string) error { return nil } -// parseNetworkOptions parse docker network options +// parseNetworkOptions parses docker network options func parseNetworkOptions(id string, option options.Generic) (*configuration, error) { var ( err error @@ -183,7 +183,7 @@ func parseNetworkOptions(id string, option options.Generic) (*configuration, err return config, nil } -// parseNetworkGenericOptions parse generic driver docker network options +// parseNetworkGenericOptions parses generic driver docker network options func parseNetworkGenericOptions(data interface{}) (*configuration, error) { var ( err error diff --git a/drivers/macvlan/macvlan_setup.go b/drivers/macvlan/macvlan_setup.go index a3e17f28e2..b5b4be3499 100644 --- a/drivers/macvlan/macvlan_setup.go +++ b/drivers/macvlan/macvlan_setup.go @@ -64,7 +64,7 @@ func setMacVlanMode(mode string) (netlink.MacvlanMode, error) { } } -// parentExists check if the specified interface exists in the default namespace +// parentExists checks if the specified interface exists in the default namespace func parentExists(ifaceStr string) bool { _, err := ns.NlHandle().LinkByName(ifaceStr) if err != nil { diff --git a/endpoint.go b/endpoint.go index 1c75b6fea5..31ddf3a72e 100644 --- a/endpoint.go +++ b/endpoint.go @@ -767,7 +767,7 @@ func (ep *endpoint) Delete(force bool) error { ep.releaseAddress() if err := n.getEpCnt().DecEndpointCnt(); err != nil { - log.Warnf("failed to decrement endpoint coint for ep %s: %v", ep.ID(), err) + log.Warnf("failed to decrement endpoint count for ep %s: %v", ep.ID(), err) } return nil diff --git a/error.go b/error.go index d1291f1db6..a4635acf79 100644 --- a/error.go +++ b/error.go @@ -107,7 +107,7 @@ func (nnr NetworkNameError) Error() string { // Forbidden denotes the type of this error func (nnr NetworkNameError) Forbidden() {} -// UnknownNetworkError is returned when libnetwork could not find in it's database +// UnknownNetworkError is returned when libnetwork could not find in its database // a network with the same name and id. type UnknownNetworkError struct { name string diff --git a/network.go b/network.go index 8a068d22e9..bc54d04b97 100644 --- a/network.go +++ b/network.go @@ -34,7 +34,7 @@ type Network interface { Type() string // Create a new endpoint to this network symbolically identified by the - // specified unique name. The options parameter carry driver specific options. + // specified unique name. The options parameter carries driver specific options. CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) // Delete the network. diff --git a/resolvconf/resolvconf.go b/resolvconf/resolvconf.go index 017b413dfc..e1db6191e4 100644 --- a/resolvconf/resolvconf.go +++ b/resolvconf/resolvconf.go @@ -123,10 +123,10 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) { // if the resulting resolvConf has no more nameservers defined, add appropriate // default DNS servers for IPv4 and (optionally) IPv6 if len(GetNameservers(cleanedResolvConf, types.IP)) == 0 { - logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers : %v", defaultIPv4Dns) + logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers: %v", defaultIPv4Dns) dns := defaultIPv4Dns if ipv6Enabled { - logrus.Infof("IPv6 enabled; Adding default IPv6 external servers : %v", defaultIPv6Dns) + logrus.Infof("IPv6 enabled; Adding default IPv6 external servers: %v", defaultIPv6Dns) dns = append(dns, defaultIPv6Dns...) } cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...) From a8095fe3d51663e12c02ac9cf2993bb21677798e Mon Sep 17 00:00:00 2001 From: yuexiao-wang Date: Sat, 29 Oct 2016 01:38:16 +0800 Subject: [PATCH 128/799] Modify the serial number from 1 to 9 Signed-off-by: yuexiao-wang --- docs/design.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/design.md b/docs/design.md index 82bccff7f8..b2c821c8db 100644 --- a/docs/design.md +++ b/docs/design.md @@ -67,26 +67,26 @@ Networks consist of *many* endpoints. Consumers of the CNM, like Docker for example, interact through the CNM Objects and its APIs to network the containers that they manage. -0. `Drivers` registers with `NetworkController`. Build-in drivers registers inside of LibNetwork, while remote Drivers registers with LibNetwork via Plugin mechanism. (*plugin-mechanism is WIP*). Each `driver` handles a particular `networkType`. +1. `Drivers` registers with `NetworkController`. Build-in drivers registers inside of LibNetwork, while remote Drivers registers with LibNetwork via Plugin mechanism. (*plugin-mechanism is WIP*). Each `driver` handles a particular `networkType`. -1. `NetworkController` object is created using `libnetwork.New()` API to manage the allocation of Networks and optionally configure a `Driver` with driver specific `Options`. +2. `NetworkController` object is created using `libnetwork.New()` API to manage the allocation of Networks and optionally configure a `Driver` with driver specific `Options`. -2. `Network` is created using the controller's `NewNetwork()` API by providing a `name` and `networkType`. `networkType` parameter helps to choose a corresponding `Driver` and binds the created `Network` to that `Driver`. From this point, any operation on `Network` will be handled by that `Driver`. +3. `Network` is created using the controller's `NewNetwork()` API by providing a `name` and `networkType`. `networkType` parameter helps to choose a corresponding `Driver` and binds the created `Network` to that `Driver`. From this point, any operation on `Network` will be handled by that `Driver`. -3. `controller.NewNetwork()` API also takes in optional `options` parameter which carries Driver-specific options and `Labels`, which the Drivers can make use of for its purpose. +4. `controller.NewNetwork()` API also takes in optional `options` parameter which carries Driver-specific options and `Labels`, which the Drivers can make use of for its purpose. -4. `network.CreateEndpoint()` can be called to create a new Endpoint in a given network. This API also accepts optional `options` parameter which drivers can make use of. These 'options' carry both well-known labels and driver-specific labels. Drivers will in turn be called with `driver.CreateEndpoint` and it can choose to reserve IPv4/IPv6 addresses when an `Endpoint` is created in a `Network`. The `Driver` will assign these addresses using `InterfaceInfo` interface defined in the `driverapi`. The IP/IPv6 are needed to complete the endpoint as service definition along with the ports the endpoint exposes since essentially a service endpoint is nothing but a network address and the port number that the application container is listening on. +5. `network.CreateEndpoint()` can be called to create a new Endpoint in a given network. This API also accepts optional `options` parameter which drivers can make use of. These 'options' carry both well-known labels and driver-specific labels. Drivers will in turn be called with `driver.CreateEndpoint` and it can choose to reserve IPv4/IPv6 addresses when an `Endpoint` is created in a `Network`. The `Driver` will assign these addresses using `InterfaceInfo` interface defined in the `driverapi`. The IP/IPv6 are needed to complete the endpoint as service definition along with the ports the endpoint exposes since essentially a service endpoint is nothing but a network address and the port number that the application container is listening on. -5. `endpoint.Join()` can be used to attach a container to an `Endpoint`. The Join operation will create a `Sandbox` if it doesn't exist already for that container. The Drivers can make use of the Sandbox Key to identify multiple endpoints attached to a same container. This API also accepts optional `options` parameter which drivers can make use of. +6. `endpoint.Join()` can be used to attach a container to an `Endpoint`. The Join operation will create a `Sandbox` if it doesn't exist already for that container. The Drivers can make use of the Sandbox Key to identify multiple endpoints attached to a same container. This API also accepts optional `options` parameter which drivers can make use of. * Though it is not a direct design issue of LibNetwork, it is highly encouraged to have users like `Docker` to call the endpoint.Join() during Container's `Start()` lifecycle that is invoked *before* the container is made operational. As part of Docker integration, this will be taken care of. * One of a FAQ on endpoint join() API is that, why do we need an API to create an Endpoint and another to join the endpoint. - The answer is based on the fact that Endpoint represents a Service which may or may not be backed by a Container. When an Endpoint is created, it will have its resources reserved so that any container can get attached to the endpoint later and get a consistent networking behaviour. -6. `endpoint.Leave()` can be invoked when a container is stopped. The `Driver` can cleanup the states that it allocated during the `Join()` call. LibNetwork will delete the `Sandbox` when the last referencing endpoint leaves the network. But LibNetwork keeps hold of the IP addresses as long as the endpoint is still present and will be reused when the container(or any container) joins again. This ensures that the container's resources are reused when they are Stopped and Started again. +7. `endpoint.Leave()` can be invoked when a container is stopped. The `Driver` can cleanup the states that it allocated during the `Join()` call. LibNetwork will delete the `Sandbox` when the last referencing endpoint leaves the network. But LibNetwork keeps hold of the IP addresses as long as the endpoint is still present and will be reused when the container(or any container) joins again. This ensures that the container's resources are reused when they are Stopped and Started again. -7. `endpoint.Delete()` is used to delete an endpoint from a network. This results in deleting an endpoint and cleaning up the cached `sandbox.Info`. +8. `endpoint.Delete()` is used to delete an endpoint from a network. This results in deleting an endpoint and cleaning up the cached `sandbox.Info`. -8. `network.Delete()` is used to delete a network. LibNetwork will not allow the delete to proceed if there are any existing endpoints attached to the Network. +9. `network.Delete()` is used to delete a network. LibNetwork will not allow the delete to proceed if there are any existing endpoints attached to the Network. ## Implementation Details From 856ea84cde4ee0b655d719082e0016950d3f0d88 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 1 Nov 2016 14:32:19 -0700 Subject: [PATCH 129/799] Allow concurrent calls to agentClose - This fixes a panic in memberlist.Leave() because called after memberlist.shutdown = false It happens because of two interlocking calls to NetworkDB.clusterLeave() It is easily reproducible with two back-to-back calls to docker swarm init && docker swarm leave --force While the first clusterLeave() is waiting for sendNodeEvent(NodeEventTypeLeave) to timeout (5 sec) a second clusterLeave() is called. The second clusterLeave() will end up invoking memberlist.Leave() after the previous call already did the same, therefore after memberlist.shutdown was set false. - The fix is to have agentClose() acquire the agent instance and reset the agent pointer right away under lock. Then execute the closing/leave functions on the agent instance. Signed-off-by: Alessandro Boch --- agent.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/agent.go b/agent.go index 4c8980b2e1..f589d7bee2 100644 --- a/agent.go +++ b/agent.go @@ -328,22 +328,26 @@ func (c *controller) agentDriverNotify(d driverapi.Driver) { } func (c *controller) agentClose() { - if c.agent == nil { + // Acquire current agent instance and reset its pointer + // then run closing functions + c.Lock() + agent := c.agent + c.agent = nil + c.Unlock() + + if agent == nil { return } - for _, cancelFuncs := range c.agent.driverCancelFuncs { + for _, cancelFuncs := range agent.driverCancelFuncs { for _, cancel := range cancelFuncs { cancel() } } - c.agent.epTblCancel() - c.agent.networkDB.Close() + agent.epTblCancel() - c.Lock() - c.agent = nil - c.Unlock() + agent.networkDB.Close() } func (n *network) isClusterEligible() bool { From c32fc3bd7ede9a62740df52215c2dd51db0ddea2 Mon Sep 17 00:00:00 2001 From: msabansal Date: Tue, 1 Nov 2016 14:51:41 -0700 Subject: [PATCH 130/799] Fixing incorrect resovler error message shown on daemon startup Signed-off-by: msabansal --- network_windows.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/network_windows.go b/network_windows.go index f529d5b799..4bf95c75d3 100644 --- a/network_windows.go +++ b/network_windows.go @@ -30,6 +30,10 @@ func (n *network) startResolver() { options := n.Info().DriverOptions() hnsid := options[windows.HNSID] + if hnsid == "" { + return + } + hnsresponse, err := hcsshim.HNSNetworkRequest("GET", hnsid, "") if err != nil { log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) From fb3c38d655bc93e5c02869473d97a5696e6e48cc Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 25 Oct 2016 14:52:36 -0700 Subject: [PATCH 131/799] Add NetworkDB API to fetch the per network peer (gossip cluster) list Signed-off-by: Santhosh Manohar --- network.go | 24 ++++++++++++++++++++++++ networkdb/networkdb.go | 20 ++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/network.go b/network.go index 8a068d22e9..9c23ad9011 100644 --- a/network.go +++ b/network.go @@ -17,6 +17,7 @@ import ( "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/networkdb" "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/types" ) @@ -67,6 +68,11 @@ type NetworkInfo interface { Labels() map[string]string Dynamic() bool Created() time.Time + // Peers returns a slice of PeerInfo structures which has the information about the peer + // nodes participating in the same overlay network. This is currently the per-network + // gossip cluster. For non-dynamic overlay networks and bridge networks it returns an + // empty slice + Peers() []networkdb.PeerInfo } // EndpointWalker is a client provided function which will be used to walk the Endpoints. @@ -1459,6 +1465,24 @@ func (n *network) Info() NetworkInfo { return n } +func (n *network) Peers() []networkdb.PeerInfo { + if !n.Dynamic() { + return []networkdb.PeerInfo{} + } + + var nDB *networkdb.NetworkDB + n.ctrlr.Lock() + if n.ctrlr.agentInitDone == nil && n.ctrlr.agent != nil { + nDB = n.ctrlr.agent.networkDB + } + n.ctrlr.Unlock() + + if nDB != nil { + return n.ctrlr.agent.networkDB.Peers(n.id) + } + return []networkdb.PeerInfo{} +} + func (n *network) DriverOptions() map[string]string { n.Lock() defer n.Unlock() diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index a79b4231d2..04ac498b5a 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -91,6 +91,12 @@ type NetworkDB struct { keyring *memberlist.Keyring } +// PeerInfo represents the peer (gossip cluster) nodes of a network +type PeerInfo struct { + Name string + IP string +} + type node struct { memberlist.Node ltime serf.LamportTime @@ -200,6 +206,20 @@ func (nDB *NetworkDB) Close() { } } +// Peers returns the gossip peers for a given network. +func (nDB *NetworkDB) Peers(nid string) []PeerInfo { + nDB.RLock() + defer nDB.RUnlock() + peers := make([]PeerInfo, 0, len(nDB.networkNodes[nid])) + for _, nodeName := range nDB.networkNodes[nid] { + peers = append(peers, PeerInfo{ + Name: nDB.nodes[nodeName].Name, + IP: nDB.nodes[nodeName].Addr.String(), + }) + } + return peers +} + // GetEntry retrieves the value of a table entry in a given (network, // table, key) tuple func (nDB *NetworkDB) GetEntry(tname, nid, key string) ([]byte, error) { From 4be6b82bcafc4423638b72e34a30d5bdcf4d2442 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 13 Oct 2016 08:22:58 -0700 Subject: [PATCH 132/799] Vendoring hcsshim to pick overlay changes Signed-off-by: Madhu Venugopal --- Godeps/Godeps.json | 4 ++-- .../src/github.com/Microsoft/hcsshim/hnsfuncs.go | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index c3fe20f234..bcd738d090 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -26,8 +26,8 @@ }, { "ImportPath": "github.com/Microsoft/hcsshim", - "Comment": "v0.4.3", - "Rev": "6611816fb4c1693b429ada0f358102119a0b1466" + "Comment": "v0.5.1", + "Rev": "523023ef1ef8ec08b23bbff88ab68552c5f1a6d7" }, { "ImportPath": "github.com/Sirupsen/logrus", diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go index 7bf46a6881..57ad519891 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go @@ -30,6 +30,11 @@ type VsidPolicy struct { VSID uint } +type PaPolicy struct { + Type string + PA string +} + // Subnet is assoicated with a network and represents a list // of subnets available to the network type Subnet struct { @@ -58,6 +63,7 @@ type HNSNetwork struct { DNSSuffix string `json:",omitempty"` DNSServerList string `json:",omitempty"` DNSServerCompartment uint32 `json:",omitempty"` + ManagementIP string `json:",omitempty"` } // HNSEndpoint represents a network endpoint in HNS @@ -74,6 +80,7 @@ type HNSEndpoint struct { GatewayAddress string `json:",omitempty"` EnableInternalDNS bool `json:",omitempty"` PrefixLength uint8 `json:",omitempty"` + IsRemoteEndpoint bool `json:",omitempty"` } type hnsNetworkResponse struct { From 0bf056d59f2b54cd2ffb2da8f5af1acffd6354fc Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Wed, 12 Oct 2016 16:55:20 -0700 Subject: [PATCH 133/799] Windows overlay driver support 1. Base work was done by msabansal and nwoodmsft from : https://github.com/msabansal/docker/tree/overlay 2. reorganized under drivers/windows/overlay and rebased to libnetwork master 3. Porting overlay common fixes to windows driver * 4658085 * bb736c4 * f6d8968 4. Windows Service Discovery changes for swarm-mode 5. renaming default windows ipam drivers as "windows" Signed-off-by: Madhu Venugopal Signed-off-by: msabansal Signed-off-by: nwoodmsft --- controller.go | 3 +- drivers/windows/overlay/joinleave_windows.go | 114 ++++ .../windows/overlay/ov_endpoint_windows.go | 346 ++++++++++++ .../overlay/ov_network_local_windows.go | 209 +++++++ drivers/windows/overlay/ov_network_windows.go | 512 ++++++++++++++++++ drivers/windows/overlay/ov_serf_windows.go | 179 ++++++ drivers/windows/overlay/overlay.pb.go | 468 ++++++++++++++++ drivers/windows/overlay/overlay.proto | 27 + drivers/windows/overlay/overlay_windows.go | 297 ++++++++++ drivers/windows/overlay/peerdb_windows.go | 154 ++++++ drivers/windows/windows.go | 5 +- drivers_windows.go | 2 + ipams/builtin/builtin_windows.go | 43 +- ipams/windowsipam/windowsipam.go | 3 + netutils/utils_windows.go | 4 +- network.go | 3 + network_unix.go | 6 + network_windows.go | 30 +- service_common.go | 225 ++++++++ service_linux.go | 216 -------- service_unsupported.go | 2 +- service_windows.go | 15 + 22 files changed, 2634 insertions(+), 229 deletions(-) create mode 100644 drivers/windows/overlay/joinleave_windows.go create mode 100644 drivers/windows/overlay/ov_endpoint_windows.go create mode 100644 drivers/windows/overlay/ov_network_local_windows.go create mode 100644 drivers/windows/overlay/ov_network_windows.go create mode 100644 drivers/windows/overlay/ov_serf_windows.go create mode 100644 drivers/windows/overlay/overlay.pb.go create mode 100644 drivers/windows/overlay/overlay.proto create mode 100644 drivers/windows/overlay/overlay_windows.go create mode 100644 drivers/windows/overlay/peerdb_windows.go create mode 100644 service_common.go create mode 100644 service_windows.go diff --git a/controller.go b/controller.go index aee0827f1d..e2289c050e 100644 --- a/controller.go +++ b/controller.go @@ -634,12 +634,13 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... id = stringid.GenerateRandomID() } + defaultIpam := defaultIpamForNetworkType(networkType) // Construct the network object network := &network{ name: name, networkType: networkType, generic: map[string]interface{}{netlabel.GenericData: make(map[string]string)}, - ipamType: ipamapi.DefaultIPAM, + ipamType: defaultIpam, id: id, created: time.Now(), ctrlr: c, diff --git a/drivers/windows/overlay/joinleave_windows.go b/drivers/windows/overlay/joinleave_windows.go new file mode 100644 index 0000000000..0bef47c7db --- /dev/null +++ b/drivers/windows/overlay/joinleave_windows.go @@ -0,0 +1,114 @@ +package overlay + +import ( + "fmt" + "net" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/types" + "github.com/gogo/protobuf/proto" +) + +// Join method is invoked when a Sandbox is attached to an endpoint. +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { + if err := validateID(nid, eid); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("could not find network with id %s", nid) + } + + ep := n.endpoint(eid) + if ep == nil { + return fmt.Errorf("could not find endpoint with id %s", eid) + } + + if err := d.writeEndpointToStore(ep); err != nil { + return fmt.Errorf("failed to update overlay endpoint %s to local data store: %v", ep.id[0:7], err) + } + + buf, err := proto.Marshal(&PeerRecord{ + EndpointIP: ep.addr.String(), + EndpointMAC: ep.mac.String(), + TunnelEndpointIP: n.providerAddress, + }) + + if err != nil { + return err + } + + if err := jinfo.AddTableEntry(ovPeerTable, eid, buf); err != nil { + logrus.Errorf("overlay: Failed adding table entry to joininfo: %v", err) + } + + jinfo.DisableGatewayService() + + d.pushLocalEndpointEvent("join", nid, eid) + + return nil +} + +func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { + if tableName != ovPeerTable { + logrus.Errorf("Unexpected table notification for table %s received", tableName) + return + } + + eid := key + + var peer PeerRecord + if err := proto.Unmarshal(value, &peer); err != nil { + logrus.Errorf("Failed to unmarshal peer record: %v", err) + return + } + + n := d.network(nid) + if n == nil { + return + } + + // Ignore local peers. We already know about them and they + // should not be added to vxlan fdb. + if peer.TunnelEndpointIP == n.providerAddress { + return + } + + addr, err := types.ParseCIDR(peer.EndpointIP) + if err != nil { + logrus.Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP) + return + } + + mac, err := net.ParseMAC(peer.EndpointMAC) + if err != nil { + logrus.Errorf("Invalid mac %s received in event notify", peer.EndpointMAC) + return + } + + vtep := net.ParseIP(peer.TunnelEndpointIP) + if vtep == nil { + logrus.Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP) + return + } + + if etype == driverapi.Delete { + d.peerDelete(nid, eid, addr.IP, addr.Mask, mac, vtep, true) + return + } + + d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, true) +} + +// Leave method is invoked when a Sandbox detaches from an endpoint. +func (d *driver) Leave(nid, eid string) error { + if err := validateID(nid, eid); err != nil { + return err + } + + d.pushLocalEndpointEvent("leave", nid, eid) + + return nil +} diff --git a/drivers/windows/overlay/ov_endpoint_windows.go b/drivers/windows/overlay/ov_endpoint_windows.go new file mode 100644 index 0000000000..2e4e933324 --- /dev/null +++ b/drivers/windows/overlay/ov_endpoint_windows.go @@ -0,0 +1,346 @@ +package overlay + +import ( + "encoding/json" + "fmt" + "net" + + "github.com/Microsoft/hcsshim" + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/types" +) + +type endpointTable map[string]*endpoint + +const overlayEndpointPrefix = "overlay/endpoint" + +type endpoint struct { + id string + nid string + profileId string + remote bool + mac net.HardwareAddr + addr *net.IPNet + dbExists bool + dbIndex uint64 +} + +func validateID(nid, eid string) error { + if nid == "" { + return fmt.Errorf("invalid network id") + } + + if eid == "" { + return fmt.Errorf("invalid endpoint id") + } + + return nil +} + +func (n *network) endpoint(eid string) *endpoint { + n.Lock() + defer n.Unlock() + + return n.endpoints[eid] +} + +func (n *network) addEndpoint(ep *endpoint) { + n.Lock() + n.endpoints[ep.id] = ep + n.Unlock() +} + +func (n *network) deleteEndpoint(eid string) { + n.Lock() + delete(n.endpoints, eid) + n.Unlock() +} + +func (n *network) removeEndpointWithAddress(addr *net.IPNet) { + var networkEndpoint *endpoint + n.Lock() + for _, ep := range n.endpoints { + if ep.addr.IP.Equal(addr.IP) { + networkEndpoint = ep + break + } + } + if networkEndpoint != nil { + delete(n.endpoints, networkEndpoint.id) + } + n.Unlock() + + if networkEndpoint != nil { + logrus.Debugf("Removing stale endpoint from HNS") + _, err := hcsshim.HNSEndpointRequest("DELETE", networkEndpoint.profileId, "") + + if err != nil { + logrus.Debugf("Failed to delete stale overlay endpoint (%s) from hns", networkEndpoint.id[0:7]) + } + + if err := n.driver.deleteEndpointFromStore(networkEndpoint); err != nil { + logrus.Debugf("Failed to delete stale overlay endpoint (%s) from store", networkEndpoint.id[0:7]) + } + } +} + +func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, + epOptions map[string]interface{}) error { + var err error + if err = validateID(nid, eid); err != nil { + return err + } + + // Since we perform lazy configuration make sure we try + // configuring the driver when we enter CreateEndpoint since + // CreateNetwork may not be called in every node. + if err := d.configure(); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("network id %q not found", nid) + } + + ep := &endpoint{ + id: eid, + nid: n.id, + addr: ifInfo.Address(), + mac: ifInfo.MacAddress(), + } + + if ep.addr == nil { + return fmt.Errorf("create endpoint was not passed interface IP address") + } + + if s := n.getSubnetforIP(ep.addr); s == nil { + return fmt.Errorf("no matching subnet for IP %q in network %q\n", ep.addr, nid) + } + + // Todo: Add port bindings and qos policies here + + hnsEndpoint := &hcsshim.HNSEndpoint{ + VirtualNetwork: n.hnsId, + IPAddress: ep.addr.IP, + EnableInternalDNS: true, + } + + if ep.mac != nil { + hnsEndpoint.MacAddress = ep.mac.String() + } + + paPolicy, err := json.Marshal(hcsshim.PaPolicy{ + Type: "PA", + PA: n.providerAddress, + }) + + if err != nil { + return err + } + + hnsEndpoint.Policies = append(hnsEndpoint.Policies, paPolicy) + + configurationb, err := json.Marshal(hnsEndpoint) + if err != nil { + return err + } + + hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb)) + if err != nil { + return err + } + + ep.profileId = hnsresponse.Id + + if ep.mac == nil { + ep.mac, err = net.ParseMAC(hnsresponse.MacAddress) + if err != nil { + return err + } + + if err := ifInfo.SetMacAddress(ep.mac); err != nil { + return err + } + } + + n.addEndpoint(ep) + if err := d.writeEndpointToStore(ep); err != nil { + return fmt.Errorf("failed to update overlay endpoint %s to local store: %v", ep.id[0:7], err) + } + + return nil +} + +func (d *driver) DeleteEndpoint(nid, eid string) error { + if err := validateID(nid, eid); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("network id %q not found", nid) + } + + ep := n.endpoint(eid) + if ep == nil { + return fmt.Errorf("endpoint id %q not found", eid) + } + + n.deleteEndpoint(eid) + + if err := d.deleteEndpointFromStore(ep); err != nil { + logrus.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err) + } + + _, err := hcsshim.HNSEndpointRequest("DELETE", ep.profileId, "") + if err != nil { + return err + } + + return nil +} + +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { + if err := validateID(nid, eid); err != nil { + return nil, err + } + + n := d.network(nid) + if n == nil { + return nil, fmt.Errorf("network id %q not found", nid) + } + + ep := n.endpoint(eid) + if ep == nil { + return nil, fmt.Errorf("endpoint id %q not found", eid) + } + + data := make(map[string]interface{}, 1) + data["hnsid"] = ep.profileId + data["AllowUnqualifiedDNSQuery"] = true + return data, nil +} + +func (d *driver) deleteEndpointFromStore(e *endpoint) error { + if d.localStore == nil { + return fmt.Errorf("overlay local store not initialized, ep not deleted") + } + + if err := d.localStore.DeleteObjectAtomic(e); err != nil { + return err + } + + return nil +} + +func (d *driver) writeEndpointToStore(e *endpoint) error { + if d.localStore == nil { + return fmt.Errorf("overlay local store not initialized, ep not added") + } + + if err := d.localStore.PutObjectAtomic(e); err != nil { + return err + } + return nil +} + +func (ep *endpoint) DataScope() string { + return datastore.LocalScope +} + +func (ep *endpoint) New() datastore.KVObject { + return &endpoint{} +} + +func (ep *endpoint) CopyTo(o datastore.KVObject) error { + dstep := o.(*endpoint) + *dstep = *ep + return nil +} + +func (ep *endpoint) Key() []string { + return []string{overlayEndpointPrefix, ep.id} +} + +func (ep *endpoint) KeyPrefix() []string { + return []string{overlayEndpointPrefix} +} + +func (ep *endpoint) Index() uint64 { + return ep.dbIndex +} + +func (ep *endpoint) SetIndex(index uint64) { + ep.dbIndex = index + ep.dbExists = true +} + +func (ep *endpoint) Exists() bool { + return ep.dbExists +} + +func (ep *endpoint) Skip() bool { + return false +} + +func (ep *endpoint) Value() []byte { + b, err := json.Marshal(ep) + if err != nil { + return nil + } + return b +} + +func (ep *endpoint) SetValue(value []byte) error { + return json.Unmarshal(value, ep) +} + +func (ep *endpoint) MarshalJSON() ([]byte, error) { + epMap := make(map[string]interface{}) + + epMap["id"] = ep.id + epMap["nid"] = ep.nid + epMap["remote"] = ep.remote + if ep.profileId != "" { + epMap["profileId"] = ep.profileId + } + + if ep.addr != nil { + epMap["addr"] = ep.addr.String() + } + if len(ep.mac) != 0 { + epMap["mac"] = ep.mac.String() + } + + return json.Marshal(epMap) +} + +func (ep *endpoint) UnmarshalJSON(value []byte) error { + var ( + err error + epMap map[string]interface{} + ) + + json.Unmarshal(value, &epMap) + + ep.id = epMap["id"].(string) + ep.nid = epMap["nid"].(string) + ep.remote = epMap["remote"].(bool) + if v, ok := epMap["profileId"]; ok { + ep.profileId = v.(string) + } + if v, ok := epMap["mac"]; ok { + if ep.mac, err = net.ParseMAC(v.(string)); err != nil { + return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string)) + } + } + if v, ok := epMap["addr"]; ok { + if ep.addr, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err) + } + } + return nil +} diff --git a/drivers/windows/overlay/ov_network_local_windows.go b/drivers/windows/overlay/ov_network_local_windows.go new file mode 100644 index 0000000000..1f27c549e4 --- /dev/null +++ b/drivers/windows/overlay/ov_network_local_windows.go @@ -0,0 +1,209 @@ +package overlay + +import ( + "encoding/json" + "fmt" + "sync" + + "github.com/Microsoft/hcsshim" + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" +) + +const overlayNetworkPrefix = "overlay/network" + +type localNetwork struct { + id string + hnsID string + providerAddress string + dbIndex uint64 + dbExists bool + sync.Mutex +} + +func (d *driver) findHnsNetwork(n *network) error { + ln, err := d.getLocalNetworkFromStore(n.id) + + if err != nil { + return err + } + + if ln == nil { + subnets := []hcsshim.Subnet{} + + for _, s := range n.subnets { + subnet := hcsshim.Subnet{ + AddressPrefix: s.subnetIP.String(), + } + + if s.gwIP != nil { + subnet.GatewayAddress = s.gwIP.IP.String() + } + + vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{ + Type: "VSID", + VSID: uint(s.vni), + }) + + if err != nil { + return err + } + + subnet.Policies = append(subnet.Policies, vsidPolicy) + subnets = append(subnets, subnet) + } + + network := &hcsshim.HNSNetwork{ + Name: n.name, + Type: d.Type(), + Subnets: subnets, + NetworkAdapterName: n.interfaceName, + } + + configurationb, err := json.Marshal(network) + if err != nil { + return err + } + + configuration := string(configurationb) + logrus.Infof("HNSNetwork Request =%v", configuration) + + hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration) + if err != nil { + return err + } + + n.hnsId = hnsresponse.Id + n.providerAddress = hnsresponse.ManagementIP + + // Save local host specific info + if err := d.writeLocalNetworkToStore(n); err != nil { + return fmt.Errorf("failed to update data store for network %v: %v", n.id, err) + } + } else { + n.hnsId = ln.hnsID + n.providerAddress = ln.providerAddress + } + + return nil +} + +func (d *driver) getLocalNetworkFromStore(nid string) (*localNetwork, error) { + + if d.localStore == nil { + return nil, fmt.Errorf("overlay local store not initialized, network not found") + } + + n := &localNetwork{id: nid} + if err := d.localStore.GetObject(datastore.Key(n.Key()...), n); err != nil { + return nil, nil + } + + return n, nil +} + +func (d *driver) deleteLocalNetworkFromStore(n *network) error { + if d.localStore == nil { + return fmt.Errorf("overlay local store not initialized, network not deleted") + } + + ln, err := d.getLocalNetworkFromStore(n.id) + + if err != nil { + return err + } + + if err = d.localStore.DeleteObjectAtomic(ln); err != nil { + return err + } + + return nil +} + +func (d *driver) writeLocalNetworkToStore(n *network) error { + if d.localStore == nil { + return fmt.Errorf("overlay local store not initialized, network not added") + } + + ln := &localNetwork{ + id: n.id, + hnsID: n.hnsId, + providerAddress: n.providerAddress, + } + + if err := d.localStore.PutObjectAtomic(ln); err != nil { + return err + } + return nil +} + +func (n *localNetwork) DataScope() string { + return datastore.LocalScope +} + +func (n *localNetwork) New() datastore.KVObject { + return &localNetwork{} +} + +func (n *localNetwork) CopyTo(o datastore.KVObject) error { + dstep := o.(*localNetwork) + *dstep = *n + return nil +} + +func (n *localNetwork) Key() []string { + return []string{overlayNetworkPrefix, n.id} +} + +func (n *localNetwork) KeyPrefix() []string { + return []string{overlayNetworkPrefix} +} + +func (n *localNetwork) Index() uint64 { + return n.dbIndex +} + +func (n *localNetwork) SetIndex(index uint64) { + n.dbIndex = index + n.dbExists = true +} + +func (n *localNetwork) Exists() bool { + return n.dbExists +} + +func (n *localNetwork) Skip() bool { + return false +} + +func (n *localNetwork) Value() []byte { + b, err := json.Marshal(n) + if err != nil { + return nil + } + return b +} + +func (n *localNetwork) SetValue(value []byte) error { + return json.Unmarshal(value, n) +} + +func (n *localNetwork) MarshalJSON() ([]byte, error) { + networkMap := make(map[string]interface{}) + + networkMap["id"] = n.id + networkMap["hnsID"] = n.hnsID + networkMap["providerAddress"] = n.providerAddress + return json.Marshal(networkMap) +} + +func (n *localNetwork) UnmarshalJSON(value []byte) error { + var networkMap map[string]interface{} + + json.Unmarshal(value, &networkMap) + + n.id = networkMap["id"].(string) + n.hnsID = networkMap["hnsID"].(string) + n.providerAddress = networkMap["providerAddress"].(string) + return nil +} diff --git a/drivers/windows/overlay/ov_network_windows.go b/drivers/windows/overlay/ov_network_windows.go new file mode 100644 index 0000000000..f89469f744 --- /dev/null +++ b/drivers/windows/overlay/ov_network_windows.go @@ -0,0 +1,512 @@ +package overlay + +import ( + "encoding/json" + "fmt" + "net" + "strconv" + "strings" + "sync" + + "github.com/Microsoft/hcsshim" + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/types" +) + +var ( + hostMode bool + networkMu sync.Mutex +) + +type networkTable map[string]*network + +type subnet struct { + vni uint32 + initErr error + subnetIP *net.IPNet + gwIP *net.IPNet +} + +type subnetJSON struct { + SubnetIP string + GwIP string + Vni uint32 +} + +type network struct { + id string + name string + hnsId string + dbIndex uint64 + dbExists bool + providerAddress string + interfaceName string + endpoints endpointTable + driver *driver + initEpoch int + initErr error + subnets []*subnet + secure bool + sync.Mutex +} + +func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { + return nil, types.NotImplementedErrorf("not implemented") +} + +func (d *driver) NetworkFree(id string) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { + var ( + networkName string + interfaceName string + ) + + if id == "" { + return fmt.Errorf("invalid network id") + } + + if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" { + return types.BadRequestErrorf("ipv4 pool is empty") + } + + vnis := make([]uint32, 0, len(ipV4Data)) + + // Since we perform lazy configuration make sure we try + // configuring the driver when we enter CreateNetwork + if err := d.configure(); err != nil { + return err + } + + n := &network{ + id: id, + driver: d, + endpoints: endpointTable{}, + subnets: []*subnet{}, + } + + genData, ok := option[netlabel.GenericData].(map[string]string) + + if !ok { + return fmt.Errorf("Unknown generic data option") + } + + for label, value := range genData { + switch label { + case "com.docker.network.windowsshim.networkname": + networkName = value + case "com.docker.network.windowsshim.interface": + interfaceName = value + case "com.docker.network.windowsshim.hnsid": + n.hnsId = value + case netlabel.OverlayVxlanIDList: + vniStrings := strings.Split(value, ",") + for _, vniStr := range vniStrings { + vni, err := strconv.Atoi(vniStr) + if err != nil { + return fmt.Errorf("invalid vxlan id value %q passed", vniStr) + } + + vnis = append(vnis, uint32(vni)) + } + } + } + + // If we are getting vnis from libnetwork, either we get for + // all subnets or none. + if len(vnis) != 0 && len(vnis) < len(ipV4Data) { + return fmt.Errorf("insufficient vnis(%d) passed to overlay", len(vnis)) + } + + for i, ipd := range ipV4Data { + s := &subnet{ + subnetIP: ipd.Pool, + gwIP: ipd.Gateway, + } + + if len(vnis) != 0 { + s.vni = vnis[i] + } + + n.subnets = append(n.subnets, s) + } + + n.name = networkName + if n.name == "" { + n.name = id + } + + n.interfaceName = interfaceName + + if err := n.writeToStore(); err != nil { + return fmt.Errorf("failed to update data store for network %v: %v", n.id, err) + } + + if nInfo != nil { + if err := nInfo.TableEventRegister(ovPeerTable); err != nil { + return err + } + } + + d.addNetwork(n) + + err := d.findHnsNetwork(n) + genData["com.docker.network.windowsshim.hnsid"] = n.hnsId + + return err +} + +func (d *driver) DeleteNetwork(nid string) error { + if nid == "" { + return fmt.Errorf("invalid network id") + } + + // Make sure driver resources are initialized before proceeding + if err := d.configure(); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return fmt.Errorf("could not find network with id %s", nid) + } + + _, err := hcsshim.HNSNetworkRequest("DELETE", n.hnsId, "") + if err != nil { + return err + } + + d.deleteNetwork(nid) + d.deleteLocalNetworkFromStore(n) + + return nil +} + +func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { + return nil +} + +func (d *driver) RevokeExternalConnectivity(nid, eid string) error { + return nil +} + +func (d *driver) addNetwork(n *network) { + d.Lock() + d.networks[n.id] = n + d.Unlock() +} + +func (d *driver) deleteNetwork(nid string) { + d.Lock() + delete(d.networks, nid) + d.Unlock() +} + +func (d *driver) network(nid string) *network { + d.Lock() + networks := d.networks + d.Unlock() + + n, ok := networks[nid] + if !ok { + n = d.getNetworkFromStore(nid) + if n != nil { + n.driver = d + n.endpoints = endpointTable{} + networks[nid] = n + } + } + + return n +} + +func (d *driver) getNetworkFromStore(nid string) *network { + if d.store == nil { + return nil + } + + n := &network{id: nid} + if err := d.store.GetObject(datastore.Key(n.Key()...), n); err != nil { + return nil + } + + // As the network is being discovered from the global store, HNS may not be aware of it yet + err := d.findHnsNetwork(n) + if err != nil { + logrus.Errorf("Failed to find hns network: %v", err) + return nil + } + + return n +} + +func (n *network) vxlanID(s *subnet) uint32 { + n.Lock() + defer n.Unlock() + + return s.vni +} + +func (n *network) setVxlanID(s *subnet, vni uint32) { + n.Lock() + s.vni = vni + n.Unlock() +} + +func (n *network) Key() []string { + return []string{"overlay", "network", n.id} +} + +func (n *network) KeyPrefix() []string { + return []string{"overlay", "network"} +} + +func (n *network) Value() []byte { + m := map[string]interface{}{} + + netJSON := []*subnetJSON{} + + for _, s := range n.subnets { + sj := &subnetJSON{ + SubnetIP: s.subnetIP.String(), + GwIP: s.gwIP.String(), + Vni: s.vni, + } + netJSON = append(netJSON, sj) + } + + b, err := json.Marshal(netJSON) + if err != nil { + return []byte{} + } + + m["secure"] = n.secure + m["subnets"] = netJSON + m["interfaceName"] = n.interfaceName + m["providerAddress"] = n.providerAddress + m["hnsId"] = n.hnsId + m["name"] = n.name + b, err = json.Marshal(m) + if err != nil { + return []byte{} + } + + return b +} + +func (n *network) Index() uint64 { + return n.dbIndex +} + +func (n *network) SetIndex(index uint64) { + n.dbIndex = index + n.dbExists = true +} + +func (n *network) Exists() bool { + return n.dbExists +} + +func (n *network) Skip() bool { + return false +} + +func (n *network) SetValue(value []byte) error { + var ( + m map[string]interface{} + newNet bool + isMap = true + netJSON = []*subnetJSON{} + ) + + if err := json.Unmarshal(value, &m); err != nil { + err := json.Unmarshal(value, &netJSON) + if err != nil { + return err + } + isMap = false + } + + if len(n.subnets) == 0 { + newNet = true + } + + if isMap { + if val, ok := m["secure"]; ok { + n.secure = val.(bool) + } + if val, ok := m["providerAddress"]; ok { + n.providerAddress = val.(string) + } + if val, ok := m["interfaceName"]; ok { + n.interfaceName = val.(string) + } + if val, ok := m["hnsId"]; ok { + n.hnsId = val.(string) + } + if val, ok := m["name"]; ok { + n.name = val.(string) + } + bytes, err := json.Marshal(m["subnets"]) + if err != nil { + return err + } + if err := json.Unmarshal(bytes, &netJSON); err != nil { + return err + } + } + + for _, sj := range netJSON { + subnetIPstr := sj.SubnetIP + gwIPstr := sj.GwIP + vni := sj.Vni + + subnetIP, _ := types.ParseCIDR(subnetIPstr) + gwIP, _ := types.ParseCIDR(gwIPstr) + + if newNet { + s := &subnet{ + subnetIP: subnetIP, + gwIP: gwIP, + vni: vni, + } + n.subnets = append(n.subnets, s) + } else { + sNet := n.getMatchingSubnet(subnetIP) + if sNet != nil { + sNet.vni = vni + } + } + } + return nil +} + +func (n *network) DataScope() string { + return datastore.GlobalScope +} + +func (n *network) writeToStore() error { + if n.driver.store == nil { + return nil + } + + return n.driver.store.PutObjectAtomic(n) +} + +func (n *network) releaseVxlanID() ([]uint32, error) { + if len(n.subnets) == 0 { + return nil, nil + } + + if n.driver.store != nil { + if err := n.driver.store.DeleteObjectAtomic(n); err != nil { + if err == datastore.ErrKeyModified || err == datastore.ErrKeyNotFound { + // In both the above cases we can safely assume that the key has been removed by some other + // instance and so simply get out of here + return nil, nil + } + + return nil, fmt.Errorf("failed to delete network to vxlan id map: %v", err) + } + } + var vnis []uint32 + for _, s := range n.subnets { + if n.driver.vxlanIdm != nil { + vni := n.vxlanID(s) + vnis = append(vnis, vni) + n.driver.vxlanIdm.Release(uint64(vni)) + } + + n.setVxlanID(s, 0) + } + + return vnis, nil +} + +func (n *network) obtainVxlanID(s *subnet) error { + //return if the subnet already has a vxlan id assigned + if s.vni != 0 { + return nil + } + + if n.driver.store == nil { + return fmt.Errorf("no valid vxlan id and no datastore configured, cannot obtain vxlan id") + } + + for { + if err := n.driver.store.GetObject(datastore.Key(n.Key()...), n); err != nil { + return fmt.Errorf("getting network %q from datastore failed %v", n.id, err) + } + + if s.vni == 0 { + vxlanID, err := n.driver.vxlanIdm.GetID() + if err != nil { + return fmt.Errorf("failed to allocate vxlan id: %v", err) + } + + n.setVxlanID(s, uint32(vxlanID)) + if err := n.writeToStore(); err != nil { + n.driver.vxlanIdm.Release(uint64(n.vxlanID(s))) + n.setVxlanID(s, 0) + if err == datastore.ErrKeyModified { + continue + } + return fmt.Errorf("network %q failed to update data store: %v", n.id, err) + } + return nil + } + return nil + } +} + +// contains return true if the passed ip belongs to one the network's +// subnets +func (n *network) contains(ip net.IP) bool { + for _, s := range n.subnets { + if s.subnetIP.Contains(ip) { + return true + } + } + + return false +} + +// getSubnetforIP returns the subnet to which the given IP belongs +func (n *network) getSubnetforIP(ip *net.IPNet) *subnet { + for _, s := range n.subnets { + // first check if the mask lengths are the same + i, _ := s.subnetIP.Mask.Size() + j, _ := ip.Mask.Size() + if i != j { + continue + } + if s.subnetIP.Contains(ip.IP) { + return s + } + } + return nil +} + +// getMatchingSubnet return the network's subnet that matches the input +func (n *network) getMatchingSubnet(ip *net.IPNet) *subnet { + if ip == nil { + return nil + } + for _, s := range n.subnets { + // first check if the mask lengths are the same + i, _ := s.subnetIP.Mask.Size() + j, _ := ip.Mask.Size() + if i != j { + continue + } + if s.subnetIP.IP.Equal(ip.IP) { + return s + } + } + return nil +} diff --git a/drivers/windows/overlay/ov_serf_windows.go b/drivers/windows/overlay/ov_serf_windows.go new file mode 100644 index 0000000000..78a703c3f7 --- /dev/null +++ b/drivers/windows/overlay/ov_serf_windows.go @@ -0,0 +1,179 @@ +package overlay + +import ( + "fmt" + "net" + "strings" + "time" + + "github.com/Sirupsen/logrus" + "github.com/hashicorp/serf/serf" +) + +type ovNotify struct { + action string + ep *endpoint + nw *network +} + +type logWriter struct{} + +func (l *logWriter) Write(p []byte) (int, error) { + str := string(p) + + switch { + case strings.Contains(str, "[WARN]"): + logrus.Warn(str) + case strings.Contains(str, "[DEBUG]"): + logrus.Debug(str) + case strings.Contains(str, "[INFO]"): + logrus.Info(str) + case strings.Contains(str, "[ERR]"): + logrus.Error(str) + } + + return len(p), nil +} + +func (d *driver) serfInit() error { + var err error + + config := serf.DefaultConfig() + config.Init() + config.MemberlistConfig.BindAddr = d.bindAddress + + d.eventCh = make(chan serf.Event, 4) + config.EventCh = d.eventCh + config.UserCoalescePeriod = 1 * time.Second + config.UserQuiescentPeriod = 50 * time.Millisecond + + config.LogOutput = &logWriter{} + config.MemberlistConfig.LogOutput = config.LogOutput + + s, err := serf.Create(config) + if err != nil { + return fmt.Errorf("failed to create cluster node: %v", err) + } + defer func() { + if err != nil { + s.Shutdown() + } + }() + + d.serfInstance = s + + d.notifyCh = make(chan ovNotify) + d.exitCh = make(chan chan struct{}) + + go d.startSerfLoop(d.eventCh, d.notifyCh, d.exitCh) + return nil +} + +func (d *driver) serfJoin(neighIP string) error { + if neighIP == "" { + return fmt.Errorf("no neighbor to join") + } + if _, err := d.serfInstance.Join([]string{neighIP}, false); err != nil { + return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v", + neighIP, err) + } + return nil +} + +func (d *driver) notifyEvent(event ovNotify) { + ep := event.ep + + ePayload := fmt.Sprintf("%s %s %s %s", event.action, ep.addr.IP.String(), + net.IP(ep.addr.Mask).String(), ep.mac.String()) + eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(), + event.nw.id, ep.id) + + if err := d.serfInstance.UserEvent(eName, []byte(ePayload), true); err != nil { + logrus.Errorf("Sending user event failed: %v\n", err) + } +} + +func (d *driver) processEvent(u serf.UserEvent) { + logrus.Debugf("Received user event name:%s, payload:%s\n", u.Name, + string(u.Payload)) + + var dummy, action, vtepStr, nid, eid, ipStr, maskStr, macStr string + if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil { + fmt.Printf("Failed to scan name string: %v\n", err) + } + + if _, err := fmt.Sscan(string(u.Payload), &action, + &ipStr, &maskStr, &macStr); err != nil { + fmt.Printf("Failed to scan value string: %v\n", err) + } + + logrus.Debugf("Parsed data = %s/%s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, maskStr, macStr) + + mac, err := net.ParseMAC(macStr) + if err != nil { + logrus.Errorf("Failed to parse mac: %v\n", err) + } + + if d.serfInstance.LocalMember().Addr.String() == vtepStr { + return + } + + switch action { + case "join": + if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac, + net.ParseIP(vtepStr), true); err != nil { + logrus.Errorf("Peer add failed in the driver: %v\n", err) + } + case "leave": + if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac, + net.ParseIP(vtepStr), true); err != nil { + logrus.Errorf("Peer delete failed in the driver: %v\n", err) + } + } +} + +func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify, + exitCh chan chan struct{}) { + + for { + select { + case notify, ok := <-notifyCh: + if !ok { + break + } + + d.notifyEvent(notify) + case ch, ok := <-exitCh: + if !ok { + break + } + + if err := d.serfInstance.Leave(); err != nil { + logrus.Errorf("failed leaving the cluster: %v\n", err) + } + + d.serfInstance.Shutdown() + close(ch) + return + case e, ok := <-eventCh: + if !ok { + break + } + u, ok := e.(serf.UserEvent) + if !ok { + break + } + d.processEvent(u) + } + } +} + +func (d *driver) isSerfAlive() bool { + d.Lock() + serfInstance := d.serfInstance + d.Unlock() + if serfInstance == nil || serfInstance.State() != serf.SerfAlive { + return false + } + return true +} diff --git a/drivers/windows/overlay/overlay.pb.go b/drivers/windows/overlay/overlay.pb.go new file mode 100644 index 0000000000..cfa0eeeae4 --- /dev/null +++ b/drivers/windows/overlay/overlay.pb.go @@ -0,0 +1,468 @@ +// Code generated by protoc-gen-gogo. +// source: overlay.proto +// DO NOT EDIT! + +/* + Package overlay is a generated protocol buffer package. + + It is generated from these files: + overlay.proto + + It has these top-level messages: + PeerRecord +*/ +package overlay + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" +import _ "github.com/gogo/protobuf/gogoproto" + +import strings "strings" +import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" +import sort "sort" +import strconv "strconv" +import reflect "reflect" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +const _ = proto.GoGoProtoPackageIsVersion1 + +// PeerRecord defines the information corresponding to a peer +// container in the overlay network. +type PeerRecord struct { + // Endpoint IP is the IP of the container attachment on the + // given overlay network. + EndpointIP string `protobuf:"bytes,1,opt,name=endpoint_ip,json=endpointIp,proto3" json:"endpoint_ip,omitempty"` + // Endpoint MAC is the mac address of the container attachment + // on the given overlay network. + EndpointMAC string `protobuf:"bytes,2,opt,name=endpoint_mac,json=endpointMac,proto3" json:"endpoint_mac,omitempty"` + // Tunnel Endpoint IP defines the host IP for the host in + // which this container is running and can be reached by + // building a tunnel to that host IP. + TunnelEndpointIP string `protobuf:"bytes,3,opt,name=tunnel_endpoint_ip,json=tunnelEndpointIp,proto3" json:"tunnel_endpoint_ip,omitempty"` +} + +func (m *PeerRecord) Reset() { *m = PeerRecord{} } +func (*PeerRecord) ProtoMessage() {} +func (*PeerRecord) Descriptor() ([]byte, []int) { return fileDescriptorOverlay, []int{0} } + +func init() { + proto.RegisterType((*PeerRecord)(nil), "overlay.PeerRecord") +} +func (this *PeerRecord) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 7) + s = append(s, "&overlay.PeerRecord{") + s = append(s, "EndpointIP: "+fmt.Sprintf("%#v", this.EndpointIP)+",\n") + s = append(s, "EndpointMAC: "+fmt.Sprintf("%#v", this.EndpointMAC)+",\n") + s = append(s, "TunnelEndpointIP: "+fmt.Sprintf("%#v", this.TunnelEndpointIP)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} +func valueToGoStringOverlay(v interface{}, typ string) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv) +} +func extensionToGoStringOverlay(e map[int32]github_com_gogo_protobuf_proto.Extension) string { + if e == nil { + return "nil" + } + s := "map[int32]proto.Extension{" + keys := make([]int, 0, len(e)) + for k := range e { + keys = append(keys, int(k)) + } + sort.Ints(keys) + ss := []string{} + for _, k := range keys { + ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString()) + } + s += strings.Join(ss, ",") + "}" + return s +} +func (m *PeerRecord) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *PeerRecord) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.EndpointIP) > 0 { + data[i] = 0xa + i++ + i = encodeVarintOverlay(data, i, uint64(len(m.EndpointIP))) + i += copy(data[i:], m.EndpointIP) + } + if len(m.EndpointMAC) > 0 { + data[i] = 0x12 + i++ + i = encodeVarintOverlay(data, i, uint64(len(m.EndpointMAC))) + i += copy(data[i:], m.EndpointMAC) + } + if len(m.TunnelEndpointIP) > 0 { + data[i] = 0x1a + i++ + i = encodeVarintOverlay(data, i, uint64(len(m.TunnelEndpointIP))) + i += copy(data[i:], m.TunnelEndpointIP) + } + return i, nil +} + +func encodeFixed64Overlay(data []byte, offset int, v uint64) int { + data[offset] = uint8(v) + data[offset+1] = uint8(v >> 8) + data[offset+2] = uint8(v >> 16) + data[offset+3] = uint8(v >> 24) + data[offset+4] = uint8(v >> 32) + data[offset+5] = uint8(v >> 40) + data[offset+6] = uint8(v >> 48) + data[offset+7] = uint8(v >> 56) + return offset + 8 +} +func encodeFixed32Overlay(data []byte, offset int, v uint32) int { + data[offset] = uint8(v) + data[offset+1] = uint8(v >> 8) + data[offset+2] = uint8(v >> 16) + data[offset+3] = uint8(v >> 24) + return offset + 4 +} +func encodeVarintOverlay(data []byte, offset int, v uint64) int { + for v >= 1<<7 { + data[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + data[offset] = uint8(v) + return offset + 1 +} +func (m *PeerRecord) Size() (n int) { + var l int + _ = l + l = len(m.EndpointIP) + if l > 0 { + n += 1 + l + sovOverlay(uint64(l)) + } + l = len(m.EndpointMAC) + if l > 0 { + n += 1 + l + sovOverlay(uint64(l)) + } + l = len(m.TunnelEndpointIP) + if l > 0 { + n += 1 + l + sovOverlay(uint64(l)) + } + return n +} + +func sovOverlay(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozOverlay(x uint64) (n int) { + return sovOverlay(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *PeerRecord) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PeerRecord{`, + `EndpointIP:` + fmt.Sprintf("%v", this.EndpointIP) + `,`, + `EndpointMAC:` + fmt.Sprintf("%v", this.EndpointMAC) + `,`, + `TunnelEndpointIP:` + fmt.Sprintf("%v", this.TunnelEndpointIP) + `,`, + `}`, + }, "") + return s +} +func valueToStringOverlay(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *PeerRecord) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOverlay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PeerRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PeerRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndpointIP", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOverlay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthOverlay + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndpointIP = string(data[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndpointMAC", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOverlay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthOverlay + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndpointMAC = string(data[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TunnelEndpointIP", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOverlay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthOverlay + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TunnelEndpointIP = string(data[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipOverlay(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthOverlay + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipOverlay(data []byte) (n int, err error) { + l := len(data) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOverlay + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOverlay + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if data[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOverlay + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthOverlay + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOverlay + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipOverlay(data[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthOverlay = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowOverlay = fmt.Errorf("proto: integer overflow") +) + +var fileDescriptorOverlay = []byte{ + // 195 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xcd, 0x2f, 0x4b, 0x2d, + 0xca, 0x49, 0xac, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x87, 0x72, 0xa5, 0x44, 0xd2, + 0xf3, 0xd3, 0xf3, 0xc1, 0x62, 0xfa, 0x20, 0x16, 0x44, 0x5a, 0x69, 0x2b, 0x23, 0x17, 0x57, 0x40, + 0x6a, 0x6a, 0x51, 0x50, 0x6a, 0x72, 0x7e, 0x51, 0x8a, 0x90, 0x3e, 0x17, 0x77, 0x6a, 0x5e, 0x4a, + 0x41, 0x7e, 0x66, 0x5e, 0x49, 0x7c, 0x66, 0x81, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xa7, 0x13, 0xdf, + 0xa3, 0x7b, 0xf2, 0x5c, 0xae, 0x50, 0x61, 0xcf, 0x80, 0x20, 0x2e, 0x98, 0x12, 0xcf, 0x02, 0x21, + 0x23, 0x2e, 0x1e, 0xb8, 0x86, 0xdc, 0xc4, 0x64, 0x09, 0x26, 0xb0, 0x0e, 0x7e, 0xa0, 0x0e, 0x6e, + 0x98, 0x0e, 0x5f, 0x47, 0xe7, 0x20, 0xb8, 0xa9, 0xbe, 0x89, 0xc9, 0x42, 0x4e, 0x5c, 0x42, 0x25, + 0xa5, 0x79, 0x79, 0xa9, 0x39, 0xf1, 0xc8, 0x76, 0x31, 0x83, 0x75, 0x8a, 0x00, 0x75, 0x0a, 0x84, + 0x80, 0x65, 0x91, 0x6c, 0x14, 0x28, 0x41, 0x15, 0x29, 0x70, 0x92, 0xb8, 0xf1, 0x50, 0x8e, 0xe1, + 0xc3, 0x43, 0x39, 0xc6, 0x86, 0x47, 0x72, 0x8c, 0x27, 0x80, 0xf8, 0x02, 0x10, 0x3f, 0x00, 0xe2, + 0x24, 0x36, 0xb0, 0xc7, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xd7, 0x7d, 0x7d, 0x08, + 0x01, 0x00, 0x00, +} diff --git a/drivers/windows/overlay/overlay.proto b/drivers/windows/overlay/overlay.proto new file mode 100644 index 0000000000..45b8c9de7e --- /dev/null +++ b/drivers/windows/overlay/overlay.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +import "gogoproto/gogo.proto"; + +package overlay; + +option (gogoproto.marshaler_all) = true; +option (gogoproto.unmarshaler_all) = true; +option (gogoproto.stringer_all) = true; +option (gogoproto.gostring_all) = true; +option (gogoproto.sizer_all) = true; +option (gogoproto.goproto_stringer_all) = false; + +// PeerRecord defines the information corresponding to a peer +// container in the overlay network. +message PeerRecord { + // Endpoint IP is the IP of the container attachment on the + // given overlay network. + string endpoint_ip = 1 [(gogoproto.customname) = "EndpointIP"]; + // Endpoint MAC is the mac address of the container attachment + // on the given overlay network. + string endpoint_mac = 2 [(gogoproto.customname) = "EndpointMAC"]; + // Tunnel Endpoint IP defines the host IP for the host in + // which this container is running and can be reached by + // building a tunnel to that host IP. + string tunnel_endpoint_ip = 3 [(gogoproto.customname) = "TunnelEndpointIP"]; +} \ No newline at end of file diff --git a/drivers/windows/overlay/overlay_windows.go b/drivers/windows/overlay/overlay_windows.go new file mode 100644 index 0000000000..7ebc16eebd --- /dev/null +++ b/drivers/windows/overlay/overlay_windows.go @@ -0,0 +1,297 @@ +package overlay + +//go:generate protoc -I.:../../Godeps/_workspace/src/github.com/gogo/protobuf --gogo_out=import_path=github.com/docker/libnetwork/drivers/overlay,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto:. overlay.proto + +import ( + "fmt" + "net" + "sync" + + "github.com/Microsoft/hcsshim" + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/idm" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/types" + "github.com/hashicorp/serf/serf" +) + +const ( + networkType = "overlay" + vethPrefix = "veth" + vethLen = 7 + vxlanIDStart = 4096 + vxlanIDEnd = (1 << 24) - 1 + vxlanPort = 4789 + vxlanEncap = 50 + secureOption = "encrypted" +) + +var initVxlanIdm = make(chan (bool), 1) + +type driver struct { + eventCh chan serf.Event + notifyCh chan ovNotify + exitCh chan chan struct{} + bindAddress string + advertiseAddress string + neighIP string + config map[string]interface{} + serfInstance *serf.Serf + networks networkTable + store datastore.DataStore + localStore datastore.DataStore + vxlanIdm *idm.Idm + once sync.Once + joinOnce sync.Once + sync.Mutex +} + +// Init registers a new instance of overlay driver +func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { + c := driverapi.Capability{ + DataScope: datastore.GlobalScope, + } + + d := &driver{ + networks: networkTable{}, + config: config, + } + + if data, ok := config[netlabel.GlobalKVClient]; ok { + var err error + dsc, ok := data.(discoverapi.DatastoreConfigData) + if !ok { + return types.InternalErrorf("incorrect data in datastore configuration: %v", data) + } + d.store, err = datastore.NewDataStoreFromConfig(dsc) + if err != nil { + return types.InternalErrorf("failed to initialize data store: %v", err) + } + } + + if data, ok := config[netlabel.LocalKVClient]; ok { + var err error + dsc, ok := data.(discoverapi.DatastoreConfigData) + if !ok { + return types.InternalErrorf("incorrect data in datastore configuration: %v", data) + } + d.localStore, err = datastore.NewDataStoreFromConfig(dsc) + if err != nil { + return types.InternalErrorf("failed to initialize local data store: %v", err) + } + } + + d.restoreEndpoints() + + return dc.RegisterDriver(networkType, d, c) +} + +// Endpoints are stored in the local store. Restore them and reconstruct the overlay sandbox +func (d *driver) restoreEndpoints() error { + if d.localStore == nil { + logrus.Warnf("Cannot restore overlay endpoints because local datastore is missing") + return nil + } + kvol, err := d.localStore.List(datastore.Key(overlayEndpointPrefix), &endpoint{}) + if err != nil && err != datastore.ErrKeyNotFound { + return fmt.Errorf("failed to read overlay endpoint from store: %v", err) + } + + if err == datastore.ErrKeyNotFound { + return nil + } + + for _, kvo := range kvol { + ep := kvo.(*endpoint) + + n := d.network(ep.nid) + if n == nil || ep.remote { + if !ep.remote { + logrus.Debugf("Network (%s) not found for restored endpoint (%s)", ep.nid[0:7], ep.id[0:7]) + logrus.Debugf("Deleting stale overlay endpoint (%s) from store", ep.id[0:7]) + } + + hcsshim.HNSEndpointRequest("DELETE", ep.profileId, "") + + if err := d.deleteEndpointFromStore(ep); err != nil { + logrus.Debugf("Failed to delete stale overlay endpoint (%s) from store", ep.id[0:7]) + } + + continue + } + + n.addEndpoint(ep) + } + + return nil +} + +// Fini cleans up the driver resources +func Fini(drv driverapi.Driver) { + d := drv.(*driver) + + if d.exitCh != nil { + waitCh := make(chan struct{}) + + d.exitCh <- waitCh + + <-waitCh + } +} + +func (d *driver) configure() error { + if d.store == nil { + return nil + } + + if d.vxlanIdm == nil { + return d.initializeVxlanIdm() + } + + return nil +} + +func (d *driver) initializeVxlanIdm() error { + var err error + + initVxlanIdm <- true + defer func() { <-initVxlanIdm }() + + if d.vxlanIdm != nil { + return nil + } + + d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd) + if err != nil { + return fmt.Errorf("failed to initialize vxlan id manager: %v", err) + } + + return nil +} + +func (d *driver) Type() string { + return networkType +} + +func validateSelf(node string) error { + advIP := net.ParseIP(node) + if advIP == nil { + return fmt.Errorf("invalid self address (%s)", node) + } + + addrs, err := net.InterfaceAddrs() + if err != nil { + return fmt.Errorf("Unable to get interface addresses %v", err) + } + for _, addr := range addrs { + ip, _, err := net.ParseCIDR(addr.String()) + if err == nil && ip.Equal(advIP) { + return nil + } + } + return fmt.Errorf("Multi-Host overlay networking requires cluster-advertise(%s) to be configured with a local ip-address that is reachable within the cluster", advIP.String()) +} + +func (d *driver) nodeJoin(advertiseAddress, bindAddress string, self bool) { + if self && !d.isSerfAlive() { + if err := validateSelf(advertiseAddress); err != nil { + logrus.Errorf("%s", err.Error()) + } + + d.Lock() + d.advertiseAddress = advertiseAddress + d.bindAddress = bindAddress + d.Unlock() + + // If there is no cluster store there is no need to start serf. + if d.store != nil { + err := d.serfInit() + if err != nil { + logrus.Errorf("initializing serf instance failed: %v", err) + return + } + } + } + + d.Lock() + if !self { + d.neighIP = advertiseAddress + } + neighIP := d.neighIP + d.Unlock() + + if d.serfInstance != nil && neighIP != "" { + var err error + d.joinOnce.Do(func() { + err = d.serfJoin(neighIP) + if err == nil { + d.pushLocalDb() + } + }) + if err != nil { + logrus.Errorf("joining serf neighbor %s failed: %v", advertiseAddress, err) + d.Lock() + d.joinOnce = sync.Once{} + d.Unlock() + return + } + } +} + +func (d *driver) pushLocalEndpointEvent(action, nid, eid string) { + n := d.network(nid) + if n == nil { + logrus.Debugf("Error pushing local endpoint event for network %s", nid) + return + } + ep := n.endpoint(eid) + if ep == nil { + logrus.Debugf("Error pushing local endpoint event for ep %s / %s", nid, eid) + return + } + + if !d.isSerfAlive() { + return + } + d.notifyCh <- ovNotify{ + action: action, + nw: n, + ep: ep, + } +} + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { + + var err error + switch dType { + case discoverapi.NodeDiscovery: + nodeData, ok := data.(discoverapi.NodeDiscoveryData) + if !ok || nodeData.Address == "" { + return fmt.Errorf("invalid discovery data") + } + d.nodeJoin(nodeData.Address, nodeData.BindAddress, nodeData.Self) + case discoverapi.DatastoreConfig: + if d.store != nil { + return types.ForbiddenErrorf("cannot accept datastore configuration: Overlay driver has a datastore configured already") + } + dsc, ok := data.(discoverapi.DatastoreConfigData) + if !ok { + return types.InternalErrorf("incorrect data in datastore configuration: %v", data) + } + d.store, err = datastore.NewDataStoreFromConfig(dsc) + if err != nil { + return types.InternalErrorf("failed to initialize data store: %v", err) + } + default: + } + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { + return nil +} diff --git a/drivers/windows/overlay/peerdb_windows.go b/drivers/windows/overlay/peerdb_windows.go new file mode 100644 index 0000000000..4937539d45 --- /dev/null +++ b/drivers/windows/overlay/peerdb_windows.go @@ -0,0 +1,154 @@ +package overlay + +import ( + "fmt" + "net" + + "encoding/json" + + log "github.com/Sirupsen/logrus" + + "github.com/Microsoft/hcsshim" + "github.com/docker/libnetwork/types" +) + +const ovPeerTable = "overlay_peer_table" + +func (d *driver) pushLocalDb() { + if !d.isSerfAlive() { + return + } + + d.Lock() + networks := d.networks + d.Unlock() + + for _, n := range networks { + n.Lock() + endpoints := n.endpoints + n.Unlock() + + for _, ep := range endpoints { + if !ep.remote { + d.notifyCh <- ovNotify{ + action: "join", + nw: n, + ep: ep, + } + + } + } + } +} + +func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, + peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { + + log.Debugf("WINOVERLAY: Enter peerAdd for ca ip %s with ca mac %s", peerIP.String(), peerMac.String()) + + if err := validateID(nid, eid); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return nil + } + + if updateDb { + log.Info("WINOVERLAY: peerAdd: notifying HNS of the REMOTE endpoint") + + hnsEndpoint := &hcsshim.HNSEndpoint{ + VirtualNetwork: n.hnsId, + MacAddress: peerMac.String(), + IPAddress: peerIP, + IsRemoteEndpoint: true, + } + + paPolicy, err := json.Marshal(hcsshim.PaPolicy{ + Type: "PA", + PA: vtep.String(), + }) + + if err != nil { + return err + } + + hnsEndpoint.Policies = append(hnsEndpoint.Policies, paPolicy) + + configurationb, err := json.Marshal(hnsEndpoint) + if err != nil { + return err + } + + // Temp: We have to create a endpoint object to keep track of the HNS ID for + // this endpoint so that we can retrieve it later when the endpoint is deleted. + // This seems unnecessary when we already have dockers EID. See if we can pass + // the global EID to HNS to use as it's ID, rather than having each HNS assign + // it's own local ID for the endpoint + + addr, err := types.ParseCIDR(peerIP.String() + "/32") + if err != nil { + return err + } + + n.removeEndpointWithAddress(addr) + + hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb)) + if err != nil { + return err + } + + ep := &endpoint{ + id: eid, + nid: nid, + addr: addr, + mac: peerMac, + profileId: hnsresponse.Id, + remote: true, + } + + n.addEndpoint(ep) + + if err := d.writeEndpointToStore(ep); err != nil { + return fmt.Errorf("failed to update overlay endpoint %s to local store: %v", ep.id[0:7], err) + } + } + + return nil +} + +func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, + peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { + + log.Infof("WINOVERLAY: Enter peerDelete for endpoint %s and peer ip %s", eid, peerIP.String()) + + if err := validateID(nid, eid); err != nil { + return err + } + + n := d.network(nid) + if n == nil { + return nil + } + + ep := n.endpoint(eid) + if ep == nil { + return fmt.Errorf("could not find endpoint with id %s", eid) + } + + if updateDb { + _, err := hcsshim.HNSEndpointRequest("DELETE", ep.profileId, "") + if err != nil { + return err + } + + n.deleteEndpoint(eid) + + if err := d.deleteEndpointFromStore(ep); err != nil { + log.Debugf("Failed to delete stale overlay endpoint (%s) from store", ep.id[0:7]) + } + } + + return nil +} diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index ed6f7c2f26..0165814118 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -75,7 +75,8 @@ type driver struct { sync.Mutex } -func isValidNetworkType(networkType string) bool { +// IsBuiltinWindowsDriver vaidates if network-type is a builtin local-scoped driver +func IsBuiltinLocalDriver(networkType string) bool { if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "ics" == networkType || "transparent" == networkType { return true } @@ -91,7 +92,7 @@ func newDriver(networkType string) *driver { // GetInit returns an initializer for the given network type func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error { return func(dc driverapi.DriverCallback, config map[string]interface{}) error { - if !isValidNetworkType(networkType) { + if !IsBuiltinLocalDriver(networkType) { return types.BadRequestErrorf("Network type not supported: %s", networkType) } diff --git a/drivers_windows.go b/drivers_windows.go index 1e44b626d4..b5058d6cfc 100644 --- a/drivers_windows.go +++ b/drivers_windows.go @@ -3,11 +3,13 @@ package libnetwork import ( "github.com/docker/libnetwork/drivers/null" "github.com/docker/libnetwork/drivers/windows" + "github.com/docker/libnetwork/drivers/windows/overlay" ) func getInitializers() []initializer { return []initializer{ {null.Init, "null"}, + {overlay.Init, "overlay"}, {windows.GetInit("transparent"), "transparent"}, {windows.GetInit("l2bridge"), "l2bridge"}, {windows.GetInit("l2tunnel"), "l2tunnel"}, diff --git a/ipams/builtin/builtin_windows.go b/ipams/builtin/builtin_windows.go index d24f5e63dc..155c046875 100644 --- a/ipams/builtin/builtin_windows.go +++ b/ipams/builtin/builtin_windows.go @@ -3,14 +3,55 @@ package builtin import ( + "fmt" + + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/ipam" "github.com/docker/libnetwork/ipamapi" + "github.com/docker/libnetwork/ipamutils" windowsipam "github.com/docker/libnetwork/ipams/windowsipam" ) +// InitDockerDefault registers the built-in ipam service with libnetwork +func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error { + var ( + ok bool + localDs, globalDs datastore.DataStore + ) + + if l != nil { + if localDs, ok = l.(datastore.DataStore); !ok { + return fmt.Errorf("incorrect local datastore passed to built-in ipam init") + } + } + + if g != nil { + if globalDs, ok = g.(datastore.DataStore); !ok { + return fmt.Errorf("incorrect global datastore passed to built-in ipam init") + } + } + + ipamutils.InitNetworks() + + a, err := ipam.NewAllocator(localDs, globalDs) + if err != nil { + return err + } + + cps := &ipamapi.Capability{RequiresRequestReplay: true} + + return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps) +} + // Init registers the built-in ipam service with libnetwork func Init(ic ipamapi.Callback, l, g interface{}) error { - initFunc := windowsipam.GetInit(ipamapi.DefaultIPAM) + initFunc := windowsipam.GetInit(windowsipam.DefaultIPAM) + + err := InitDockerDefault(ic, l, g) + if err != nil { + return err + } return initFunc(ic, l, g) } diff --git a/ipams/windowsipam/windowsipam.go b/ipams/windowsipam/windowsipam.go index 661fd6a464..5fcd7255a5 100644 --- a/ipams/windowsipam/windowsipam.go +++ b/ipams/windowsipam/windowsipam.go @@ -15,6 +15,9 @@ const ( globalAddressSpace = "GlobalDefault" ) +// DefaultIPAM defines the default ipam-driver for local-scoped windows networks +const DefaultIPAM = "windows" + var ( defaultPool, _ = types.ParseCIDR("0.0.0.0/0") ) diff --git a/netutils/utils_windows.go b/netutils/utils_windows.go index b6e79c7538..73af44ec71 100644 --- a/netutils/utils_windows.go +++ b/netutils/utils_windows.go @@ -18,6 +18,8 @@ func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) { // FindAvailableNetwork returns a network from the passed list which does not // overlap with existing interfaces in the system + +// TODO : Use appropriate windows APIs to identify non-overlapping subnets func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) { - return nil, types.NotImplementedErrorf("not supported on windows") + return nil, nil } diff --git a/network.go b/network.go index 90d77998c5..a3511a5fae 100644 --- a/network.go +++ b/network.go @@ -633,6 +633,9 @@ func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ip return func(n *network) { if ipamDriver != "" { n.ipamType = ipamDriver + if ipamDriver == ipamapi.DefaultIPAM { + n.ipamType = defaultIpamForNetworkType(n.Type()) + } } n.ipamOptions = opts n.addrSpace = addrSpace diff --git a/network_unix.go b/network_unix.go index 77b6e1ce97..585261ece0 100644 --- a/network_unix.go +++ b/network_unix.go @@ -2,7 +2,13 @@ package libnetwork +import "github.com/docker/libnetwork/ipamapi" + // Stub implementations for DNS related functions func (n *network) startResolver() { } + +func defaultIpamForNetworkType(networkType string) string { + return ipamapi.DefaultIPAM +} diff --git a/network_windows.go b/network_windows.go index 4bf95c75d3..9d6fa7e4e4 100644 --- a/network_windows.go +++ b/network_windows.go @@ -4,10 +4,13 @@ package libnetwork import ( "runtime" + "time" "github.com/Microsoft/hcsshim" log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/drivers/windows" + "github.com/docker/libnetwork/ipamapi" + "github.com/docker/libnetwork/ipams/windowsipam" ) func executeInCompartment(compartmentID uint32, x func()) { @@ -42,15 +45,28 @@ func (n *network) startResolver() { for _, subnet := range hnsresponse.Subnets { if subnet.GatewayAddress != "" { - resolver := NewResolver(subnet.GatewayAddress, false, "", n) - log.Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress) - executeInCompartment(hnsresponse.DNSServerCompartment, resolver.SetupFunc(53)) - if err = resolver.Start(); err != nil { - log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) - } else { - n.resolver = append(n.resolver, resolver) + for i := 0; i < 3; i++ { + resolver := NewResolver(subnet.GatewayAddress, false, "", n) + log.Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress) + executeInCompartment(hnsresponse.DNSServerCompartment, resolver.SetupFunc(53)) + + if err = resolver.Start(); err != nil { + log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) + time.Sleep(1 * time.Second) + } else { + log.Debugf("Resolver bound successfuly for network %s", n.Name()) + n.resolver = append(n.resolver, resolver) + break + } } } } }) } + +func defaultIpamForNetworkType(networkType string) string { + if windows.IsBuiltinLocalDriver(networkType) { + return windowsipam.DefaultIPAM + } + return ipamapi.DefaultIPAM +} diff --git a/service_common.go b/service_common.go new file mode 100644 index 0000000000..a0172f5944 --- /dev/null +++ b/service_common.go @@ -0,0 +1,225 @@ +// +build linux windows + +package libnetwork + +import ( + "net" + + "github.com/Sirupsen/logrus" +) + +func newService(name string, id string, ingressPorts []*PortConfig, aliases []string) *service { + return &service{ + name: name, + id: id, + ingressPorts: ingressPorts, + loadBalancers: make(map[string]*loadBalancer), + aliases: aliases, + } +} + +func (c *controller) cleanupServiceBindings(cleanupNID string) { + var cleanupFuncs []func() + + c.Lock() + services := make([]*service, 0, len(c.serviceBindings)) + for _, s := range c.serviceBindings { + services = append(services, s) + } + c.Unlock() + + for _, s := range services { + s.Lock() + for nid, lb := range s.loadBalancers { + if cleanupNID != "" && nid != cleanupNID { + continue + } + + for eid, ip := range lb.backEnds { + service := s + loadBalancer := lb + networkID := nid + epID := eid + epIP := ip + + cleanupFuncs = append(cleanupFuncs, func() { + if err := c.rmServiceBinding(service.name, service.id, networkID, epID, loadBalancer.vip, + service.ingressPorts, service.aliases, epIP); err != nil { + logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v", + service.id, networkID, epID, err) + } + }) + } + } + s.Unlock() + } + + for _, f := range cleanupFuncs { + f() + } + +} + +func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error { + var ( + s *service + addService bool + ) + + n, err := c.NetworkByID(nid) + if err != nil { + return err + } + + skey := serviceKey{ + id: sid, + ports: portConfigs(ingressPorts).String(), + } + + c.Lock() + s, ok := c.serviceBindings[skey] + if !ok { + // Create a new service if we are seeing this service + // for the first time. + s = newService(name, sid, ingressPorts, aliases) + c.serviceBindings[skey] = s + } + c.Unlock() + + // Add endpoint IP to special "tasks.svc_name" so that the + // applications have access to DNS RR. + n.(*network).addSvcRecords("tasks."+name, ip, nil, false) + for _, alias := range aliases { + n.(*network).addSvcRecords("tasks."+alias, ip, nil, false) + } + + // Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR + svcIP := vip + if len(svcIP) == 0 { + svcIP = ip + } + n.(*network).addSvcRecords(name, svcIP, nil, false) + for _, alias := range aliases { + n.(*network).addSvcRecords(alias, svcIP, nil, false) + } + + s.Lock() + defer s.Unlock() + + lb, ok := s.loadBalancers[nid] + if !ok { + // Create a new load balancer if we are seeing this + // network attachment on the service for the first + // time. + lb = &loadBalancer{ + vip: vip, + fwMark: fwMarkCtr, + backEnds: make(map[string]net.IP), + service: s, + } + + fwMarkCtrMu.Lock() + fwMarkCtr++ + fwMarkCtrMu.Unlock() + + s.loadBalancers[nid] = lb + + // Since we just created this load balancer make sure + // we add a new service service in IPVS rules. + addService = true + + } + + lb.backEnds[eid] = ip + + // Add loadbalancer service and backend in all sandboxes in + // the network only if vip is valid. + if len(vip) != 0 { + n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts, addService) + } + + return nil +} + +func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error { + var rmService bool + + n, err := c.NetworkByID(nid) + if err != nil { + return err + } + + skey := serviceKey{ + id: sid, + ports: portConfigs(ingressPorts).String(), + } + + c.Lock() + s, ok := c.serviceBindings[skey] + if !ok { + c.Unlock() + return nil + } + c.Unlock() + + s.Lock() + lb, ok := s.loadBalancers[nid] + if !ok { + s.Unlock() + return nil + } + + _, ok = lb.backEnds[eid] + if !ok { + s.Unlock() + return nil + } + + delete(lb.backEnds, eid) + if len(lb.backEnds) == 0 { + // All the backends for this service have been + // removed. Time to remove the load balancer and also + // remove the service entry in IPVS. + rmService = true + + delete(s.loadBalancers, nid) + } + + if len(s.loadBalancers) == 0 { + // All loadbalancers for the service removed. Time to + // remove the service itself. + delete(c.serviceBindings, skey) + } + + // Remove loadbalancer service(if needed) and backend in all + // sandboxes in the network only if the vip is valid. + if len(vip) != 0 { + n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService) + } + s.Unlock() + + // Delete the special "tasks.svc_name" backend record. + n.(*network).deleteSvcRecords("tasks."+name, ip, nil, false) + for _, alias := range aliases { + n.(*network).deleteSvcRecords("tasks."+alias, ip, nil, false) + } + + // If we are doing DNS RR add the endpoint IP to DNS record + // right away. + if len(vip) == 0 { + n.(*network).deleteSvcRecords(name, ip, nil, false) + for _, alias := range aliases { + n.(*network).deleteSvcRecords(alias, ip, nil, false) + } + } + + // Remove the DNS record for VIP only if we are removing the service + if rmService && len(vip) != 0 { + n.(*network).deleteSvcRecords(name, vip, nil, false) + for _, alias := range aliases { + n.(*network).deleteSvcRecords(alias, vip, nil, false) + } + } + + return nil +} diff --git a/service_linux.go b/service_linux.go index 669eda9fb3..8d382d5540 100644 --- a/service_linux.go +++ b/service_linux.go @@ -29,222 +29,6 @@ func init() { reexec.Register("redirecter", redirecter) } -func newService(name string, id string, ingressPorts []*PortConfig, aliases []string) *service { - return &service{ - name: name, - id: id, - ingressPorts: ingressPorts, - loadBalancers: make(map[string]*loadBalancer), - aliases: aliases, - } -} - -func (c *controller) cleanupServiceBindings(cleanupNID string) { - var cleanupFuncs []func() - - c.Lock() - services := make([]*service, 0, len(c.serviceBindings)) - for _, s := range c.serviceBindings { - services = append(services, s) - } - c.Unlock() - - for _, s := range services { - s.Lock() - for nid, lb := range s.loadBalancers { - if cleanupNID != "" && nid != cleanupNID { - continue - } - - for eid, ip := range lb.backEnds { - service := s - loadBalancer := lb - networkID := nid - epID := eid - epIP := ip - - cleanupFuncs = append(cleanupFuncs, func() { - if err := c.rmServiceBinding(service.name, service.id, networkID, epID, loadBalancer.vip, - service.ingressPorts, service.aliases, epIP); err != nil { - logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v", - service.id, networkID, epID, err) - } - }) - } - } - s.Unlock() - } - - for _, f := range cleanupFuncs { - f() - } - -} - -func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error { - var ( - s *service - addService bool - ) - - n, err := c.NetworkByID(nid) - if err != nil { - return err - } - - skey := serviceKey{ - id: sid, - ports: portConfigs(ingressPorts).String(), - } - - c.Lock() - s, ok := c.serviceBindings[skey] - if !ok { - // Create a new service if we are seeing this service - // for the first time. - s = newService(name, sid, ingressPorts, aliases) - c.serviceBindings[skey] = s - } - c.Unlock() - - // Add endpoint IP to special "tasks.svc_name" so that the - // applications have access to DNS RR. - n.(*network).addSvcRecords("tasks."+name, ip, nil, false) - for _, alias := range aliases { - n.(*network).addSvcRecords("tasks."+alias, ip, nil, false) - } - - // Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR - svcIP := vip - if len(svcIP) == 0 { - svcIP = ip - } - n.(*network).addSvcRecords(name, svcIP, nil, false) - for _, alias := range aliases { - n.(*network).addSvcRecords(alias, svcIP, nil, false) - } - - s.Lock() - defer s.Unlock() - - lb, ok := s.loadBalancers[nid] - if !ok { - // Create a new load balancer if we are seeing this - // network attachment on the service for the first - // time. - lb = &loadBalancer{ - vip: vip, - fwMark: fwMarkCtr, - backEnds: make(map[string]net.IP), - service: s, - } - - fwMarkCtrMu.Lock() - fwMarkCtr++ - fwMarkCtrMu.Unlock() - - s.loadBalancers[nid] = lb - - // Since we just created this load balancer make sure - // we add a new service service in IPVS rules. - addService = true - - } - - lb.backEnds[eid] = ip - - // Add loadbalancer service and backend in all sandboxes in - // the network only if vip is valid. - if len(vip) != 0 { - n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts, addService) - } - - return nil -} - -func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error { - var rmService bool - - n, err := c.NetworkByID(nid) - if err != nil { - return err - } - - skey := serviceKey{ - id: sid, - ports: portConfigs(ingressPorts).String(), - } - - c.Lock() - s, ok := c.serviceBindings[skey] - if !ok { - c.Unlock() - return nil - } - c.Unlock() - - s.Lock() - lb, ok := s.loadBalancers[nid] - if !ok { - s.Unlock() - return nil - } - - _, ok = lb.backEnds[eid] - if !ok { - s.Unlock() - return nil - } - - delete(lb.backEnds, eid) - if len(lb.backEnds) == 0 { - // All the backends for this service have been - // removed. Time to remove the load balancer and also - // remove the service entry in IPVS. - rmService = true - - delete(s.loadBalancers, nid) - } - - if len(s.loadBalancers) == 0 { - // All loadbalancers for the service removed. Time to - // remove the service itself. - delete(c.serviceBindings, skey) - } - - // Remove loadbalancer service(if needed) and backend in all - // sandboxes in the network only if the vip is valid. - if len(vip) != 0 { - n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService) - } - s.Unlock() - - // Delete the special "tasks.svc_name" backend record. - n.(*network).deleteSvcRecords("tasks."+name, ip, nil, false) - for _, alias := range aliases { - n.(*network).deleteSvcRecords("tasks."+alias, ip, nil, false) - } - - // If we are doing DNS RR add the endpoint IP to DNS record - // right away. - if len(vip) == 0 { - n.(*network).deleteSvcRecords(name, ip, nil, false) - for _, alias := range aliases { - n.(*network).deleteSvcRecords(alias, ip, nil, false) - } - } - - // Remove the DNS record for VIP only if we are removing the service - if rmService && len(vip) != 0 { - n.(*network).deleteSvcRecords(name, vip, nil, false) - for _, alias := range aliases { - n.(*network).deleteSvcRecords(alias, vip, nil, false) - } - } - - return nil -} - // Get all loadbalancers on this network that is currently discovered // on this node. func (n *network) connectedLoadbalancers() []*loadBalancer { diff --git a/service_unsupported.go b/service_unsupported.go index 0ae384a99c..37b9828191 100644 --- a/service_unsupported.go +++ b/service_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux,!windows package libnetwork diff --git a/service_windows.go b/service_windows.go new file mode 100644 index 0000000000..8d79b2d8b0 --- /dev/null +++ b/service_windows.go @@ -0,0 +1,15 @@ +package libnetwork + +import "net" + +func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, addService bool) { +} + +func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, rmService bool) { +} + +func (sb *sandbox) populateLoadbalancers(ep *endpoint) { +} + +func arrangeIngressFilterRule() { +} From b4dac7298a93bd3157cf54fb5b2ef8c9a5335a43 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Fri, 14 Oct 2016 08:34:06 -0700 Subject: [PATCH 134/799] Change vxlan-id start-idx to 4096 To make it consistent with windows and linux workers Signed-off-by: Madhu Venugopal Fixed build breaks Signed-off-by: msabansal --- drivers/overlay/ovmanager/ovmanager.go | 2 +- drivers/overlay/ovmanager/ovmanager_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/overlay/ovmanager/ovmanager.go b/drivers/overlay/ovmanager/ovmanager.go index 78a586e08e..7b5caff0c8 100644 --- a/drivers/overlay/ovmanager/ovmanager.go +++ b/drivers/overlay/ovmanager/ovmanager.go @@ -18,7 +18,7 @@ import ( const ( networkType = "overlay" - vxlanIDStart = 256 + vxlanIDStart = 4096 vxlanIDEnd = (1 << 24) - 1 ) diff --git a/drivers/overlay/ovmanager/ovmanager_test.go b/drivers/overlay/ovmanager/ovmanager_test.go index f6d5921de5..b16fdb1cbd 100644 --- a/drivers/overlay/ovmanager/ovmanager_test.go +++ b/drivers/overlay/ovmanager/ovmanager_test.go @@ -70,7 +70,7 @@ func TestNetworkAllocateUserDefinedVNIs(t *testing.T) { options := make(map[string]string) // Intentionally add mode vnis than subnets - options[netlabel.OverlayVxlanIDList] = fmt.Sprintf("%d,%d,%d", 256, 257, 258) + options[netlabel.OverlayVxlanIDList] = fmt.Sprintf("%d,%d,%d", vxlanIDStart, vxlanIDStart+1, vxlanIDStart+2) vals, err := d.NetworkAllocate("testnetwork", options, ipamData, nil) require.NoError(t, err) @@ -81,7 +81,7 @@ func TestNetworkAllocateUserDefinedVNIs(t *testing.T) { // We should only get exactly the same number of vnis as // subnets. No more, no less, even if we passed more vnis. assert.Equal(t, 2, len(strings.Split(vxlanIDs, ","))) - assert.Equal(t, fmt.Sprintf("%d,%d", 256, 257), vxlanIDs) + assert.Equal(t, fmt.Sprintf("%d,%d", vxlanIDStart, vxlanIDStart+1), vxlanIDs) err = d.NetworkFree("testnetwork") require.NoError(t, err) From a493ddb42f7ef9e0a224c90489015202fc7398d9 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Fri, 28 Oct 2016 13:54:52 -0700 Subject: [PATCH 135/799] If enabling ip forwarding set the default forward policy to drop Signed-off-by: Santhosh Manohar --- drivers/bridge/bridge.go | 15 +++++----- drivers/bridge/setup_ip_forwarding.go | 34 +++++++++++++++++++--- drivers/bridge/setup_ip_forwarding_test.go | 2 +- iptables/iptables.go | 15 ++++++++++ 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index a30140feae..f6cbe07783 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -380,13 +380,6 @@ func (d *driver) configure(option map[string]interface{}) error { return &ErrInvalidDriverConfig{} } - if config.EnableIPForwarding { - err = setupIPForwarding() - if err != nil { - return err - } - } - if config.EnableIPTables { if _, err := os.Stat("/proc/sys/net/bridge"); err != nil { if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil { @@ -402,6 +395,14 @@ func (d *driver) configure(option map[string]interface{}) error { iptables.OnReloaded(func() { logrus.Debugf("Recreating iptables chains on firewall reload"); setupIPChains(config) }) } + if config.EnableIPForwarding { + err = setupIPForwarding(config.EnableIPTables) + if err != nil { + logrus.Warn(err) + return err + } + } + d.Lock() d.natChain = natChain d.filterChain = filterChain diff --git a/drivers/bridge/setup_ip_forwarding.go b/drivers/bridge/setup_ip_forwarding.go index 53f9c88d4d..2c6fedcb0e 100644 --- a/drivers/bridge/setup_ip_forwarding.go +++ b/drivers/bridge/setup_ip_forwarding.go @@ -2,6 +2,8 @@ package bridge import ( "fmt" + log "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/iptables" "io/ioutil" ) @@ -10,7 +12,15 @@ const ( ipv4ForwardConfPerm = 0644 ) -func setupIPForwarding() error { +func configureIPForwarding(enable bool) error { + var val byte + if enable { + val = '1' + } + return ioutil.WriteFile(ipv4ForwardConf, []byte{val, '\n'}, ipv4ForwardConfPerm) +} + +func setupIPForwarding(enableIPTables bool) error { // Get current IPv4 forward setup ipv4ForwardData, err := ioutil.ReadFile(ipv4ForwardConf) if err != nil { @@ -20,10 +30,26 @@ func setupIPForwarding() error { // Enable IPv4 forwarding only if it is not already enabled if ipv4ForwardData[0] != '1' { // Enable IPv4 forwarding - if err := ioutil.WriteFile(ipv4ForwardConf, []byte{'1', '\n'}, ipv4ForwardConfPerm); err != nil { - return fmt.Errorf("Setup IP forwarding failed: %v", err) + if err := configureIPForwarding(true); err != nil { + return fmt.Errorf("Enabling IP forwarding failed: %v", err) } + // When enabling ip_forward set the default policy on forward chain to + // drop only if the daemon option iptables is not set to false. + if !enableIPTables { + return nil + } + if err := iptables.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil { + if err := configureIPForwarding(false); err != nil { + log.Errorf("Disabling IP forwarding failed, %v", err) + } + return err + } + iptables.OnReloaded(func() { + log.Debugf("Setting the default DROP policy on firewall reload") + if err := iptables.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil { + log.Warnf("Settig the default DROP policy on firewall reload failed, %v", err) + } + }) } - return nil } diff --git a/drivers/bridge/setup_ip_forwarding_test.go b/drivers/bridge/setup_ip_forwarding_test.go index 1487b5b00b..c6b88c89d4 100644 --- a/drivers/bridge/setup_ip_forwarding_test.go +++ b/drivers/bridge/setup_ip_forwarding_test.go @@ -17,7 +17,7 @@ func TestSetupIPForwarding(t *testing.T) { } // Set IP Forwarding - if err := setupIPForwarding(); err != nil { + if err := setupIPForwarding(true); err != nil { t.Fatalf("Failed to setup IP forwarding: %v", err) } diff --git a/iptables/iptables.go b/iptables/iptables.go index 340bba6b0b..026f7bfc62 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -16,6 +16,9 @@ import ( // Action signifies the iptable action. type Action string +// Policy is the default iptable policies +type Policy string + // Table refers to Nat, Filter or Mangle. type Table string @@ -32,6 +35,10 @@ const ( Filter Table = "filter" // Mangle table is used for mangling the packet. Mangle Table = "mangle" + // Drop is the default iptables DROP policy + Drop Policy = "DROP" + // Accept is the default iptables ACCEPT policy + Accept Policy = "ACCEPT" ) var ( @@ -422,6 +429,14 @@ func GetVersion() (major, minor, micro int, err error) { return } +// SetDefaultPolicy sets the passed default policy for the table/chain +func SetDefaultPolicy(table Table, chain string, policy Policy) error { + if err := RawCombinedOutput("-t", string(table), "-P", chain, string(policy)); err != nil { + return fmt.Errorf("setting default policy to %v in %v chain failed: %v", policy, chain, err) + } + return nil +} + func parseVersionNumbers(input string) (major, minor, micro int) { re := regexp.MustCompile(`v\d*.\d*.\d*`) line := re.FindString(input) From 2c4f66b937a2d93a10c8295a732b4da94b4b9098 Mon Sep 17 00:00:00 2001 From: m-kostrzewa Date: Wed, 2 Nov 2016 16:18:12 +0100 Subject: [PATCH 136/799] Register remote network driver on Windows. Without this change, specifying a remote network driver on Windows results in "could not resolve driver X in registry" error. Signed-off-by: Michal Kostrzewa --- drivers_windows.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers_windows.go b/drivers_windows.go index b5058d6cfc..87705e7652 100644 --- a/drivers_windows.go +++ b/drivers_windows.go @@ -2,6 +2,7 @@ package libnetwork import ( "github.com/docker/libnetwork/drivers/null" + "github.com/docker/libnetwork/drivers/remote" "github.com/docker/libnetwork/drivers/windows" "github.com/docker/libnetwork/drivers/windows/overlay" ) @@ -10,6 +11,7 @@ func getInitializers() []initializer { return []initializer{ {null.Init, "null"}, {overlay.Init, "overlay"}, + {remote.Init, "remote"}, {windows.GetInit("transparent"), "transparent"}, {windows.GetInit("l2bridge"), "l2bridge"}, {windows.GetInit("l2tunnel"), "l2tunnel"}, From 2638e83ffc7acaeae2d0cbf58c12a403cb17f39d Mon Sep 17 00:00:00 2001 From: allencloud Date: Tue, 8 Nov 2016 15:28:42 +0800 Subject: [PATCH 137/799] update reapNode interval Signed-off-by: allencloud --- controller.go | 2 +- networkdb/cluster.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/controller.go b/controller.go index e2289c050e..449d8d59e1 100644 --- a/controller.go +++ b/controller.go @@ -702,7 +702,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... defer func() { if err != nil { if e := c.deleteFromStore(epCnt); e != nil { - log.Warnf("couldnt rollback from store, epCnt %v on failure (%v): %v", epCnt, err, e) + log.Warnf("could not rollback from store, epCnt %v on failure (%v): %v", epCnt, err, e) } } }() diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 1ba1b14b0d..820e2f1ae1 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -242,7 +242,7 @@ func (nDB *NetworkDB) reapDeadNode() { defer nDB.Unlock() for id, n := range nDB.failedNodes { if n.reapTime > 0 { - n.reapTime -= reapPeriod + n.reapTime -= nodeReapPeriod continue } logrus.Debugf("Removing failed node %v from gossip cluster", n.Name) From 5794d382d7023c4f2a630f9b6d7bcca6835fe22b Mon Sep 17 00:00:00 2001 From: allencloud Date: Tue, 8 Nov 2016 18:18:55 +0800 Subject: [PATCH 138/799] remove unused mConfig Signed-off-by: allencloud --- networkdb/cluster.go | 1 - networkdb/networkdb.go | 5 ----- 2 files changed, 6 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 1ba1b14b0d..5fc6a988a8 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -139,7 +139,6 @@ func (nDB *NetworkDB) clusterInit() error { nDB.stopCh = make(chan struct{}) nDB.memberlist = mlist - nDB.mConfig = config for _, trigger := range []struct { interval time.Duration diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 835853bb8b..2518030e30 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -29,10 +29,6 @@ type NetworkDB struct { // NetworkDB configuration. config *Config - // local copy of memberlist config that we use to driver - // network scoped gossip and bulk sync. - mConfig *memberlist.Config - // All the tree index (byTable, byNetwork) that we maintain // the db. indexes map[int]*radix.Tree @@ -57,7 +53,6 @@ type NetworkDB struct { // A map of nodes which are participating in a given // network. The key is a network ID. - networkNodes map[string][]string // A table of ack channels for every node from which we are From 3c20c075a353ecb5689d7ccbef6dee500801b6c2 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Thu, 13 Oct 2016 11:14:39 -0700 Subject: [PATCH 139/799] Check subnet overlap when programming of sandbox interface Signed-off-by: Alessandro Boch --- endpoint.go | 8 ++--- libnetwork_linux_test.go | 16 +++++++++- libnetwork_test.go | 30 +++++++++++++++++- osl/interface_linux.go | 23 +++++++++++++- osl/sandbox_linux_test.go | 66 +++++++++++++++++++++++++++++++++++++-- sandbox_test.go | 57 +++++++++++++++------------------ 6 files changed, 160 insertions(+), 40 deletions(-) diff --git a/endpoint.go b/endpoint.go index 4fbe81b409..9f378b02fc 100644 --- a/endpoint.go +++ b/endpoint.go @@ -495,10 +495,6 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { return err } - if err = n.getController().updateToStore(ep); err != nil { - return err - } - // Current endpoint providing external connectivity for the sandbox extEp := sb.getGatewayEndpoint() @@ -515,6 +511,10 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { return err } + if err = n.getController().updateToStore(ep); err != nil { + return err + } + if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil { return sb.setupDefaultGW() } diff --git a/libnetwork_linux_test.go b/libnetwork_linux_test.go index 37121bd8b0..7cca41037f 100644 --- a/libnetwork_linux_test.go +++ b/libnetwork_linux_test.go @@ -402,6 +402,20 @@ func externalKeyTest(t *testing.T, reexec bool) { } }() + n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": "testnetwork2", + }, + }, nil, nil) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n2.Delete(); err != nil { + t.Fatal(err) + } + }() + ep, err := n.CreateEndpoint("ep1") if err != nil { t.Fatal(err) @@ -413,7 +427,7 @@ func externalKeyTest(t *testing.T, reexec bool) { } }() - ep2, err := n.CreateEndpoint("ep2") + ep2, err := n2.CreateEndpoint("ep2") if err != nil { t.Fatal(err) } diff --git a/libnetwork_test.go b/libnetwork_test.go index 4510174d8b..f68dcfda46 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -882,6 +882,20 @@ func TestEndpointDeleteWithActiveContainer(t *testing.T) { } }() + n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": "testnetwork2", + }, + }, nil, nil) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n2.Delete(); err != nil { + t.Fatal(err) + } + }() + ep, err := n.CreateEndpoint("ep1") if err != nil { t.Fatal(err) @@ -1012,12 +1026,26 @@ func TestLeaveAll(t *testing.T) { } }() + n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": "testnetwork2", + }, + }, nil, nil) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n2.Delete(); err != nil { + t.Fatal(err) + } + }() + ep1, err := n.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } - ep2, err := n.CreateEndpoint("ep2") + ep2, err := n2.CreateEndpoint("ep2") if err != nil { t.Fatal(err) } diff --git a/osl/interface_linux.go b/osl/interface_linux.go index 643939322e..04b85369f7 100644 --- a/osl/interface_linux.go +++ b/osl/interface_linux.go @@ -377,7 +377,9 @@ func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { if i.Address() == nil { return nil } - + if err := checkRouteConflict(nlh, i.Address(), netlink.FAMILY_V4); err != nil { + return err + } ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""} return nlh.AddrAdd(iface, ipAddr) } @@ -386,6 +388,9 @@ func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error if i.AddressIPv6() == nil { return nil } + if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil { + return err + } ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD} return nlh.AddrAdd(iface, ipAddr) } @@ -442,3 +447,19 @@ func scanInterfaceStats(data, ifName string, i *types.InterfaceStatistics) error return err } + +func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error { + routes, err := nlh.RouteList(nil, family) + if err != nil { + return err + } + for _, route := range routes { + if route.Dst != nil { + if route.Dst.Contains(address.IP) || address.Contains(route.Dst.IP) { + return fmt.Errorf("cannot program address %v in sandbox interface because it conflicts with existing route %s", + address, route) + } + } + } + return nil +} diff --git a/osl/sandbox_linux_test.go b/osl/sandbox_linux_test.go index b76377806e..d71e24a21d 100644 --- a/osl/sandbox_linux_test.go +++ b/osl/sandbox_linux_test.go @@ -7,6 +7,7 @@ import ( "net" "os" "path/filepath" + "strings" "syscall" "testing" "time" @@ -74,8 +75,7 @@ func newInfo(hnd *netlink.Handle, t *testing.T) (Sandbox, error) { intf1.address = addr intf1.address.IP = ip4 - // ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48") - ip6, addrv6, err := net.ParseCIDR("fe80::2/64") + ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48") if err != nil { return nil, err } @@ -225,3 +225,65 @@ func TestDisableIPv6DAD(t *testing.T) { t.Fatalf("Unexpected interface flags: 0x%x. Expected to contain 0x%x", addrList[0].Flags, syscall.IFA_F_NODAD) } } + +func TestSetInterfaceIP(t *testing.T) { + defer testutils.SetupTestOSContext(t)() + + ipv4, _ := types.ParseCIDR("172.30.0.33/24") + ipv6, _ := types.ParseCIDR("2001:db8::44/64") + iface := &nwIface{address: ipv4, addressIPv6: ipv6} + + nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE) + if err != nil { + t.Fatal(err) + } + + if err := nlh.LinkAdd(&netlink.Veth{ + LinkAttrs: netlink.LinkAttrs{Name: "sideA"}, + PeerName: "sideB", + }); err != nil { + t.Fatal(err) + } + + linkA, err := nlh.LinkByName("sideA") + if err != nil { + t.Fatal(err) + } + + linkB, err := nlh.LinkByName("sideB") + if err != nil { + t.Fatal(err) + } + + if err := nlh.LinkSetUp(linkA); err != nil { + t.Fatal(err) + } + + if err := nlh.LinkSetUp(linkB); err != nil { + t.Fatal(err) + } + + if err := setInterfaceIP(nlh, linkA, iface); err != nil { + t.Fatal(err) + } + + if err := setInterfaceIPv6(nlh, linkA, iface); err != nil { + t.Fatal(err) + } + + err = setInterfaceIP(nlh, linkB, iface) + if err == nil { + t.Fatalf("Expected route conflict error, but succeeded") + } + if !strings.Contains(err.Error(), "conflicts with existing route") { + t.Fatalf("Unexpected error: %v", err) + } + + err = setInterfaceIPv6(nlh, linkB, iface) + if err == nil { + t.Fatalf("Expected route conflict error, but succeeded") + } + if !strings.Contains(err.Error(), "conflicts with existing route") { + t.Fatalf("Unexpected error: %v", err) + } +} diff --git a/sandbox_test.go b/sandbox_test.go index 6ce245d767..76a55699ef 100644 --- a/sandbox_test.go +++ b/sandbox_test.go @@ -1,6 +1,7 @@ package libnetwork import ( + "fmt" "testing" "github.com/docker/libnetwork/config" @@ -10,7 +11,7 @@ import ( "github.com/docker/libnetwork/testutils" ) -func getTestEnv(t *testing.T, empty bool) (NetworkController, Network, Network) { +func getTestEnv(t *testing.T, numNetworks int) (NetworkController, []Network) { netType := "bridge" option := options.Generic{ @@ -28,37 +29,31 @@ func getTestEnv(t *testing.T, empty bool) (NetworkController, Network, Network) t.Fatal(err) } - if empty { - return c, nil, nil + if numNetworks == 0 { + return c, nil } - name1 := "test_nw_1" - netOption1 := options.Generic{ - netlabel.GenericData: options.Generic{ - "BridgeName": name1, - }, - } - n1, err := c.NewNetwork(netType, name1, "", NetworkOptionGeneric(netOption1)) - if err != nil { - t.Fatal(err) - } + nwList := make([]Network, 0, numNetworks) + for i := 0; i < numNetworks; i++ { + name := fmt.Sprintf("test_nw_%d", i) + netOption := options.Generic{ + netlabel.GenericData: options.Generic{ + "BridgeName": name, + }, + } + n, err := c.NewNetwork(netType, name, "", NetworkOptionGeneric(netOption)) + if err != nil { + t.Fatal(err) + } - name2 := "test_nw_2" - netOption2 := options.Generic{ - netlabel.GenericData: options.Generic{ - "BridgeName": name2, - }, - } - n2, err := c.NewNetwork(netType, name2, "", NetworkOptionGeneric(netOption2)) - if err != nil { - t.Fatal(err) + nwList = append(nwList, n) } - return c, n1, n2 + return c, nwList } func TestSandboxAddEmpty(t *testing.T) { - c, _, _ := getTestEnv(t, true) + c, _ := getTestEnv(t, 0) ctrlr := c.(*controller) sbx, err := ctrlr.NewSandbox("sandbox0") @@ -82,7 +77,7 @@ func TestSandboxAddMultiPrio(t *testing.T) { defer testutils.SetupTestOSContext(t)() } - c, nw, _ := getTestEnv(t, false) + c, nws := getTestEnv(t, 3) ctrlr := c.(*controller) sbx, err := ctrlr.NewSandbox("sandbox1") @@ -91,15 +86,15 @@ func TestSandboxAddMultiPrio(t *testing.T) { } sid := sbx.ID() - ep1, err := nw.CreateEndpoint("ep1") + ep1, err := nws[0].CreateEndpoint("ep1") if err != nil { t.Fatal(err) } - ep2, err := nw.CreateEndpoint("ep2") + ep2, err := nws[1].CreateEndpoint("ep2") if err != nil { t.Fatal(err) } - ep3, err := nw.CreateEndpoint("ep3") + ep3, err := nws[2].CreateEndpoint("ep3") if err != nil { t.Fatal(err) } @@ -163,7 +158,7 @@ func TestSandboxAddSamePrio(t *testing.T) { defer testutils.SetupTestOSContext(t)() } - c, nw1, nw2 := getTestEnv(t, false) + c, nws := getTestEnv(t, 2) ctrlr := c.(*controller) @@ -173,11 +168,11 @@ func TestSandboxAddSamePrio(t *testing.T) { } sid := sbx.ID() - ep1, err := nw1.CreateEndpoint("ep1") + ep1, err := nws[0].CreateEndpoint("ep1") if err != nil { t.Fatal(err) } - ep2, err := nw2.CreateEndpoint("ep2") + ep2, err := nws[1].CreateEndpoint("ep2") if err != nil { t.Fatal(err) } From b735bb2adae211d26961b75611d98719a73fa324 Mon Sep 17 00:00:00 2001 From: Daehyeok Mun Date: Mon, 31 Oct 2016 22:26:14 -0600 Subject: [PATCH 140/799] Refactoring logrus import and formatting This fix tries to fix logrus formatting by removing `f` from `logrus.[Error|Warn|Debug|Fatal|Panic|Info]f` when formatting string is not present. Also fix import name to use original project name 'logrus' instead of 'log' Signed-off-by: Daehyeok Mun --- bitseq/sequence.go | 4 +- config/config.go | 22 ++++---- controller.go | 40 ++++++------- drivers/bridge/link.go | 4 +- drivers/bridge/setup_ipv4.go | 4 +- drivers/bridge/setup_verify.go | 4 +- drivers/overlay/encryption.go | 60 ++++++++++---------- drivers/overlay/joinleave.go | 20 +++---- drivers/overlay/ov_endpoint.go | 8 +-- drivers/overlay/overlay.go | 2 +- drivers/overlay/peerdb.go | 8 +-- drivers/remote/driver.go | 6 +- drivers/solaris/bridge/bridge.go | 10 ++-- drivers/solaris/bridge/port_mapping.go | 2 +- drivers/solaris/overlay/encryption.go | 28 +++++----- drivers/solaris/overlay/joinleave.go | 20 +++---- drivers/solaris/overlay/ov_endpoint.go | 4 +- drivers/solaris/overlay/peerdb.go | 8 +-- drivers/windows/overlay/peerdb_windows.go | 10 ++-- drivers/windows/windows.go | 4 +- endpoint.go | 68 +++++++++++------------ hostdiscovery/hostdiscovery.go | 4 +- ipam/allocator.go | 18 +++--- ipam/store.go | 4 +- ipams/remote/remote.go | 10 ++-- ipams/windowsipam/windowsipam.go | 10 ++-- ipvs/netlink.go | 2 +- libnetwork_linux_test.go | 4 +- libnetwork_test.go | 4 +- network.go | 42 +++++++------- network_windows.go | 14 ++--- ns/init_linux.go | 8 +-- osl/interface_linux.go | 8 +-- osl/namespace_linux.go | 8 +-- resolver.go | 24 ++++---- resolver_unix.go | 10 ++-- sandbox.go | 34 ++++++------ sandbox_dns_unix.go | 14 ++--- sandbox_store.go | 2 +- store.go | 24 ++++---- 40 files changed, 290 insertions(+), 290 deletions(-) diff --git a/bitseq/sequence.go b/bitseq/sequence.go index fb99944098..9c815e5e3c 100644 --- a/bitseq/sequence.go +++ b/bitseq/sequence.go @@ -9,7 +9,7 @@ import ( "fmt" "sync" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/types" ) @@ -286,7 +286,7 @@ func (h *Handle) CheckConsistency() error { continue } - log.Infof("Fixed inconsistent bit sequence in datastore:\n%s\n%s", h, nh) + logrus.Infof("Fixed inconsistent bit sequence in datastore:\n%s\n%s", h, nh) h.Lock() h.head = nh.head diff --git a/config/config.go b/config/config.go index a6ebd05284..592ea91113 100644 --- a/config/config.go +++ b/config/config.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/BurntSushi/toml" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" "github.com/docker/docker/pkg/plugingetter" "github.com/docker/go-connections/tlsconfig" @@ -100,7 +100,7 @@ type Option func(c *Config) // OptionDefaultNetwork function returns an option setter for a default network func OptionDefaultNetwork(dn string) Option { return func(c *Config) { - log.Debugf("Option DefaultNetwork: %s", dn) + logrus.Debugf("Option DefaultNetwork: %s", dn) c.Daemon.DefaultNetwork = strings.TrimSpace(dn) } } @@ -108,7 +108,7 @@ func OptionDefaultNetwork(dn string) Option { // OptionDefaultDriver function returns an option setter for default driver func OptionDefaultDriver(dd string) Option { return func(c *Config) { - log.Debugf("Option DefaultDriver: %s", dd) + logrus.Debugf("Option DefaultDriver: %s", dd) c.Daemon.DefaultDriver = strings.TrimSpace(dd) } } @@ -134,7 +134,7 @@ func OptionLabels(labels []string) Option { // OptionKVProvider function returns an option setter for kvstore provider func OptionKVProvider(provider string) Option { return func(c *Config) { - log.Debugf("Option OptionKVProvider: %s", provider) + logrus.Debugf("Option OptionKVProvider: %s", provider) if _, ok := c.Scopes[datastore.GlobalScope]; !ok { c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{} } @@ -145,7 +145,7 @@ func OptionKVProvider(provider string) Option { // OptionKVProviderURL function returns an option setter for kvstore url func OptionKVProviderURL(url string) Option { return func(c *Config) { - log.Debugf("Option OptionKVProviderURL: %s", url) + logrus.Debugf("Option OptionKVProviderURL: %s", url) if _, ok := c.Scopes[datastore.GlobalScope]; !ok { c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{} } @@ -157,14 +157,14 @@ func OptionKVProviderURL(url string) Option { func OptionKVOpts(opts map[string]string) Option { return func(c *Config) { if opts["kv.cacertfile"] != "" && opts["kv.certfile"] != "" && opts["kv.keyfile"] != "" { - log.Info("Option Initializing KV with TLS") + logrus.Info("Option Initializing KV with TLS") tlsConfig, err := tlsconfig.Client(tlsconfig.Options{ CAFile: opts["kv.cacertfile"], CertFile: opts["kv.certfile"], KeyFile: opts["kv.keyfile"], }) if err != nil { - log.Errorf("Unable to set up TLS: %s", err) + logrus.Errorf("Unable to set up TLS: %s", err) return } if _, ok := c.Scopes[datastore.GlobalScope]; !ok { @@ -182,7 +182,7 @@ func OptionKVOpts(opts map[string]string) Option { KeyFile: opts["kv.keyfile"], } } else { - log.Info("Option Initializing KV without TLS") + logrus.Info("Option Initializing KV without TLS") } } } @@ -242,7 +242,7 @@ func ValidateName(name string) error { // OptionLocalKVProvider function returns an option setter for kvstore provider func OptionLocalKVProvider(provider string) Option { return func(c *Config) { - log.Debugf("Option OptionLocalKVProvider: %s", provider) + logrus.Debugf("Option OptionLocalKVProvider: %s", provider) if _, ok := c.Scopes[datastore.LocalScope]; !ok { c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{} } @@ -253,7 +253,7 @@ func OptionLocalKVProvider(provider string) Option { // OptionLocalKVProviderURL function returns an option setter for kvstore url func OptionLocalKVProviderURL(url string) Option { return func(c *Config) { - log.Debugf("Option OptionLocalKVProviderURL: %s", url) + logrus.Debugf("Option OptionLocalKVProviderURL: %s", url) if _, ok := c.Scopes[datastore.LocalScope]; !ok { c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{} } @@ -264,7 +264,7 @@ func OptionLocalKVProviderURL(url string) Option { // OptionLocalKVProviderConfig function returns an option setter for kvstore config func OptionLocalKVProviderConfig(config *store.Config) Option { return func(c *Config) { - log.Debugf("Option OptionLocalKVProviderConfig: %v", config) + logrus.Debugf("Option OptionLocalKVProviderConfig: %v", config) if _, ok := c.Scopes[datastore.LocalScope]; !ok { c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{} } diff --git a/controller.go b/controller.go index 449d8d59e1..6eaa1c6638 100644 --- a/controller.go +++ b/controller.go @@ -51,7 +51,7 @@ import ( "sync" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" "github.com/docker/docker/pkg/locker" "github.com/docker/docker/pkg/plugingetter" @@ -212,7 +212,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) { if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil { // Failing to initialize discovery is a bad situation to be in. // But it cannot fail creating the Controller - log.Errorf("Failed to Initialize Discovery : %v", err) + logrus.Errorf("Failed to Initialize Discovery : %v", err) } } @@ -283,7 +283,7 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error { if clusterConfigAvailable { return c.agentSetup() } - log.Debugf("received encryption keys before cluster config") + logrus.Debug("received encryption keys before cluster config") return nil } if agent == nil { @@ -441,7 +441,7 @@ func (c *controller) ReloadConfiguration(cfgOptions ...config.Option) error { c.drvRegistry.WalkIPAMs(func(name string, driver ipamapi.Ipam, cap *ipamapi.Capability) bool { err := driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig) if err != nil { - log.Errorf("Failed to set datastore in driver %s: %v", name, err) + logrus.Errorf("Failed to set datastore in driver %s: %v", name, err) } return false }) @@ -449,14 +449,14 @@ func (c *controller) ReloadConfiguration(cfgOptions ...config.Option) error { c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { err := driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig) if err != nil { - log.Errorf("Failed to set datastore in driver %s: %v", name, err) + logrus.Errorf("Failed to set datastore in driver %s: %v", name, err) } return false }) if c.discovery == nil && c.cfg.Cluster.Watcher != nil { if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil { - log.Errorf("Failed to Initialize Discovery after configuration update: %v", err) + logrus.Errorf("Failed to Initialize Discovery after configuration update: %v", err) } } @@ -561,7 +561,7 @@ func (c *controller) pushNodeDiscovery(d driverapi.Driver, cap driverapi.Capabil err = d.DiscoverDelete(discoverapi.NodeDiscovery, nodeData) } if err != nil { - log.Debugf("discovery notification error : %v", err) + logrus.Debugf("discovery notification error : %v", err) } } } @@ -687,7 +687,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... defer func() { if err != nil { if e := network.deleteNetwork(); e != nil { - log.Warnf("couldn't roll back driver network on network %s creation failure: %v", network.name, err) + logrus.Warnf("couldn't roll back driver network on network %s creation failure: %v", network.name, err) } } }() @@ -702,7 +702,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... defer func() { if err != nil { if e := c.deleteFromStore(epCnt); e != nil { - log.Warnf("could not rollback from store, epCnt %v on failure (%v): %v", epCnt, err, e) + logrus.Warnf("could not rollback from store, epCnt %v on failure (%v): %v", epCnt, err, e) } } }() @@ -723,7 +723,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... var joinCluster NetworkWalker = func(nw Network) bool { n := nw.(*network) if err := n.joinCluster(); err != nil { - log.Errorf("Failed to join network %s (%s) into agent cluster: %v", n.Name(), n.ID(), err) + logrus.Errorf("Failed to join network %s (%s) into agent cluster: %v", n.Name(), n.ID(), err) } n.addDriverWatches() return false @@ -732,7 +732,7 @@ var joinCluster NetworkWalker = func(nw Network) bool { func (c *controller) reservePools() { networks, err := c.getNetworksForScope(datastore.LocalScope) if err != nil { - log.Warnf("Could not retrieve networks from local store during ipam allocation for existing networks: %v", err) + logrus.Warnf("Could not retrieve networks from local store during ipam allocation for existing networks: %v", err) return } @@ -764,22 +764,22 @@ func (c *controller) reservePools() { } // Reserve pools if err := n.ipamAllocate(); err != nil { - log.Warnf("Failed to allocate ipam pool(s) for network %q (%s): %v", n.Name(), n.ID(), err) + logrus.Warnf("Failed to allocate ipam pool(s) for network %q (%s): %v", n.Name(), n.ID(), err) } // Reserve existing endpoints' addresses ipam, _, err := n.getController().getIPAMDriver(n.ipamType) if err != nil { - log.Warnf("Failed to retrieve ipam driver for network %q (%s) during address reservation", n.Name(), n.ID()) + logrus.Warnf("Failed to retrieve ipam driver for network %q (%s) during address reservation", n.Name(), n.ID()) continue } epl, err := n.getEndpointsFromStore() if err != nil { - log.Warnf("Failed to retrieve list of current endpoints on network %q (%s)", n.Name(), n.ID()) + logrus.Warnf("Failed to retrieve list of current endpoints on network %q (%s)", n.Name(), n.ID()) continue } for _, ep := range epl { if err := ep.assignAddress(ipam, true, ep.Iface().AddressIPv6() != nil); err != nil { - log.Warnf("Failed to reserve current adress for endpoint %q (%s) on network %q (%s)", + logrus.Warnf("Failed to reserve current adress for endpoint %q (%s) on network %q (%s)", ep.Name(), ep.ID(), n.Name(), n.ID()) } } @@ -789,7 +789,7 @@ func (c *controller) reservePools() { func doReplayPoolReserve(n *network) bool { _, caps, err := n.getController().getIPAMDriver(n.ipamType) if err != nil { - log.Warnf("Failed to retrieve ipam driver for network %q (%s): %v", n.Name(), n.ID(), err) + logrus.Warnf("Failed to retrieve ipam driver for network %q (%s): %v", n.Name(), n.ID(), err) return false } return caps.RequiresRequestReplay @@ -816,7 +816,7 @@ func (c *controller) Networks() []Network { networks, err := c.getNetworksFromStore() if err != nil { - log.Error(err) + logrus.Error(err) } for _, n := range networks { @@ -1133,18 +1133,18 @@ func (c *controller) clearIngress(clusterLeave bool) { if ingressSandbox != nil { if err := ingressSandbox.Delete(); err != nil { - log.Warnf("Could not delete ingress sandbox while leaving: %v", err) + logrus.Warnf("Could not delete ingress sandbox while leaving: %v", err) } } n, err := c.NetworkByName("ingress") if err != nil && clusterLeave { - log.Warnf("Could not find ingress network while leaving: %v", err) + logrus.Warnf("Could not find ingress network while leaving: %v", err) } if n != nil { if err := n.Delete(); err != nil { - log.Warnf("Could not delete ingress network while leaving: %v", err) + logrus.Warnf("Could not delete ingress network while leaving: %v", err) } } } diff --git a/drivers/bridge/link.go b/drivers/bridge/link.go index 25877737ba..53e9eeef99 100644 --- a/drivers/bridge/link.go +++ b/drivers/bridge/link.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/iptables" "github.com/docker/libnetwork/types" ) @@ -44,7 +44,7 @@ func (l *link) Disable() { // -D == iptables delete flag err := linkContainers("-D", l.parentIP, l.childIP, l.ports, l.bridge, true) if err != nil { - log.Errorf("Error removing IPTables rules for a link %s due to %s", l.String(), err.Error()) + logrus.Errorf("Error removing IPTables rules for a link %s due to %s", l.String(), err.Error()) } // Return proper error once we move to use a proper iptables package // that returns typed errors diff --git a/drivers/bridge/setup_ipv4.go b/drivers/bridge/setup_ipv4.go index 3af5836d52..772b40eed3 100644 --- a/drivers/bridge/setup_ipv4.go +++ b/drivers/bridge/setup_ipv4.go @@ -6,7 +6,7 @@ import ( "net" "path/filepath" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" ) @@ -39,7 +39,7 @@ func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error { return fmt.Errorf("failed to remove current ip address from bridge: %v", err) } } - log.Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4) + logrus.Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4) if err := i.nlh.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil { return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err} } diff --git a/drivers/bridge/setup_verify.go b/drivers/bridge/setup_verify.go index ec37d16d06..330a5b4560 100644 --- a/drivers/bridge/setup_verify.go +++ b/drivers/bridge/setup_verify.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/ns" "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" @@ -39,7 +39,7 @@ func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) e for _, addrv6 := range addrsv6 { if addrv6.IP.IsGlobalUnicast() && !types.CompareIPNet(addrv6.IPNet, i.bridgeIPv6) { if err := i.nlh.AddrDel(i.Link, &addrv6); err != nil { - log.Warnf("Failed to remove residual IPv6 address %s from bridge: %v", addrv6.IPNet, err) + logrus.Warnf("Failed to remove residual IPv6 address %s from bridge: %v", addrv6.IPNet, err) } } } diff --git a/drivers/overlay/encryption.go b/drivers/overlay/encryption.go index fefb5da65c..14844f4cef 100644 --- a/drivers/overlay/encryption.go +++ b/drivers/overlay/encryption.go @@ -12,7 +12,7 @@ import ( "strconv" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/iptables" "github.com/docker/libnetwork/ns" "github.com/docker/libnetwork/types" @@ -77,7 +77,7 @@ func (e *encrMap) String() string { } func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal, add bool) error { - log.Debugf("checkEncryption(%s, %v, %d, %t)", nid[0:7], rIP, vxlanID, isLocal) + logrus.Debugf("checkEncryption(%s, %v, %d, %t)", nid[0:7], rIP, vxlanID, isLocal) n := d.network(nid) if n == nil || !n.secure { @@ -100,7 +100,7 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal } return false }); err != nil { - log.Warnf("Failed to retrieve list of participating nodes in overlay network %s: %v", nid[0:5], err) + logrus.Warnf("Failed to retrieve list of participating nodes in overlay network %s: %v", nid[0:5], err) } default: if len(d.network(nid).endpoints) > 0 { @@ -108,18 +108,18 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal } } - log.Debugf("List of nodes: %s", nodes) + logrus.Debugf("List of nodes: %s", nodes) if add { for _, rIP := range nodes { if err := setupEncryption(lIP, aIP, rIP, vxlanID, d.secMap, d.keys); err != nil { - log.Warnf("Failed to program network encryption between %s and %s: %v", lIP, rIP, err) + logrus.Warnf("Failed to program network encryption between %s and %s: %v", lIP, rIP, err) } } } else { if len(nodes) == 0 { if err := removeEncryption(lIP, rIP, d.secMap); err != nil { - log.Warnf("Failed to remove network encryption between %s and %s: %v", lIP, rIP, err) + logrus.Warnf("Failed to remove network encryption between %s and %s: %v", lIP, rIP, err) } } } @@ -128,14 +128,14 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal } func setupEncryption(localIP, advIP, remoteIP net.IP, vni uint32, em *encrMap, keys []*key) error { - log.Debugf("Programming encryption for vxlan %d between %s and %s", vni, localIP, remoteIP) + logrus.Debugf("Programming encryption for vxlan %d between %s and %s", vni, localIP, remoteIP) rIPs := remoteIP.String() indices := make([]*spi, 0, len(keys)) err := programMangle(vni, true) if err != nil { - log.Warn(err) + logrus.Warn(err) } for i, k := range keys { @@ -146,7 +146,7 @@ func setupEncryption(localIP, advIP, remoteIP net.IP, vni uint32, em *encrMap, k } fSA, rSA, err := programSA(localIP, remoteIP, spis, k, dir, true) if err != nil { - log.Warn(err) + logrus.Warn(err) } indices = append(indices, spis) if i != 0 { @@ -154,7 +154,7 @@ func setupEncryption(localIP, advIP, remoteIP net.IP, vni uint32, em *encrMap, k } err = programSP(fSA, rSA, true) if err != nil { - log.Warn(err) + logrus.Warn(err) } } @@ -179,14 +179,14 @@ func removeEncryption(localIP, remoteIP net.IP, em *encrMap) error { } fSA, rSA, err := programSA(localIP, remoteIP, idxs, nil, dir, false) if err != nil { - log.Warn(err) + logrus.Warn(err) } if i != 0 { continue } err = programSP(fSA, rSA, false) if err != nil { - log.Warn(err) + logrus.Warn(err) } } return nil @@ -213,7 +213,7 @@ func programMangle(vni uint32, add bool) (err error) { } if err = iptables.RawCombinedOutput(append([]string{"-t", string(iptables.Mangle), a, chain}, rule...)...); err != nil { - log.Warnf("could not %s mangle rule: %v", action, err) + logrus.Warnf("could not %s mangle rule: %v", action, err) } return @@ -248,9 +248,9 @@ func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (f } if add != exists { - log.Debugf("%s: rSA{%s}", action, rSA) + logrus.Debugf("%s: rSA{%s}", action, rSA) if err := xfrmProgram(rSA); err != nil { - log.Warnf("Failed %s rSA{%s}: %v", action, rSA, err) + logrus.Warnf("Failed %s rSA{%s}: %v", action, rSA, err) } } } @@ -273,9 +273,9 @@ func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (f } if add != exists { - log.Debugf("%s fSA{%s}", action, fSA) + logrus.Debugf("%s fSA{%s}", action, fSA) if err := xfrmProgram(fSA); err != nil { - log.Warnf("Failed %s fSA{%s}: %v.", action, fSA, err) + logrus.Warnf("Failed %s fSA{%s}: %v.", action, fSA, err) } } } @@ -319,9 +319,9 @@ func programSP(fSA *netlink.XfrmState, rSA *netlink.XfrmState, add bool) error { } if add != exists { - log.Debugf("%s fSP{%s}", action, fPol) + logrus.Debugf("%s fSP{%s}", action, fPol) if err := xfrmProgram(fPol); err != nil { - log.Warnf("%s fSP{%s}: %v", action, fPol, err) + logrus.Warnf("%s fSP{%s}: %v", action, fPol, err) } } @@ -337,7 +337,7 @@ func saExists(sa *netlink.XfrmState) (bool, error) { return false, nil default: err = fmt.Errorf("Error while checking for SA existence: %v", err) - log.Warn(err) + logrus.Warn(err) return false, err } } @@ -351,7 +351,7 @@ func spExists(sp *netlink.XfrmPolicy) (bool, error) { return false, nil default: err = fmt.Errorf("Error while checking for SP existence: %v", err) - log.Warn(err) + logrus.Warn(err) return false, err } } @@ -397,16 +397,16 @@ func (d *driver) setKeys(keys []*key) error { d.keys = keys d.secMap = &encrMap{nodes: map[string][]*spi{}} d.Unlock() - log.Debugf("Initial encryption keys: %v", d.keys) + logrus.Debugf("Initial encryption keys: %v", d.keys) return nil } // updateKeys allows to add a new key and/or change the primary key and/or prune an existing key // The primary key is the key used in transmission and will go in first position in the list. func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { - log.Debugf("Updating Keys. New: %v, Primary: %v, Pruned: %v", newKey, primary, pruneKey) + logrus.Debugf("Updating Keys. New: %v, Primary: %v, Pruned: %v", newKey, primary, pruneKey) - log.Debugf("Current: %v", d.keys) + logrus.Debugf("Current: %v", d.keys) var ( newIdx = -1 @@ -459,7 +459,7 @@ func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { } d.Unlock() - log.Debugf("Updated: %v", d.keys) + logrus.Debugf("Updated: %v", d.keys) return nil } @@ -472,10 +472,10 @@ func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { // Spis and keys are sorted in such away the one in position 0 is the primary func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, delIdx int) []*spi { - log.Debugf("Updating keys for node: %s (%d,%d,%d)", rIP, newIdx, priIdx, delIdx) + logrus.Debugf("Updating keys for node: %s (%d,%d,%d)", rIP, newIdx, priIdx, delIdx) spis := idxs - log.Debugf("Current: %v", spis) + logrus.Debugf("Current: %v", spis) // add new if newIdx != -1 { @@ -520,9 +520,9 @@ func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, }, }, } - log.Debugf("Updating fSP{%s}", fSP1) + logrus.Debugf("Updating fSP{%s}", fSP1) if err := ns.NlHandle().XfrmPolicyUpdate(fSP1); err != nil { - log.Warnf("Failed to update fSP{%s}: %v", fSP1, err) + logrus.Warnf("Failed to update fSP{%s}: %v", fSP1, err) } // -fSA1 @@ -543,7 +543,7 @@ func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, spis = append(spis[:delIdx], spis[delIdx+1:]...) } - log.Debugf("Updated: %v", spis) + logrus.Debugf("Updated: %v", spis) return spis } diff --git a/drivers/overlay/joinleave.go b/drivers/overlay/joinleave.go index d01c0fa6fd..26743a12fa 100644 --- a/drivers/overlay/joinleave.go +++ b/drivers/overlay/joinleave.go @@ -5,7 +5,7 @@ import ( "net" "syscall" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/ns" "github.com/docker/libnetwork/types" @@ -109,7 +109,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, continue } if err := jinfo.AddStaticRoute(sub.subnetIP, types.NEXTHOP, s.gwIP.IP); err != nil { - log.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id) + logrus.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id) } } @@ -124,7 +124,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, net.ParseIP(d.advertiseAddress), true) if err := d.checkEncryption(nid, nil, n.vxlanID(s), true, true); err != nil { - log.Warn(err) + logrus.Warn(err) } buf, err := proto.Marshal(&PeerRecord{ @@ -137,7 +137,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, } if err := jinfo.AddTableEntry(ovPeerTable, eid, buf); err != nil { - log.Errorf("overlay: Failed adding table entry to joininfo: %v", err) + logrus.Errorf("overlay: Failed adding table entry to joininfo: %v", err) } d.pushLocalEndpointEvent("join", nid, eid) @@ -147,7 +147,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { if tableName != ovPeerTable { - log.Errorf("Unexpected table notification for table %s received", tableName) + logrus.Errorf("Unexpected table notification for table %s received", tableName) return } @@ -155,7 +155,7 @@ func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key stri var peer PeerRecord if err := proto.Unmarshal(value, &peer); err != nil { - log.Errorf("Failed to unmarshal peer record: %v", err) + logrus.Errorf("Failed to unmarshal peer record: %v", err) return } @@ -167,19 +167,19 @@ func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key stri addr, err := types.ParseCIDR(peer.EndpointIP) if err != nil { - log.Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP) + logrus.Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP) return } mac, err := net.ParseMAC(peer.EndpointMAC) if err != nil { - log.Errorf("Invalid mac %s received in event notify", peer.EndpointMAC) + logrus.Errorf("Invalid mac %s received in event notify", peer.EndpointMAC) return } vtep := net.ParseIP(peer.TunnelEndpointIP) if vtep == nil { - log.Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP) + logrus.Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP) return } @@ -219,7 +219,7 @@ func (d *driver) Leave(nid, eid string) error { n.leaveSandbox() if err := d.checkEncryption(nid, nil, 0, true, false); err != nil { - log.Warn(err) + logrus.Warn(err) } return nil diff --git a/drivers/overlay/ov_endpoint.go b/drivers/overlay/ov_endpoint.go index 7dcc530119..1906ed35f8 100644 --- a/drivers/overlay/ov_endpoint.go +++ b/drivers/overlay/ov_endpoint.go @@ -5,7 +5,7 @@ import ( "fmt" "net" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/netutils" @@ -116,7 +116,7 @@ func (d *driver) DeleteEndpoint(nid, eid string) error { n.deleteEndpoint(eid) if err := d.deleteEndpointFromStore(ep); err != nil { - log.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err) + logrus.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err) } if ep.ifName == "" { @@ -125,11 +125,11 @@ func (d *driver) DeleteEndpoint(nid, eid string) error { link, err := nlh.LinkByName(ep.ifName) if err != nil { - log.Debugf("Failed to retrieve interface (%s)'s link on endpoint (%s) delete: %v", ep.ifName, ep.id, err) + logrus.Debugf("Failed to retrieve interface (%s)'s link on endpoint (%s) delete: %v", ep.ifName, ep.id, err) return nil } if err := nlh.LinkDel(link); err != nil { - log.Debugf("Failed to delete interface (%s)'s link on endpoint (%s) delete: %v", ep.ifName, ep.id, err) + logrus.Debugf("Failed to delete interface (%s)'s link on endpoint (%s) delete: %v", ep.ifName, ep.id, err) } return nil diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index 492f7f4254..c1c87461a7 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -111,7 +111,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { // Endpoints are stored in the local store. Restore them and reconstruct the overlay sandbox func (d *driver) restoreEndpoints() error { if d.localStore == nil { - logrus.Warnf("Cannot restore overlay endpoints because local datastore is missing") + logrus.Warn("Cannot restore overlay endpoints because local datastore is missing") return nil } kvol, err := d.localStore.List(datastore.Key(overlayEndpointPrefix), &endpoint{}) diff --git a/drivers/overlay/peerdb.go b/drivers/overlay/peerdb.go index 517909a816..87fc2d107b 100644 --- a/drivers/overlay/peerdb.go +++ b/drivers/overlay/peerdb.go @@ -6,7 +6,7 @@ import ( "sync" "syscall" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" ) const ovPeerTable = "overlay_peer_table" @@ -90,7 +90,7 @@ func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool for pKeyStr, pEntry := range pMap.mp { var pKey peerKey if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil { - log.Warnf("Peer key scan on network %s failed: %v", nid, err) + logrus.Warnf("Peer key scan on network %s failed: %v", nid, err) } if f(&pKey, &pEntry) { @@ -289,7 +289,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, } if err := d.checkEncryption(nid, vtep, n.vxlanID(s), false, true); err != nil { - log.Warn(err) + logrus.Warn(err) } // Add neighbor entry for the peer IP @@ -349,7 +349,7 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMas } if err := d.checkEncryption(nid, vtep, 0, false, false); err != nil { - log.Warn(err) + logrus.Warn(err) } return nil diff --git a/drivers/remote/driver.go b/drivers/remote/driver.go index 3452eb9db1..04be60124f 100644 --- a/drivers/remote/driver.go +++ b/drivers/remote/driver.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/plugins" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" @@ -39,11 +39,11 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { d := newDriver(name, client) c, err := d.(*driver).getCapabilities() if err != nil { - log.Errorf("error getting capability for %s due to %v", name, err) + logrus.Errorf("error getting capability for %s due to %v", name, err) return } if err = dc.RegisterDriver(name, d, *c); err != nil { - log.Errorf("error registering driver for %s due to %v", name, err) + logrus.Errorf("error registering driver for %s due to %v", name, err) } }) return nil diff --git a/drivers/solaris/bridge/bridge.go b/drivers/solaris/bridge/bridge.go index c3a87de042..82d0e8c44c 100644 --- a/drivers/solaris/bridge/bridge.go +++ b/drivers/solaris/bridge/bridge.go @@ -390,7 +390,7 @@ func bridgeSetup(config *networkConfiguration) error { "/usr/bin/grep " + config.DefaultBindingIP.String() out, err := exec.Command("/usr/bin/bash", "-c", ipadmCmd).Output() if err != nil { - logrus.Warnf("cannot find binding interface") + logrus.Warn("cannot find binding interface") return err } bindingIntf = strings.SplitN(string(out), "/", 2)[0] @@ -456,21 +456,21 @@ func bridgeCleanup(config *networkConfiguration, logErr bool) { err = exec.Command("/usr/sbin/pfctl", "-a", pfAnchor, "-F", "all").Run() if err != nil && logErr { - logrus.Warnf("cannot flush firewall rules") + logrus.Warn("cannot flush firewall rules") } err = exec.Command("/usr/sbin/ifconfig", gwName, "unplumb").Run() if err != nil && logErr { - logrus.Warnf("cannot remove gateway interface") + logrus.Warn("cannot remove gateway interface") } err = exec.Command("/usr/sbin/dladm", "delete-vnic", "-t", gwName).Run() if err != nil && logErr { - logrus.Warnf("cannot delete vnic") + logrus.Warn("cannot delete vnic") } err = exec.Command("/usr/sbin/dladm", "delete-etherstub", "-t", config.BridgeNameInternal).Run() if err != nil && logErr { - logrus.Warnf("cannot delete etherstub") + logrus.Warn("cannot delete etherstub") } err = exec.Command("/usr/sbin/pfctl", "-a", tableAnchor, "-t", tableName, "-T", "delete", gwIP).Run() if err != nil && logErr { diff --git a/drivers/solaris/bridge/port_mapping.go b/drivers/solaris/bridge/port_mapping.go index 38162c7592..1cf22c13c9 100644 --- a/drivers/solaris/bridge/port_mapping.go +++ b/drivers/solaris/bridge/port_mapping.go @@ -36,7 +36,7 @@ func addPFRules(epid, bindIntf string, bs []types.PortBinding) { f, err := os.OpenFile(fname, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) if err != nil { - logrus.Warnf("cannot open temp pf file") + logrus.Warn("cannot open temp pf file") return } for _, b := range bs { diff --git a/drivers/solaris/overlay/encryption.go b/drivers/solaris/overlay/encryption.go index 932fdbb000..ca7b60b4c7 100644 --- a/drivers/solaris/overlay/encryption.go +++ b/drivers/solaris/overlay/encryption.go @@ -9,7 +9,7 @@ import ( "net" "sync" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/types" ) @@ -71,7 +71,7 @@ func (e *encrMap) String() string { } func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal, add bool) error { - log.Debugf("checkEncryption(%s, %v, %d, %t)", nid[0:7], rIP, vxlanID, isLocal) + logrus.Debugf("checkEncryption(%s, %v, %d, %t)", nid[0:7], rIP, vxlanID, isLocal) n := d.network(nid) if n == nil || !n.secure { @@ -94,7 +94,7 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal } return false }); err != nil { - log.Warnf("Failed to retrieve list of participating nodes in overlay network %s: %v", nid[0:5], err) + logrus.Warnf("Failed to retrieve list of participating nodes in overlay network %s: %v", nid[0:5], err) } default: if len(d.network(nid).endpoints) > 0 { @@ -102,18 +102,18 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal } } - log.Debugf("List of nodes: %s", nodes) + logrus.Debugf("List of nodes: %s", nodes) if add { for _, rIP := range nodes { if err := setupEncryption(lIP, aIP, rIP, vxlanID, d.secMap, d.keys); err != nil { - log.Warnf("Failed to program network encryption between %s and %s: %v", lIP, rIP, err) + logrus.Warnf("Failed to program network encryption between %s and %s: %v", lIP, rIP, err) } } } else { if len(nodes) == 0 { if err := removeEncryption(lIP, rIP, d.secMap); err != nil { - log.Warnf("Failed to remove network encryption between %s and %s: %v", lIP, rIP, err) + logrus.Warnf("Failed to remove network encryption between %s and %s: %v", lIP, rIP, err) } } } @@ -122,14 +122,14 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal } func setupEncryption(localIP, advIP, remoteIP net.IP, vni uint32, em *encrMap, keys []*key) error { - log.Debugf("Programming encryption for vxlan %d between %s and %s", vni, localIP, remoteIP) + logrus.Debugf("Programming encryption for vxlan %d between %s and %s", vni, localIP, remoteIP) rIPs := remoteIP.String() indices := make([]*spi, 0, len(keys)) err := programMangle(vni, true) if err != nil { - log.Warn(err) + logrus.Warn(err) } em.Lock() @@ -177,16 +177,16 @@ func (d *driver) setKeys(keys []*key) error { return types.ForbiddenErrorf("initial keys are already present") } d.keys = keys - log.Debugf("Initial encryption keys: %v", d.keys) + logrus.Debugf("Initial encryption keys: %v", d.keys) return nil } // updateKeys allows to add a new key and/or change the primary key and/or prune an existing key // The primary key is the key used in transmission and will go in first position in the list. func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { - log.Debugf("Updating Keys. New: %v, Primary: %v, Pruned: %v", newKey, primary, pruneKey) + logrus.Debugf("Updating Keys. New: %v, Primary: %v, Pruned: %v", newKey, primary, pruneKey) - log.Debugf("Current: %v", d.keys) + logrus.Debugf("Current: %v", d.keys) var ( newIdx = -1 @@ -216,7 +216,7 @@ func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { (pruneKey != nil && delIdx == -1) { err := types.BadRequestErrorf("cannot find proper key indices while processing key update:"+ "(newIdx,priIdx,delIdx):(%d, %d, %d)", newIdx, priIdx, delIdx) - log.Warn(err) + logrus.Warn(err) return err } @@ -241,7 +241,7 @@ func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { } d.Unlock() - log.Debugf("Updated: %v", d.keys) + logrus.Debugf("Updated: %v", d.keys) return nil } @@ -254,7 +254,7 @@ func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { // Spis and keys are sorted in such away the one in position 0 is the primary func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, delIdx int) []*spi { - log.Debugf("Updating keys for node: %s (%d,%d,%d)", rIP, newIdx, priIdx, delIdx) + logrus.Debugf("Updating keys for node: %s (%d,%d,%d)", rIP, newIdx, priIdx, delIdx) return nil } diff --git a/drivers/solaris/overlay/joinleave.go b/drivers/solaris/overlay/joinleave.go index 78656391a5..f213b1fe7c 100644 --- a/drivers/solaris/overlay/joinleave.go +++ b/drivers/solaris/overlay/joinleave.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/types" "github.com/gogo/protobuf/proto" @@ -67,7 +67,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, continue } if err := jinfo.AddStaticRoute(sub.subnetIP, types.NEXTHOP, s.gwIP.IP); err != nil { - log.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id) + logrus.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id) } } @@ -82,7 +82,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, net.ParseIP(d.advertiseAddress), true) if err := d.checkEncryption(nid, nil, n.vxlanID(s), true, true); err != nil { - log.Warn(err) + logrus.Warn(err) } buf, err := proto.Marshal(&PeerRecord{ @@ -95,7 +95,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, } if err := jinfo.AddTableEntry(ovPeerTable, eid, buf); err != nil { - log.Errorf("overlay: Failed adding table entry to joininfo: %v", err) + logrus.Errorf("overlay: Failed adding table entry to joininfo: %v", err) } d.pushLocalEndpointEvent("join", nid, eid) @@ -105,7 +105,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { if tableName != ovPeerTable { - log.Errorf("Unexpected table notification for table %s received", tableName) + logrus.Errorf("Unexpected table notification for table %s received", tableName) return } @@ -113,7 +113,7 @@ func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key stri var peer PeerRecord if err := proto.Unmarshal(value, &peer); err != nil { - log.Errorf("Failed to unmarshal peer record: %v", err) + logrus.Errorf("Failed to unmarshal peer record: %v", err) return } @@ -125,19 +125,19 @@ func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key stri addr, err := types.ParseCIDR(peer.EndpointIP) if err != nil { - log.Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP) + logrus.Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP) return } mac, err := net.ParseMAC(peer.EndpointMAC) if err != nil { - log.Errorf("Invalid mac %s received in event notify", peer.EndpointMAC) + logrus.Errorf("Invalid mac %s received in event notify", peer.EndpointMAC) return } vtep := net.ParseIP(peer.TunnelEndpointIP) if vtep == nil { - log.Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP) + logrus.Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP) return } @@ -177,7 +177,7 @@ func (d *driver) Leave(nid, eid string) error { n.leaveSandbox() if err := d.checkEncryption(nid, nil, 0, true, false); err != nil { - log.Warn(err) + logrus.Warn(err) } return nil diff --git a/drivers/solaris/overlay/ov_endpoint.go b/drivers/solaris/overlay/ov_endpoint.go index 4b2431dc71..471cc38896 100644 --- a/drivers/solaris/overlay/ov_endpoint.go +++ b/drivers/solaris/overlay/ov_endpoint.go @@ -5,7 +5,7 @@ import ( "fmt" "net" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/netutils" @@ -113,7 +113,7 @@ func (d *driver) DeleteEndpoint(nid, eid string) error { n.deleteEndpoint(eid) if err := d.deleteEndpointFromStore(ep); err != nil { - log.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err) + logrus.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err) } if ep.ifName == "" { diff --git a/drivers/solaris/overlay/peerdb.go b/drivers/solaris/overlay/peerdb.go index 7c57517917..6d17067f72 100644 --- a/drivers/solaris/overlay/peerdb.go +++ b/drivers/solaris/overlay/peerdb.go @@ -5,7 +5,7 @@ import ( "net" "sync" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" ) const ovPeerTable = "overlay_peer_table" @@ -89,7 +89,7 @@ func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool for pKeyStr, pEntry := range pMap.mp { var pKey peerKey if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil { - log.Warnf("Peer key scan on network %s failed: %v", nid, err) + logrus.Warnf("Peer key scan on network %s failed: %v", nid, err) } if f(&pKey, &pEntry) { @@ -275,7 +275,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, } if err := d.checkEncryption(nid, vtep, n.vxlanID(s), false, true); err != nil { - log.Warn(err) + logrus.Warn(err) } // Add neighbor entry for the peer IP @@ -320,7 +320,7 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMas } if err := d.checkEncryption(nid, vtep, 0, false, false); err != nil { - log.Warn(err) + logrus.Warn(err) } return nil diff --git a/drivers/windows/overlay/peerdb_windows.go b/drivers/windows/overlay/peerdb_windows.go index 4937539d45..47f4bfbcc4 100644 --- a/drivers/windows/overlay/peerdb_windows.go +++ b/drivers/windows/overlay/peerdb_windows.go @@ -6,7 +6,7 @@ import ( "encoding/json" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/Microsoft/hcsshim" "github.com/docker/libnetwork/types" @@ -44,7 +44,7 @@ func (d *driver) pushLocalDb() { func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { - log.Debugf("WINOVERLAY: Enter peerAdd for ca ip %s with ca mac %s", peerIP.String(), peerMac.String()) + logrus.Debugf("WINOVERLAY: Enter peerAdd for ca ip %s with ca mac %s", peerIP.String(), peerMac.String()) if err := validateID(nid, eid); err != nil { return err @@ -56,7 +56,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, } if updateDb { - log.Info("WINOVERLAY: peerAdd: notifying HNS of the REMOTE endpoint") + logrus.Info("WINOVERLAY: peerAdd: notifying HNS of the REMOTE endpoint") hnsEndpoint := &hcsshim.HNSEndpoint{ VirtualNetwork: n.hnsId, @@ -121,7 +121,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { - log.Infof("WINOVERLAY: Enter peerDelete for endpoint %s and peer ip %s", eid, peerIP.String()) + logrus.Infof("WINOVERLAY: Enter peerDelete for endpoint %s and peer ip %s", eid, peerIP.String()) if err := validateID(nid, eid); err != nil { return err @@ -146,7 +146,7 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMas n.deleteEndpoint(eid) if err := d.deleteEndpointFromStore(ep); err != nil { - log.Debugf("Failed to delete stale overlay endpoint (%s) from store", ep.id[0:7]) + logrus.Debugf("Failed to delete stale overlay endpoint (%s) from store", ep.id[0:7]) } } diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index 0165814118..a53aad26af 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -20,7 +20,7 @@ import ( "sync" "github.com/Microsoft/hcsshim" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" "github.com/docker/libnetwork/driverapi" @@ -271,7 +271,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d } configuration := string(configurationb) - log.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets) + logrus.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets) hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration) if err != nil { diff --git a/endpoint.go b/endpoint.go index 4fbe81b409..ad6ddd5571 100644 --- a/endpoint.go +++ b/endpoint.go @@ -8,7 +8,7 @@ import ( "strings" "sync" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/netlabel" @@ -142,12 +142,12 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) { bytes, err := json.Marshal(tmp) if err != nil { - log.Error(err) + logrus.Error(err) break } err = json.Unmarshal(bytes, &pb) if err != nil { - log.Error(err) + logrus.Error(err) break } pblist = append(pblist, pb) @@ -164,12 +164,12 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) { bytes, err := json.Marshal(tmp) if err != nil { - log.Error(err) + logrus.Error(err) break } err = json.Unmarshal(bytes, &tp) if err != nil { - log.Error(err) + logrus.Error(err) break } tplist = append(tplist, tp) @@ -472,7 +472,7 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { defer func() { if err != nil { if err := d.Leave(nid, epid); err != nil { - log.Warnf("driver leave failed while rolling back join: %v", err) + logrus.Warnf("driver leave failed while rolling back join: %v", err) } } }() @@ -523,7 +523,7 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { if moveExtConn { if extEp != nil { - log.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) + logrus.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) extN, err := extEp.getNetworkFromStore() if err != nil { return fmt.Errorf("failed to get network from store during join: %v", err) @@ -540,14 +540,14 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { defer func() { if err != nil { if e := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil { - log.Warnf("Failed to roll-back external connectivity on endpoint %s (%s): %v", + logrus.Warnf("Failed to roll-back external connectivity on endpoint %s (%s): %v", extEp.Name(), extEp.ID(), e) } } }() } if !n.internal { - log.Debugf("Programming external connectivity on endpoint %s (%s)", ep.Name(), ep.ID()) + logrus.Debugf("Programming external connectivity on endpoint %s (%s)", ep.Name(), ep.ID()) if err = d.ProgramExternalConnectivity(n.ID(), ep.ID(), sb.Labels()); err != nil { return types.InternalErrorf( "driver failed programming external connectivity on endpoint %s (%s): %v", @@ -559,7 +559,7 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { if !sb.needDefaultGW() { if err := sb.clearDefaultGW(); err != nil { - log.Warnf("Failure while disconnecting sandbox %s (%s) from gateway network: %v", + logrus.Warnf("Failure while disconnecting sandbox %s (%s) from gateway network: %v", sb.ID(), sb.ContainerID(), err) } } @@ -682,22 +682,22 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) if d != nil { if moveExtConn { - log.Debugf("Revoking external connectivity on endpoint %s (%s)", ep.Name(), ep.ID()) + logrus.Debugf("Revoking external connectivity on endpoint %s (%s)", ep.Name(), ep.ID()) if err := d.RevokeExternalConnectivity(n.id, ep.id); err != nil { - log.Warnf("driver failed revoking external connectivity on endpoint %s (%s): %v", + logrus.Warnf("driver failed revoking external connectivity on endpoint %s (%s): %v", ep.Name(), ep.ID(), err) } } if err := d.Leave(n.id, ep.id); err != nil { if _, ok := err.(types.MaskableError); !ok { - log.Warnf("driver error disconnecting container %s : %v", ep.name, err) + logrus.Warnf("driver error disconnecting container %s : %v", ep.name, err) } } } if err := sb.clearNetworkResources(ep); err != nil { - log.Warnf("Could not cleanup network resources on container %s disconnect: %v", ep.name, err) + logrus.Warnf("Could not cleanup network resources on container %s disconnect: %v", ep.name, err) } // Update the store about the sandbox detach only after we @@ -710,7 +710,7 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) } if e := ep.deleteFromCluster(); e != nil { - log.Errorf("Could not delete state for endpoint %s from cluster: %v", ep.Name(), e) + logrus.Errorf("Could not delete state for endpoint %s from cluster: %v", ep.Name(), e) } sb.deleteHostsEntries(n.getSvcRecords(ep)) @@ -721,7 +721,7 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) // New endpoint providing external connectivity for the sandbox extEp = sb.getGatewayEndpoint() if moveExtConn && extEp != nil { - log.Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) + logrus.Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) extN, err := extEp.getNetworkFromStore() if err != nil { return fmt.Errorf("failed to get network from store during leave: %v", err) @@ -731,14 +731,14 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) return fmt.Errorf("failed to leave endpoint: %v", err) } if err := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil { - log.Warnf("driver failed programming external connectivity on endpoint %s: (%s) %v", + logrus.Warnf("driver failed programming external connectivity on endpoint %s: (%s) %v", extEp.Name(), extEp.ID(), err) } } if !sb.needDefaultGW() { if err := sb.clearDefaultGW(); err != nil { - log.Warnf("Failure while disconnecting sandbox %s (%s) from gateway network: %v", + logrus.Warnf("Failure while disconnecting sandbox %s (%s) from gateway network: %v", sb.ID(), sb.ContainerID(), err) } } @@ -771,7 +771,7 @@ func (ep *endpoint) Delete(force bool) error { if sb != nil { if e := ep.sbLeave(sb.(*sandbox), force); e != nil { - log.Warnf("failed to leave sandbox for endpoint %s : %v", name, e) + logrus.Warnf("failed to leave sandbox for endpoint %s : %v", name, e) } } @@ -783,7 +783,7 @@ func (ep *endpoint) Delete(force bool) error { if err != nil && !force { ep.dbExists = false if e := n.getController().updateToStore(ep); e != nil { - log.Warnf("failed to recreate endpoint in store %s : %v", name, e) + logrus.Warnf("failed to recreate endpoint in store %s : %v", name, e) } } }() @@ -798,7 +798,7 @@ func (ep *endpoint) Delete(force bool) error { ep.releaseAddress() if err := n.getEpCnt().DecEndpointCnt(); err != nil { - log.Warnf("failed to decrement endpoint count for ep %s: %v", ep.ID(), err) + logrus.Warnf("failed to decrement endpoint count for ep %s: %v", ep.ID(), err) } return nil @@ -826,7 +826,7 @@ func (ep *endpoint) deleteEndpoint(force bool) error { } if _, ok := err.(types.MaskableError); !ok { - log.Warnf("driver error deleting endpoint %s : %v", name, err) + logrus.Warnf("driver error deleting endpoint %s : %v", name, err) } } @@ -976,7 +976,7 @@ func JoinOptionPriority(ep Endpoint, prio int) EndpointOption { sb, ok := c.sandboxes[ep.sandboxID] c.Unlock() if !ok { - log.Errorf("Could not set endpoint priority value during Join to endpoint %s: No sandbox id present in endpoint", ep.id) + logrus.Errorf("Could not set endpoint priority value during Join to endpoint %s: No sandbox id present in endpoint", ep.id) return } sb.epPriority[ep.id] = prio @@ -995,7 +995,7 @@ func (ep *endpoint) assignAddress(ipam ipamapi.Ipam, assignIPv4, assignIPv6 bool return nil } - log.Debugf("Assigning addresses for endpoint %s's interface on network %s", ep.Name(), n.Name()) + logrus.Debugf("Assigning addresses for endpoint %s's interface on network %s", ep.Name(), n.Name()) if assignIPv4 { if err = ep.assignAddressVersion(4, ipam); err != nil { @@ -1075,23 +1075,23 @@ func (ep *endpoint) releaseAddress() { return } - log.Debugf("Releasing addresses for endpoint %s's interface on network %s", ep.Name(), n.Name()) + logrus.Debugf("Releasing addresses for endpoint %s's interface on network %s", ep.Name(), n.Name()) ipam, _, err := n.getController().getIPAMDriver(n.ipamType) if err != nil { - log.Warnf("Failed to retrieve ipam driver to release interface address on delete of endpoint %s (%s): %v", ep.Name(), ep.ID(), err) + logrus.Warnf("Failed to retrieve ipam driver to release interface address on delete of endpoint %s (%s): %v", ep.Name(), ep.ID(), err) return } if ep.iface.addr != nil { if err := ipam.ReleaseAddress(ep.iface.v4PoolID, ep.iface.addr.IP); err != nil { - log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addr.IP, ep.Name(), ep.ID(), err) + logrus.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addr.IP, ep.Name(), ep.ID(), err) } } if ep.iface.addrv6 != nil && ep.iface.addrv6.IP.IsGlobalUnicast() { if err := ipam.ReleaseAddress(ep.iface.v6PoolID, ep.iface.addrv6.IP); err != nil { - log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addrv6.IP, ep.Name(), ep.ID(), err) + logrus.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addrv6.IP, ep.Name(), ep.ID(), err) } } } @@ -1106,14 +1106,14 @@ func (c *controller) cleanupLocalEndpoints() { } nl, err := c.getNetworksForScope(datastore.LocalScope) if err != nil { - log.Warnf("Could not get list of networks during endpoint cleanup: %v", err) + logrus.Warnf("Could not get list of networks during endpoint cleanup: %v", err) return } for _, n := range nl { epl, err := n.getEndpointsFromStore() if err != nil { - log.Warnf("Could not get list of endpoints in network %s during endpoint cleanup: %v", n.name, err) + logrus.Warnf("Could not get list of endpoints in network %s during endpoint cleanup: %v", n.name, err) continue } @@ -1121,21 +1121,21 @@ func (c *controller) cleanupLocalEndpoints() { if _, ok := eps[ep.id]; ok { continue } - log.Infof("Removing stale endpoint %s (%s)", ep.name, ep.id) + logrus.Infof("Removing stale endpoint %s (%s)", ep.name, ep.id) if err := ep.Delete(true); err != nil { - log.Warnf("Could not delete local endpoint %s during endpoint cleanup: %v", ep.name, err) + logrus.Warnf("Could not delete local endpoint %s during endpoint cleanup: %v", ep.name, err) } } epl, err = n.getEndpointsFromStore() if err != nil { - log.Warnf("Could not get list of endpoints in network %s for count update: %v", n.name, err) + logrus.Warnf("Could not get list of endpoints in network %s for count update: %v", n.name, err) continue } epCnt := n.getEpCnt().EndpointCnt() if epCnt != uint64(len(epl)) { - log.Infof("Fixing inconsistent endpoint_cnt for network %s. Expected=%d, Actual=%d", n.name, len(epl), epCnt) + logrus.Infof("Fixing inconsistent endpoint_cnt for network %s. Expected=%d, Actual=%d", n.name, len(epl), epCnt) n.getEpCnt().setCnt(uint64(len(epl))) } } diff --git a/hostdiscovery/hostdiscovery.go b/hostdiscovery/hostdiscovery.go index 3fe2a64a17..a45ecb60a3 100644 --- a/hostdiscovery/hostdiscovery.go +++ b/hostdiscovery/hostdiscovery.go @@ -4,7 +4,7 @@ import ( "net" "sync" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" mapset "github.com/deckarep/golang-set" "github.com/docker/docker/pkg/discovery" @@ -54,7 +54,7 @@ func (h *hostDiscovery) monitorDiscovery(ch <-chan discovery.Entries, errCh <-ch h.processCallback(entries, activeCallback, joinCallback, leaveCallback) case err := <-errCh: if err != nil { - log.Errorf("discovery error: %v", err) + logrus.Errorf("discovery error: %v", err) } case <-h.stopChan: return diff --git a/ipam/allocator.go b/ipam/allocator.go index c259a05283..3d69bd9b4f 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -6,7 +6,7 @@ import ( "sort" "sync" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/bitseq" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" @@ -135,7 +135,7 @@ func (a *Allocator) checkConsistency(as string) { bm := a.addresses[sk] a.Unlock() if err := bm.CheckConsistency(); err != nil { - log.Warnf("Error while running consistency check for %s: %v", sk, err) + logrus.Warnf("Error while running consistency check for %s: %v", sk, err) } } } @@ -198,7 +198,7 @@ func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) { // RequestPool returns an address pool along with its unique id. func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { - log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6) + logrus.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6) k, nw, ipr, err := a.parsePoolRequest(addressSpace, pool, subPool, v6) if err != nil { @@ -227,7 +227,7 @@ retry: insert, err := aSpace.updatePoolDBOnAdd(*k, nw, ipr, pdf) if err != nil { if _, ok := err.(types.MaskableError); ok { - log.Debugf("Retrying predefined pool search: %v", err) + logrus.Debugf("Retrying predefined pool search: %v", err) goto retry } return "", nil, nil, err @@ -246,7 +246,7 @@ retry: // ReleasePool releases the address pool identified by the passed id func (a *Allocator) ReleasePool(poolID string) error { - log.Debugf("ReleasePool(%s)", poolID) + logrus.Debugf("ReleasePool(%s)", poolID) k := SubnetKey{} if err := k.FromString(poolID); err != nil { return types.BadRequestErrorf("invalid pool id: %s", poolID) @@ -322,7 +322,7 @@ func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool } func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error { - //log.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String()) + //logrus.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String()) store := a.getStore(key.AddressSpace) ipVer := getAddressVersion(pool.IP) @@ -360,7 +360,7 @@ func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, bm, ok := a.addresses[k] a.Unlock() if !ok { - log.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String()) + logrus.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String()) if err := a.insertBitMask(k, n); err != nil { return nil, types.InternalErrorf("could not find bitmask in datastore for %s", k.String()) } @@ -418,7 +418,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) // RequestAddress returns an address from the specified pool ID func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) { - log.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts) + logrus.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts) k := SubnetKey{} if err := k.FromString(poolID); err != nil { return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID) @@ -467,7 +467,7 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s // ReleaseAddress releases the address from the specified pool ID func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error { - log.Debugf("ReleaseAddress(%s, %v)", poolID, address) + logrus.Debugf("ReleaseAddress(%s, %v)", poolID, address) k := SubnetKey{} if err := k.FromString(poolID); err != nil { return types.BadRequestErrorf("invalid pool id: %s", poolID) diff --git a/ipam/store.go b/ipam/store.go index 02f627b66e..d05e1b70b9 100644 --- a/ipam/store.go +++ b/ipam/store.go @@ -3,7 +3,7 @@ package ipam import ( "encoding/json" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/types" ) @@ -26,7 +26,7 @@ func (aSpace *addrSpace) KeyPrefix() []string { func (aSpace *addrSpace) Value() []byte { b, err := json.Marshal(aSpace) if err != nil { - log.Warnf("Failed to marshal ipam configured pools: %v", err) + logrus.Warnf("Failed to marshal ipam configured pools: %v", err) return nil } return b diff --git a/ipams/remote/remote.go b/ipams/remote/remote.go index ab00fc6fe7..b23c52a6d0 100644 --- a/ipams/remote/remote.go +++ b/ipams/remote/remote.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/plugins" "github.com/docker/libnetwork/discoverapi" "github.com/docker/libnetwork/ipamapi" @@ -40,13 +40,13 @@ func Init(cb ipamapi.Callback, l, g interface{}) error { a := newAllocator(name, client) if cps, err := a.(*allocator).getCapabilities(); err == nil { if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil { - log.Errorf("error registering remote ipam driver %s due to %v", name, err) + logrus.Errorf("error registering remote ipam driver %s due to %v", name, err) } } else { - log.Infof("remote ipam driver %s does not support capabilities", name) - log.Debug(err) + logrus.Infof("remote ipam driver %s does not support capabilities", name) + logrus.Debug(err) if err := cb.RegisterIpamDriver(name, a); err != nil { - log.Errorf("error registering remote ipam driver %s due to %v", name, err) + logrus.Errorf("error registering remote ipam driver %s due to %v", name, err) } } }) diff --git a/ipams/windowsipam/windowsipam.go b/ipams/windowsipam/windowsipam.go index 5fcd7255a5..1b9cd5a983 100644 --- a/ipams/windowsipam/windowsipam.go +++ b/ipams/windowsipam/windowsipam.go @@ -3,7 +3,7 @@ package windowsipam import ( "net" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/discoverapi" "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/netlabel" @@ -39,7 +39,7 @@ func (a *allocator) GetDefaultAddressSpaces() (string, string, error) { // RequestPool returns an address pool along with its unique id. This is a null ipam driver. It allocates the // subnet user asked and does not validate anything. Doesn't support subpool allocation func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { - log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6) + logrus.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6) if subPool != "" || v6 { return "", nil, nil, types.InternalErrorf("This request is not supported by null ipam driver") } @@ -61,14 +61,14 @@ func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[ // ReleasePool releases the address pool - always succeeds func (a *allocator) ReleasePool(poolID string) error { - log.Debugf("ReleasePool(%s)", poolID) + logrus.Debugf("ReleasePool(%s)", poolID) return nil } // RequestAddress returns an address from the specified pool ID. // Always allocate the 0.0.0.0/32 ip if no preferred address was specified func (a *allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) { - log.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts) + logrus.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts) _, ipNet, err := net.ParseCIDR(poolID) if err != nil { @@ -88,7 +88,7 @@ func (a *allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s // ReleaseAddress releases the address - always succeeds func (a *allocator) ReleaseAddress(poolID string, address net.IP) error { - log.Debugf("ReleaseAddress(%s, %v)", poolID, address) + logrus.Debugf("ReleaseAddress(%s, %v)", poolID, address) return nil } diff --git a/ipvs/netlink.go b/ipvs/netlink.go index 509c288f70..26ce6cc471 100644 --- a/ipvs/netlink.go +++ b/ipvs/netlink.go @@ -64,7 +64,7 @@ func setup() { ipvsFamily, err = getIPVSFamily() if err != nil { - logrus.Errorf("Could not get ipvs family information from the kernel. It is possible that ipvs is not enabled in your kernel. Native loadbalancing will not work until this is fixed.") + logrus.Error("Could not get ipvs family information from the kernel. It is possible that ipvs is not enabled in your kernel. Native loadbalancing will not work until this is fixed.") } }) } diff --git a/libnetwork_linux_test.go b/libnetwork_linux_test.go index 37121bd8b0..ccbaccbaf2 100644 --- a/libnetwork_linux_test.go +++ b/libnetwork_linux_test.go @@ -14,7 +14,7 @@ import ( "strings" "testing" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/reexec" "github.com/docker/libnetwork" "github.com/docker/libnetwork/ipamapi" @@ -471,7 +471,7 @@ func externalKeyTest(t *testing.T, reexec bool) { } else { defer func() { if err := extOsBox.Destroy(); err != nil { - log.Warnf("Failed to remove os sandbox: %v", err) + logrus.Warnf("Failed to remove os sandbox: %v", err) } }() } diff --git a/libnetwork_test.go b/libnetwork_test.go index 4510174d8b..71a44d1784 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -10,7 +10,7 @@ import ( "sync" "testing" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/reexec" "github.com/docker/libnetwork" @@ -37,7 +37,7 @@ func TestMain(m *testing.M) { } if err := createController(); err != nil { - log.Errorf("Error creating controller: %v", err) + logrus.Errorf("Error creating controller: %v", err) os.Exit(1) } diff --git a/network.go b/network.go index a3511a5fae..d58abdcc65 100644 --- a/network.go +++ b/network.go @@ -8,7 +8,7 @@ import ( "sync" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/stringid" "github.com/docker/libnetwork/config" "github.com/docker/libnetwork/datastore" @@ -473,7 +473,7 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { if v, ok := netMap["created"]; ok { // n.created is time.Time but marshalled as string if err = n.created.UnmarshalText([]byte(v.(string))); err != nil { - log.Warnf("failed to unmarshal creation time %v: %v", v, err) + logrus.Warnf("failed to unmarshal creation time %v: %v", v, err) n.created = time.Time{} } } @@ -779,12 +779,12 @@ func (n *network) delete(force bool) error { if !force { return err } - log.Debugf("driver failed to delete stale network %s (%s): %v", n.Name(), n.ID(), err) + logrus.Debugf("driver failed to delete stale network %s (%s): %v", n.Name(), n.ID(), err) } n.ipamRelease() if err = c.updateToStore(n); err != nil { - log.Warnf("Failed to update store after ipam release for network %s (%s): %v", n.Name(), n.ID(), err) + logrus.Warnf("Failed to update store after ipam release for network %s (%s): %v", n.Name(), n.ID(), err) } // We are about to delete the network. Leave the gossip @@ -795,7 +795,7 @@ func (n *network) delete(force bool) error { // bindings cleanup requires the network in the store. n.cancelDriverWatches() if err = n.leaveCluster(); err != nil { - log.Errorf("Failed leaving network %s from the agent cluster: %v", n.Name(), err) + logrus.Errorf("Failed leaving network %s from the agent cluster: %v", n.Name(), err) } c.cleanupServiceBindings(n.ID()) @@ -807,7 +807,7 @@ func (n *network) delete(force bool) error { if !force { return fmt.Errorf("error deleting network endpoint count from store: %v", err) } - log.Debugf("Error deleting endpoint count from store for stale network %s (%s) for deletion: %v", n.Name(), n.ID(), err) + logrus.Debugf("Error deleting endpoint count from store for stale network %s (%s) for deletion: %v", n.Name(), n.ID(), err) } if err = c.deleteFromStore(n); err != nil { @@ -830,7 +830,7 @@ func (n *network) deleteNetwork() error { } if _, ok := err.(types.MaskableError); !ok { - log.Warnf("driver error deleting network %s : %v", n.name, err) + logrus.Warnf("driver error deleting network %s : %v", n.name, err) } } @@ -923,7 +923,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi defer func() { if err != nil { if e := ep.deleteEndpoint(false); e != nil { - log.Warnf("cleaning up endpoint failed %s : %v", name, e) + logrus.Warnf("cleaning up endpoint failed %s : %v", name, e) } } }() @@ -938,7 +938,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi defer func() { if err != nil { if e := n.getController().deleteFromStore(ep); e != nil { - log.Warnf("error rolling back endpoint %s from store: %v", name, e) + logrus.Warnf("error rolling back endpoint %s from store: %v", name, e) } } }() @@ -964,7 +964,7 @@ func (n *network) Endpoints() []Endpoint { endpoints, err := n.getEndpointsFromStore() if err != nil { - log.Error(err) + logrus.Error(err) } for _, ep := range endpoints { @@ -1172,7 +1172,7 @@ func (n *network) getSvcRecords(ep *endpoint) []etchosts.Record { continue } if len(ip) == 0 { - log.Warnf("Found empty list of IP addresses for service %s on network %s (%s)", h, n.name, n.id) + logrus.Warnf("Found empty list of IP addresses for service %s on network %s (%s)", h, n.name, n.id) continue } recs = append(recs, etchosts.Record{ @@ -1256,7 +1256,7 @@ func (n *network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, preferredPo // pools. defer func() { if err := ipam.ReleasePool(poolID); err != nil { - log.Warnf("Failed to release overlapping pool %s while returning from pool request helper for network %s", pool, n.Name()) + logrus.Warnf("Failed to release overlapping pool %s while returning from pool request helper for network %s", pool, n.Name()) } }() @@ -1297,7 +1297,7 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error { *infoList = make([]*IpamInfo, len(*cfgList)) - log.Debugf("Allocating IPv%d pools for network %s (%s)", ipVer, n.Name(), n.ID()) + logrus.Debugf("Allocating IPv%d pools for network %s (%s)", ipVer, n.Name(), n.ID()) for i, cfg := range *cfgList { if err = cfg.Validate(); err != nil { @@ -1315,7 +1315,7 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error { defer func() { if err != nil { if err := ipam.ReleasePool(d.PoolID); err != nil { - log.Warnf("Failed to release address pool %s after failure to create network %s (%s)", d.PoolID, n.Name(), n.ID()) + logrus.Warnf("Failed to release address pool %s after failure to create network %s (%s)", d.PoolID, n.Name(), n.ID()) } } }() @@ -1367,7 +1367,7 @@ func (n *network) ipamRelease() { } ipam, _, err := n.getController().getIPAMDriver(n.ipamType) if err != nil { - log.Warnf("Failed to retrieve ipam driver to release address pool(s) on delete of network %s (%s): %v", n.Name(), n.ID(), err) + logrus.Warnf("Failed to retrieve ipam driver to release address pool(s) on delete of network %s (%s): %v", n.Name(), n.ID(), err) return } n.ipamReleaseVersion(4, ipam) @@ -1383,7 +1383,7 @@ func (n *network) ipamReleaseVersion(ipVer int, ipam ipamapi.Ipam) { case 6: infoList = &n.ipamV6Info default: - log.Warnf("incorrect ip version passed to ipam release: %d", ipVer) + logrus.Warnf("incorrect ip version passed to ipam release: %d", ipVer) return } @@ -1391,25 +1391,25 @@ func (n *network) ipamReleaseVersion(ipVer int, ipam ipamapi.Ipam) { return } - log.Debugf("releasing IPv%d pools from network %s (%s)", ipVer, n.Name(), n.ID()) + logrus.Debugf("releasing IPv%d pools from network %s (%s)", ipVer, n.Name(), n.ID()) for _, d := range *infoList { if d.Gateway != nil { if err := ipam.ReleaseAddress(d.PoolID, d.Gateway.IP); err != nil { - log.Warnf("Failed to release gateway ip address %s on delete of network %s (%s): %v", d.Gateway.IP, n.Name(), n.ID(), err) + logrus.Warnf("Failed to release gateway ip address %s on delete of network %s (%s): %v", d.Gateway.IP, n.Name(), n.ID(), err) } } if d.IPAMData.AuxAddresses != nil { for k, nw := range d.IPAMData.AuxAddresses { if d.Pool.Contains(nw.IP) { if err := ipam.ReleaseAddress(d.PoolID, nw.IP); err != nil && err != ipamapi.ErrIPOutOfRange { - log.Warnf("Failed to release secondary ip address %s (%v) on delete of network %s (%s): %v", k, nw.IP, n.Name(), n.ID(), err) + logrus.Warnf("Failed to release secondary ip address %s (%v) on delete of network %s (%s): %v", k, nw.IP, n.Name(), n.ID(), err) } } } } if err := ipam.ReleasePool(d.PoolID); err != nil { - log.Warnf("Failed to release address pool %s on delete of network %s (%s): %v", d.PoolID, n.Name(), n.ID(), err) + logrus.Warnf("Failed to release address pool %s on delete of network %s (%s): %v", d.PoolID, n.Name(), n.ID(), err) } } @@ -1661,7 +1661,7 @@ func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) { srv := []*net.SRV{} ip := []net.IP{} - log.Debugf("Service name To resolve: %v", name) + logrus.Debugf("Service name To resolve: %v", name) // There are DNS implementaions that allow SRV queries for names not in // the format defined by RFC 2782. Hence specific validations checks are diff --git a/network_windows.go b/network_windows.go index 9d6fa7e4e4..7ae7a68798 100644 --- a/network_windows.go +++ b/network_windows.go @@ -7,7 +7,7 @@ import ( "time" "github.com/Microsoft/hcsshim" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/drivers/windows" "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/ipams/windowsipam" @@ -17,7 +17,7 @@ func executeInCompartment(compartmentID uint32, x func()) { runtime.LockOSThread() if err := hcsshim.SetCurrentThreadCompartmentId(compartmentID); err != nil { - log.Error(err) + logrus.Error(err) } defer func() { hcsshim.SetCurrentThreadCompartmentId(0) @@ -29,7 +29,7 @@ func executeInCompartment(compartmentID uint32, x func()) { func (n *network) startResolver() { n.resolverOnce.Do(func() { - log.Debugf("Launching DNS server for network", n.Name()) + logrus.Debugf("Launching DNS server for network", n.Name()) options := n.Info().DriverOptions() hnsid := options[windows.HNSID] @@ -39,7 +39,7 @@ func (n *network) startResolver() { hnsresponse, err := hcsshim.HNSNetworkRequest("GET", hnsid, "") if err != nil { - log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) + logrus.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) return } @@ -47,14 +47,14 @@ func (n *network) startResolver() { if subnet.GatewayAddress != "" { for i := 0; i < 3; i++ { resolver := NewResolver(subnet.GatewayAddress, false, "", n) - log.Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress) + logrus.Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress) executeInCompartment(hnsresponse.DNSServerCompartment, resolver.SetupFunc(53)) if err = resolver.Start(); err != nil { - log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) + logrus.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) time.Sleep(1 * time.Second) } else { - log.Debugf("Resolver bound successfuly for network %s", n.Name()) + logrus.Debugf("Resolver bound successfuly for network %s", n.Name()) n.resolver = append(n.resolver, resolver) break } diff --git a/ns/init_linux.go b/ns/init_linux.go index dd31f3e7e7..3022e8ddbf 100644 --- a/ns/init_linux.go +++ b/ns/init_linux.go @@ -8,7 +8,7 @@ import ( "sync" "syscall" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/vishvananda/netlink" "github.com/vishvananda/netns" ) @@ -24,11 +24,11 @@ func Init() { var err error initNs, err = netns.Get() if err != nil { - log.Errorf("could not get initial namespace: %v", err) + logrus.Errorf("could not get initial namespace: %v", err) } initNl, err = netlink.NewHandle(getSupportedNlFamilies()...) if err != nil { - log.Errorf("could not create netlink handle on initial namespace: %v", err) + logrus.Errorf("could not create netlink handle on initial namespace: %v", err) } } @@ -70,7 +70,7 @@ func getSupportedNlFamilies() []int { fams := []int{syscall.NETLINK_ROUTE} if err := loadXfrmModules(); err != nil { if checkXfrmSocket() != nil { - log.Warnf("Could not load necessary modules for IPSEC rules: %v", err) + logrus.Warnf("Could not load necessary modules for IPSEC rules: %v", err) return fams } } diff --git a/osl/interface_linux.go b/osl/interface_linux.go index 643939322e..48c4024b38 100644 --- a/osl/interface_linux.go +++ b/osl/interface_linux.go @@ -8,7 +8,7 @@ import ( "syscall" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/ns" "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" @@ -167,7 +167,7 @@ func (i *nwIface) Remove() error { err = nlh.LinkSetName(iface, i.SrcName()) if err != nil { - log.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err) + logrus.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err) return err } @@ -179,7 +179,7 @@ func (i *nwIface) Remove() error { } else if !isDefault { // Move the network interface to caller namespace. if err := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); err != nil { - log.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err) + logrus.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err) return err } } @@ -315,7 +315,7 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If // Up the interface. cnt := 0 for err = nlh.LinkSetUp(iface); err != nil && cnt < 3; cnt++ { - log.Debugf("retrying link setup because of: %v", err) + logrus.Debugf("retrying link setup because of: %v", err) time.Sleep(10 * time.Millisecond) err = nlh.LinkSetUp(iface) } diff --git a/osl/namespace_linux.go b/osl/namespace_linux.go index d3f88191f0..4f0d446a05 100644 --- a/osl/namespace_linux.go +++ b/osl/namespace_linux.go @@ -14,7 +14,7 @@ import ( "syscall" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/reexec" "github.com/docker/libnetwork/ns" "github.com/docker/libnetwork/types" @@ -263,10 +263,10 @@ func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) { func reexecCreateNamespace() { if len(os.Args) < 2 { - log.Fatal("no namespace path provided") + logrus.Fatal("no namespace path provided") } if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil { - log.Fatal(err) + logrus.Fatal(err) } } @@ -338,7 +338,7 @@ func (n *networkNamespace) InvokeFunc(f func()) error { func InitOSContext() func() { runtime.LockOSThread() if err := ns.SetNamespace(); err != nil { - log.Error(err) + logrus.Error(err) } return runtime.UnlockOSThread } diff --git a/resolver.go b/resolver.go index 81b3520ae2..e92c24887c 100644 --- a/resolver.go +++ b/resolver.go @@ -8,7 +8,7 @@ import ( "sync" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/types" "github.com/miekg/dns" ) @@ -219,7 +219,7 @@ func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns. if addr == nil && ipv6Miss { // Send a reply without any Answer sections - log.Debugf("Lookup name %s present without IPv6 address", name) + logrus.Debugf("Lookup name %s present without IPv6 address", name) resp := createRespMsg(query) return resp, nil } @@ -227,7 +227,7 @@ func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns. return nil, nil } - log.Debugf("Lookup for %s: IP %v", name, addr) + logrus.Debugf("Lookup for %s: IP %v", name, addr) resp := createRespMsg(query) if len(addr) > 1 { @@ -268,7 +268,7 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error) return nil, nil } - log.Debugf("Lookup for IP %s: name %s", parts[0], host) + logrus.Debugf("Lookup for IP %s: name %s", parts[0], host) fqdn := dns.Fqdn(host) resp := new(dns.Msg) @@ -352,7 +352,7 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { } if err != nil { - log.Error(err) + logrus.Error(err) return } @@ -411,10 +411,10 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { execErr := r.backend.ExecFunc(extConnect) if execErr != nil || err != nil { - log.Debugf("Connect failed, %s", err) + logrus.Debugf("Connect failed, %s", err) continue } - log.Debugf("Query %s[%d] from %s, forwarding to %s:%s", name, query.Question[0].Qtype, + logrus.Debugf("Query %s[%d] from %s, forwarding to %s:%s", name, query.Question[0].Qtype, extConn.LocalAddr().String(), proto, extDNS.ipStr) // Timeout has to be set for every IO operation. @@ -430,7 +430,7 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { old := r.tStamp r.tStamp = time.Now() if r.tStamp.Sub(old) > logInterval { - log.Errorf("More than %v concurrent queries from %s", maxConcurrent, extConn.LocalAddr().String()) + logrus.Errorf("More than %v concurrent queries from %s", maxConcurrent, extConn.LocalAddr().String()) } continue } @@ -438,7 +438,7 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { err = co.WriteMsg(query) if err != nil { r.forwardQueryEnd() - log.Debugf("Send to DNS server failed, %s", err) + logrus.Debugf("Send to DNS server failed, %s", err) continue } @@ -447,7 +447,7 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { // client can retry over TCP if err != nil && err != dns.ErrTruncated { r.forwardQueryEnd() - log.Debugf("Read from DNS server failed, %s", err) + logrus.Debugf("Read from DNS server failed, %s", err) continue } @@ -462,7 +462,7 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { } if err = w.WriteMsg(resp); err != nil { - log.Errorf("error writing resolver resp, %s", err) + logrus.Errorf("error writing resolver resp, %s", err) } } @@ -483,7 +483,7 @@ func (r *resolver) forwardQueryEnd() { defer r.queryLock.Unlock() if r.count == 0 { - log.Errorf("Invalid concurrent query count") + logrus.Error("Invalid concurrent query count") } else { r.count-- } diff --git a/resolver_unix.go b/resolver_unix.go index 17dce480d0..5fcc6b9fa9 100644 --- a/resolver_unix.go +++ b/resolver_unix.go @@ -9,7 +9,7 @@ import ( "os/exec" "runtime" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/reexec" "github.com/docker/libnetwork/iptables" "github.com/vishvananda/netns" @@ -31,7 +31,7 @@ func reexecSetupResolver() { defer runtime.UnlockOSThread() if len(os.Args) < 4 { - log.Error("invalid number of arguments..") + logrus.Error("invalid number of arguments..") os.Exit(1) } @@ -46,14 +46,14 @@ func reexecSetupResolver() { f, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0) if err != nil { - log.Errorf("failed get network namespace %q: %v", os.Args[1], err) + logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err) os.Exit(2) } defer f.Close() nsFD := f.Fd() if err = netns.Set(netns.NsHandle(nsFD)); err != nil { - log.Errorf("setting into container net ns %v failed, %v", os.Args[1], err) + logrus.Errorf("setting into container net ns %v failed, %v", os.Args[1], err) os.Exit(3) } @@ -76,7 +76,7 @@ func reexecSetupResolver() { for _, rule := range rules { if iptables.RawCombinedOutputNative(rule...) != nil { - log.Errorf("setting up rule failed, %v", rule) + logrus.Errorf("setting up rule failed, %v", rule) } } } diff --git a/sandbox.go b/sandbox.go index fdd89b20eb..1ca1271cc7 100644 --- a/sandbox.go +++ b/sandbox.go @@ -9,7 +9,7 @@ import ( "sync" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/etchosts" "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/osl" @@ -213,18 +213,18 @@ func (sb *sandbox) delete(force bool) error { if c.isDistributedControl() { retain = true } - log.Warnf("Failed getting network for ep %s during sandbox %s delete: %v", ep.ID(), sb.ID(), err) + logrus.Warnf("Failed getting network for ep %s during sandbox %s delete: %v", ep.ID(), sb.ID(), err) continue } if !force { if err := ep.Leave(sb); err != nil { - log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) + logrus.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) } } if err := ep.Delete(force); err != nil { - log.Warnf("Failed deleting endpoint %s: %v\n", ep.ID(), err) + logrus.Warnf("Failed deleting endpoint %s: %v\n", ep.ID(), err) } } @@ -247,7 +247,7 @@ func (sb *sandbox) delete(force bool) error { } if err := sb.storeDelete(); err != nil { - log.Warnf("Failed to delete sandbox %s from store: %v", sb.ID(), err) + logrus.Warnf("Failed to delete sandbox %s from store: %v", sb.ID(), err) } c.Lock() @@ -291,7 +291,7 @@ func (sb *sandbox) Refresh(options ...SandboxOption) error { // Detach from all endpoints for _, ep := range epList { if err := ep.Leave(sb); err != nil { - log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) + logrus.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) } } @@ -307,7 +307,7 @@ func (sb *sandbox) Refresh(options ...SandboxOption) error { // Re-connect to all endpoints for _, ep := range epList { if err := ep.Join(sb); err != nil { - log.Warnf("Failed attach sandbox %s to endpoint %s: %v\n", sb.ID(), ep.ID(), err) + logrus.Warnf("Failed attach sandbox %s to endpoint %s: %v\n", sb.ID(), ep.ID(), err) } } @@ -413,7 +413,7 @@ func (sb *sandbox) updateGateway(ep *endpoint) error { func (sb *sandbox) ResolveIP(ip string) string { var svc string - log.Debugf("IP To resolve %v", ip) + logrus.Debugf("IP To resolve %v", ip) for _, ep := range sb.getConnectedEndpoints() { n := ep.getNetwork() @@ -434,7 +434,7 @@ func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP) { srv := []*net.SRV{} ip := []net.IP{} - log.Debugf("Service name To resolve: %v", name) + logrus.Debugf("Service name To resolve: %v", name) // There are DNS implementaions that allow SRV queries for names not in // the format defined by RFC 2782. Hence specific validations checks are @@ -497,7 +497,7 @@ func (sb *sandbox) ResolveName(name string, ipType int) ([]net.IP, bool) { // {a.b in network c.d}, // {a in network b.c.d}, - log.Debugf("Name To resolve: %v", name) + logrus.Debugf("Name To resolve: %v", name) name = strings.TrimSuffix(name, ".") reqName := []string{name} networkName := []string{""} @@ -605,7 +605,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin func (sb *sandbox) SetKey(basePath string) error { start := time.Now() defer func() { - log.Debugf("sandbox set key processing took %s for container %s", time.Now().Sub(start), sb.ContainerID()) + logrus.Debugf("sandbox set key processing took %s for container %s", time.Now().Sub(start), sb.ContainerID()) }() if basePath == "" { @@ -646,10 +646,10 @@ func (sb *sandbox) SetKey(basePath string) error { if err := sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err == nil { if err := sb.resolver.Start(); err != nil { - log.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) + logrus.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) } } else { - log.Errorf("Resolver Setup Function failed for container %s, %q", sb.ContainerID(), err) + logrus.Errorf("Resolver Setup Function failed for container %s, %q", sb.ContainerID(), err) } } @@ -690,7 +690,7 @@ func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) { // Only remove the interfaces owned by this endpoint from the sandbox. if ep.hasInterface(i.SrcName()) { if err := i.Remove(); err != nil { - log.Debugf("Remove interface %s failed: %v", i.SrcName(), err) + logrus.Debugf("Remove interface %s failed: %v", i.SrcName(), err) } } } @@ -706,7 +706,7 @@ func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) { // Remove non-interface routes. for _, r := range joinInfo.StaticRoutes { if err := osSbox.RemoveStaticRoute(r); err != nil { - log.Debugf("Remove route failed: %v", err) + logrus.Debugf("Remove route failed: %v", err) } } } @@ -741,7 +741,7 @@ func (sb *sandbox) restoreOslSandbox() error { ep.Unlock() if i == nil { - log.Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID()) + logrus.Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID()) continue } @@ -876,7 +876,7 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error { if len(sb.endpoints) == 0 { // sb.endpoints should never be empty and this is unexpected error condition // We log an error message to note this down for debugging purposes. - log.Errorf("No endpoints in sandbox while trying to remove endpoint %s", ep.Name()) + logrus.Errorf("No endpoints in sandbox while trying to remove endpoint %s", ep.Name()) sb.Unlock() return nil } diff --git a/sandbox_dns_unix.go b/sandbox_dns_unix.go index 3f734511d8..f4d1fad605 100644 --- a/sandbox_dns_unix.go +++ b/sandbox_dns_unix.go @@ -11,7 +11,7 @@ import ( "strconv" "strings" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/etchosts" "github.com/docker/libnetwork/resolvconf" "github.com/docker/libnetwork/types" @@ -40,19 +40,19 @@ func (sb *sandbox) startResolver(restore bool) { if !restore { err = sb.rebuildDNS() if err != nil { - log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err) + logrus.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err) return } } sb.resolver.SetExtServers(sb.extDNS) if err = sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err != nil { - log.Errorf("Resolver Setup function failed for container %s, %q", sb.ContainerID(), err) + logrus.Errorf("Resolver Setup function failed for container %s, %q", sb.ContainerID(), err) return } if err = sb.resolver.Start(); err != nil { - log.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) + logrus.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) } }) } @@ -125,13 +125,13 @@ func (sb *sandbox) updateHostsFile(ifaceIP string) error { func (sb *sandbox) addHostsEntries(recs []etchosts.Record) { if err := etchosts.Add(sb.config.hostsPath, recs); err != nil { - log.Warnf("Failed adding service host entries to the running container: %v", err) + logrus.Warnf("Failed adding service host entries to the running container: %v", err) } } func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) { if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil { - log.Warnf("Failed deleting service host entries to the running container: %v", err) + logrus.Warnf("Failed deleting service host entries to the running container: %v", err) } } @@ -261,7 +261,7 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error { if currHash != "" && currHash != currRC.Hash { // Seems the user has changed the container resolv.conf since the last time // we checked so return without doing anything. - //log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled) + //logrus.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled) return nil } diff --git a/sandbox_store.go b/sandbox_store.go index 58a939c3ea..8b36d688a1 100644 --- a/sandbox_store.go +++ b/sandbox_store.go @@ -178,7 +178,7 @@ func (sb *sandbox) storeDelete() error { func (c *controller) sandboxCleanup(activeSandboxes map[string]interface{}) { store := c.getStore(datastore.LocalScope) if store == nil { - logrus.Errorf("Could not find local scope store while trying to cleanup sandboxes") + logrus.Error("Could not find local scope store while trying to cleanup sandboxes") return } diff --git a/store.go b/store.go index 9830a22d47..c48a8dd73d 100644 --- a/store.go +++ b/store.go @@ -3,7 +3,7 @@ package libnetwork import ( "fmt" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libkv/store/boltdb" "github.com/docker/libkv/store/consul" "github.com/docker/libkv/store/etcd" @@ -85,7 +85,7 @@ func (c *controller) getNetworkFromStore(nid string) (*network, error) { // Continue searching in the next store if the key is not found in this store if err != nil { if err != datastore.ErrKeyNotFound { - log.Debugf("could not find network %s: %v", nid, err) + logrus.Debugf("could not find network %s: %v", nid, err) } continue } @@ -126,7 +126,7 @@ func (c *controller) getNetworksForScope(scope string) ([]*network, error) { ec := &endpointCnt{n: n} err = store.GetObject(datastore.Key(ec.Key()...), ec) if err != nil && !n.inDelete { - log.Warnf("Could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err) + logrus.Warnf("Could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err) continue } @@ -147,7 +147,7 @@ func (c *controller) getNetworksFromStore() ([]*network, error) { // Continue searching in the next store if no keys found in this store if err != nil { if err != datastore.ErrKeyNotFound { - log.Debugf("failed to get networks for scope %s: %v", store.Scope(), err) + logrus.Debugf("failed to get networks for scope %s: %v", store.Scope(), err) } continue } @@ -161,7 +161,7 @@ func (c *controller) getNetworksFromStore() ([]*network, error) { ec := &endpointCnt{n: n} err = store.GetObject(datastore.Key(ec.Key()...), ec) if err != nil && !n.inDelete { - log.Warnf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err) + logrus.Warnf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err) continue } @@ -185,7 +185,7 @@ func (n *network) getEndpointFromStore(eid string) (*endpoint, error) { if err != nil { if err != datastore.ErrKeyNotFound { errors = append(errors, fmt.Sprintf("{%s:%v}, ", store.Scope(), err)) - log.Debugf("could not find endpoint %s in %s: %v", eid, store.Scope(), err) + logrus.Debugf("could not find endpoint %s in %s: %v", eid, store.Scope(), err) } continue } @@ -203,7 +203,7 @@ func (n *network) getEndpointsFromStore() ([]*endpoint, error) { // Continue searching in the next store if no keys found in this store if err != nil { if err != datastore.ErrKeyNotFound { - log.Debugf("failed to get endpoints for network %s scope %s: %v", + logrus.Debugf("failed to get endpoints for network %s scope %s: %v", n.Name(), store.Scope(), err) } continue @@ -396,7 +396,7 @@ func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoi ch, err := store.Watch(ep.getNetwork().getEpCnt(), nw.stopCh) if err != nil { - log.Warnf("Error creating watch for network: %v", err) + logrus.Warnf("Error creating watch for network: %v", err) return } @@ -459,15 +459,15 @@ func (c *controller) startWatch() { func (c *controller) networkCleanup() { networks, err := c.getNetworksFromStore() if err != nil { - log.Warnf("Could not retrieve networks from store(s) during network cleanup: %v", err) + logrus.Warnf("Could not retrieve networks from store(s) during network cleanup: %v", err) return } for _, n := range networks { if n.inDelete { - log.Infof("Removing stale network %s (%s)", n.Name(), n.ID()) + logrus.Infof("Removing stale network %s (%s)", n.Name(), n.ID()) if err := n.delete(true); err != nil { - log.Debugf("Error while removing stale network: %v", err) + logrus.Debugf("Error while removing stale network: %v", err) } } } @@ -476,7 +476,7 @@ func (c *controller) networkCleanup() { var populateSpecial NetworkWalker = func(nw Network) bool { if n := nw.(*network); n.hasSpecialDriver() { if err := n.getController().addNetwork(n); err != nil { - log.Warnf("Failed to populate network %q with driver %q", nw.Name(), nw.Type()) + logrus.Warnf("Failed to populate network %q with driver %q", nw.Name(), nw.Type()) } } return false From 0c0c7828b0a46e3e092d2b378d4f72c75e44a208 Mon Sep 17 00:00:00 2001 From: msabansal Date: Fri, 4 Nov 2016 13:26:50 -0700 Subject: [PATCH 141/799] Default GW support for overlay networks Signed-off-by: msabansal --- Godeps/Godeps.json | 4 +- .../github.com/Microsoft/hcsshim/baselayer.go | 35 +- .../github.com/Microsoft/hcsshim/container.go | 213 +++++--- .../github.com/Microsoft/hcsshim/errors.go | 25 +- .../github.com/Microsoft/hcsshim/hcsshim.go | 29 +- .../github.com/Microsoft/hcsshim/hnsfuncs.go | 5 +- .../Microsoft/hcsshim/importlayer.go | 47 +- .../github.com/Microsoft/hcsshim/interface.go | 28 +- .../github.com/Microsoft/hcsshim/legacy.go | 348 ++++++++++++-- .../Microsoft/hcsshim/preparelayer.go | 12 +- .../github.com/Microsoft/hcsshim/process.go | 94 ++-- .../src/github.com/Microsoft/hcsshim/utils.go | 6 - .../Microsoft/hcsshim/waithelper.go | 78 +-- .../github.com/Microsoft/hcsshim/zhcsshim.go | 454 +++--------------- default_gateway.go | 24 +- default_gateway_freebsd.go | 6 + default_gateway_linux.go | 6 + default_gateway_solaris.go | 6 + default_gateway_windows.go | 17 +- drivers/windows/labels.go | 6 + drivers/windows/overlay/joinleave_windows.go | 2 - drivers/windows/windows.go | 113 +++-- endpoint_info.go | 25 - endpoint_info_unix.go | 30 ++ endpoint_info_windows.go | 45 ++ 25 files changed, 912 insertions(+), 746 deletions(-) create mode 100644 endpoint_info_unix.go create mode 100644 endpoint_info_windows.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index bcd738d090..8fa0717b35 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -26,8 +26,8 @@ }, { "ImportPath": "github.com/Microsoft/hcsshim", - "Comment": "v0.5.1", - "Rev": "523023ef1ef8ec08b23bbff88ab68552c5f1a6d7" + "Comment": "v0.5.6", + "Rev": "e439b7d2b63f036d3a50c93a9e0b154a0d50e788" }, { "ImportPath": "github.com/Sirupsen/logrus", diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go index 4b04a681e9..9babd4e18a 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go @@ -23,6 +23,26 @@ type dirInfo struct { fileInfo winio.FileBasicInfo } +// reapplyDirectoryTimes reapplies directory modification, creation, etc. times +// after processing of the directory tree has completed. The times are expected +// to be ordered such that parent directories come before child directories. +func reapplyDirectoryTimes(dis []dirInfo) error { + for i := range dis { + di := &dis[len(dis)-i-1] // reverse order: process child directories first + f, err := winio.OpenForBackup(di.path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING) + if err != nil { + return err + } + + err = winio.SetFileBasicInfo(f, &di.fileInfo) + f.Close() + if err != nil { + return err + } + } + return nil +} + func (w *baseLayerWriter) closeCurrentFile() error { if w.f != nil { err := w.bw.Close() @@ -142,18 +162,9 @@ func (w *baseLayerWriter) Close() error { if w.err == nil { // Restore the file times of all the directories, since they may have // been modified by creating child directories. - for i := range w.dirInfo { - di := &w.dirInfo[len(w.dirInfo)-i-1] - f, err := winio.OpenForBackup(di.path, uint32(syscall.GENERIC_READ|syscall.GENERIC_WRITE), syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING) - if err != nil { - return makeError(err, "Failed to OpenForBackup", di.path) - } - - err = winio.SetFileBasicInfo(f, &di.fileInfo) - f.Close() - if err != nil { - return makeError(err, "Failed to SetFileBasicInfo", di.path) - } + err = reapplyDirectoryTimes(w.dirInfo) + if err != nil { + return err } err = ProcessBaseLayer(w.root) diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go index 9e76e33230..48a7549704 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go @@ -3,6 +3,7 @@ package hcsshim import ( "encoding/json" "runtime" + "sync" "syscall" "time" @@ -20,12 +21,14 @@ const ( ) type container struct { + handleLock sync.RWMutex handle hcsSystem id string callbackNumber uintptr } -type containerProperties struct { +// ContainerProperties holds the properties for a container and the processes running in that container +type ContainerProperties struct { ID string `json:"Id"` Name string SystemType string @@ -33,6 +36,8 @@ type containerProperties struct { SiloGUID string `json:"SiloGuid,omitempty"` IsDummy bool `json:",omitempty"` RuntimeID string `json:"RuntimeId,omitempty"` + IsRuntimeTemplate bool `json:",omitempty"` + RuntimeImagePath string `json:",omitempty"` Stopped bool `json:",omitempty"` ExitType string `json:",omitempty"` AreUpdatesPending bool `json:",omitempty"` @@ -116,20 +121,15 @@ func CreateContainer(id string, c *ContainerConfig) (Container, error) { logrus.Debugf(title+" id=%s config=%s", id, configuration) var ( - resultp *uint16 - createError error + resultp *uint16 + identity syscall.Handle ) - if hcsCallbacksSupported { - var identity syscall.Handle - createError = hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp) - - if createError == nil || IsPending(createError) { - if err := container.registerCallback(); err != nil { - return nil, makeContainerError(container, operation, "", err) - } + createError := hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp) + + if createError == nil || IsPending(createError) { + if err := container.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) } - } else { - createError = hcsCreateComputeSystemTP5(id, configuration, &container.handle, &resultp) } err = processAsyncHcsResult(createError, resultp, container.callbackNumber, hcsNotificationSystemCreateCompleted, &defaultTimeout) @@ -164,19 +164,61 @@ func OpenContainer(id string) (Container, error) { container.handle = handle + if err := container.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) + } + logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle) runtime.SetFinalizer(container, closeContainer) return container, nil } +// GetContainers gets a list of the containers on the system that match the query +func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) { + operation := "GetContainers" + title := "HCSShim::" + operation + + queryb, err := json.Marshal(q) + if err != nil { + return nil, err + } + + query := string(queryb) + logrus.Debugf(title+" query=%s", query) + + var ( + resultp *uint16 + computeSystemsp *uint16 + ) + err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp) + err = processHcsResult(err, resultp) + if computeSystemsp == nil { + return nil, ErrUnexpectedValue + } + computeSystemsRaw := convertAndFreeCoTaskMemBytes(computeSystemsp) + computeSystems := []ContainerProperties{} + if err := json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil { + return nil, err + } + + logrus.Debugf(title + " succeeded") + return computeSystems, nil +} + // Start synchronously starts the container. func (container *container) Start() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Start" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 - err := hcsStartComputeSystemTP5(container.handle, nil, &resultp) + err := hcsStartComputeSystem(container.handle, "", &resultp) err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemStartCompleted, &defaultTimeout) if err != nil { return makeContainerError(container, operation, "", err) @@ -189,12 +231,18 @@ func (container *container) Start() error { // Shutdown requests a container shutdown, if IsPending() on the error returned is true, // it may not actually be shut down until Wait() succeeds. func (container *container) Shutdown() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Shutdown" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 - err := hcsShutdownComputeSystemTP5(container.handle, nil, &resultp) + err := hcsShutdownComputeSystem(container.handle, "", &resultp) err = processHcsResult(err, resultp) if err != nil { return makeContainerError(container, operation, "", err) @@ -207,12 +255,18 @@ func (container *container) Shutdown() error { // Terminate requests a container terminate, if IsPending() on the error returned is true, // it may not actually be shut down until Wait() succeeds. func (container *container) Terminate() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Terminate" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 - err := hcsTerminateComputeSystemTP5(container.handle, nil, &resultp) + err := hcsTerminateComputeSystem(container.handle, "", &resultp) err = processHcsResult(err, resultp) if err != nil { return makeContainerError(container, operation, "", err) @@ -228,26 +282,15 @@ func (container *container) Wait() error { title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) - if hcsCallbacksSupported { - err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil) - if err != nil { - return makeContainerError(container, operation, "", err) - } - } else { - _, err := container.waitTimeoutInternal(syscall.INFINITE) - if err != nil { - return makeContainerError(container, operation, "", err) - } + err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil) + if err != nil { + return makeContainerError(container, operation, "", err) } logrus.Debugf(title+" succeeded id=%s", container.id) return nil } -func (container *container) waitTimeoutInternal(timeout uint32) (bool, error) { - return waitTimeoutInternalHelper(container, timeout) -} - // WaitTimeout synchronously waits for the container to terminate or the duration to elapse. // If the timeout expires, IsTimeout(err) == true func (container *container) WaitTimeout(timeout time.Duration) error { @@ -255,42 +298,16 @@ func (container *container) WaitTimeout(timeout time.Duration) error { title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) - if hcsCallbacksSupported { - err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout) - if err != nil { - return makeContainerError(container, operation, "", err) - } - } else { - finished, err := waitTimeoutHelper(container, timeout) - if !finished { - err = ErrTimeout - } - if err != nil { - return makeContainerError(container, operation, "", err) - } + err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout) + if err != nil { + return makeContainerError(container, operation, "", err) } logrus.Debugf(title+" succeeded id=%s", container.id) return nil } -func (container *container) hcsWait(timeout uint32) (bool, error) { - var ( - resultp *uint16 - exitEvent syscall.Handle - ) - - err := hcsCreateComputeSystemWait(container.handle, &exitEvent, &resultp) - err = processHcsResult(err, resultp) - if err != nil { - return false, err - } - defer syscall.CloseHandle(exitEvent) - - return waitForSingleObject(exitEvent, timeout) -} - -func (container *container) properties(query string) (*containerProperties, error) { +func (container *container) properties(query string) (*ContainerProperties, error) { var ( resultp *uint16 propertiesp *uint16 @@ -305,7 +322,7 @@ func (container *container) properties(query string) (*containerProperties, erro return nil, ErrUnexpectedValue } propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp) - properties := &containerProperties{} + properties := &ContainerProperties{} if err := json.Unmarshal(propertiesRaw, properties); err != nil { return nil, err } @@ -314,9 +331,16 @@ func (container *container) properties(query string) (*containerProperties, erro // HasPendingUpdates returns true if the container has updates pending to install func (container *container) HasPendingUpdates() (bool, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "HasPendingUpdates" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + + if container.handle == 0 { + return false, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + properties, err := container.properties(pendingUpdatesQuery) if err != nil { return false, makeContainerError(container, operation, "", err) @@ -328,9 +352,16 @@ func (container *container) HasPendingUpdates() (bool, error) { // Statistics returns statistics for the container func (container *container) Statistics() (Statistics, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Statistics" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + + if container.handle == 0 { + return Statistics{}, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + properties, err := container.properties(statisticsQuery) if err != nil { return Statistics{}, makeContainerError(container, operation, "", err) @@ -342,9 +373,16 @@ func (container *container) Statistics() (Statistics, error) { // ProcessList returns an array of ProcessListItems for the container func (container *container) ProcessList() ([]ProcessListItem, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "ProcessList" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + + if container.handle == 0 { + return nil, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + properties, err := container.properties(processListQuery) if err != nil { return nil, makeContainerError(container, operation, "", err) @@ -356,12 +394,18 @@ func (container *container) ProcessList() ([]ProcessListItem, error) { // Pause pauses the execution of the container. This feature is not enabled in TP5. func (container *container) Pause() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Pause" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 - err := hcsPauseComputeSystemTP5(container.handle, nil, &resultp) + err := hcsPauseComputeSystem(container.handle, "", &resultp) err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemPauseCompleted, &defaultTimeout) if err != nil { return makeContainerError(container, operation, "", err) @@ -373,14 +417,18 @@ func (container *container) Pause() error { // Resume resumes the execution of the container. This feature is not enabled in TP5. func (container *container) Resume() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Resume" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) - var ( - resultp *uint16 - ) - err := hcsResumeComputeSystemTP5(container.handle, nil, &resultp) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + + var resultp *uint16 + err := hcsResumeComputeSystem(container.handle, "", &resultp) err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemResumeCompleted, &defaultTimeout) if err != nil { return makeContainerError(container, operation, "", err) @@ -392,6 +440,8 @@ func (container *container) Resume() error { // CreateProcess launches a new process within the container. func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "CreateProcess" title := "HCSShim::Container::" + operation var ( @@ -400,6 +450,10 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { resultp *uint16 ) + if container.handle == 0 { + return nil, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + // If we are not emulating a console, ignore any console size passed to us if !c.EmulateConsole { c.ConsoleSize[0] = 0 @@ -431,10 +485,8 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { }, } - if hcsCallbacksSupported { - if err := process.registerCallback(); err != nil { - return nil, makeContainerError(container, operation, "", err) - } + if err := process.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) } logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) @@ -444,6 +496,8 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { // OpenProcess gets an interface to an existing process within the container. func (container *container) OpenProcess(pid int) (Process, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "OpenProcess" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s, processid=%d", container.id, pid) @@ -452,6 +506,10 @@ func (container *container) OpenProcess(pid int) (Process, error) { resultp *uint16 ) + if container.handle == 0 { + return nil, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp) err = processHcsResult(err, resultp) if err != nil { @@ -464,10 +522,8 @@ func (container *container) OpenProcess(pid int) (Process, error) { container: container, } - if hcsCallbacksSupported { - if err := process.registerCallback(); err != nil { - return nil, makeContainerError(container, operation, "", err) - } + if err := process.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) } logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) @@ -477,6 +533,8 @@ func (container *container) OpenProcess(pid int) (Process, error) { // Close cleans up any state associated with the container but does not terminate or wait for it. func (container *container) Close() error { + container.handleLock.Lock() + defer container.handleLock.Unlock() operation := "Close" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) @@ -486,10 +544,8 @@ func (container *container) Close() error { return nil } - if hcsCallbacksSupported { - if err := container.unregisterCallback(); err != nil { - return makeContainerError(container, operation, "", err) - } + if err := container.unregisterCallback(); err != nil { + return makeContainerError(container, operation, "", err) } if err := hcsCloseComputeSystem(container.handle); err != nil { @@ -497,6 +553,7 @@ func (container *container) Close() error { } container.handle = 0 + runtime.SetFinalizer(container, nil) logrus.Debugf(title+" succeeded id=%s", container.id) return nil diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go index 0d4dad5950..19bb97a05b 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go @@ -16,6 +16,9 @@ var ( // ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed") + // ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method + ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed") + // ErrInvalidNotificationType is an error encountered when an invalid notification type is used ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type") @@ -80,8 +83,13 @@ func (e *ContainerError) Error() string { s += " encountered an error during " + e.Operation } - if e.Err != nil { - s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) + switch e.Err.(type) { + case nil: + break + case syscall.Errno: + s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, win32FromError(e.Err)) + default: + s += fmt.Sprintf(": %s", e.Err.Error()) } if e.ExtraInfo != "" { @@ -116,16 +124,16 @@ func (e *ProcessError) Error() string { } if e.Operation != "" { - s += " " + e.Operation + s += " encountered an error during " + e.Operation } switch e.Err.(type) { case nil: break case syscall.Errno: - s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) + s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, win32FromError(e.Err)) default: - s += fmt.Sprintf(" failed: %s", e.Error()) + s += fmt.Sprintf(": %s", e.Err.Error()) } return s @@ -151,6 +159,13 @@ func IsNotExist(err error) bool { err == ErrProcNotFound } +// IsAlreadyClosed checks if an error is caused by the Container or Process having been +// already closed by a call to the Close() method. +func IsAlreadyClosed(err error) bool { + err = getInnerError(err) + return err == ErrAlreadyClosed +} + // IsPending returns a boolean indicating whether the error is that // the requested operation is being completed in the background. func IsPending(err error) bool { diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go index eaecf1321e..3cb3a299ff 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go @@ -1,4 +1,4 @@ -// Shim for the Host Compute Service (HSC) to manage Windows Server +// Shim for the Host Compute Service (HCS) to manage Windows Server // containers and Hyper-V containers. package hcsshim @@ -44,16 +44,6 @@ import ( //sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead? //sys exportLayerEnd(context uintptr) (hr error) = vmcompute.ExportLayerEnd? -//sys createComputeSystem(id string, configuration string) (hr error) = vmcompute.CreateComputeSystem? -//sys createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) = vmcompute.CreateProcessWithStdHandlesInComputeSystem? -//sys resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) = vmcompute.ResizeConsoleInComputeSystem? -//sys shutdownComputeSystem(id string, timeout uint32) (hr error) = vmcompute.ShutdownComputeSystem? -//sys startComputeSystem(id string) (hr error) = vmcompute.StartComputeSystem? -//sys terminateComputeSystem(id string) (hr error) = vmcompute.TerminateComputeSystem? -//sys terminateProcessInComputeSystem(id string, pid uint32) (hr error) = vmcompute.TerminateProcessInComputeSystem? -//sys waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) = vmcompute.WaitForProcessInComputeSystem? -//sys getComputeSystemProperties(id string, flags uint32, properties **uint16) (hr error) = vmcompute.GetComputeSystemProperties? - //sys hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) = vmcompute.HcsEnumerateComputeSystems? //sys hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem? //sys hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsOpenComputeSystem? @@ -65,7 +55,9 @@ import ( //sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? //sys hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties? //sys hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem? -//sys hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystemWait? +//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback? +//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback? + //sys hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess? //sys hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess? //sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess? @@ -73,21 +65,12 @@ import ( //sys hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) = vmcompute.HcsGetProcessInfo? //sys hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties? //sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess? -//sys hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateProcessWait? //sys hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetServiceProperties? -//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings? - -//sys hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem? -//sys hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem? -//sys hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem? -//sys hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem? -//sys hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem? -//sys hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? -//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback? -//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback? //sys hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback? //sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback? +//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings? + //sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall? const ( diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go index 57ad519891..e3d8c0b145 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go @@ -52,7 +52,7 @@ type MacPool struct { // HNSNetwork represents a network in HNS type HNSNetwork struct { - Id string `json:",omitempty"` + Id string `json:"ID,omitempty"` Name string `json:",omitempty"` Type string `json:",omitempty"` NetworkAdapterName string `json:",omitempty"` @@ -68,7 +68,7 @@ type HNSNetwork struct { // HNSEndpoint represents a network endpoint in HNS type HNSEndpoint struct { - Id string `json:",omitempty"` + Id string `json:"ID,omitempty"` Name string `json:",omitempty"` VirtualNetwork string `json:",omitempty"` VirtualNetworkName string `json:",omitempty"` @@ -79,6 +79,7 @@ type HNSEndpoint struct { DNSServerList string `json:",omitempty"` GatewayAddress string `json:",omitempty"` EnableInternalDNS bool `json:",omitempty"` + DisableICC bool `json:",omitempty"` PrefixLength uint8 `json:",omitempty"` IsRemoteEndpoint bool `json:",omitempty"` } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go index 42d7270448..5f826301e1 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go @@ -130,21 +130,42 @@ type legacyLayerWriterWrapper struct { } func (r *legacyLayerWriterWrapper) Close() error { + defer os.RemoveAll(r.root) err := r.legacyLayerWriter.Close() - if err == nil { - var fullPath string - // Use the original path here because ImportLayer does not support long paths for the source in TP5. - // But do use a long path for the destination to work around another bug with directories - // with MAX_PATH - 12 < length < MAX_PATH. - info := r.info - fullPath, err = makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID)) - if err == nil { - info.HomeDir = "" - err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths) + if err != nil { + return err + } + + // Use the original path here because ImportLayer does not support long paths for the source in TP5. + // But do use a long path for the destination to work around another bug with directories + // with MAX_PATH - 12 < length < MAX_PATH. + info := r.info + fullPath, err := makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID)) + if err != nil { + return err + } + + info.HomeDir = "" + if err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths); err != nil { + return err + } + // Add any hard links that were collected. + for _, lnk := range r.PendingLinks { + if err = os.Remove(lnk.Path); err != nil && !os.IsNotExist(err) { + return err + } + if err = os.Link(lnk.Target, lnk.Path); err != nil { + return err } } - os.RemoveAll(r.root) - return err + // Prepare the utility VM for use if one is present in the layer. + if r.HasUtilityVM { + err = ProcessUtilityVMImage(filepath.Join(fullPath, "UtilityVM")) + if err != nil { + return err + } + } + return nil } // NewLayerWriter returns a new layer writer for creating a layer on disk. @@ -166,7 +187,7 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) return nil, err } return &legacyLayerWriterWrapper{ - legacyLayerWriter: newLegacyLayerWriter(path), + legacyLayerWriter: newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID)), info: info, layerID: layerID, path: path, diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go index 528cde2f86..000a18c1be 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go @@ -10,13 +10,14 @@ import ( type ProcessConfig struct { ApplicationName string CommandLine string + User string WorkingDirectory string Environment map[string]string EmulateConsole bool CreateStdInPipe bool CreateStdOutPipe bool CreateStdErrPipe bool - ConsoleSize [2]int + ConsoleSize [2]uint } type Layer struct { @@ -25,9 +26,11 @@ type Layer struct { } type MappedDir struct { - HostPath string - ContainerPath string - ReadOnly bool + HostPath string + ContainerPath string + ReadOnly bool + BandwidthMaximum uint64 + IOPSMaximum uint64 } type HvRuntime struct { @@ -42,10 +45,10 @@ type ContainerConfig struct { Name string // Name of the container. We use the docker ID. Owner string // The management platform that created this container IsDummy bool // Used for development purposes. - VolumePath string // Windows volume path for scratch space + VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID} IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows - LayerFolderPath string // Where the layer folders are located - Layers []Layer // List of storage layers + LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID + Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID Credentials string `json:",omitempty"` // Credentials information ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container. ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default. @@ -56,14 +59,21 @@ type ContainerConfig struct { MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes HostName string // Hostname MappedDirectories []MappedDir // List of mapped directories (volumes/mounts) - SandboxPath string // Location of unmounted sandbox (used for Hyper-V containers) + SandboxPath string `json:",omitempty"` // Location of unmounted sandbox. Used by Hyper-V containers only. Format %root%\windowsfilter HvPartition bool // True if it a Hyper-V Container EndpointList []string // List of networking endpoints to be attached to container - HvRuntime *HvRuntime // Hyper-V container settings + HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM Servicing bool // True if this container is for servicing AllowUnqualifiedDNSQuery bool // True to allow unqualified DNS name resolution } +type ComputeSystemQuery struct { + IDs []string `json:"Ids,omitempty"` + Types []string `json:",omitempty"` + Names []string `json:",omitempty"` + Owners []string `json:",omitempty"` +} + // Container represents a created (but not necessarily running) container. type Container interface { // Start synchronously starts the container. diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go index e19ac8a902..11d90a7bdd 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go @@ -16,6 +16,13 @@ import ( var errorIterationCanceled = errors.New("") +var mutatedUtilityVMFiles = map[string]bool{ + `EFI\Microsoft\Boot\BCD`: true, + `EFI\Microsoft\Boot\BCD.LOG`: true, + `EFI\Microsoft\Boot\BCD.LOG1`: true, + `EFI\Microsoft\Boot\BCD.LOG2`: true, +} + func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os.File, err error) { return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition) } @@ -49,17 +56,15 @@ type legacyLayerReader struct { proceed chan bool currentFile *os.File backupReader *winio.BackupFileReader - isTP4Format bool } // newLegacyLayerReader returns a new LayerReader that can read the Windows -// TP4 transport format from disk. +// container layer transport format from disk. func newLegacyLayerReader(root string) *legacyLayerReader { r := &legacyLayerReader{ - root: root, - result: make(chan *fileEntry), - proceed: make(chan bool), - isTP4Format: IsTP4(), + root: root, + result: make(chan *fileEntry), + proceed: make(chan bool), } go r.walk() return r @@ -251,17 +256,14 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil fileInfo.LastAccessTime = fileInfo.LastWriteTime } else { - beginning := int64(0) - if !r.isTP4Format { - // In TP5, the file attributes were added before the backup stream - var attr uint32 - err = binary.Read(f, binary.LittleEndian, &attr) - if err != nil { - return - } - fileInfo.FileAttributes = uintptr(attr) - beginning = 4 + // The file attributes are written before the backup stream. + var attr uint32 + err = binary.Read(f, binary.LittleEndian, &attr) + if err != nil { + return } + fileInfo.FileAttributes = uintptr(attr) + beginning := int64(4) // Find the accurate file size. if !fe.fi.IsDir() { @@ -301,21 +303,32 @@ func (r *legacyLayerReader) Close() error { return nil } +type pendingLink struct { + Path, Target string +} + type legacyLayerWriter struct { root string + parentRoots []string + destRoot string currentFile *os.File backupWriter *winio.BackupFileWriter tombstones []string - isTP4Format bool pathFixed bool + HasUtilityVM bool + uvmDi []dirInfo + addedFiles map[string]bool + PendingLinks []pendingLink } -// newLegacyLayerWriter returns a LayerWriter that can write the TP4 transport format -// to disk. -func newLegacyLayerWriter(root string) *legacyLayerWriter { +// newLegacyLayerWriter returns a LayerWriter that can write the contaler layer +// transport format to disk. +func newLegacyLayerWriter(root string, parentRoots []string, destRoot string) *legacyLayerWriter { return &legacyLayerWriter{ root: root, - isTP4Format: IsTP4(), + parentRoots: parentRoots, + destRoot: destRoot, + addedFiles: make(map[string]bool), } } @@ -325,12 +338,42 @@ func (w *legacyLayerWriter) init() error { if err != nil { return err } + for i, p := range w.parentRoots { + w.parentRoots[i], err = makeLongAbsPath(p) + if err != nil { + return err + } + } + destPath, err := makeLongAbsPath(w.destRoot) + if err != nil { + return err + } w.root = path + w.destRoot = destPath w.pathFixed = true } return nil } +func (w *legacyLayerWriter) initUtilityVM() error { + if !w.HasUtilityVM { + err := os.Mkdir(filepath.Join(w.destRoot, `UtilityVM`), 0) + if err != nil { + return err + } + // Server 2016 does not support multiple layers for the utility VM, so + // clone the utility VM from the parent layer into this layer. Use hard + // links to avoid unnecessary copying, since most of the files are + // immutable. + err = cloneTree(filepath.Join(w.parentRoots[0], `UtilityVM\Files`), filepath.Join(w.destRoot, `UtilityVM\Files`), mutatedUtilityVMFiles) + if err != nil { + return fmt.Errorf("cloning the parent utility VM image failed: %s", err) + } + w.HasUtilityVM = true + } + return nil +} + func (w *legacyLayerWriter) reset() { if w.backupWriter != nil { w.backupWriter.Close() @@ -342,15 +385,180 @@ func (w *legacyLayerWriter) reset() { } } +// copyFileWithMetadata copies a file using the backup/restore APIs in order to preserve metadata +func copyFileWithMetadata(srcPath, destPath string, isDir bool) (fileInfo *winio.FileBasicInfo, err error) { + createDisposition := uint32(syscall.CREATE_NEW) + if isDir { + err = os.Mkdir(destPath, 0) + if err != nil { + return nil, err + } + createDisposition = syscall.OPEN_EXISTING + } + + src, err := openFileOrDir(srcPath, syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY, syscall.OPEN_EXISTING) + if err != nil { + return nil, err + } + defer src.Close() + srcr := winio.NewBackupFileReader(src, true) + defer srcr.Close() + + fileInfo, err = winio.GetFileBasicInfo(src) + if err != nil { + return nil, err + } + + dest, err := openFileOrDir(destPath, syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, createDisposition) + if err != nil { + return nil, err + } + defer dest.Close() + + err = winio.SetFileBasicInfo(dest, fileInfo) + if err != nil { + return nil, err + } + + destw := winio.NewBackupFileWriter(dest, true) + defer func() { + cerr := destw.Close() + if err == nil { + err = cerr + } + }() + + _, err = io.Copy(destw, srcr) + if err != nil { + return nil, err + } + + return fileInfo, nil +} + +// cloneTree clones a directory tree using hard links. It skips hard links for +// the file names in the provided map and just copies those files. +func cloneTree(srcPath, destPath string, mutatedFiles map[string]bool) error { + var di []dirInfo + err := filepath.Walk(srcPath, func(srcFilePath string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + relPath, err := filepath.Rel(srcPath, srcFilePath) + if err != nil { + return err + } + destFilePath := filepath.Join(destPath, relPath) + + // Directories, reparse points, and files that will be mutated during + // utility VM import must be copied. All other files can be hard linked. + isReparsePoint := info.Sys().(*syscall.Win32FileAttributeData).FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 + if info.IsDir() || isReparsePoint || mutatedFiles[relPath] { + fi, err := copyFileWithMetadata(srcFilePath, destFilePath, info.IsDir()) + if err != nil { + return err + } + if info.IsDir() && !isReparsePoint { + di = append(di, dirInfo{path: destFilePath, fileInfo: *fi}) + } + } else { + err = os.Link(srcFilePath, destFilePath) + if err != nil { + return err + } + } + + // Don't recurse on reparse points. + if info.IsDir() && isReparsePoint { + return filepath.SkipDir + } + + return nil + }) + if err != nil { + return err + } + + return reapplyDirectoryTimes(di) +} + func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error { w.reset() err := w.init() if err != nil { return err } - path := filepath.Join(w.root, name) - createDisposition := uint32(syscall.CREATE_NEW) + if name == `UtilityVM` { + return w.initUtilityVM() + } + + if strings.HasPrefix(name, `UtilityVM\`) { + if !w.HasUtilityVM { + return errors.New("missing UtilityVM directory") + } + if !strings.HasPrefix(name, `UtilityVM\Files\`) && name != `UtilityVM\Files` { + return errors.New("invalid UtilityVM layer") + } + path := filepath.Join(w.destRoot, name) + createDisposition := uint32(syscall.OPEN_EXISTING) + if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { + st, err := os.Lstat(path) + if err != nil && !os.IsNotExist(err) { + return err + } + if st != nil { + // Delete the existing file/directory if it is not the same type as this directory. + existingAttr := st.Sys().(*syscall.Win32FileAttributeData).FileAttributes + if (uint32(fileInfo.FileAttributes)^existingAttr)&(syscall.FILE_ATTRIBUTE_DIRECTORY|syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 { + if err = os.RemoveAll(path); err != nil { + return err + } + st = nil + } + } + if st == nil { + if err = os.Mkdir(path, 0); err != nil { + return err + } + } + if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { + w.uvmDi = append(w.uvmDi, dirInfo{path: path, fileInfo: *fileInfo}) + } + } else { + // Overwrite any existing hard link. + err = os.Remove(path) + if err != nil && !os.IsNotExist(err) { + return err + } + createDisposition = syscall.CREATE_NEW + } + + f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, createDisposition) + if err != nil { + return err + } + defer func() { + if f != nil { + f.Close() + os.Remove(path) + } + }() + + err = winio.SetFileBasicInfo(f, fileInfo) + if err != nil { + return err + } + + w.backupWriter = winio.NewBackupFileWriter(f, true) + w.currentFile = f + w.addedFiles[name] = true + f = nil + return nil + } + + path := filepath.Join(w.root, name) if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { err := os.Mkdir(path, 0) if err != nil { @@ -359,7 +567,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro path += ".$wcidirs$" } - f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, createDisposition) + f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.CREATE_NEW) if err != nil { return err } @@ -380,29 +588,97 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro if strings.HasPrefix(name, `Hives\`) { w.backupWriter = winio.NewBackupFileWriter(f, false) } else { - if !w.isTP4Format { - // In TP5, the file attributes were added to the header - err = binary.Write(f, binary.LittleEndian, uint32(fileInfo.FileAttributes)) - if err != nil { - return err - } + // The file attributes are written before the stream. + err = binary.Write(f, binary.LittleEndian, uint32(fileInfo.FileAttributes)) + if err != nil { + return err } } w.currentFile = f + w.addedFiles[name] = true f = nil return nil } func (w *legacyLayerWriter) AddLink(name string, target string) error { - return errors.New("hard links not supported with legacy writer") + w.reset() + err := w.init() + if err != nil { + return err + } + + var requiredPrefix string + var roots []string + if prefix := `Files\`; strings.HasPrefix(name, prefix) { + requiredPrefix = prefix + // Look for cross-layer hard link targets in the parent layers, since + // nothing is in the destination path yet. + roots = w.parentRoots + } else if prefix := `UtilityVM\Files\`; strings.HasPrefix(name, prefix) { + requiredPrefix = prefix + // Since the utility VM is fully cloned into the destination path + // already, look for cross-layer hard link targets directly in the + // destination path. + roots = []string{w.destRoot} + } + + if requiredPrefix == "" || !strings.HasPrefix(target, requiredPrefix) { + return errors.New("invalid hard link in layer") + } + + // Find to try the target of the link in a previously added file. If that + // fails, search in parent layers. + var selectedRoot string + if _, ok := w.addedFiles[target]; ok { + selectedRoot = w.destRoot + } else { + for _, r := range roots { + if _, err = os.Lstat(filepath.Join(r, target)); err != nil { + if !os.IsNotExist(err) { + return err + } + } else { + selectedRoot = r + break + } + } + if selectedRoot == "" { + return fmt.Errorf("failed to find link target for '%s' -> '%s'", name, target) + } + } + // The link can't be written until after the ImportLayer call. + w.PendingLinks = append(w.PendingLinks, pendingLink{ + Path: filepath.Join(w.destRoot, name), + Target: filepath.Join(selectedRoot, target), + }) + w.addedFiles[name] = true + return nil } func (w *legacyLayerWriter) Remove(name string) error { - if !strings.HasPrefix(name, `Files\`) { + if strings.HasPrefix(name, `Files\`) { + w.tombstones = append(w.tombstones, name[len(`Files\`):]) + } else if strings.HasPrefix(name, `UtilityVM\Files\`) { + err := w.initUtilityVM() + if err != nil { + return err + } + // Make sure the path exists; os.RemoveAll will not fail if the file is + // already gone, and this needs to be a fatal error for diagnostics + // purposes. + path := filepath.Join(w.destRoot, name) + if _, err := os.Lstat(path); err != nil { + return err + } + err = os.RemoveAll(path) + if err != nil { + return err + } + } else { return fmt.Errorf("invalid tombstone %s", name) } - w.tombstones = append(w.tombstones, name[len(`Files\`):]) + return nil } @@ -437,5 +713,11 @@ func (w *legacyLayerWriter) Close() error { return err } } + if w.HasUtilityVM { + err = reapplyDirectoryTimes(w.uvmDi) + if err != nil { + return err + } + } return nil } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go index 69b5fe045e..2791683467 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go @@ -1,6 +1,12 @@ package hcsshim -import "github.com/Sirupsen/logrus" +import ( + "sync" + + "github.com/Sirupsen/logrus" +) + +var prepareLayerLock sync.Mutex // PrepareLayer finds a mounted read-write layer matching layerId and enables the // the filesystem filter for use on that layer. This requires the paths to all @@ -24,6 +30,10 @@ func PrepareLayer(info DriverInfo, layerId string, parentLayerPaths []string) er return err } + // This lock is a temporary workaround for a Windows bug. Only allowing one + // call to prepareLayer at a time vastly reduces the chance of a timeout. + prepareLayerLock.Lock() + defer prepareLayerLock.Unlock() err = prepareLayer(&infop, layerId, layers) if err != nil { err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour) diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go index d6e63c9223..af3fab3526 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go @@ -3,6 +3,8 @@ package hcsshim import ( "encoding/json" "io" + "runtime" + "sync" "syscall" "time" @@ -11,6 +13,7 @@ import ( // ContainerError is an error encountered in HCS type process struct { + handleLock sync.RWMutex handle hcsProcess processID int container *container @@ -64,10 +67,16 @@ func (process *process) Pid() int { // Kill signals the process to terminate but does not wait for it to finish terminating. func (process *process) Kill() error { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "Kill" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return makeProcessError(process, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 err := hcsTerminateProcess(process.handle, &resultp) err = processHcsResult(err, resultp) @@ -85,16 +94,9 @@ func (process *process) Wait() error { title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) - if hcsCallbacksSupported { - err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil) - if err != nil { - return makeProcessError(process, operation, "", err) - } - } else { - _, err := process.waitTimeoutInternal(syscall.INFINITE) - if err != nil { - return makeProcessError(process, operation, "", err) - } + err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil) + if err != nil { + return makeProcessError(process, operation, "", err) } logrus.Debugf(title+" succeeded processid=%d", process.processID) @@ -108,51 +110,28 @@ func (process *process) WaitTimeout(timeout time.Duration) error { title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) - if hcsCallbacksSupported { - err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout) - if err != nil { - return makeProcessError(process, operation, "", err) - } - } else { - finished, err := waitTimeoutHelper(process, timeout) - if !finished { - err = ErrTimeout - } - if err != nil { - return makeProcessError(process, operation, "", err) - } + err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout) + if err != nil { + return makeProcessError(process, operation, "", err) } logrus.Debugf(title+" succeeded processid=%d", process.processID) return nil } -func (process *process) hcsWait(timeout uint32) (bool, error) { - var ( - resultp *uint16 - exitEvent syscall.Handle - ) - err := hcsCreateProcessWait(process.handle, &exitEvent, &resultp) - err = processHcsResult(err, resultp) - if err != nil { - return false, err - } - defer syscall.CloseHandle(exitEvent) - - return waitForSingleObject(exitEvent, timeout) -} - -func (process *process) waitTimeoutInternal(timeout uint32) (bool, error) { - return waitTimeoutInternalHelper(process, timeout) -} - // ExitCode returns the exit code of the process. The process must have // already terminated. func (process *process) ExitCode() (int, error) { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "ExitCode" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return 0, makeProcessError(process, operation, "", ErrAlreadyClosed) + } + properties, err := process.properties() if err != nil { return 0, makeProcessError(process, operation, "", err) @@ -162,16 +141,26 @@ func (process *process) ExitCode() (int, error) { return 0, makeProcessError(process, operation, "", ErrInvalidProcessState) } + if properties.LastWaitResult != 0 { + return 0, makeProcessError(process, operation, "", syscall.Errno(properties.LastWaitResult)) + } + logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode) return int(properties.ExitCode), nil } // ResizeConsole resizes the console of the process. func (process *process) ResizeConsole(width, height uint16) error { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "ResizeConsole" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return makeProcessError(process, operation, "", ErrAlreadyClosed) + } + modifyRequest := processModifyRequest{ Operation: modifyConsoleSize, ConsoleSize: &consoleSize{ @@ -231,10 +220,16 @@ func (process *process) properties() (*processStatus, error) { // these pipes does not close the underlying pipes; it should be possible to // call this multiple times to get multiple interfaces. func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "Stdio" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return nil, nil, nil, makeProcessError(process, operation, "", ErrAlreadyClosed) + } + var stdIn, stdOut, stdErr syscall.Handle if process.cachedPipes == nil { @@ -269,10 +264,16 @@ func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e // CloseStdin closes the write side of the stdin pipe so that the process is // notified on the read side that there is no more data in stdin. func (process *process) CloseStdin() error { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "CloseStdin" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return makeProcessError(process, operation, "", ErrAlreadyClosed) + } + modifyRequest := processModifyRequest{ Operation: modifyCloseHandle, CloseHandle: &closeHandle{ @@ -301,6 +302,8 @@ func (process *process) CloseStdin() error { // Close cleans up any state associated with the process but does not kill // or wait on it. func (process *process) Close() error { + process.handleLock.Lock() + defer process.handleLock.Unlock() operation := "Close" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) @@ -310,10 +313,8 @@ func (process *process) Close() error { return nil } - if hcsCallbacksSupported { - if err := process.unregisterCallback(); err != nil { - return makeProcessError(process, operation, "", err) - } + if err := process.unregisterCallback(); err != nil { + return makeProcessError(process, operation, "", err) } if err := hcsCloseProcess(process.handle); err != nil { @@ -321,6 +322,7 @@ func (process *process) Close() error { } process.handle = 0 + runtime.SetFinalizer(process, nil) logrus.Debugf(title+" succeeded processid=%d", process.processID) return nil diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go index c219e2c07d..bd6e2d94ab 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go @@ -7,12 +7,6 @@ import ( "github.com/Microsoft/go-winio" ) -var ( - vmcomputedll = syscall.NewLazyDLL("vmcompute.dll") - hcsCallbackAPI = vmcomputedll.NewProc("HcsRegisterComputeSystemCallback") - hcsCallbacksSupported = hcsCallbackAPI.Find() == nil -) - // makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles // if there is an error. func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) { diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go index 8ce65ae110..89c94616ad 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go @@ -1,52 +1,10 @@ package hcsshim import ( - "github.com/Sirupsen/logrus" - "syscall" "time" -) - -type waitable interface { - waitTimeoutInternal(timeout uint32) (bool, error) - hcsWait(timeout uint32) (bool, error) -} - -func waitTimeoutHelper(object waitable, timeout time.Duration) (bool, error) { - var ( - millis uint32 - ) - - for totalMillis := uint64(timeout / time.Millisecond); totalMillis > 0; totalMillis = totalMillis - uint64(millis) { - if totalMillis >= syscall.INFINITE { - millis = syscall.INFINITE - 1 - } else { - millis = uint32(totalMillis) - } - - result, err := object.waitTimeoutInternal(millis) - - if err != nil { - return result, err - } - } - return true, nil -} - -func waitTimeoutInternalHelper(object waitable, timeout uint32) (bool, error) { - return object.hcsWait(timeout) -} -func waitForSingleObject(handle syscall.Handle, timeout uint32) (bool, error) { - s, e := syscall.WaitForSingleObject(handle, timeout) - switch s { - case syscall.WAIT_OBJECT_0: - return true, nil - case syscall.WAIT_TIMEOUT: - return false, nil - default: - return false, e - } -} + "github.com/Sirupsen/logrus" +) func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error { err = processHcsResult(err, resultp) @@ -68,37 +26,13 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific return ErrInvalidNotificationType } + var c <-chan time.Time if timeout != nil { timer := time.NewTimer(*timeout) + c = timer.C defer timer.Stop() - - select { - case err, ok := <-expectedChannel: - if !ok { - return ErrHandleClose - } - return err - case err, ok := <-channels[hcsNotificationSystemExited]: - if !ok { - return ErrHandleClose - } - // If the expected notification is hcsNotificationSystemExited which of the two selects - // chosen is random. Return the raw error if hcsNotificationSystemExited is expected - if channels[hcsNotificationSystemExited] == expectedChannel { - return err - } - return ErrUnexpectedContainerExit - case _, ok := <-channels[hcsNotificationServiceDisconnect]: - if !ok { - return ErrHandleClose - } - // hcsNotificationServiceDisconnect should never be an expected notification - // it does not need the same handling as hcsNotificationSystemExited - return ErrUnexpectedProcessAbort - case <-timer.C: - return ErrTimeout - } } + select { case err, ok := <-expectedChannel: if !ok { @@ -122,5 +56,7 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific // hcsNotificationServiceDisconnect should never be an expected notification // it does not need the same handling as hcsNotificationSystemExited return ErrUnexpectedProcessAbort + case <-c: + return ErrTimeout } } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go index 3ae95864cc..7c3b7bdf5f 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go @@ -13,69 +13,57 @@ var ( modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") modvmcompute = syscall.NewLazyDLL("vmcompute.dll") - procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") - procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId") - procActivateLayer = modvmcompute.NewProc("ActivateLayer") - procCopyLayer = modvmcompute.NewProc("CopyLayer") - procCreateLayer = modvmcompute.NewProc("CreateLayer") - procCreateSandboxLayer = modvmcompute.NewProc("CreateSandboxLayer") - procExpandSandboxSize = modvmcompute.NewProc("ExpandSandboxSize") - procDeactivateLayer = modvmcompute.NewProc("DeactivateLayer") - procDestroyLayer = modvmcompute.NewProc("DestroyLayer") - procExportLayer = modvmcompute.NewProc("ExportLayer") - procGetLayerMountPath = modvmcompute.NewProc("GetLayerMountPath") - procGetBaseImages = modvmcompute.NewProc("GetBaseImages") - procImportLayer = modvmcompute.NewProc("ImportLayer") - procLayerExists = modvmcompute.NewProc("LayerExists") - procNameToGuid = modvmcompute.NewProc("NameToGuid") - procPrepareLayer = modvmcompute.NewProc("PrepareLayer") - procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer") - procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage") - procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage") - procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin") - procImportLayerNext = modvmcompute.NewProc("ImportLayerNext") - procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite") - procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd") - procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin") - procExportLayerNext = modvmcompute.NewProc("ExportLayerNext") - procExportLayerRead = modvmcompute.NewProc("ExportLayerRead") - procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd") - procCreateComputeSystem = modvmcompute.NewProc("CreateComputeSystem") - procCreateProcessWithStdHandlesInComputeSystem = modvmcompute.NewProc("CreateProcessWithStdHandlesInComputeSystem") - procResizeConsoleInComputeSystem = modvmcompute.NewProc("ResizeConsoleInComputeSystem") - procShutdownComputeSystem = modvmcompute.NewProc("ShutdownComputeSystem") - procStartComputeSystem = modvmcompute.NewProc("StartComputeSystem") - procTerminateComputeSystem = modvmcompute.NewProc("TerminateComputeSystem") - procTerminateProcessInComputeSystem = modvmcompute.NewProc("TerminateProcessInComputeSystem") - procWaitForProcessInComputeSystem = modvmcompute.NewProc("WaitForProcessInComputeSystem") - procGetComputeSystemProperties = modvmcompute.NewProc("GetComputeSystemProperties") - procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems") - procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem") - procHcsOpenComputeSystem = modvmcompute.NewProc("HcsOpenComputeSystem") - procHcsCloseComputeSystem = modvmcompute.NewProc("HcsCloseComputeSystem") - procHcsStartComputeSystem = modvmcompute.NewProc("HcsStartComputeSystem") - procHcsShutdownComputeSystem = modvmcompute.NewProc("HcsShutdownComputeSystem") - procHcsTerminateComputeSystem = modvmcompute.NewProc("HcsTerminateComputeSystem") - procHcsPauseComputeSystem = modvmcompute.NewProc("HcsPauseComputeSystem") - procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem") - procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties") - procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem") - procHcsCreateComputeSystemWait = modvmcompute.NewProc("HcsCreateComputeSystemWait") - procHcsCreateProcess = modvmcompute.NewProc("HcsCreateProcess") - procHcsOpenProcess = modvmcompute.NewProc("HcsOpenProcess") - procHcsCloseProcess = modvmcompute.NewProc("HcsCloseProcess") - procHcsTerminateProcess = modvmcompute.NewProc("HcsTerminateProcess") - procHcsGetProcessInfo = modvmcompute.NewProc("HcsGetProcessInfo") - procHcsGetProcessProperties = modvmcompute.NewProc("HcsGetProcessProperties") - procHcsModifyProcess = modvmcompute.NewProc("HcsModifyProcess") - procHcsCreateProcessWait = modvmcompute.NewProc("HcsCreateProcessWait") - procHcsGetServiceProperties = modvmcompute.NewProc("HcsGetServiceProperties") - procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings") - + procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") + procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId") + procActivateLayer = modvmcompute.NewProc("ActivateLayer") + procCopyLayer = modvmcompute.NewProc("CopyLayer") + procCreateLayer = modvmcompute.NewProc("CreateLayer") + procCreateSandboxLayer = modvmcompute.NewProc("CreateSandboxLayer") + procExpandSandboxSize = modvmcompute.NewProc("ExpandSandboxSize") + procDeactivateLayer = modvmcompute.NewProc("DeactivateLayer") + procDestroyLayer = modvmcompute.NewProc("DestroyLayer") + procExportLayer = modvmcompute.NewProc("ExportLayer") + procGetLayerMountPath = modvmcompute.NewProc("GetLayerMountPath") + procGetBaseImages = modvmcompute.NewProc("GetBaseImages") + procImportLayer = modvmcompute.NewProc("ImportLayer") + procLayerExists = modvmcompute.NewProc("LayerExists") + procNameToGuid = modvmcompute.NewProc("NameToGuid") + procPrepareLayer = modvmcompute.NewProc("PrepareLayer") + procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer") + procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage") + procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage") + procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin") + procImportLayerNext = modvmcompute.NewProc("ImportLayerNext") + procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite") + procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd") + procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin") + procExportLayerNext = modvmcompute.NewProc("ExportLayerNext") + procExportLayerRead = modvmcompute.NewProc("ExportLayerRead") + procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd") + procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems") + procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem") + procHcsOpenComputeSystem = modvmcompute.NewProc("HcsOpenComputeSystem") + procHcsCloseComputeSystem = modvmcompute.NewProc("HcsCloseComputeSystem") + procHcsStartComputeSystem = modvmcompute.NewProc("HcsStartComputeSystem") + procHcsShutdownComputeSystem = modvmcompute.NewProc("HcsShutdownComputeSystem") + procHcsTerminateComputeSystem = modvmcompute.NewProc("HcsTerminateComputeSystem") + procHcsPauseComputeSystem = modvmcompute.NewProc("HcsPauseComputeSystem") + procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem") + procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties") + procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem") procHcsRegisterComputeSystemCallback = modvmcompute.NewProc("HcsRegisterComputeSystemCallback") procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback") + procHcsCreateProcess = modvmcompute.NewProc("HcsCreateProcess") + procHcsOpenProcess = modvmcompute.NewProc("HcsOpenProcess") + procHcsCloseProcess = modvmcompute.NewProc("HcsCloseProcess") + procHcsTerminateProcess = modvmcompute.NewProc("HcsTerminateProcess") + procHcsGetProcessInfo = modvmcompute.NewProc("HcsGetProcessInfo") + procHcsGetProcessProperties = modvmcompute.NewProc("HcsGetProcessProperties") + procHcsModifyProcess = modvmcompute.NewProc("HcsModifyProcess") + procHcsGetServiceProperties = modvmcompute.NewProc("HcsGetServiceProperties") procHcsRegisterProcessCallback = modvmcompute.NewProc("HcsRegisterProcessCallback") procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback") + procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings") procHNSCall = modvmcompute.NewProc("HNSCall") ) @@ -599,196 +587,6 @@ func exportLayerEnd(context uintptr) (hr error) { return } -func createComputeSystem(id string, configuration string) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - var _p1 *uint16 - _p1, hr = syscall.UTF16PtrFromString(configuration) - if hr != nil { - return - } - return _createComputeSystem(_p0, _p1) -} - -func _createComputeSystem(id *uint16, configuration *uint16) (hr error) { - if hr = procCreateComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procCreateComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - var _p1 *uint16 - _p1, hr = syscall.UTF16PtrFromString(paramsJson) - if hr != nil { - return - } - return _createProcessWithStdHandlesInComputeSystem(_p0, _p1, pid, stdin, stdout, stderr) -} - -func _createProcessWithStdHandlesInComputeSystem(id *uint16, paramsJson *uint16, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) { - if hr = procCreateProcessWithStdHandlesInComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall6(procCreateProcessWithStdHandlesInComputeSystem.Addr(), 6, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(paramsJson)), uintptr(unsafe.Pointer(pid)), uintptr(unsafe.Pointer(stdin)), uintptr(unsafe.Pointer(stdout)), uintptr(unsafe.Pointer(stderr))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - return _resizeConsoleInComputeSystem(_p0, pid, height, width, flags) -} - -func _resizeConsoleInComputeSystem(id *uint16, pid uint32, height uint16, width uint16, flags uint32) (hr error) { - if hr = procResizeConsoleInComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall6(procResizeConsoleInComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(height), uintptr(width), uintptr(flags), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func shutdownComputeSystem(id string, timeout uint32) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - return _shutdownComputeSystem(_p0, timeout) -} - -func _shutdownComputeSystem(id *uint16, timeout uint32) (hr error) { - if hr = procShutdownComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procShutdownComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(timeout), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func startComputeSystem(id string) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - return _startComputeSystem(_p0) -} - -func _startComputeSystem(id *uint16) (hr error) { - if hr = procStartComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procStartComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func terminateComputeSystem(id string) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - return _terminateComputeSystem(_p0) -} - -func _terminateComputeSystem(id *uint16) (hr error) { - if hr = procTerminateComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procTerminateComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func terminateProcessInComputeSystem(id string, pid uint32) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - return _terminateProcessInComputeSystem(_p0, pid) -} - -func _terminateProcessInComputeSystem(id *uint16, pid uint32) (hr error) { - if hr = procTerminateProcessInComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procTerminateProcessInComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(pid), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - return _waitForProcessInComputeSystem(_p0, pid, timeout, exitCode) -} - -func _waitForProcessInComputeSystem(id *uint16, pid uint32, timeout uint32, exitCode *uint32) (hr error) { - if hr = procWaitForProcessInComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall6(procWaitForProcessInComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(timeout), uintptr(unsafe.Pointer(exitCode)), 0, 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func getComputeSystemProperties(id string, flags uint32, properties **uint16) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - return _getComputeSystemProperties(_p0, flags, properties) -} - -func _getComputeSystemProperties(id *uint16, flags uint32, properties **uint16) (hr error) { - if hr = procGetComputeSystemProperties.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procGetComputeSystemProperties.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(flags), uintptr(unsafe.Pointer(properties))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - func hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(query) @@ -1005,11 +803,22 @@ func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, res return } -func hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) { - if hr = procHcsCreateComputeSystemWait.Find(); hr != nil { +func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { + if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) { + if hr = procHcsUnregisterComputeSystemCallback.Find(); hr != nil { return } - r0, _, _ := syscall.Syscall(procHcsCreateComputeSystemWait.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(exitEvent)), uintptr(unsafe.Pointer(result))) + r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) if int32(r0) < 0 { hr = syscall.Errno(win32FromHresult(r0)) } @@ -1111,17 +920,6 @@ func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (h return } -func hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) { - if hr = procHcsCreateProcessWait.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsCreateProcessWait.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - func hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(propertyQuery) @@ -1142,144 +940,42 @@ func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result return } -func hcsModifyServiceSettings(settings string, result **uint16) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(settings) - if hr != nil { - return - } - return _hcsModifyServiceSettings(_p0, result) -} - -func _hcsModifyServiceSettings(settings *uint16, result **uint16) (hr error) { - if hr = procHcsModifyServiceSettings.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsModifyServiceSettings.Addr(), 2, uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - var _p1 *uint16 - _p1, hr = syscall.UTF16PtrFromString(configuration) - if hr != nil { - return - } - return _hcsCreateComputeSystemTP5(_p0, _p1, computeSystem, result) -} - -func _hcsCreateComputeSystemTP5(id *uint16, configuration *uint16, computeSystem *hcsSystem, result **uint16) (hr error) { - if hr = procHcsCreateComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0, 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsStartComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsShutdownComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsTerminateComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsPauseComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsResumeComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { - if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil { +func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { + if hr = procHcsRegisterProcessCallback.Find(); hr != nil { return } - r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) + r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) if int32(r0) < 0 { hr = syscall.Errno(win32FromHresult(r0)) } return } -func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) { - if hr = procHcsUnregisterComputeSystemCallback.Find(); hr != nil { +func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) { + if hr = procHcsUnregisterProcessCallback.Find(); hr != nil { return } - r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) + r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) if int32(r0) < 0 { hr = syscall.Errno(win32FromHresult(r0)) } return } -func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { - if hr = procHcsRegisterProcessCallback.Find(); hr != nil { +func hcsModifyServiceSettings(settings string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(settings) + if hr != nil { return } - r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return + return _hcsModifyServiceSettings(_p0, result) } -func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) { - if hr = procHcsUnregisterProcessCallback.Find(); hr != nil { +func _hcsModifyServiceSettings(settings *uint16, result **uint16) (hr error) { + if hr = procHcsModifyServiceSettings.Find(); hr != nil { return } - r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) + r0, _, _ := syscall.Syscall(procHcsModifyServiceSettings.Addr(), 2, uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)), 0) if int32(r0) < 0 { hr = syscall.Errno(win32FromHresult(r0)) } diff --git a/default_gateway.go b/default_gateway.go index 2f2e284ff1..163348b49f 100644 --- a/default_gateway.go +++ b/default_gateway.go @@ -2,13 +2,14 @@ package libnetwork import ( "fmt" + "strings" + "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/types" ) const ( - libnGWNetwork = "docker_gwbridge" - gwEPlen = 12 + gwEPlen = 12 ) var procGwNetwork = make(chan (bool), 1) @@ -52,6 +53,21 @@ func (sb *sandbox) setupDefaultGW() error { eplen = len(sb.containerID) } + sbLabels := sb.Labels() + + if sbLabels[netlabel.PortMap] != nil { + createOptions = append(createOptions, CreateOptionPortMapping(sbLabels[netlabel.PortMap].([]types.PortBinding))) + } + + if sbLabels[netlabel.ExposedPorts] != nil { + createOptions = append(createOptions, CreateOptionExposedPorts(sbLabels[netlabel.ExposedPorts].([]types.TransportPort))) + } + + epOption := getPlatformOption() + if epOption != nil { + createOptions = append(createOptions, epOption) + } + newEp, err := n.CreateEndpoint("gateway_"+sb.containerID[0:eplen], createOptions...) if err != nil { return fmt.Errorf("container %s: endpoint create on GW Network failed: %v", sb.containerID, err) @@ -119,7 +135,7 @@ func (sb *sandbox) needDefaultGW() bool { func (sb *sandbox) getEndpointInGWNetwork() *endpoint { for _, ep := range sb.getConnectedEndpoints() { - if ep.getNetwork().name == libnGWNetwork { + if ep.getNetwork().name == libnGWNetwork && strings.HasPrefix(ep.Name(), "gateway_") { return ep } } @@ -127,7 +143,7 @@ func (sb *sandbox) getEndpointInGWNetwork() *endpoint { } func (ep *endpoint) endpointInGWNetwork() bool { - if ep.getNetwork().name == libnGWNetwork { + if ep.getNetwork().name == libnGWNetwork && strings.HasPrefix(ep.Name(), "gateway_") { return true } return false diff --git a/default_gateway_freebsd.go b/default_gateway_freebsd.go index a82687391a..dc4b1bd592 100644 --- a/default_gateway_freebsd.go +++ b/default_gateway_freebsd.go @@ -2,6 +2,12 @@ package libnetwork import "github.com/docker/libnetwork/types" +const libnGWNetwork = "docker_gwbridge" + +func getPlatformOption() EndpointOption { + return nil +} + func (c *controller) createGWNetwork() (Network, error) { return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in freebsd") } diff --git a/default_gateway_linux.go b/default_gateway_linux.go index c08b061898..60df856722 100644 --- a/default_gateway_linux.go +++ b/default_gateway_linux.go @@ -7,6 +7,12 @@ import ( "github.com/docker/libnetwork/drivers/bridge" ) +const libnGWNetwork = "docker_gwbridge" + +func getPlatformOption() EndpointOption { + return nil +} + func (c *controller) createGWNetwork() (Network, error) { netOption := map[string]string{ bridge.BridgeName: libnGWNetwork, diff --git a/default_gateway_solaris.go b/default_gateway_solaris.go index 42f4d5c630..8d86a66c1d 100644 --- a/default_gateway_solaris.go +++ b/default_gateway_solaris.go @@ -7,6 +7,12 @@ import ( "github.com/docker/libnetwork/drivers/solaris/bridge" ) +const libnGWNetwork = "docker_gwbridge" + +func getPlatformOption() EndpointOption { + return nil +} + func (c *controller) createGWNetwork() (Network, error) { netOption := map[string]string{ bridge.BridgeName: libnGWNetwork, diff --git a/default_gateway_windows.go b/default_gateway_windows.go index 48eee2ba1d..f4ba198e57 100644 --- a/default_gateway_windows.go +++ b/default_gateway_windows.go @@ -1,6 +1,21 @@ package libnetwork -import "github.com/docker/libnetwork/types" +import ( + windriver "github.com/docker/libnetwork/drivers/windows" + "github.com/docker/libnetwork/options" + "github.com/docker/libnetwork/types" +) + +const libnGWNetwork = "nat" + +func getPlatformOption() EndpointOption { + + epOption := options.Generic{ + windriver.DisableICC: true, + windriver.DisableDNS: true, + } + return EndpointOptionGeneric(epOption) +} func (c *controller) createGWNetwork() (Network, error) { return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in windows") diff --git a/drivers/windows/labels.go b/drivers/windows/labels.go index 5740913c04..b32c6ffb61 100644 --- a/drivers/windows/labels.go +++ b/drivers/windows/labels.go @@ -30,4 +30,10 @@ const ( // SourceMac of the network SourceMac = "com.docker.network.windowsshim.sourcemac" + + // DisableICC label + DisableICC = "com.docker.network.windowsshim.disableicc" + + // DisableDNS label + DisableDNS = "com.docker.network.windowsshim.disable_dns" ) diff --git a/drivers/windows/overlay/joinleave_windows.go b/drivers/windows/overlay/joinleave_windows.go index 0bef47c7db..bfdadf8674 100644 --- a/drivers/windows/overlay/joinleave_windows.go +++ b/drivers/windows/overlay/joinleave_windows.go @@ -44,8 +44,6 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, logrus.Errorf("overlay: Failed adding table entry to joininfo: %v", err) } - jinfo.DisableGatewayService() - d.pushLocalEndpointEvent("join", nid, eid) return nil diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index 0165814118..f9c61d3023 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -44,21 +44,28 @@ type networkConfiguration struct { } // endpointConfiguration represents the user specified configuration for the sandbox endpoint -type endpointConfiguration struct { - MacAddress net.HardwareAddr +type endpointOption struct { + MacAddress net.HardwareAddr + QosPolicies []types.QosPolicy + DNSServers []string + DisableDNS bool + DisableICC bool +} + +type endpointConnectivity struct { PortBindings []types.PortBinding ExposedPorts []types.TransportPort - QosPolicies []types.QosPolicy - DNSServers []string } type hnsEndpoint struct { - id string - profileID string - macAddress net.HardwareAddr - config *endpointConfiguration // User specified parameters - portMapping []types.PortBinding // Operation port bindings - addr *net.IPNet + id string + profileID string + macAddress net.HardwareAddr + epOption *endpointOption // User specified parameters + epConnectivity *endpointConnectivity // User specified parameters + portMapping []types.PortBinding // Operation port bindings + addr *net.IPNet + gateway net.IP } type hnsNetwork struct { @@ -391,12 +398,12 @@ func parsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, return bindings, nil } -func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) { +func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) { if epOptions == nil { return nil, nil } - ec := &endpointConfiguration{} + ec := &endpointOption{} if opt, ok := epOptions[netlabel.MacAddress]; ok { if mac, ok := opt.(net.HardwareAddr); ok { @@ -406,33 +413,33 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfigurat } } - if opt, ok := epOptions[netlabel.PortMap]; ok { - if bs, ok := opt.([]types.PortBinding); ok { - ec.PortBindings = bs + if opt, ok := epOptions[QosPolicies]; ok { + if policies, ok := opt.([]types.QosPolicy); ok { + ec.QosPolicies = policies } else { return nil, fmt.Errorf("Invalid endpoint configuration") } } - if opt, ok := epOptions[netlabel.ExposedPorts]; ok { - if ports, ok := opt.([]types.TransportPort); ok { - ec.ExposedPorts = ports + if opt, ok := epOptions[netlabel.DNSServers]; ok { + if dns, ok := opt.([]string); ok { + ec.DNSServers = dns } else { return nil, fmt.Errorf("Invalid endpoint configuration") } } - if opt, ok := epOptions[QosPolicies]; ok { - if policies, ok := opt.([]types.QosPolicy); ok { - ec.QosPolicies = policies + if opt, ok := epOptions[DisableICC]; ok { + if disableICC, ok := opt.(bool); ok { + ec.DisableICC = disableICC } else { return nil, fmt.Errorf("Invalid endpoint configuration") } } - if opt, ok := epOptions[netlabel.DNSServers]; ok { - if dns, ok := opt.([]string); ok { - ec.DNSServers = dns + if opt, ok := epOptions[DisableDNS]; ok { + if disableDNS, ok := opt.(bool); ok { + ec.DisableDNS = disableDNS } else { return nil, fmt.Errorf("Invalid endpoint configuration") } @@ -441,6 +448,31 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfigurat return ec, nil } +func parseEndpointConnectivity(epOptions map[string]interface{}) (*endpointConnectivity, error) { + if epOptions == nil { + return nil, nil + } + + ec := &endpointConnectivity{} + + if opt, ok := epOptions[netlabel.PortMap]; ok { + if bs, ok := opt.([]types.PortBinding); ok { + ec.PortBindings = bs + } else { + return nil, fmt.Errorf("Invalid endpoint configuration") + } + } + + if opt, ok := epOptions[netlabel.ExposedPorts]; ok { + if ports, ok := opt.([]types.TransportPort); ok { + ec.ExposedPorts = ports + } else { + return nil, fmt.Errorf("Invalid endpoint configuration") + } + } + return ec, nil +} + func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { n, err := d.getNetwork(nid) if err != nil { @@ -457,7 +489,8 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, VirtualNetwork: n.config.HnsID, } - ec, err := parseEndpointOptions(epOptions) + epOption, err := parseEndpointOptions(epOptions) + epConnectivity, err := parseEndpointConnectivity(epOptions) macAddress := ifInfo.MacAddress() // Use the macaddress if it was provided @@ -465,12 +498,12 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1) } - endpointStruct.Policies, err = convertPortBindings(ec.PortBindings) + endpointStruct.Policies, err = convertPortBindings(epConnectivity.PortBindings) if err != nil { return err } - qosPolicies, err := convertQosPolicies(ec.QosPolicies) + qosPolicies, err := convertQosPolicies(epOption.QosPolicies) if err != nil { return err } @@ -480,12 +513,14 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, endpointStruct.IPAddress = ifInfo.Address().IP } - endpointStruct.DNSServerList = strings.Join(ec.DNSServers, ",") + endpointStruct.DNSServerList = strings.Join(epOption.DNSServers, ",") - if n.driver.name == "nat" { + if n.driver.name == "nat" && !epOption.DisableDNS { endpointStruct.EnableInternalDNS = true } + endpointStruct.DisableICC = epOption.DisableICC + configurationb, err := json.Marshal(endpointStruct) if err != nil { return err @@ -508,8 +543,13 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, macAddress: mac, } + if hnsresponse.GatewayAddress != "" { + endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress) + } + endpoint.profileID = hnsresponse.Id - endpoint.config = ec + endpoint.epConnectivity = epConnectivity + endpoint.epOption = epOption endpoint.portMapping, err = parsePortBindingPolicies(hnsresponse.Policies) if err != nil { @@ -572,10 +612,10 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro } data["hnsid"] = ep.profileID - if ep.config.ExposedPorts != nil { + if ep.epConnectivity.ExposedPorts != nil { // Return a copy of the config data - epc := make([]types.TransportPort, 0, len(ep.config.ExposedPorts)) - for _, tp := range ep.config.ExposedPorts { + epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts)) + for _, tp := range ep.epConnectivity.ExposedPorts { epc = append(epc, tp.GetCopy()) } data[netlabel.ExposedPorts] = epc @@ -604,7 +644,12 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, } // Ensure that the endpoint exists - _, err = network.getEndpoint(eid) + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + err = jinfo.SetGateway(endpoint.gateway) if err != nil { return err } diff --git a/endpoint_info.go b/endpoint_info.go index 1042ddaa8f..6814de0089 100644 --- a/endpoint_info.go +++ b/endpoint_info.go @@ -205,31 +205,6 @@ func (ep *endpoint) Info() EndpointInfo { return nil } -func (ep *endpoint) DriverInfo() (map[string]interface{}, error) { - ep, err := ep.retrieveFromStore() - if err != nil { - return nil, err - } - - if sb, ok := ep.getSandbox(); ok { - if gwep := sb.getEndpointInGWNetwork(); gwep != nil && gwep.ID() != ep.ID() { - return gwep.DriverInfo() - } - } - - n, err := ep.getNetworkFromStore() - if err != nil { - return nil, fmt.Errorf("could not find network in store for driver info: %v", err) - } - - driver, err := n.driver(true) - if err != nil { - return nil, fmt.Errorf("failed to get driver info: %v", err) - } - - return driver.EndpointOperInfo(n.ID(), ep.ID()) -} - func (ep *endpoint) Iface() InterfaceInfo { ep.Lock() defer ep.Unlock() diff --git a/endpoint_info_unix.go b/endpoint_info_unix.go new file mode 100644 index 0000000000..f2534f4904 --- /dev/null +++ b/endpoint_info_unix.go @@ -0,0 +1,30 @@ +// +build !windows + +package libnetwork + +import "fmt" + +func (ep *endpoint) DriverInfo() (map[string]interface{}, error) { + ep, err := ep.retrieveFromStore() + if err != nil { + return nil, err + } + + if sb, ok := ep.getSandbox(); ok { + if gwep := sb.getEndpointInGWNetwork(); gwep != nil && gwep.ID() != ep.ID() { + return gwep.DriverInfo() + } + } + + n, err := ep.getNetworkFromStore() + if err != nil { + return nil, fmt.Errorf("could not find network in store for driver info: %v", err) + } + + driver, err := n.driver(true) + if err != nil { + return nil, fmt.Errorf("failed to get driver info: %v", err) + } + + return driver.EndpointOperInfo(n.ID(), ep.ID()) +} diff --git a/endpoint_info_windows.go b/endpoint_info_windows.go new file mode 100644 index 0000000000..93ad8330e9 --- /dev/null +++ b/endpoint_info_windows.go @@ -0,0 +1,45 @@ +// +build windows + +package libnetwork + +import "fmt" + +func (ep *endpoint) DriverInfo() (map[string]interface{}, error) { + ep, err := ep.retrieveFromStore() + if err != nil { + return nil, err + } + + var gwDriverInfo map[string]interface{} + if sb, ok := ep.getSandbox(); ok { + if gwep := sb.getEndpointInGWNetwork(); gwep != nil && gwep.ID() != ep.ID() { + + gwDriverInfo, err = gwep.DriverInfo() + if err != nil { + return nil, err + } + } + } + + n, err := ep.getNetworkFromStore() + if err != nil { + return nil, fmt.Errorf("could not find network in store for driver info: %v", err) + } + + driver, err := n.driver(true) + if err != nil { + return nil, fmt.Errorf("failed to get driver info: %v", err) + } + + epInfo, err := driver.EndpointOperInfo(n.ID(), ep.ID()) + if err != nil { + return nil, err + } + + if epInfo != nil { + epInfo["GW_INFO"] = gwDriverInfo + return epInfo, nil + } + + return gwDriverInfo, nil +} From e927d371245eb04fb582a3035a02f30b3465b439 Mon Sep 17 00:00:00 2001 From: Dong Chen Date: Tue, 8 Nov 2016 15:06:47 -0800 Subject: [PATCH 142/799] Support attachable in network. Signed-off-by: Dong Chen --- network.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/network.go b/network.go index d58abdcc65..88b70e0075 100644 --- a/network.go +++ b/network.go @@ -65,6 +65,7 @@ type NetworkInfo interface { Scope() string IPv6Enabled() bool Internal() bool + Attachable() bool Labels() map[string]string Dynamic() bool Created() time.Time @@ -196,6 +197,7 @@ type network struct { resolverOnce sync.Once resolver []Resolver internal bool + attachable bool inDelete bool ingress bool driverTables []string @@ -348,6 +350,7 @@ func (n *network) CopyTo(o datastore.KVObject) error { dstN.dbExists = n.dbExists dstN.drvOnce = n.drvOnce dstN.internal = n.internal + dstN.attachable = n.attachable dstN.inDelete = n.inDelete dstN.ingress = n.ingress @@ -456,6 +459,7 @@ func (n *network) MarshalJSON() ([]byte, error) { netMap["ipamV6Info"] = string(iis) } netMap["internal"] = n.internal + netMap["attachable"] = n.attachable netMap["inDelete"] = n.inDelete netMap["ingress"] = n.ingress return json.Marshal(netMap) @@ -550,6 +554,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { if v, ok := netMap["internal"]; ok { n.internal = v.(bool) } + if v, ok := netMap["attachable"]; ok { + n.attachable = v.(bool) + } if s, ok := netMap["scope"]; ok { n.scope = s.(string) } @@ -628,6 +635,13 @@ func NetworkOptionInternalNetwork() NetworkOption { } } +// NetworkOptionAttachable returns an option setter to set attachable for a network +func NetworkOptionAttachable(attachable bool) NetworkOption { + return func(n *network) { + n.attachable = attachable + } +} + // NetworkOptionIpam function returns an option setter for the ipam configuration for this network func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf, opts map[string]string) NetworkOption { return func(n *network) { @@ -1555,6 +1569,13 @@ func (n *network) Internal() bool { return n.internal } +func (n *network) Attachable() bool { + n.Lock() + defer n.Unlock() + + return n.attachable +} + func (n *network) Dynamic() bool { n.Lock() defer n.Unlock() From 97ec7f8a4cd1e404d191430c32942ee81b81d060 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 8 Nov 2016 18:37:29 -0800 Subject: [PATCH 143/799] Update libkv @1d84310 Signed-off-by: Alessandro Boch --- Godeps/Godeps.json | 27 +++++++++---------- .../src/github.com/docker/libkv/.travis.yml | 4 +-- .../src/github.com/docker/libkv/MAINTAINERS | 6 ----- .../docker/libkv/store/boltdb/boltdb.go | 7 ++++- .../docker/libkv/store/zookeeper/zookeeper.go | 2 +- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 8fa0717b35..8bb089fe06 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,7 +1,6 @@ { "ImportPath": "github.com/docker/libnetwork", - "GoVersion": "go1.5", - "GodepVersion": "v74", + "GoVersion": "go1.7", "Packages": [ "./..." ], @@ -218,33 +217,33 @@ }, { "ImportPath": "github.com/docker/libkv", - "Comment": "v0.2.0-1-g7283ef2", - "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" + "Comment": "v0.2.1-5-g1d84310", + "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" }, { "ImportPath": "github.com/docker/libkv/store", - "Comment": "v0.2.0-1-g7283ef2", - "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" + "Comment": "v0.2.1-5-g1d84310", + "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" }, { "ImportPath": "github.com/docker/libkv/store/boltdb", - "Comment": "v0.2.0-1-g7283ef2", - "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" + "Comment": "v0.2.1-5-g1d84310", + "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" }, { "ImportPath": "github.com/docker/libkv/store/consul", - "Comment": "v0.2.0-1-g7283ef2", - "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" + "Comment": "v0.2.1-5-g1d84310", + "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" }, { "ImportPath": "github.com/docker/libkv/store/etcd", - "Comment": "v0.2.0-1-g7283ef2", - "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" + "Comment": "v0.2.1-5-g1d84310", + "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" }, { "ImportPath": "github.com/docker/libkv/store/zookeeper", - "Comment": "v0.2.0-1-g7283ef2", - "Rev": "7283ef27ed32fe267388510a91709b307bb9942c" + "Comment": "v0.2.1-5-g1d84310", + "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" }, { "ImportPath": "github.com/godbus/dbus", diff --git a/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml b/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml index f7cecbdf9c..a7a3bcffc7 100644 --- a/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml +++ b/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml @@ -1,7 +1,7 @@ language: go go: - - 1.5.3 + - 1.7.1 # let us have speedy Docker-based Travis workers sudo: false @@ -16,7 +16,7 @@ before_install: before_script: - script/travis_consul.sh 0.6.3 - - script/travis_etcd.sh 2.2.5 + - script/travis_etcd.sh 3.0.0 - script/travis_zk.sh 3.5.1-alpha script: diff --git a/Godeps/_workspace/src/github.com/docker/libkv/MAINTAINERS b/Godeps/_workspace/src/github.com/docker/libkv/MAINTAINERS index 4dd59c7e27..4a8bbc6135 100644 --- a/Godeps/_workspace/src/github.com/docker/libkv/MAINTAINERS +++ b/Godeps/_workspace/src/github.com/docker/libkv/MAINTAINERS @@ -11,7 +11,6 @@ [Org] [Org."Core maintainers"] people = [ - "abronan", "aluzzardi", "sanimej", "vieux", @@ -25,11 +24,6 @@ # ADD YOURSELF HERE IN ALPHABETICAL ORDER - [people.abronan] - Name = "Alexandre Beslic" - Email = "abronan@docker.com" - GitHub = "abronan" - [people.aluzzardi] Name = "Andrea Luzzardi" Email = "al@docker.com" diff --git a/Godeps/_workspace/src/github.com/docker/libkv/store/boltdb/boltdb.go b/Godeps/_workspace/src/github.com/docker/libkv/store/boltdb/boltdb.go index 4026e0a20c..cdfd74f878 100644 --- a/Godeps/_workspace/src/github.com/docker/libkv/store/boltdb/boltdb.go +++ b/Godeps/_workspace/src/github.com/docker/libkv/store/boltdb/boltdb.go @@ -59,6 +59,7 @@ func New(endpoints []string, options *store.Config) (store.Store, error) { db *bolt.DB err error boltOptions *bolt.Options + timeout = transientTimeout ) if len(endpoints) > 1 { @@ -82,11 +83,15 @@ func New(endpoints []string, options *store.Config) (store.Store, error) { } } + if options.ConnectionTimeout != 0 { + timeout = options.ConnectionTimeout + } + b := &BoltDB{ client: db, path: endpoints[0], boltBucket: []byte(options.Bucket), - timeout: transientTimeout, + timeout: timeout, PersistConnection: options.PersistConnection, } diff --git a/Godeps/_workspace/src/github.com/docker/libkv/store/zookeeper/zookeeper.go b/Godeps/_workspace/src/github.com/docker/libkv/store/zookeeper/zookeeper.go index 8a44ad318a..ff8d4ebe0f 100644 --- a/Godeps/_workspace/src/github.com/docker/libkv/store/zookeeper/zookeeper.go +++ b/Godeps/_workspace/src/github.com/docker/libkv/store/zookeeper/zookeeper.go @@ -252,7 +252,7 @@ func (s *Zookeeper) List(directory string) ([]*store.KVPair, error) { pair, err := s.Get(strings.TrimSuffix(directory, "/") + s.normalize(key)) if err != nil { // If node is not found: List is out of date, retry - if err == zk.ErrNoNode { + if err == store.ErrKeyNotFound { return s.List(directory) } return nil, err From 11a6d1d9bc29ddfaca594de07b194567017dcd6c Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Fri, 4 Nov 2016 09:14:35 -0700 Subject: [PATCH 144/799] Respect auto allocation for --ipv6 Signed-off-by: Alessandro Boch --- api/api_test.go | 8 ++------ ipam/allocator.go | 2 +- network.go | 3 --- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/api/api_test.go b/api/api_test.go index ab83761239..288ef211ae 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -225,9 +225,7 @@ func TestCreateDeleteNetwork(t *testing.T) { } dops := GetOpsMap("abc", "") - nops := map[string]string{ - netlabel.EnableIPv6: "true", - } + nops := map[string]string{} nc := networkCreate{Name: "network_1", NetworkType: bridgeNetType, DriverOpts: dops, NetworkOpts: nops} goodBody, err := json.Marshal(nc) if err != nil { @@ -1807,9 +1805,7 @@ func TestEndToEnd(t *testing.T) { handleRequest := NewHTTPHandler(c) dops := GetOpsMap("cdef", "1460") - nops := map[string]string{ - netlabel.EnableIPv6: "true", - } + nops := map[string]string{} // Create network nc := networkCreate{Name: "network-fiftyfive", NetworkType: bridgeNetType, DriverOpts: dops, NetworkOpts: nops} diff --git a/ipam/allocator.go b/ipam/allocator.go index 3d69bd9b4f..bd00a14700 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -413,7 +413,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) } } - return nil, types.NotFoundErrorf("could not find an available non-overlapping address pool among the defaults to auto assign to the network") + return nil, types.NotFoundErrorf("could not find an available, non-overlapping IPv%d address pool among the defaults to assign to the network", v) } // RequestAddress returns an address from the specified pool ID diff --git a/network.go b/network.go index d58abdcc65..2fb766627d 100644 --- a/network.go +++ b/network.go @@ -1289,9 +1289,6 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error { } if len(*cfgList) == 0 { - if ipVer == 6 { - return nil - } *cfgList = []*IpamConf{{}} } From 6d4f9da19f1ecd102c59fb51d49e345790539980 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 8 Nov 2016 18:48:48 -0800 Subject: [PATCH 145/799] Increase timeout for local store client Signed-off-by: Alessandro Boch --- datastore/datastore.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/datastore/datastore.go b/datastore/datastore.go index fa6942d837..d7c17b5531 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -6,6 +6,7 @@ import ( "reflect" "strings" "sync" + "time" "github.com/docker/libkv" "github.com/docker/libkv/store" @@ -134,7 +135,8 @@ func makeDefaultScopes() map[string]*ScopeCfg { Provider: string(store.BOLTDB), Address: defaultPrefix + "/local-kv.db", Config: &store.Config{ - Bucket: "libnetwork", + Bucket: "libnetwork", + ConnectionTimeout: time.Minute, }, }, } From 2138db30077a5c8fe2b7411a581939c4746dc5f9 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Wed, 9 Nov 2016 14:07:32 -0800 Subject: [PATCH 146/799] Add GetIDInRange API in idm package Thanks @aboch Signed-off-by: Madhu Venugopal --- idm/idm.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/idm/idm.go b/idm/idm.go index 3ed820ca91..84839c1c9b 100644 --- a/idm/idm.go +++ b/idm/idm.go @@ -54,6 +54,19 @@ func (i *Idm) GetSpecificID(id uint64) error { return i.handle.Set(id - i.start) } +// GetIDInRange returns the first available id in the set within a range +func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) { + if i.handle == nil { + return 0, fmt.Errorf("ID set is not initialized") + } + + if start < i.start || end > i.end { + return 0, fmt.Errorf("Requested range does not belong to the set") + } + + return i.handle.SetAnyInRange(start, end-start) +} + // Release releases the specified id func (i *Idm) Release(id uint64) { i.handle.Unset(id - i.start) From 5ca142ab0e6c46aa74ee5467be1e7012b273f1c6 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Wed, 9 Nov 2016 13:26:59 -0800 Subject: [PATCH 147/799] IDM need not be bound by default vxlan-id start index This will allow users to use the full spectrum of vxlan-ids Signed-off-by: Madhu Venugopal --- drivers/overlay/ovmanager/ovmanager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/overlay/ovmanager/ovmanager.go b/drivers/overlay/ovmanager/ovmanager.go index 7b5caff0c8..2f69083f25 100644 --- a/drivers/overlay/ovmanager/ovmanager.go +++ b/drivers/overlay/ovmanager/ovmanager.go @@ -57,7 +57,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { config: config, } - d.vxlanIdm, err = idm.New(nil, "vxlan-id", vxlanIDStart, vxlanIDEnd) + d.vxlanIdm, err = idm.New(nil, "vxlan-id", 1, vxlanIDEnd) if err != nil { return fmt.Errorf("failed to initialize vxlan id manager: %v", err) } @@ -164,7 +164,7 @@ func (n *network) obtainVxlanID(s *subnet) error { n.Unlock() if vni == 0 { - vni, err = n.driver.vxlanIdm.GetID() + vni, err = n.driver.vxlanIdm.GetIDInRange(vxlanIDStart, vxlanIDEnd) if err != nil { return err } From 846236b6c8cfa1e11dd74a63eb968129bba9675e Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 10 Nov 2016 22:40:16 -0800 Subject: [PATCH 148/799] fix unsafe acces on arm Signed-off-by: Victor Vieux --- networkdb/networkdb.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 2518030e30..087398e3cf 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -24,6 +24,15 @@ const ( // NetworkDB instance drives the networkdb cluster and acts the broker // for cluster-scoped and network-scoped gossip and watches. type NetworkDB struct { + // The clocks MUST be the first things + // in this struct due to Golang issue #599. + + // Global lamport clock for node network attach events. + networkClock serf.LamportClock + + // Global lamport clock for table events. + tableClock serf.LamportClock + sync.RWMutex // NetworkDB configuration. @@ -59,12 +68,6 @@ type NetworkDB struct { // waiting for an ack. bulkSyncAckTbl map[string]chan struct{} - // Global lamport clock for node network attach events. - networkClock serf.LamportClock - - // Global lamport clock for table events. - tableClock serf.LamportClock - // Broadcast queue for network event gossip. networkBroadcasts *memberlist.TransmitLimitedQueue From 7fd270684d8d7134f4f8679536f0d5c1951d09be Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 14 Nov 2016 16:41:54 -0800 Subject: [PATCH 149/799] Fix new golint reported errors Signed-off-by: Alessandro Boch --- client/client.go | 2 +- cmd/dnet/dnet.go | 2 +- drivers/overlay/ov_endpoint.go | 2 +- drivers/overlay/peerdb.go | 2 +- drivers/solaris/overlay/ov_endpoint.go | 2 +- drivers/solaris/overlay/peerdb.go | 2 +- iptables/iptables.go | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/client.go b/client/client.go index f2bcca5329..ac49e24e9c 100644 --- a/client/client.go +++ b/client/client.go @@ -65,7 +65,7 @@ func (cli *NetworkCli) Cmd(chain string, args ...string) error { if len(args) > 0 { method, exists := cli.getMethod(args[0]) if !exists { - return fmt.Errorf("%s: '%s' is not a %s command. See '%s --help'.\n", chain, args[0], chain, chain) + return fmt.Errorf("%s: '%s' is not a %s command. See '%s --help'", chain, args[0], chain, chain) } return method(chain, args[1:]...) } diff --git a/cmd/dnet/dnet.go b/cmd/dnet/dnet.go index 118ea80d3a..2c434bd973 100644 --- a/cmd/dnet/dnet.go +++ b/cmd/dnet/dnet.go @@ -247,7 +247,7 @@ type NetworkOrchestration struct { func (d *dnetConnection) dnetDaemon(cfgFile string) error { if err := startTestDriver(); err != nil { - return fmt.Errorf("failed to start test driver: %v\n", err) + return fmt.Errorf("failed to start test driver: %v", err) } cfg, err := d.parseConfig(cfgFile) diff --git a/drivers/overlay/ov_endpoint.go b/drivers/overlay/ov_endpoint.go index 1906ed35f8..ebcab51501 100644 --- a/drivers/overlay/ov_endpoint.go +++ b/drivers/overlay/ov_endpoint.go @@ -77,7 +77,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, } if s := n.getSubnetforIP(ep.addr); s == nil { - return fmt.Errorf("no matching subnet for IP %q in network %q\n", ep.addr, nid) + return fmt.Errorf("no matching subnet for IP %q in network %q", ep.addr, nid) } if ep.mac == nil { diff --git a/drivers/overlay/peerdb.go b/drivers/overlay/peerdb.go index 87fc2d107b..fff7e31249 100644 --- a/drivers/overlay/peerdb.go +++ b/drivers/overlay/peerdb.go @@ -277,7 +277,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, s := n.getSubnetforIP(IP) if s == nil { - return fmt.Errorf("couldn't find the subnet %q in network %q\n", IP.String(), n.id) + return fmt.Errorf("couldn't find the subnet %q in network %q", IP.String(), n.id) } if err := n.obtainVxlanID(s); err != nil { diff --git a/drivers/solaris/overlay/ov_endpoint.go b/drivers/solaris/overlay/ov_endpoint.go index 471cc38896..ca0c477dcd 100644 --- a/drivers/solaris/overlay/ov_endpoint.go +++ b/drivers/solaris/overlay/ov_endpoint.go @@ -76,7 +76,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, } if s := n.getSubnetforIP(ep.addr); s == nil { - return fmt.Errorf("no matching subnet for IP %q in network %q\n", ep.addr, nid) + return fmt.Errorf("no matching subnet for IP %q in network %q", ep.addr, nid) } if ep.mac == nil { diff --git a/drivers/solaris/overlay/peerdb.go b/drivers/solaris/overlay/peerdb.go index 6d17067f72..d4b5e8e399 100644 --- a/drivers/solaris/overlay/peerdb.go +++ b/drivers/solaris/overlay/peerdb.go @@ -263,7 +263,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, s := n.getSubnetforIP(IP) if s == nil { - return fmt.Errorf("couldn't find the subnet %q in network %q\n", IP.String(), n.id) + return fmt.Errorf("couldn't find the subnet %q in network %q", IP.String(), n.id) } if err := n.obtainVxlanID(s); err != nil { diff --git a/iptables/iptables.go b/iptables/iptables.go index a0d83b7ff7..3884257361 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -130,7 +130,7 @@ func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) { // ProgramChain is used to add rules to a chain func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error { if c.Name == "" { - return fmt.Errorf("Could not program chain, missing chain name.") + return fmt.Errorf("Could not program chain, missing chain name") } switch c.Table { @@ -166,7 +166,7 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err } case Filter: if bridgeName == "" { - return fmt.Errorf("Could not program chain %s/%s, missing bridge name.", + return fmt.Errorf("Could not program chain %s/%s, missing bridge name", c.Table, c.Name) } link := []string{ From e9afc0be574f0471f856ea33d382c1a5f09fd908 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 14 Nov 2016 21:41:22 -0800 Subject: [PATCH 150/799] Fix bug in DeleteNeighbor - stop iterating after changing the list reference Signed-off-by: Alessandro Boch --- osl/neigh_linux.go | 1 + 1 file changed, 1 insertion(+) diff --git a/osl/neigh_linux.go b/osl/neigh_linux.go index a7669a111b..673522ad63 100644 --- a/osl/neigh_linux.go +++ b/osl/neigh_linux.go @@ -80,6 +80,7 @@ func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr, for i, nh := range n.neighbors { if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) { n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...) + break } } n.Unlock() From 95c683b1bbb07f0109ab1b842eb3fe7b048998ed Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 15 Nov 2016 09:49:00 -0800 Subject: [PATCH 151/799] Add a nil check for sandbox.osSbox Signed-off-by: Santhosh Manohar --- sandbox.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sandbox.go b/sandbox.go index 1ca1271cc7..0329e4b7ee 100644 --- a/sandbox.go +++ b/sandbox.go @@ -427,7 +427,13 @@ func (sb *sandbox) ResolveIP(ip string) string { } func (sb *sandbox) ExecFunc(f func()) error { - return sb.osSbox.InvokeFunc(f) + sb.Lock() + osSbox := sb.osSbox + sb.Unlock() + if osSbox != nil { + return osSbox.InvokeFunc(f) + } + return fmt.Errorf("osl sandbox unavailable in ExecFunc for %v", sb.ContainerID()) } func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP) { From 30c32dfb30c26988aee748d18d6444c60ff2419d Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 15 Nov 2016 11:34:59 -0800 Subject: [PATCH 152/799] Update netlink @17ea11b Signed-off-by: Alessandro Boch --- Godeps/Godeps.json | 4 +- .../vishvananda/netlink/bpf_linux.go | 12 +- .../github.com/vishvananda/netlink/filter.go | 4 +- .../vishvananda/netlink/handle_linux.go | 25 +++ .../github.com/vishvananda/netlink/link.go | 14 +- .../vishvananda/netlink/link_linux.go | 147 ++++++++++++++++-- .../vishvananda/netlink/neigh_linux.go | 25 ++- .../vishvananda/netlink/nl/link_linux.go | 36 ++++- .../vishvananda/netlink/nl/nl_linux.go | 141 +++++++++++++++++ .../vishvananda/netlink/route_linux.go | 2 +- .../vishvananda/netlink/rule_linux.go | 14 +- .../vishvananda/netlink/xfrm_state_linux.go | 2 +- 12 files changed, 393 insertions(+), 33 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 8bb089fe06..e5d0df3bbf 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -414,11 +414,11 @@ }, { "ImportPath": "github.com/vishvananda/netlink", - "Rev": "e73bad418fd727ed3a02830b1af1ad0283a1de6c" + "Rev": "17ea11b5a11c5614597c65a671105e8ee58c4d04" }, { "ImportPath": "github.com/vishvananda/netlink/nl", - "Rev": "e73bad418fd727ed3a02830b1af1ad0283a1de6c" + "Rev": "17ea11b5a11c5614597c65a671105e8ee58c4d04" }, { "ImportPath": "github.com/vishvananda/netns", diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go index acd9490131..533743987a 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go @@ -8,11 +8,11 @@ package netlink #include #include -static int load_simple_bpf(int prog_type) { +static int load_simple_bpf(int prog_type, int ret) { #ifdef __NR_bpf - // { return 1; } + // { return ret; } __u64 __attribute__((aligned(8))) insns[] = { - 0x00000001000000b7ull, + 0x00000000000000b7ull | ((__u64)ret<<32), 0x0000000000000095ull, }; __u8 __attribute__((aligned(8))) license[] = "ASL2"; @@ -51,10 +51,12 @@ const ( BPF_PROG_TYPE_KPROBE BPF_PROG_TYPE_SCHED_CLS BPF_PROG_TYPE_SCHED_ACT + BPF_PROG_TYPE_TRACEPOINT + BPF_PROG_TYPE_XDP ) // loadSimpleBpf loads a trivial bpf program for testing purposes -func loadSimpleBpf(progType BpfProgType) (int, error) { - fd, err := C.load_simple_bpf(C.int(progType)) +func loadSimpleBpf(progType BpfProgType, ret int) (int, error) { + fd, err := C.load_simple_bpf(C.int(progType), C.int(ret)) return int(fd), err } diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go index 116aeba06e..bc8a1e9614 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go @@ -60,7 +60,7 @@ func (a TcAct) String() string { case TC_ACT_JUMP: return "jump" } - return fmt.Sprintf("0x%x", a) + return fmt.Sprintf("0x%x", int32(a)) } type TcPolAct int32 @@ -86,7 +86,7 @@ func (a TcPolAct) String() string { case TC_POLICE_PIPE: return "pipe" } - return fmt.Sprintf("0x%x", a) + return fmt.Sprintf("0x%x", int32(a)) } type ActionAttrs struct { diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/handle_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/handle_linux.go index 5377988752..a04ceae6b6 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/handle_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/handle_linux.go @@ -1,7 +1,9 @@ package netlink import ( + "fmt" "syscall" + "time" "github.com/vishvananda/netlink/nl" "github.com/vishvananda/netns" @@ -33,6 +35,29 @@ func NewHandle(nlFamilies ...int) (*Handle, error) { return newHandle(netns.None(), netns.None(), nlFamilies...) } +// SetSocketTimeout sets the send and receive timeout for each socket in the +// netlink handle. Although the socket timeout has granularity of one +// microsecond, the effective granularity is floored by the kernel timer tick, +// which default value is four milliseconds. +func (h *Handle) SetSocketTimeout(to time.Duration) error { + if to < time.Microsecond { + return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond) + } + tv := syscall.NsecToTimeval(to.Nanoseconds()) + for _, sh := range h.sockets { + fd := sh.Socket.GetFd() + err := syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) + if err != nil { + return err + } + err = syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &tv) + if err != nil { + return err + } + } + return nil +} + // NewHandle returns a netlink handle on the network namespace // specified by ns. If ns=netns.None(), current network namespace // will be assumed diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go index 9dbc221506..0e160a9fbb 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go @@ -26,11 +26,15 @@ type LinkAttrs struct { Name string HardwareAddr net.HardwareAddr Flags net.Flags + RawFlags uint32 ParentIndex int // index of the parent link device MasterIndex int // must be the index of a bridge Namespace interface{} // nil | NsPid | NsFd Alias string Statistics *LinkStatistics + Promisc int + Xdp *LinkXdp + EncapType string } // NewLinkAttrs returns LinkAttrs structure filled with default values @@ -69,6 +73,11 @@ type LinkStatistics struct { TxCompressed uint32 } +type LinkXdp struct { + Fd int + Attached bool +} + // Device links cannot be created via netlink. These links // are links created by udev like 'lo' and 'etho0' type Device struct { @@ -171,11 +180,13 @@ func (macvtap Macvtap) Type() string { } type TuntapMode uint16 +type TuntapFlag uint16 // Tuntap links created via /dev/tun/tap, but can be destroyed via netlink type Tuntap struct { LinkAttrs - Mode TuntapMode + Mode TuntapMode + Flags TuntapFlag } func (tuntap *Tuntap) Attrs() *LinkAttrs { @@ -251,6 +262,7 @@ type IPVlanMode uint16 const ( IPVLAN_MODE_L2 IPVlanMode = iota IPVLAN_MODE_L3 + IPVLAN_MODE_L3S IPVLAN_MODE_MAX ) diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go index cfa5bf3e6c..ff45cde81a 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go @@ -16,8 +16,13 @@ import ( const SizeofLinkStats = 0x5c const ( - TUNTAP_MODE_TUN TuntapMode = syscall.IFF_TUN - TUNTAP_MODE_TAP TuntapMode = syscall.IFF_TAP + TUNTAP_MODE_TUN TuntapMode = syscall.IFF_TUN + TUNTAP_MODE_TAP TuntapMode = syscall.IFF_TAP + TUNTAP_DEFAULTS TuntapFlag = syscall.IFF_TUN_EXCL | syscall.IFF_ONE_QUEUE + TUNTAP_VNET_HDR TuntapFlag = syscall.IFF_VNET_HDR + TUNTAP_TUN_EXCL TuntapFlag = syscall.IFF_TUN_EXCL + TUNTAP_NO_PI TuntapFlag = syscall.IFF_NO_PI + TUNTAP_ONE_QUEUE TuntapFlag = syscall.IFF_ONE_QUEUE ) var native = nl.NativeEndian() @@ -50,6 +55,44 @@ func (h *Handle) ensureIndex(link *LinkAttrs) { } } +func (h *Handle) SetPromiscOn(link Link) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) + msg.Change = syscall.IFF_PROMISC + msg.Flags = syscall.IFF_UP + msg.Index = int32(base.Index) + req.AddData(msg) + + _, err := req.Execute(syscall.NETLINK_ROUTE, 0) + return err +} + +func SetPromiscOn(link Link) error { + return pkgHandle.SetPromiscOn(link) +} + +func (h *Handle) SetPromiscOff(link Link) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) + msg.Change = syscall.IFF_PROMISC + msg.Flags = 0 & ^syscall.IFF_UP + msg.Index = int32(base.Index) + req.AddData(msg) + + _, err := req.Execute(syscall.NETLINK_ROUTE, 0) + return err +} + +func SetPromiscOff(link Link) error { + return pkgHandle.SetPromiscOff(link) +} + // LinkSetUp enables the link device. // Equivalent to: `ip link set $link up` func LinkSetUp(link Link) error { @@ -255,6 +298,36 @@ func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error { return err } +// LinkSetVfTxRate sets the tx rate of a vf for the link. +// Equivalent to: `ip link set $link vf $vf rate $rate` +func LinkSetVfTxRate(link Link, vf, rate int) error { + return pkgHandle.LinkSetVfTxRate(link, vf, rate) +} + +// LinkSetVfTxRate sets the tx rate of a vf for the link. +// Equivalent to: `ip link set $link vf $vf rate $rate` +func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) + msg.Index = int32(base.Index) + req.AddData(msg) + + data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil) + info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil) + vfmsg := nl.VfTxRate{ + Vf: uint32(vf), + Rate: uint32(rate), + } + nl.NewRtAttrChild(info, nl.IFLA_VF_TX_RATE, vfmsg.Serialize()) + req.AddData(data) + + _, err := req.Execute(syscall.NETLINK_ROUTE, 0) + return err +} + // LinkSetMaster sets the master of the link device. // Equivalent to: `ip link set $link master $master` func LinkSetMaster(link Link, master *Bridge) error { @@ -373,6 +446,23 @@ func (h *Handle) LinkSetNsFd(link Link, fd int) error { return err } +// LinkSetXdpFd adds a bpf function to the driver. The fd must be a bpf +// program loaded with bpf(type=BPF_PROG_TYPE_XDP) +func LinkSetXdpFd(link Link, fd int) error { + base := link.Attrs() + ensureIndex(base) + req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) + msg.Index = int32(base.Index) + req.AddData(msg) + + addXdpAttrs(&LinkXdp{Fd: fd}, req) + + _, err := req.Execute(syscall.NETLINK_ROUTE, 0) + return err +} + func boolAttr(val bool) []byte { var v uint8 if val { @@ -552,9 +642,7 @@ func (h *Handle) LinkAdd(link Link) error { if tuntap, ok := link.(*Tuntap); ok { // TODO: support user // TODO: support group - // TODO: support non- one_queue - // TODO: support pi | vnet_hdr | multi_queue - // TODO: support non- exclusive + // TODO: multi_queue // TODO: support non- persistent if tuntap.Mode < syscall.IFF_TUN || tuntap.Mode > syscall.IFF_TAP { return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode) @@ -565,10 +653,13 @@ func (h *Handle) LinkAdd(link Link) error { } defer file.Close() var req ifReq - req.Flags |= syscall.IFF_ONE_QUEUE - req.Flags |= syscall.IFF_TUN_EXCL - copy(req.Name[:15], base.Name) + if tuntap.Flags == 0 { + req.Flags = uint16(TUNTAP_DEFAULTS) + } else { + req.Flags = uint16(tuntap.Flags) + } req.Flags |= uint16(tuntap.Mode) + copy(req.Name[:15], base.Name) _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETIFF), uintptr(unsafe.Pointer(&req))) if errno != 0 { return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed, errno %v", errno) @@ -649,6 +740,10 @@ func (h *Handle) LinkAdd(link Link) error { req.AddData(attr) } + if base.Xdp != nil { + addXdpAttrs(base.Xdp, req) + } + linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil) nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) @@ -871,7 +966,10 @@ func linkDeserialize(m []byte) (Link, error) { return nil, err } - base := LinkAttrs{Index: int(msg.Index), Flags: linkFlags(msg.Flags)} + base := LinkAttrs{Index: int(msg.Index), RawFlags: msg.Flags, Flags: linkFlags(msg.Flags), EncapType: msg.EncapType()} + if msg.Flags&syscall.IFF_PROMISC != 0 { + base.Promisc = 1 + } var link Link linkType := "" for _, attr := range attrs { @@ -958,6 +1056,12 @@ func linkDeserialize(m []byte) (Link, error) { base.Alias = string(attr.Value[:len(attr.Value)-1]) case syscall.IFLA_STATS: base.Statistics = parseLinkStats(attr.Value[:]) + case nl.IFLA_XDP: + xdp, err := parseLinkXdp(attr.Value[:]) + if err != nil { + return nil, err + } + base.Xdp = xdp } } // Links that don't have IFLA_INFO_KIND are hardware devices @@ -1389,3 +1493,28 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) { func parseLinkStats(data []byte) *LinkStatistics { return (*LinkStatistics)(unsafe.Pointer(&data[0:SizeofLinkStats][0])) } + +func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) { + attrs := nl.NewRtAttr(nl.IFLA_XDP|syscall.NLA_F_NESTED, nil) + b := make([]byte, 4) + native.PutUint32(b, uint32(xdp.Fd)) + nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FD, b) + req.AddData(attrs) +} + +func parseLinkXdp(data []byte) (*LinkXdp, error) { + attrs, err := nl.ParseRouteAttr(data) + if err != nil { + return nil, err + } + xdp := &LinkXdp{} + for _, attr := range attrs { + switch attr.Attr.Type { + case nl.IFLA_XDP_FD: + xdp.Fd = int(native.Uint32(attr.Value[0:4])) + case nl.IFLA_XDP_ATTACHED: + xdp.Attached = attr.Value[0] != 0 + } + } + return xdp, nil +} diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go index 9b6cd2c256..f069db2573 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go @@ -151,8 +151,10 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error { dstData := nl.NewRtAttr(NDA_DST, ipData) req.AddData(dstData) - hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr)) - req.AddData(hwData) + if neigh.Flags != NTF_PROXY || neigh.HardwareAddr != nil { + hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr)) + req.AddData(hwData) + } _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err @@ -165,14 +167,33 @@ func NeighList(linkIndex, family int) ([]Neigh, error) { return pkgHandle.NeighList(linkIndex, family) } +// NeighProxyList gets a list of neighbor proxies in the system. +// Equivalent to: `ip neighbor show proxy`. +// The list can be filtered by link and ip family. +func NeighProxyList(linkIndex, family int) ([]Neigh, error) { + return pkgHandle.NeighProxyList(linkIndex, family) +} + // NeighList gets a list of IP-MAC mappings in the system (ARP table). // Equivalent to: `ip neighbor show`. // The list can be filtered by link and ip family. func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) { + return h.neighList(linkIndex, family, 0) +} + +// NeighProxyList gets a list of neighbor proxies in the system. +// Equivalent to: `ip neighbor show proxy`. +// The list can be filtered by link, ip family. +func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) { + return h.neighList(linkIndex, family, NTF_PROXY) +} + +func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) { req := h.newNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP) msg := Ndmsg{ Family: uint8(family), Index: uint32(linkIndex), + Flags: uint8(flags), } req.AddData(&msg) diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go index b7f50646d2..115f60bb3b 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go @@ -1,13 +1,35 @@ package nl import ( + "syscall" "unsafe" ) const ( DEFAULT_CHANGE = 0xFFFFFFFF // doesn't exist in syscall - IFLA_VFINFO_LIST = 0x16 + IFLA_VFINFO_LIST = syscall.IFLA_IFALIAS + 1 + iota + IFLA_STATS64 + IFLA_VF_PORTS + IFLA_PORT_SELF + IFLA_AF_SPEC + IFLA_GROUP + IFLA_NET_NS_FD + IFLA_EXT_MASK + IFLA_PROMISCUITY + IFLA_NUM_TX_QUEUES + IFLA_NUM_RX_QUEUES + IFLA_CARRIER + IFLA_PHYS_PORT_ID + IFLA_CARRIER_CHANGES + IFLA_PHYS_SWITCH_ID + IFLA_LINK_NETNSID + IFLA_PHYS_PORT_NAME + IFLA_PROTO_DOWN + IFLA_GSO_MAX_SEGS + IFLA_GSO_MAX_SIZE + IFLA_PAD + IFLA_XDP ) const ( @@ -89,11 +111,6 @@ const ( IFLA_IPVLAN_MAX = IFLA_IPVLAN_MODE ) -const ( - // not defined in syscall - IFLA_NET_NS_FD = 28 -) - const ( IFLA_MACVLAN_UNSPEC = iota IFLA_MACVLAN_MODE @@ -394,3 +411,10 @@ func DeserializeVfRssQueryEn(b []byte) *VfRssQueryEn { func (msg *VfRssQueryEn) Serialize() []byte { return (*(*[SizeofVfRssQueryEn]byte)(unsafe.Pointer(msg)))[:] } + +const ( + IFLA_XDP_UNSPEC = iota + IFLA_XDP_FD /* fd of xdp program to attach, or -1 to remove */ + IFLA_XDP_ATTACHED /* read-only bool indicating if prog is attached */ + IFLA_XDP_MAX = IFLA_XDP_ATTACHED +) diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go index 17683a7556..d46fff281f 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go @@ -100,6 +100,147 @@ func (msg *IfInfomsg) Len() int { return syscall.SizeofIfInfomsg } +func (msg *IfInfomsg) EncapType() string { + switch msg.Type { + case 0: + return "generic" + case syscall.ARPHRD_ETHER: + return "ether" + case syscall.ARPHRD_EETHER: + return "eether" + case syscall.ARPHRD_AX25: + return "ax25" + case syscall.ARPHRD_PRONET: + return "pronet" + case syscall.ARPHRD_CHAOS: + return "chaos" + case syscall.ARPHRD_IEEE802: + return "ieee802" + case syscall.ARPHRD_ARCNET: + return "arcnet" + case syscall.ARPHRD_APPLETLK: + return "atalk" + case syscall.ARPHRD_DLCI: + return "dlci" + case syscall.ARPHRD_ATM: + return "atm" + case syscall.ARPHRD_METRICOM: + return "metricom" + case syscall.ARPHRD_IEEE1394: + return "ieee1394" + case syscall.ARPHRD_INFINIBAND: + return "infiniband" + case syscall.ARPHRD_SLIP: + return "slip" + case syscall.ARPHRD_CSLIP: + return "cslip" + case syscall.ARPHRD_SLIP6: + return "slip6" + case syscall.ARPHRD_CSLIP6: + return "cslip6" + case syscall.ARPHRD_RSRVD: + return "rsrvd" + case syscall.ARPHRD_ADAPT: + return "adapt" + case syscall.ARPHRD_ROSE: + return "rose" + case syscall.ARPHRD_X25: + return "x25" + case syscall.ARPHRD_HWX25: + return "hwx25" + case syscall.ARPHRD_PPP: + return "ppp" + case syscall.ARPHRD_HDLC: + return "hdlc" + case syscall.ARPHRD_LAPB: + return "lapb" + case syscall.ARPHRD_DDCMP: + return "ddcmp" + case syscall.ARPHRD_RAWHDLC: + return "rawhdlc" + case syscall.ARPHRD_TUNNEL: + return "ipip" + case syscall.ARPHRD_TUNNEL6: + return "tunnel6" + case syscall.ARPHRD_FRAD: + return "frad" + case syscall.ARPHRD_SKIP: + return "skip" + case syscall.ARPHRD_LOOPBACK: + return "loopback" + case syscall.ARPHRD_LOCALTLK: + return "ltalk" + case syscall.ARPHRD_FDDI: + return "fddi" + case syscall.ARPHRD_BIF: + return "bif" + case syscall.ARPHRD_SIT: + return "sit" + case syscall.ARPHRD_IPDDP: + return "ip/ddp" + case syscall.ARPHRD_IPGRE: + return "gre" + case syscall.ARPHRD_PIMREG: + return "pimreg" + case syscall.ARPHRD_HIPPI: + return "hippi" + case syscall.ARPHRD_ASH: + return "ash" + case syscall.ARPHRD_ECONET: + return "econet" + case syscall.ARPHRD_IRDA: + return "irda" + case syscall.ARPHRD_FCPP: + return "fcpp" + case syscall.ARPHRD_FCAL: + return "fcal" + case syscall.ARPHRD_FCPL: + return "fcpl" + case syscall.ARPHRD_FCFABRIC: + return "fcfb0" + case syscall.ARPHRD_FCFABRIC + 1: + return "fcfb1" + case syscall.ARPHRD_FCFABRIC + 2: + return "fcfb2" + case syscall.ARPHRD_FCFABRIC + 3: + return "fcfb3" + case syscall.ARPHRD_FCFABRIC + 4: + return "fcfb4" + case syscall.ARPHRD_FCFABRIC + 5: + return "fcfb5" + case syscall.ARPHRD_FCFABRIC + 6: + return "fcfb6" + case syscall.ARPHRD_FCFABRIC + 7: + return "fcfb7" + case syscall.ARPHRD_FCFABRIC + 8: + return "fcfb8" + case syscall.ARPHRD_FCFABRIC + 9: + return "fcfb9" + case syscall.ARPHRD_FCFABRIC + 10: + return "fcfb10" + case syscall.ARPHRD_FCFABRIC + 11: + return "fcfb11" + case syscall.ARPHRD_FCFABRIC + 12: + return "fcfb12" + case syscall.ARPHRD_IEEE802_TR: + return "tr" + case syscall.ARPHRD_IEEE80211: + return "ieee802.11" + case syscall.ARPHRD_IEEE80211_PRISM: + return "ieee802.11/prism" + case syscall.ARPHRD_IEEE80211_RADIOTAP: + return "ieee802.11/radiotap" + case syscall.ARPHRD_IEEE802154: + return "ieee802.15.4" + + case 65534: + return "none" + case 65535: + return "void" + } + return fmt.Sprintf("unknown%d", msg.Type) +} + func rtaAlignOf(attrlen int) int { return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1) } diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go index 6ba3ea1264..b749ddb2c7 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go @@ -153,7 +153,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg } else { gw = nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16())) } - gwData := gw.Serialize() + gwData = gw.Serialize() rtnh.Len += uint16(len(gwData)) } buf = append(buf, rtnh.Serialize()...) diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go index 58fac557c0..f9cdc855f1 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go @@ -82,41 +82,46 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error { req.AddData(rtAttrs[i]) } - var ( - b = make([]byte, 4) - native = nl.NativeEndian() - ) + native := nl.NativeEndian() if rule.Priority >= 0 { + b := make([]byte, 4) native.PutUint32(b, uint32(rule.Priority)) req.AddData(nl.NewRtAttr(nl.FRA_PRIORITY, b)) } if rule.Mark >= 0 { + b := make([]byte, 4) native.PutUint32(b, uint32(rule.Mark)) req.AddData(nl.NewRtAttr(nl.FRA_FWMARK, b)) } if rule.Mask >= 0 { + b := make([]byte, 4) native.PutUint32(b, uint32(rule.Mask)) req.AddData(nl.NewRtAttr(nl.FRA_FWMASK, b)) } if rule.Flow >= 0 { + b := make([]byte, 4) native.PutUint32(b, uint32(rule.Flow)) req.AddData(nl.NewRtAttr(nl.FRA_FLOW, b)) } if rule.TunID > 0 { + b := make([]byte, 4) native.PutUint32(b, uint32(rule.TunID)) req.AddData(nl.NewRtAttr(nl.FRA_TUN_ID, b)) } if rule.Table >= 256 { + b := make([]byte, 4) native.PutUint32(b, uint32(rule.Table)) req.AddData(nl.NewRtAttr(nl.FRA_TABLE, b)) } if msg.Table > 0 { if rule.SuppressPrefixlen >= 0 { + b := make([]byte, 4) native.PutUint32(b, uint32(rule.SuppressPrefixlen)) req.AddData(nl.NewRtAttr(nl.FRA_SUPPRESS_PREFIXLEN, b)) } if rule.SuppressIfgroup >= 0 { + b := make([]byte, 4) native.PutUint32(b, uint32(rule.SuppressIfgroup)) req.AddData(nl.NewRtAttr(nl.FRA_SUPPRESS_IFGROUP, b)) } @@ -129,6 +134,7 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error { } if rule.Goto >= 0 { msg.Type = nl.FR_ACT_NOP + b := make([]byte, 4) native.PutUint32(b, uint32(rule.Goto)) req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b)) } diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go index b100f71bd1..7b0b2e7585 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go @@ -213,7 +213,7 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState req.AddData(out) } if state.Src != nil { - out := nl.NewRtAttr(nl.XFRMA_SRCADDR, state.Src) + out := nl.NewRtAttr(nl.XFRMA_SRCADDR, state.Src.To16()) req.AddData(out) } From f459afbcfc5f1cb09051f7843c5766d2c1a6776c Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 15 Nov 2016 11:42:47 -0800 Subject: [PATCH 153/799] Set a timeout on the netlink handle sockets Signed-off-by: Alessandro Boch --- drivers/overlay/ov_network.go | 5 +++++ drivers/overlay/ov_utils.go | 6 ++++++ ns/init_linux.go | 7 +++++++ osl/namespace_linux.go | 10 ++++++++++ 4 files changed, 28 insertions(+) diff --git a/drivers/overlay/ov_network.go b/drivers/overlay/ov_network.go index c6bc67cab5..703d13f9a5 100644 --- a/drivers/overlay/ov_network.go +++ b/drivers/overlay/ov_network.go @@ -320,6 +320,11 @@ func populateVNITbl() { } defer nlh.Delete() + err = nlh.SetSocketTimeout(soTimeout) + if err != nil { + logrus.Warnf("Failed to set the timeout on the netlink handle sockets for vni table population: %v", err) + } + links, err := nlh.LinkList() if err != nil { logrus.Errorf("Failed to list interfaces during vni population for ns %s: %v", path, err) diff --git a/drivers/overlay/ov_utils.go b/drivers/overlay/ov_utils.go index a702e760af..8a01914fa4 100644 --- a/drivers/overlay/ov_utils.go +++ b/drivers/overlay/ov_utils.go @@ -13,6 +13,8 @@ import ( "github.com/vishvananda/netns" ) +var soTimeout = ns.NetlinkSocketsTimeout + func validateID(nid, eid string) error { if nid == "" { return fmt.Errorf("invalid network id") @@ -134,6 +136,10 @@ func deleteVxlanByVNI(path string, vni uint32) error { return fmt.Errorf("failed to get netlink handle for ns %s: %v", path, err) } defer nlh.Delete() + err = nlh.SetSocketTimeout(soTimeout) + if err != nil { + logrus.Warnf("Failed to set the timeout on the netlink handle sockets for vxlan deletion: %v", err) + } } links, err := nlh.LinkList() diff --git a/ns/init_linux.go b/ns/init_linux.go index 3022e8ddbf..2c3aff5668 100644 --- a/ns/init_linux.go +++ b/ns/init_linux.go @@ -7,6 +7,7 @@ import ( "strings" "sync" "syscall" + "time" "github.com/Sirupsen/logrus" "github.com/vishvananda/netlink" @@ -17,6 +18,8 @@ var ( initNs netns.NsHandle initNl *netlink.Handle initOnce sync.Once + // NetlinkSocketsTimeout represents the default timeout duration for the sockets + NetlinkSocketsTimeout = 3 * time.Second ) // Init initializes a new network namespace @@ -30,6 +33,10 @@ func Init() { if err != nil { logrus.Errorf("could not create netlink handle on initial namespace: %v", err) } + err = initNl.SetSocketTimeout(NetlinkSocketsTimeout) + if err != nil { + logrus.Warnf("Failed to set the timeout on the default netlink handle sockets: %v", err) + } } // SetNamespace sets the initial namespace handler diff --git a/osl/namespace_linux.go b/osl/namespace_linux.go index 4f0d446a05..fe8065a31e 100644 --- a/osl/namespace_linux.go +++ b/osl/namespace_linux.go @@ -211,6 +211,11 @@ func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) { return nil, fmt.Errorf("failed to create a netlink handle: %v", err) } + err = n.nlHandle.SetSocketTimeout(ns.NetlinkSocketsTimeout) + if err != nil { + logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err) + } + if err = n.loopbackUp(); err != nil { n.nlHandle.Delete() return nil, err @@ -253,6 +258,11 @@ func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) { return nil, fmt.Errorf("failed to create a netlink handle: %v", err) } + err = n.nlHandle.SetSocketTimeout(ns.NetlinkSocketsTimeout) + if err != nil { + logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err) + } + if err = n.loopbackUp(); err != nil { n.nlHandle.Delete() return nil, err From 1e66084c1b2f8d5f643046a741ca68afb2e190ee Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 16 Nov 2016 17:06:41 -0800 Subject: [PATCH 154/799] Allow spaces in network names Signed-off-by: Alessandro Boch --- config/config.go | 8 ++++---- config/config_test.go | 42 +++++++++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/config/config.go b/config/config.go index 592ea91113..6e29563df6 100644 --- a/config/config.go +++ b/config/config.go @@ -17,11 +17,11 @@ import ( "github.com/docker/libnetwork/osl" ) -// RestrictedNameChars collects the characters allowed to represent a network or endpoint name. -const restrictedNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]` +// restrictedNameRegex represents the regular expression which regulates the allowed network or endpoint names. +const restrictedNameRegex = `^[\w]+[\w-. ]*[\w]+$` // RestrictedNamePattern is a regular expression to validate names against the collection of restricted characters. -var restrictedNamePattern = regexp.MustCompile(`^/?` + restrictedNameChars + `+$`) +var restrictedNamePattern = regexp.MustCompile(restrictedNameRegex) // Config encapsulates configurations of various Libnetwork components type Config struct { @@ -234,7 +234,7 @@ func (c *Config) ProcessOptions(options ...Option) { // ValidateName validates configuration objects supported by libnetwork func ValidateName(name string) error { if !restrictedNamePattern.MatchString(name) { - return fmt.Errorf("%s includes invalid characters, only %q are allowed", name, restrictedNameChars) + return fmt.Errorf("%q includes invalid characters, resource name has to conform to %q", name, restrictedNameRegex) } return nil } diff --git a/config/config_test.go b/config/config_test.go index a5feebac58..72776f0e9e 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -46,17 +46,37 @@ func TestOptionsLabels(t *testing.T) { } func TestValidName(t *testing.T) { - if err := ValidateName("test"); err != nil { - t.Fatal("Name validation fails for a name that must be accepted") - } - if err := ValidateName(""); err == nil { - t.Fatal("Name validation succeeds for a case when it is expected to fail") - } - if err := ValidateName(" "); err == nil { - t.Fatal("Name validation succeeds for a case when it is expected to fail") - } - if err := ValidateName("<>$$^"); err == nil { - t.Fatal("Name validation succeeds for a case when it is expected to fail") + assertName(t, "test", true) + assertName(t, "test1", true) + assertName(t, "test1.2_3", true) + assertName(t, "_test", true) + assertName(t, "test_", true) + assertName(t, "looks-good", true) + assertName(t, " test", false) + assertName(t, "test ", false) + assertName(t, "test.", false) + assertName(t, ".test", false) + assertName(t, "", false) + assertName(t, " ", false) + assertName(t, "<>$$^", false) + assertName(t, "this is a good network name", true) + assertName(t, "this is also-good", true) + assertName(t, " this is a not good network name", false) + assertName(t, "this is a not either ", false) + assertName(t, "this one\nis not good", false) + assertName(t, "this one\tis not good", false) + assertName(t, "this one\ris not good", false) + assertName(t, "this one\vis not good", false) + assertName(t, "this one\fis not good", false) +} +func assertName(t *testing.T, name string, mustSucceed bool) { + msg := "Name validation succeeds for a case when it is expected to fail" + if mustSucceed { + msg = "Name validation fails for a name that must be accepted" + } + err := ValidateName(name) + if (err == nil) != mustSucceed { + t.Fatalf("%s: %s", msg, name) } } From 19e42ae0e7aa80f8477351d3597148ba772eb138 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Fri, 11 Nov 2016 00:42:34 -0800 Subject: [PATCH 155/799] Separate service LB & SD from network plumbing Signed-off-by: Santhosh Manohar --- agent.go | 71 +++++++++++++++++++++++++++++++----------- endpoint.go | 12 +++++-- networkdb/networkdb.go | 2 +- sandbox.go | 4 +-- 4 files changed, 65 insertions(+), 24 deletions(-) diff --git a/agent.go b/agent.go index f589d7bee2..c4f18ba9a8 100644 --- a/agent.go +++ b/agent.go @@ -381,7 +381,57 @@ func (n *network) leaveCluster() error { return c.agent.networkDB.LeaveNetwork(n.ID()) } -func (ep *endpoint) addToCluster() error { +func (ep *endpoint) addDriverInfoToCluster() error { + n := ep.getNetwork() + if !n.isClusterEligible() { + return nil + } + if ep.joinInfo == nil { + return nil + } + + ctrlr := n.ctrlr + ctrlr.Lock() + agent := ctrlr.agent + ctrlr.Unlock() + if agent == nil { + return nil + } + + for _, te := range ep.joinInfo.driverTableEntries { + if err := agent.networkDB.CreateEntry(te.tableName, n.ID(), te.key, te.value); err != nil { + return err + } + } + return nil +} + +func (ep *endpoint) deleteDriverInfoFromCluster() error { + n := ep.getNetwork() + if !n.isClusterEligible() { + return nil + } + if ep.joinInfo == nil { + return nil + } + + ctrlr := n.ctrlr + ctrlr.Lock() + agent := ctrlr.agent + ctrlr.Unlock() + if agent == nil { + return nil + } + + for _, te := range ep.joinInfo.driverTableEntries { + if err := agent.networkDB.DeleteEntry(te.tableName, n.ID(), te.key); err != nil { + return err + } + } + return nil +} + +func (ep *endpoint) addServiceInfoToCluster() error { n := ep.getNetwork() if !n.isClusterEligible() { return nil @@ -421,16 +471,10 @@ func (ep *endpoint) addToCluster() error { } } - for _, te := range ep.joinInfo.driverTableEntries { - if err := c.agent.networkDB.CreateEntry(te.tableName, n.ID(), te.key, te.value); err != nil { - return err - } - } - return nil } -func (ep *endpoint) deleteFromCluster() error { +func (ep *endpoint) deleteServiceInfoFromCluster() error { n := ep.getNetwork() if !n.isClusterEligible() { return nil @@ -453,17 +497,6 @@ func (ep *endpoint) deleteFromCluster() error { return err } } - - if ep.joinInfo == nil { - return nil - } - - for _, te := range ep.joinInfo.driverTableEntries { - if err := c.agent.networkDB.DeleteEntry(te.tableName, n.ID(), te.key); err != nil { - return err - } - } - return nil } diff --git a/endpoint.go b/endpoint.go index 519e8ede8d..df79477dbb 100644 --- a/endpoint.go +++ b/endpoint.go @@ -515,6 +515,10 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error { return err } + if err = ep.addDriverInfoToCluster(); err != nil { + return err + } + if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil { return sb.setupDefaultGW() } @@ -709,8 +713,12 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) return err } - if e := ep.deleteFromCluster(); e != nil { - logrus.Errorf("Could not delete state for endpoint %s from cluster: %v", ep.Name(), e) + if e := ep.deleteServiceInfoFromCluster(); e != nil { + logrus.Errorf("Could not delete service state for endpoint %s from cluster: %v", ep.Name(), e) + } + + if e := ep.deleteDriverInfoFromCluster(); e != nil { + logrus.Errorf("Could not delete endpoint state for endpoint %s from cluster: %v", ep.Name(), e) } sb.deleteHostsEntries(n.getSvcRecords(ep)) diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 087398e3cf..71a4e2b9ee 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -265,7 +265,7 @@ func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error { } if err := nDB.sendTableEvent(TableEventTypeCreate, nid, tname, key, entry); err != nil { - return fmt.Errorf("cannot send table create event: %v", err) + return fmt.Errorf("cannot send create event for table %s, %v", tname, err) } nDB.Lock() diff --git a/sandbox.go b/sandbox.go index 0329e4b7ee..5512e2a57b 100644 --- a/sandbox.go +++ b/sandbox.go @@ -670,7 +670,7 @@ func (sb *sandbox) SetKey(basePath string) error { func (sb *sandbox) EnableService() error { for _, ep := range sb.getConnectedEndpoints() { if ep.enableService(true) { - if err := ep.addToCluster(); err != nil { + if err := ep.addServiceInfoToCluster(); err != nil { ep.enableService(false) return fmt.Errorf("could not update state for endpoint %s into cluster: %v", ep.Name(), err) } @@ -682,7 +682,7 @@ func (sb *sandbox) EnableService() error { func (sb *sandbox) DisableService() error { for _, ep := range sb.getConnectedEndpoints() { if ep.enableService(false) { - if err := ep.deleteFromCluster(); err != nil { + if err := ep.deleteServiceInfoFromCluster(); err != nil { ep.enableService(true) return fmt.Errorf("could not delete state for endpoint %s from cluster: %v", ep.Name(), err) } From 09a2c502f54b0e74a55f4c49a8eda81ebe805740 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Sat, 19 Nov 2016 19:23:37 -0800 Subject: [PATCH 156/799] Fix bug in needDefaultGW() Signed-off-by: Alessandro Boch --- default_gateway.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default_gateway.go b/default_gateway.go index 163348b49f..b042539b88 100644 --- a/default_gateway.go +++ b/default_gateway.go @@ -123,7 +123,7 @@ func (sb *sandbox) needDefaultGW() bool { return false } for _, r := range ep.StaticRoutes() { - if r.Destination.String() == "0.0.0.0/0" { + if r.Destination != nil && r.Destination.String() == "0.0.0.0/0" { return false } } From 097cea5dedc5908ae90559deb8fdba932204655d Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Sat, 19 Nov 2016 08:18:19 -0800 Subject: [PATCH 157/799] Revert "Enable ping for service vip address" This reverts commit 185fd8d362f0c71b54f62d75a31a26a63234d97f. Signed-off-by: Madhu Venugopal --- endpoint.go | 17 ----------------- osl/interface_linux.go | 41 +++++++++++++++++++---------------------- osl/options_linux.go | 6 ++++++ osl/sandbox.go | 10 ++++++---- sandbox.go | 8 ++++++++ service_linux.go | 28 ++-------------------------- 6 files changed, 41 insertions(+), 69 deletions(-) diff --git a/endpoint.go b/endpoint.go index df79477dbb..f47ea4e18f 100644 --- a/endpoint.go +++ b/endpoint.go @@ -1148,20 +1148,3 @@ func (c *controller) cleanupLocalEndpoints() { } } } - -func (ep *endpoint) setAliasIP(sb *sandbox, ip net.IP, add bool) error { - sb.Lock() - sbox := sb.osSbox - sb.Unlock() - - for _, i := range sbox.Info().Interfaces() { - if ep.hasInterface(i.SrcName()) { - ipNet := &net.IPNet{IP: ip, Mask: []byte{255, 255, 255, 255}} - if err := i.SetAliasIP(ipNet, add); err != nil { - return err - } - break - } - } - return nil -} diff --git a/osl/interface_linux.go b/osl/interface_linux.go index 65ad2ea144..2be99d72ea 100644 --- a/osl/interface_linux.go +++ b/osl/interface_linux.go @@ -26,6 +26,7 @@ type nwIface struct { mac net.HardwareAddr address *net.IPNet addressIPv6 *net.IPNet + ipAliases []*net.IPNet llAddrs []*net.IPNet routes []*net.IPNet bridge bool @@ -96,6 +97,13 @@ func (i *nwIface) LinkLocalAddresses() []*net.IPNet { return i.llAddrs } +func (i *nwIface) IPAliases() []*net.IPNet { + i.Lock() + defer i.Unlock() + + return i.ipAliases +} + func (i *nwIface) Routes() []*net.IPNet { i.Lock() defer i.Unlock() @@ -122,28 +130,6 @@ func (n *networkNamespace) Interfaces() []Interface { return ifaces } -func (i *nwIface) SetAliasIP(ip *net.IPNet, add bool) error { - i.Lock() - n := i.ns - i.Unlock() - - n.Lock() - nlh := n.nlHandle - n.Unlock() - - // Find the network interface identified by the DstName attribute. - iface, err := nlh.LinkByName(i.DstName()) - if err != nil { - return err - } - - ipAddr := &netlink.Addr{IPNet: ip, Label: ""} - if add { - return nlh.AddrAdd(iface, ipAddr) - } - return nlh.AddrDel(iface, ipAddr) -} - func (i *nwIface) Remove() error { i.Lock() n := i.ns @@ -347,6 +333,7 @@ func configureInterface(nlh *netlink.Handle, iface netlink.Link, i *nwIface) err {setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %v", ifaceName, i.AddressIPv6())}, {setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())}, {setInterfaceLinkLocalIPs, fmt.Sprintf("error setting interface %q link local IPs to %v", ifaceName, i.LinkLocalAddresses())}, + {setInterfaceIPAliases, fmt.Sprintf("error setting interface %q IP Aliases to %v", ifaceName, i.IPAliases())}, } for _, config := range ifaceConfigurators { @@ -405,6 +392,16 @@ func setInterfaceLinkLocalIPs(nlh *netlink.Handle, iface netlink.Link, i *nwIfac return nil } +func setInterfaceIPAliases(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { + for _, si := range i.IPAliases() { + ipAddr := &netlink.Addr{IPNet: si} + if err := nlh.AddrAdd(iface, ipAddr); err != nil { + return err + } + } + return nil +} + func setInterfaceName(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { return nlh.LinkSetName(iface, i.DstName()) } diff --git a/osl/options_linux.go b/osl/options_linux.go index 818669647f..64309d0506 100644 --- a/osl/options_linux.go +++ b/osl/options_linux.go @@ -66,6 +66,12 @@ func (n *networkNamespace) LinkLocalAddresses(list []*net.IPNet) IfaceOption { } } +func (n *networkNamespace) IPAliases(list []*net.IPNet) IfaceOption { + return func(i *nwIface) { + i.ipAliases = list + } +} + func (n *networkNamespace) Routes(routes []*net.IPNet) IfaceOption { return func(i *nwIface) { i.routes = routes diff --git a/osl/sandbox.go b/osl/sandbox.go index 051a7facc2..18085c9082 100644 --- a/osl/sandbox.go +++ b/osl/sandbox.go @@ -91,6 +91,9 @@ type IfaceOptionSetter interface { // LinkLocalAddresses returns an option setter to set the link-local IP addresses. LinkLocalAddresses([]*net.IPNet) IfaceOption + // IPAliases returns an option setter to set IP address Aliases + IPAliases([]*net.IPNet) IfaceOption + // Master returns an option setter to set the master interface if any for this // interface. The master interface name should refer to the srcname of a // previously added interface of type bridge. @@ -147,6 +150,9 @@ type Interface interface { // LinkLocalAddresses returns the link-local IP addresses assigned to the interface. LinkLocalAddresses() []*net.IPNet + // IPAliases returns the IP address aliases assigned to the interface. + IPAliases() []*net.IPNet + // IP routes for the interface. Routes() []*net.IPNet @@ -160,10 +166,6 @@ type Interface interface { // and moving it out of the sandbox. Remove() error - // SetAliasIP adds or deletes the passed IP as an alias on the interface. - // ex: set the vip of services in the same network as secondary IP. - SetAliasIP(ip *net.IPNet, add bool) error - // Statistics returns the statistics for this interface Statistics() (*types.InterfaceStatistics, error) } diff --git a/sandbox.go b/sandbox.go index 5512e2a57b..1fd585cd28 100644 --- a/sandbox.go +++ b/sandbox.go @@ -761,6 +761,10 @@ func (sb *sandbox) restoreOslSandbox() error { if len(i.llAddrs) != 0 { ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs)) } + if len(ep.virtualIP) != 0 { + vipAlias := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)} + ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().IPAliases([]*net.IPNet{vipAlias})) + } Ifaces[fmt.Sprintf("%s+%s", i.srcName, i.dstPrefix)] = ifaceOptions if joinInfo != nil { for _, r := range joinInfo.StaticRoutes { @@ -814,6 +818,10 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error { if len(i.llAddrs) != 0 { ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs)) } + if len(ep.virtualIP) != 0 { + vipAlias := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)} + ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().IPAliases([]*net.IPNet{vipAlias})) + } if i.mac != nil { ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac)) } diff --git a/service_linux.go b/service_linux.go index 8d382d5540..9edbadefe8 100644 --- a/service_linux.go +++ b/service_linux.go @@ -101,14 +101,6 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) { for _, ip := range lb.backEnds { sb.addLBBackend(ip, lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, gwIP, addService, n.ingress) - // For a new service program the vip as an alias on the task's sandbox interface - // connected to this network. - if !addService { - continue - } - if err := ep.setAliasIP(sb, lb.vip, true); err != nil { - logrus.Errorf("Adding Service VIP %v to ep %v(%v) failed: %v", lb.vip, ep.ID(), ep.Name(), err) - } addService = false } lb.service.Unlock() @@ -132,16 +124,8 @@ func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po } sb.addLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, addService, n.ingress) - - // For a new service program the vip as an alias on the task's sandbox interface - // connected to this network. - if !addService { - return false - } - if err := ep.setAliasIP(sb, vip, true); err != nil { - logrus.Errorf("Adding Service VIP %v to ep %v(%v) failed: %v", vip, ep.ID(), ep.Name(), err) - } } + return false }) } @@ -163,16 +147,8 @@ func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Por } sb.rmLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, rmService, n.ingress) - - // If the service is being remove its vip alias on on the task's sandbox interface - // has to be removed as well. - if !rmService { - return false - } - if err := ep.setAliasIP(sb, vip, false); err != nil { - logrus.Errorf("Removing Service VIP %v from ep %v(%v) failed: %v", vip, ep.ID(), ep.Name(), err) - } } + return false }) } From e97818680df0874526bddec9d9731a51271cf314 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Sun, 20 Nov 2016 16:54:32 -0800 Subject: [PATCH 158/799] Add a ICMP reply rule for service VIP Ping on VIP has been behaving inconsistently depending on if a task for a service is local or remote. With this fix, the ICMP echo-request packets to service VIP are replied to by the NAT rule to self Signed-off-by: Madhu Venugopal --- service_linux.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/service_linux.go b/service_linux.go index 9edbadefe8..be8dc84d3e 100644 --- a/service_linux.go +++ b/service_linux.go @@ -654,6 +654,9 @@ func fwMarker() { rule := strings.Fields(fmt.Sprintf("-t mangle %s OUTPUT -d %s/32 -j MARK --set-mark %d", addDelOpt, vip, fwMark)) rules = append(rules, rule) + rule = strings.Fields(fmt.Sprintf("-t nat %s OUTPUT -p icmp --icmp echo-request -d %s -j DNAT --to 127.0.0.1", addDelOpt, vip)) + rules = append(rules, rule) + for _, rule := range rules { if err := iptables.RawCombinedOutputNative(rule...); err != nil { logrus.Errorf("setting up rule failed, %v: %v", rule, err) From 82a12c3af3cfd5ee8f8fd8957495c5743d2ef8df Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Sun, 20 Nov 2016 21:25:01 -0800 Subject: [PATCH 159/799] Fix bug in link-local unmarshalling Signed-off-by: Alessandro Boch --- endpoint_info.go | 6 +++--- libnetwork_internal_test.go | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/endpoint_info.go b/endpoint_info.go index 6814de0089..4e9592a56d 100644 --- a/endpoint_info.go +++ b/endpoint_info.go @@ -114,12 +114,12 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) error { } } if v, ok := epMap["llAddrs"]; ok { - list := v.([]string) + list := v.([]interface{}) epi.llAddrs = make([]*net.IPNet, 0, len(list)) for _, llS := range list { - ll, err := types.ParseCIDR(llS) + ll, err := types.ParseCIDR(llS.(string)) if err != nil { - return types.InternalErrorf("failed to decode endpoint interface link-local address (%s) after json unmarshal: %v", llS, err) + return types.InternalErrorf("failed to decode endpoint interface link-local address (%v) after json unmarshal: %v", llS, err) } epi.llAddrs = append(epi.llAddrs, ll) } diff --git a/libnetwork_internal_test.go b/libnetwork_internal_test.go index 8adee2a4d8..e4e90151f5 100644 --- a/libnetwork_internal_test.go +++ b/libnetwork_internal_test.go @@ -175,6 +175,12 @@ func TestEndpointMarshalling(t *testing.T) { } nw6.IP = ip + var lla []*net.IPNet + for _, nw := range []string{"169.254.0.1/16", "169.254.1.1/16", "169.254.2.2/16"} { + ll, _ := types.ParseCIDR(nw) + lla = append(lla, ll) + } + e := &endpoint{ name: "Bau", id: "efghijklmno", @@ -191,6 +197,7 @@ func TestEndpointMarshalling(t *testing.T) { dstPrefix: "eth", v4PoolID: "poolpool", v6PoolID: "poolv6", + llAddrs: lla, }, } @@ -218,7 +225,7 @@ func compareEndpointInterface(a, b *endpointInterface) bool { return false } return a.srcName == b.srcName && a.dstPrefix == b.dstPrefix && a.v4PoolID == b.v4PoolID && a.v6PoolID == b.v6PoolID && - types.CompareIPNet(a.addr, b.addr) && types.CompareIPNet(a.addrv6, b.addrv6) + types.CompareIPNet(a.addr, b.addr) && types.CompareIPNet(a.addrv6, b.addrv6) && compareNwLists(a.llAddrs, b.llAddrs) } func compareIpamConfList(listA, listB []*IpamConf) bool { @@ -285,6 +292,18 @@ func compareAddresses(a, b map[string]*net.IPNet) bool { return true } +func compareNwLists(a, b []*net.IPNet) bool { + if len(a) != len(b) { + return false + } + for k := range a { + if !types.CompareIPNet(a[k], b[k]) { + return false + } + } + return true +} + func TestAuxAddresses(t *testing.T) { c, err := New() if err != nil { From 392b201de13ec58e7864182f93a4ad8d5eb358cd Mon Sep 17 00:00:00 2001 From: Daehyeok Mun Date: Mon, 21 Nov 2016 11:53:07 -0700 Subject: [PATCH 160/799] Refactoring logrus import and formatting Fix import name to use original project name 'logrus' instead of 'log' Removing `f` from `logrus.Debugf` when formatting string is not present. Signed-off-by: Daehyeok Mun --- drivers/bridge/setup_ip_forwarding.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/bridge/setup_ip_forwarding.go b/drivers/bridge/setup_ip_forwarding.go index 2c6fedcb0e..d46f8ddf83 100644 --- a/drivers/bridge/setup_ip_forwarding.go +++ b/drivers/bridge/setup_ip_forwarding.go @@ -2,9 +2,10 @@ package bridge import ( "fmt" - log "github.com/Sirupsen/logrus" - "github.com/docker/libnetwork/iptables" "io/ioutil" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/iptables" ) const ( @@ -40,14 +41,14 @@ func setupIPForwarding(enableIPTables bool) error { } if err := iptables.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil { if err := configureIPForwarding(false); err != nil { - log.Errorf("Disabling IP forwarding failed, %v", err) + logrus.Errorf("Disabling IP forwarding failed, %v", err) } return err } iptables.OnReloaded(func() { - log.Debugf("Setting the default DROP policy on firewall reload") + logrus.Debug("Setting the default DROP policy on firewall reload") if err := iptables.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil { - log.Warnf("Settig the default DROP policy on firewall reload failed, %v", err) + logrus.Warnf("Settig the default DROP policy on firewall reload failed, %v", err) } }) } From 33819721fb22be234c861eaa306df8bbd0939c4e Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Mon, 21 Nov 2016 11:08:41 -0800 Subject: [PATCH 161/799] Serialize embedded resolver Start and Stop Signed-off-by: Santhosh Manohar --- resolver.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resolver.go b/resolver.go index e92c24887c..68e4831d53 100644 --- a/resolver.go +++ b/resolver.go @@ -87,6 +87,7 @@ type resolver struct { listenAddress string proxyDNS bool resolverKey string + startCh chan struct{} } func init() { @@ -101,6 +102,7 @@ func NewResolver(address string, proxyDNS bool, resolverKey string, backend DNSB listenAddress: address, resolverKey: resolverKey, err: fmt.Errorf("setup not done yet"), + startCh: make(chan struct{}, 1), } } @@ -136,6 +138,9 @@ func (r *resolver) SetupFunc(port int) func() { } func (r *resolver) Start() error { + r.startCh <- struct{}{} + defer func() { <-r.startCh }() + // make sure the resolver has been setup before starting if r.err != nil { return r.err @@ -160,6 +165,9 @@ func (r *resolver) Start() error { } func (r *resolver) Stop() { + r.startCh <- struct{}{} + defer func() { <-r.startCh }() + if r.server != nil { r.server.Shutdown() } From a3aa25c794018c478f06126d705249b77121b513 Mon Sep 17 00:00:00 2001 From: Ke Li Date: Tue, 22 Nov 2016 09:29:53 +0800 Subject: [PATCH 162/799] Remove unnecessary string formats Signed-off-by: Ke Li --- api/api_test.go | 128 ++++++++++----------- bitseq/sequence.go | 9 +- bitseq/sequence_test.go | 16 +-- client/client_service_test.go | 2 +- client/client_test.go | 6 +- client/mflag/flag_test.go | 2 +- client/service.go | 5 +- cmd/dnet/cmd.go | 4 +- cmd/dnet/dnet.go | 22 ++-- cmd/proxy/proxy.go | 4 +- cmd/readme_test/readme.go | 2 +- datastore/cache.go | 5 +- datastore/datastore_test.go | 2 +- driverapi/driverapi_test.go | 12 +- drivers/bridge/bridge.go | 8 +- drivers/bridge/bridge_test.go | 50 ++++---- drivers/bridge/network_test.go | 10 +- drivers/bridge/port_mapping_test.go | 4 +- drivers/bridge/setup_bridgenetfiltering.go | 3 +- drivers/bridge/setup_device_test.go | 4 +- drivers/bridge/setup_ip_forwarding_test.go | 2 +- drivers/bridge/setup_ip_tables.go | 5 +- drivers/bridge/setup_ipv4.go | 3 +- drivers/host/host_test.go | 16 +-- drivers/remote/driver.go | 3 +- drivers/remote/driver_test.go | 11 +- drvregistry/drvregistry.go | 5 +- hostdiscovery/hostdiscovery_test.go | 6 +- idm/idm.go | 13 ++- idm/idm_test.go | 20 ++-- ipam/allocator_test.go | 54 ++++----- ipams/builtin/builtin_unix.go | 6 +- ipams/builtin/builtin_windows.go | 6 +- ipams/null/null_test.go | 10 +- ipams/remote/remote_test.go | 10 +- iptables/firewalld_test.go | 6 +- iptables/iptables.go | 2 +- iptables/iptables_test.go | 16 +-- netutils/utils.go | 2 +- netutils/utils_test.go | 10 +- networkdb/broadcast.go | 4 +- networkdb/networkdb_test.go | 2 +- 42 files changed, 260 insertions(+), 250 deletions(-) diff --git a/api/api_test.go b/api/api_test.go index 288ef211ae..1d2e4e5fbc 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -147,7 +147,7 @@ func TestSandboxOptionParser(t *testing.T) { } if len(sb.parseOptions()) != 9 { - t.Fatalf("Failed to generate all libnetwork.SandboxOption methods") + t.Fatal("Failed to generate all libnetwork.SandboxOption methods") } } @@ -205,7 +205,7 @@ func TestCreateDeleteNetwork(t *testing.T) { vars := make(map[string]string) _, errRsp := procCreateNetwork(c, nil, badBody) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp) @@ -218,7 +218,7 @@ func TestCreateDeleteNetwork(t *testing.T) { _, errRsp = procCreateNetwork(c, vars, incompleteBody) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp) @@ -240,13 +240,13 @@ func TestCreateDeleteNetwork(t *testing.T) { vars[urlNwName] = "" _, errRsp = procDeleteNetwork(c, vars, nil) if errRsp == &successResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } vars[urlNwName] = "abc" _, errRsp = procDeleteNetwork(c, vars, nil) if errRsp == &successResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } vars[urlNwName] = "network_1" @@ -406,7 +406,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) { t.Fatalf("Did not return the expected number (2) of endpoint resources: %d", len(epList)) } if "sh" != epList[0].Network || "sh" != epList[1].Network { - t.Fatalf("Did not find expected network name in endpoint resources") + t.Fatal("Did not find expected network name in endpoint resources") } vars = make(map[string]string) @@ -458,7 +458,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) { } netList := i2nL(iList) if len(netList) != 1 { - t.Fatalf("Did not return the expected number of network resources") + t.Fatal("Did not return the expected number of network resources") } if nid != netList[0].ID { t.Fatalf("Did not find expected network %s: %v", nid, netList) @@ -509,7 +509,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) { } netList = i2nL(iList) if len(netList) != 0 { - t.Fatalf("Did not return the expected number of network resources") + t.Fatal("Did not return the expected number of network resources") } } @@ -700,7 +700,7 @@ func TestProcGetService(t *testing.T) { vars := map[string]string{urlEpID: ""} _, errRsp := procGetService(c, vars, nil) if errRsp.isOK() { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected %d, but got: %d", http.StatusBadRequest, errRsp.StatusCode) @@ -709,7 +709,7 @@ func TestProcGetService(t *testing.T) { vars[urlEpID] = "unknown-service-id" _, errRsp = procGetService(c, vars, nil) if errRsp.isOK() { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } if errRsp.StatusCode != http.StatusNotFound { t.Fatalf("Expected %d, but got: %d. (%v)", http.StatusNotFound, errRsp.StatusCode, errRsp) @@ -750,7 +750,7 @@ func TestProcPublishUnpublishService(t *testing.T) { } _, errRsp := procPublishService(c, vars, vbad) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp) @@ -762,7 +762,7 @@ func TestProcPublishUnpublishService(t *testing.T) { } _, errRsp = procPublishService(c, vars, b) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp) @@ -774,7 +774,7 @@ func TestProcPublishUnpublishService(t *testing.T) { } _, errRsp = procPublishService(c, vars, b) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp) @@ -786,7 +786,7 @@ func TestProcPublishUnpublishService(t *testing.T) { } _, errRsp = procPublishService(c, vars, b) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusNotFound { t.Fatalf("Expected %d. Got: %v", http.StatusNotFound, errRsp) @@ -798,7 +798,7 @@ func TestProcPublishUnpublishService(t *testing.T) { } _, errRsp = procPublishService(c, vars, b) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp) @@ -830,7 +830,7 @@ func TestProcPublishUnpublishService(t *testing.T) { vars[urlEpID] = "" _, errRsp = procUnpublishService(c, vars, nil) if errRsp.isOK() { - t.Fatalf("Expected failure but succeeded") + t.Fatal("Expected failure but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp) @@ -839,7 +839,7 @@ func TestProcPublishUnpublishService(t *testing.T) { vars[urlEpID] = "unknown-service-id" _, errRsp = procUnpublishService(c, vars, nil) if errRsp.isOK() { - t.Fatalf("Expected failure but succeeded") + t.Fatal("Expected failure but succeeded") } if errRsp.StatusCode != http.StatusNotFound { t.Fatalf("Expected %d. Got: %v", http.StatusNotFound, errRsp) @@ -853,7 +853,7 @@ func TestProcPublishUnpublishService(t *testing.T) { _, errRsp = procGetService(c, vars, nil) if errRsp.isOK() { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } if errRsp.StatusCode != http.StatusNotFound { t.Fatalf("Expected %d, but got: %d. (%v)", http.StatusNotFound, errRsp.StatusCode, errRsp) @@ -942,7 +942,7 @@ func TestAttachDetachBackend(t *testing.T) { _, errRsp = procUnpublishService(c, vars, nil) if errRsp.isOK() { - t.Fatalf("Expected failure but succeeded") + t.Fatal("Expected failure but succeeded") } if errRsp.StatusCode != http.StatusForbidden { t.Fatalf("Expected %d. Got: %v", http.StatusForbidden, errRsp) @@ -1046,7 +1046,7 @@ func TestFindNetworkUtil(t *testing.T) { _, errRsp := findNetwork(c, "", byName) if errRsp == &successResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { t.Fatalf("Expected %d, but got: %d", http.StatusBadRequest, errRsp.StatusCode) @@ -1057,7 +1057,7 @@ func TestFindNetworkUtil(t *testing.T) { t.Fatalf("Unexpected failure: %v", errRsp) } if n == nil { - t.Fatalf("Unexpected nil libnetwork.Network") + t.Fatal("Unexpected nil libnetwork.Network") } if nid != n.ID() { t.Fatalf("Incorrect libnetwork.Network resource. It has different id: %v", n) @@ -1071,7 +1071,7 @@ func TestFindNetworkUtil(t *testing.T) { t.Fatalf("Unexpected failure: %v", errRsp) } if n == nil { - t.Fatalf("Unexpected nil libnetwork.Network") + t.Fatal("Unexpected nil libnetwork.Network") } if nid != n.ID() { t.Fatalf("Incorrect libnetwork.Network resource. It has different id: %v", n) @@ -1086,7 +1086,7 @@ func TestFindNetworkUtil(t *testing.T) { _, errRsp = findNetwork(c, nid, byID) if errRsp == &successResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusNotFound { t.Fatalf("Expected %d, but got: %d", http.StatusNotFound, errRsp.StatusCode) @@ -1094,7 +1094,7 @@ func TestFindNetworkUtil(t *testing.T) { _, errRsp = findNetwork(c, "network", byName) if errRsp == &successResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusNotFound { t.Fatalf("Expected %d, but got: %d", http.StatusNotFound, errRsp.StatusCode) @@ -1134,7 +1134,7 @@ func TestCreateDeleteEndpoints(t *testing.T) { vars[urlNwName] = "firstNet" _, errRsp = procCreateEndpoint(c, vars, vbad) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } b, err := json.Marshal(endpointCreate{Name: ""}) @@ -1145,7 +1145,7 @@ func TestCreateDeleteEndpoints(t *testing.T) { vars[urlNwName] = "secondNet" _, errRsp = procCreateEndpoint(c, vars, b) if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") + t.Fatal("Expected to fail but succeeded") } vars[urlNwName] = "firstNet" @@ -1318,7 +1318,7 @@ func TestJoinLeave(t *testing.T) { keyStr := i2s(key) if keyStr == "" { - t.Fatalf("Empty sandbox key") + t.Fatal("Empty sandbox key") } _, errRsp = procDeleteEndpoint(c, vars, nil) if errRsp == &successResponse { @@ -1460,7 +1460,7 @@ func TestFindEndpointUtil(t *testing.T) { if ep0.ID() != ep1.ID() || ep0.ID() != ep2.ID() || ep0.ID() != ep3.ID() || ep0.ID() != ep4.ID() || ep0.ID() != ep5.ID() { - t.Fatalf("Diffenrent queries returned different endpoints") + t.Fatal("Diffenrent queries returned different endpoints") } ep.Delete(false) @@ -1534,7 +1534,7 @@ func checkPanic(t *testing.T) { panic(r) } } else { - t.Fatalf("Expected to panic, but succeeded") + t.Fatal("Expected to panic, but succeeded") } } @@ -1597,12 +1597,12 @@ func TestResponseStatus(t *testing.T) { r := responseStatus{StatusCode: http.StatusOK} if !r.isOK() { - t.Fatalf("isOK() failed") + t.Fatal("isOK() failed") } r = responseStatus{StatusCode: http.StatusCreated} if !r.isOK() { - t.Fatalf("isOK() failed") + t.Fatal("isOK() failed") } } @@ -1623,7 +1623,7 @@ func (l *localReader) Read(p []byte) (n int, err error) { return 0, errors.New("I am a bad reader") } if p == nil { - return -1, fmt.Errorf("nil buffer passed") + return -1, errors.New("nil buffer passed") } if l.data == nil || len(l.data) == 0 { return 0, io.EOF @@ -1647,7 +1647,7 @@ func (f *localResponseWriter) Header() http.Header { func (f *localResponseWriter) Write(data []byte) (int, error) { if data == nil { - return -1, fmt.Errorf("nil data passed") + return -1, errors.New("nil data passed") } f.body = make([]byte, len(data)) @@ -1699,7 +1699,7 @@ func TestHttpHandlerUninit(t *testing.T) { h := &httpHandler{c: c} h.initRouter() if h.r == nil { - t.Fatalf("initRouter() did not initialize the router") + t.Fatal("initRouter() did not initialize the router") } rsp := newWriter() @@ -1745,10 +1745,10 @@ func TestHttpHandlerUninit(t *testing.T) { t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body) } if len(rsp.body) == 0 { - t.Fatalf("Empty list of networks") + t.Fatal("Empty list of networks") } if bytes.Equal(rsp.body, expected) { - t.Fatalf("Incorrect list of networks in response's body") + t.Fatal("Incorrect list of networks in response's body") } } @@ -1823,7 +1823,7 @@ func TestEndToEnd(t *testing.T) { t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body)) } if len(rsp.body) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } var nid string @@ -1872,7 +1872,7 @@ func TestEndToEnd(t *testing.T) { } if !bytes.Equal(b0, rsp.body) { - t.Fatalf("Expected same body from GET /networks and GET /networks?name= when only network exist.") + t.Fatal("Expected same body from GET /networks and GET /networks?name= when only network exist.") } // Query network by name @@ -1907,7 +1907,7 @@ func TestEndToEnd(t *testing.T) { t.Fatal(err) } if len(list) == 0 { - t.Fatalf("Expected non empty list") + t.Fatal("Expected non empty list") } if list[0].Name != "network-fiftyfive" || nid != list[0].ID { t.Fatalf("Incongruent resource found: %v", list[0]) @@ -1930,7 +1930,7 @@ func TestEndToEnd(t *testing.T) { t.Fatal(err) } if len(list) == 0 { - t.Fatalf("Expected non empty list") + t.Fatal("Expected non empty list") } if list[0].Name != "network-fiftyfive" || nid != list[0].ID { t.Fatalf("Incongruent resource found: %v", list[0]) @@ -1971,7 +1971,7 @@ func TestEndToEnd(t *testing.T) { t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body)) } if len(rsp.body) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } var eid string @@ -2022,7 +2022,7 @@ func TestEndToEnd(t *testing.T) { t.Fatal(err) } if len(epList) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } if epList[0].Name != "ep-TwentyTwo" || eid != epList[0].ID { t.Fatalf("Incongruent resource found: %v", epList[0]) @@ -2045,7 +2045,7 @@ func TestEndToEnd(t *testing.T) { t.Fatal(err) } if len(epList) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } if epList[0].Name != "ep-TwentyTwo" || eid != epList[0].ID { t.Fatalf("Incongruent resource found: %v", epList[0]) @@ -2095,7 +2095,7 @@ func TestEndToEnd(t *testing.T) { t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body)) } if len(rsp.body) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } // Get sandbox id and partial id var sid1 string @@ -2122,7 +2122,7 @@ func TestEndToEnd(t *testing.T) { t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body)) } if len(rsp.body) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } // Get sandbox id and partial id var sid2 string @@ -2186,7 +2186,7 @@ func TestEndToEnd(t *testing.T) { t.Fatal(err) } if len(sbList) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } if sbList[0].ID != sid2 { t.Fatalf("Incongruent resource found: %v", sbList[0]) @@ -2207,7 +2207,7 @@ func TestEndToEnd(t *testing.T) { t.Fatal(err) } if len(sbList) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } if sbList[0].ContainerID != cid2 { t.Fatalf("Incongruent resource found: %v", sbList[0]) @@ -2228,7 +2228,7 @@ func TestEndToEnd(t *testing.T) { t.Fatal(err) } if len(sbList) == 0 { - t.Fatalf("Empty response body") + t.Fatal("Empty response body") } if sbList[0].ContainerID != cid1 { t.Fatalf("Incongruent resource found: %v", sbList[0]) @@ -2259,11 +2259,11 @@ func TestEndToEndErrorMessage(t *testing.T) { handleRequest(rsp, req) if len(rsp.body) == 0 { - t.Fatalf("Empty response body.") + t.Fatal("Empty response body.") } empty := []byte("\"\"") if bytes.Equal(empty, bytes.TrimSpace(rsp.body)) { - t.Fatalf("Empty response error message.") + t.Fatal("Empty response error message.") } } @@ -2324,35 +2324,35 @@ func (noc *notclassified) Error() string { func TestErrorConversion(t *testing.T) { if convertNetworkError(new(bre)).StatusCode != http.StatusBadRequest { - t.Fatalf("Failed to recognize BadRequest error") + t.Fatal("Failed to recognize BadRequest error") } if convertNetworkError(new(nfe)).StatusCode != http.StatusNotFound { - t.Fatalf("Failed to recognize NotFound error") + t.Fatal("Failed to recognize NotFound error") } if convertNetworkError(new(forb)).StatusCode != http.StatusForbidden { - t.Fatalf("Failed to recognize Forbidden error") + t.Fatal("Failed to recognize Forbidden error") } if convertNetworkError(new(notimpl)).StatusCode != http.StatusNotImplemented { - t.Fatalf("Failed to recognize NotImplemented error") + t.Fatal("Failed to recognize NotImplemented error") } if convertNetworkError(new(inter)).StatusCode != http.StatusInternalServerError { - t.Fatalf("Failed to recognize Internal error") + t.Fatal("Failed to recognize Internal error") } if convertNetworkError(new(tout)).StatusCode != http.StatusRequestTimeout { - t.Fatalf("Failed to recognize Timeout error") + t.Fatal("Failed to recognize Timeout error") } if convertNetworkError(new(noserv)).StatusCode != http.StatusServiceUnavailable { - t.Fatalf("Failed to recognize No Service error") + t.Fatal("Failed to recognize No Service error") } if convertNetworkError(new(notclassified)).StatusCode != http.StatusInternalServerError { - t.Fatalf("Failed to recognize not classified error as Internal error") + t.Fatal("Failed to recognize not classified error as Internal error") } } @@ -2361,23 +2361,23 @@ func TestFieldRegex(t *testing.T) { qr := regexp.MustCompile(`^` + qregx + `$`) // mux compiles it like this if pr.MatchString("") { - t.Fatalf("Unexpected match") + t.Fatal("Unexpected match") } if !qr.MatchString("") { - t.Fatalf("Unexpected match failure") + t.Fatal("Unexpected match failure") } if pr.MatchString(":") { - t.Fatalf("Unexpected match") + t.Fatal("Unexpected match") } if qr.MatchString(":") { - t.Fatalf("Unexpected match") + t.Fatal("Unexpected match") } if pr.MatchString(".") { - t.Fatalf("Unexpected match") + t.Fatal("Unexpected match") } if qr.MatchString(".") { - t.Fatalf("Unexpected match") + t.Fatal("Unexpected match") } } diff --git a/bitseq/sequence.go b/bitseq/sequence.go index 9c815e5e3c..9a7e90e1de 100644 --- a/bitseq/sequence.go +++ b/bitseq/sequence.go @@ -6,6 +6,7 @@ package bitseq import ( "encoding/binary" "encoding/json" + "errors" "fmt" "sync" @@ -26,9 +27,9 @@ const ( var ( // ErrNoBitAvailable is returned when no more bits are available to set - ErrNoBitAvailable = fmt.Errorf("no bit available") + ErrNoBitAvailable = errors.New("no bit available") // ErrBitAllocated is returned when the specific bit requested is already set - ErrBitAllocated = fmt.Errorf("requested bit is already allocated") + ErrBitAllocated = errors.New("requested bit is already allocated") ) // Handle contains the sequece representing the bitmask and its identifier @@ -373,7 +374,7 @@ func (h *Handle) validateOrdinal(ordinal uint64) error { h.Lock() defer h.Unlock() if ordinal >= h.bits { - return fmt.Errorf("bit does not belong to the sequence") + return errors.New("bit does not belong to the sequence") } return nil } @@ -418,7 +419,7 @@ func (h *Handle) ToByteArray() ([]byte, error) { // FromByteArray reads his handle's data from a byte array func (h *Handle) FromByteArray(ba []byte) error { if ba == nil { - return fmt.Errorf("nil byte array") + return errors.New("nil byte array") } nh := &sequence{} diff --git a/bitseq/sequence_test.go b/bitseq/sequence_test.go index 4ef3bbb6fe..777303d008 100644 --- a/bitseq/sequence_test.go +++ b/bitseq/sequence_test.go @@ -145,10 +145,10 @@ func TestSequenceCopy(t *testing.T) { s := getTestSequence() n := s.getCopy() if !s.equal(n) { - t.Fatalf("copy of s failed") + t.Fatal("copy of s failed") } if n == s { - t.Fatalf("not true copy of s") + t.Fatal("not true copy of s") } } @@ -556,7 +556,7 @@ func TestSet(t *testing.T) { } if err := hnd.Set(0); err == nil { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } os, err := hnd.SetAny() @@ -583,7 +583,7 @@ func TestSet(t *testing.T) { } if err := hnd.Set(last); err == nil { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } } @@ -595,10 +595,10 @@ func TestSetUnset(t *testing.T) { } if err := hnd.Set(uint64(32 * blockLen)); err == nil { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } if err := hnd.Unset(uint64(32 * blockLen)); err == nil { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } // set and unset all one by one @@ -608,10 +608,10 @@ func TestSetUnset(t *testing.T) { } } if _, err := hnd.SetAny(); err != ErrNoBitAvailable { - t.Fatalf("Expected error. Got success") + t.Fatal("Expected error. Got success") } if _, err := hnd.SetAnyInRange(10, 20); err != ErrNoBitAvailable { - t.Fatalf("Expected error. Got success") + t.Fatal("Expected error. Got success") } if err := hnd.Set(50); err != ErrBitAllocated { t.Fatalf("Expected error. Got %v: %s", err, hnd) diff --git a/client/client_service_test.go b/client/client_service_test.go index 8b6fbd2d81..e904056989 100644 --- a/client/client_service_test.go +++ b/client/client_service_test.go @@ -13,7 +13,7 @@ func TestClientServiceInvalidCommand(t *testing.T) { err := cli.Cmd("docker", "service", "invalid") if err == nil { - t.Fatalf("Passing invalid commands must fail") + t.Fatal("Passing invalid commands must fail") } } diff --git a/client/client_test.go b/client/client_test.go index 20203375e1..ab15a3eef3 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -114,7 +114,7 @@ func TestClientDummyCommand(t *testing.T) { err := cli.Cmd("docker", "dummy") if err == nil { - t.Fatalf("Incorrect Command must fail") + t.Fatal("Incorrect Command must fail") } } @@ -124,7 +124,7 @@ func TestClientNetworkInvalidCommand(t *testing.T) { err := cli.Cmd("docker", "network", "invalid") if err == nil { - t.Fatalf("Passing invalid commands must fail") + t.Fatal("Passing invalid commands must fail") } } @@ -144,7 +144,7 @@ func TestClientNetworkCreateWithDriver(t *testing.T) { err := cli.Cmd("docker", "network", "create", "-f=dummy", mockNwName) if err == nil { - t.Fatalf("Passing incorrect flags to the create command must fail") + t.Fatal("Passing incorrect flags to the create command must fail") } err = cli.Cmd("docker", "network", "create", "-d=dummy", mockNwName) diff --git a/client/mflag/flag_test.go b/client/mflag/flag_test.go index a09d49cd60..c11693a870 100644 --- a/client/mflag/flag_test.go +++ b/client/mflag/flag_test.go @@ -72,7 +72,7 @@ func TestEverything(t *testing.T) { m = make(map[string]*Flag) Visit(visitor) if len(m) != 0 { - t.Errorf("Visit sees unset flags") + t.Error("Visit sees unset flags") for k, v := range m { t.Log(k, *v) } diff --git a/client/service.go b/client/service.go index da69af3a1f..532afcff3b 100644 --- a/client/service.go +++ b/client/service.go @@ -3,6 +3,7 @@ package client import ( "bytes" "encoding/json" + "errors" "fmt" "net/http" "strings" @@ -111,9 +112,9 @@ func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) { if id, ok := iid.(string); ok { return id, nil } - return "", fmt.Errorf("Unexpected data type for container ID in json response") + return "", errors.New("Unexpected data type for container ID in json response") } - return "", fmt.Errorf("Cannot find container ID in json response") + return "", errors.New("Cannot find container ID in json response") } func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) { diff --git a/cmd/dnet/cmd.go b/cmd/dnet/cmd.go index 5c30cb81e6..c9ec2d2b1d 100644 --- a/cmd/dnet/cmd.go +++ b/cmd/dnet/cmd.go @@ -44,7 +44,7 @@ var ( func runContainerCreate(c *cli.Context) { if len(c.Args()) == 0 { - fmt.Printf("Please provide container id argument\n") + fmt.Print("Please provide container id argument\n") os.Exit(1) } @@ -70,7 +70,7 @@ func runContainerRm(c *cli.Context) { var sbList []*client.SandboxResource if len(c.Args()) == 0 { - fmt.Printf("Please provide container id argument\n") + fmt.Print("Please provide container id argument\n") os.Exit(1) } diff --git a/cmd/dnet/dnet.go b/cmd/dnet/dnet.go index 2c434bd973..d4f1d03261 100644 --- a/cmd/dnet/dnet.go +++ b/cmd/dnet/dnet.go @@ -134,7 +134,7 @@ func processConfig(cfg *config.Config) []config.Option { func startDiscovery(cfg *config.ClusterCfg) ([]config.Option, error) { if cfg == nil { - return nil, fmt.Errorf("discovery requires a valid configuration") + return nil, errors.New("discovery requires a valid configuration") } hb := time.Duration(cfg.Heartbeat) * time.Second @@ -367,7 +367,7 @@ func startTestDriver() error { mux := http.NewServeMux() server := httptest.NewServer(mux) if server == nil { - return fmt.Errorf("Failed to start an HTTP Server") + return errors.New("Failed to start an HTTP Server") } mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { @@ -377,37 +377,37 @@ func startTestDriver() error { mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") - fmt.Fprintf(w, `{"Scope":"global"}`) + fmt.Fprint(w, `{"Scope":"global"}`) }) mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") - fmt.Fprintf(w, "null") + fmt.Fprint(w, "null") }) mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") - fmt.Fprintf(w, "null") + fmt.Fprint(w, "null") }) mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") - fmt.Fprintf(w, "null") + fmt.Fprint(w, "null") }) mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") - fmt.Fprintf(w, "null") + fmt.Fprint(w, "null") }) mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") - fmt.Fprintf(w, "null") + fmt.Fprint(w, "null") }) mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") - fmt.Fprintf(w, "null") + fmt.Fprint(w, "null") }) if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil { @@ -428,10 +428,10 @@ func newDnetConnection(val string) (*dnetConnection, error) { } protoAddrParts := strings.SplitN(url, "://", 2) if len(protoAddrParts) != 2 { - return nil, fmt.Errorf("bad format, expected tcp://ADDR") + return nil, errors.New("bad format, expected tcp://ADDR") } if strings.ToLower(protoAddrParts[0]) != "tcp" { - return nil, fmt.Errorf("dnet currently only supports tcp transport") + return nil, errors.New("dnet currently only supports tcp transport") } return &dnetConnection{protoAddrParts[0], protoAddrParts[1], &NetworkOrchestration{}, make(chan struct{}, 10)}, nil diff --git a/cmd/proxy/proxy.go b/cmd/proxy/proxy.go index 44dd177bb6..b846905316 100644 --- a/cmd/proxy/proxy.go +++ b/cmd/proxy/proxy.go @@ -3,7 +3,7 @@ package main import ( - "fmt" + "errors" "net" ) @@ -32,6 +32,6 @@ func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) { case *net.TCPAddr: return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr)) default: - panic(fmt.Errorf("Unsupported protocol")) + panic(errors.New("Unsupported protocol")) } } diff --git a/cmd/readme_test/readme.go b/cmd/readme_test/readme.go index 600f99bcff..5529f7c6fd 100644 --- a/cmd/readme_test/readme.go +++ b/cmd/readme_test/readme.go @@ -67,7 +67,7 @@ func main() { macAddress, ok := epInfo[netlabel.MacAddress] if !ok { - log.Fatalf("failed to get mac address from endpoint info") + log.Fatal("failed to get mac address from endpoint info") } fmt.Printf("Joined endpoint %s (%s) to sandbox %s (%s)\n", ep.Name(), macAddress, sbx.ContainerID(), sbx.Key()) diff --git a/datastore/cache.go b/datastore/cache.go index 97b6009113..49839ae8f2 100644 --- a/datastore/cache.go +++ b/datastore/cache.go @@ -1,6 +1,7 @@ package datastore import ( + "errors" "fmt" "sync" @@ -36,7 +37,7 @@ func (c *cache) kmap(kvObject KVObject) (kvMap, error) { // Bail out right away if the kvObject does not implement KVConstructor ctor, ok := kvObject.(KVConstructor) if !ok { - return nil, fmt.Errorf("error while populating kmap, object does not implement KVConstructor interface") + return nil, errors.New("error while populating kmap, object does not implement KVConstructor interface") } kvList, err := c.ds.store.List(keyPrefix) @@ -153,7 +154,7 @@ func (c *cache) get(key string, kvObject KVObject) error { ctor, ok := o.(KVConstructor) if !ok { - return fmt.Errorf("kvobject does not implement KVConstructor interface. could not get object") + return errors.New("kvobject does not implement KVConstructor interface. could not get object") } return ctor.CopyTo(kvObject) diff --git a/datastore/datastore_test.go b/datastore/datastore_test.go index f1de9472e6..3cd0aea1ca 100644 --- a/datastore/datastore_test.go +++ b/datastore/datastore_test.go @@ -61,7 +61,7 @@ func TestKVObjectFlatKey(t *testing.T) { var n dummyObject json.Unmarshal(data.Value, &n) if n.Name != expected.Name { - t.Fatalf("Dummy object doesn't match the expected object") + t.Fatal("Dummy object doesn't match the expected object") } } diff --git a/driverapi/driverapi_test.go b/driverapi/driverapi_test.go index 8923d3d204..de7a72b9ca 100644 --- a/driverapi/driverapi_test.go +++ b/driverapi/driverapi_test.go @@ -66,14 +66,14 @@ func TestValidateAndIsV6(t *testing.T) { // Check ip version if i.IsV6() { - t.Fatalf("incorrect ip version returned") + t.Fatal("incorrect ip version returned") } orig := i.Pool if i.Pool, err = types.ParseCIDR("2001:db8::33/64"); err != nil { t.Fatal(err) } if !i.IsV6() { - t.Fatalf("incorrect ip version returned") + t.Fatal("incorrect ip version returned") } i.Pool = orig @@ -87,7 +87,7 @@ func TestValidateAndIsV6(t *testing.T) { t.Fatal(err) } if err = i.Validate(); err == nil { - t.Fatalf("expected error but succeeded") + t.Fatal("expected error but succeeded") } i.Gateway = nil @@ -96,7 +96,7 @@ func TestValidateAndIsV6(t *testing.T) { t.Fatal(err) } if err = i.Validate(); err == nil { - t.Fatalf("expected error but succeeded") + t.Fatal("expected error but succeeded") } delete(i.AuxAddresses, "ip2") @@ -105,7 +105,7 @@ func TestValidateAndIsV6(t *testing.T) { t.Fatal(err) } if err = i.Validate(); err == nil { - t.Fatalf("expected error but succeeded") + t.Fatal("expected error but succeeded") } i.Gateway = nil @@ -114,6 +114,6 @@ func TestValidateAndIsV6(t *testing.T) { t.Fatal(err) } if err = i.Validate(); err == nil { - t.Fatalf("expected error but succeeded") + t.Fatal("expected error but succeeded") } } diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index f6cbe07783..f1d2dcab4e 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -186,24 +186,24 @@ func (c *networkConfiguration) Validate() error { // Conflicts check if two NetworkConfiguration objects overlap func (c *networkConfiguration) Conflicts(o *networkConfiguration) error { if o == nil { - return fmt.Errorf("same configuration") + return errors.New("same configuration") } // Also empty, because only one network with empty name is allowed if c.BridgeName == o.BridgeName { - return fmt.Errorf("networks have same bridge name") + return errors.New("networks have same bridge name") } // They must be in different subnets if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) && (c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) { - return fmt.Errorf("networks have overlapping IPv4") + return errors.New("networks have overlapping IPv4") } // They must be in different v6 subnets if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) && (c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) { - return fmt.Errorf("networks have overlapping IPv6") + return errors.New("networks have overlapping IPv6") } return nil diff --git a/drivers/bridge/bridge_test.go b/drivers/bridge/bridge_test.go index a44a595968..5acb8dbebc 100644 --- a/drivers/bridge/bridge_test.go +++ b/drivers/bridge/bridge_test.go @@ -300,23 +300,23 @@ func TestCreateFullOptionsLabels(t *testing.T) { nw, ok := d.networks["dummy"] if !ok { - t.Fatalf("Cannot find dummy network in bridge driver") + t.Fatal("Cannot find dummy network in bridge driver") } if nw.config.BridgeName != DefaultBridgeName { - t.Fatalf("incongruent name in bridge network") + t.Fatal("incongruent name in bridge network") } if !nw.config.EnableIPv6 { - t.Fatalf("incongruent EnableIPv6 in bridge network") + t.Fatal("incongruent EnableIPv6 in bridge network") } if !nw.config.EnableICC { - t.Fatalf("incongruent EnableICC in bridge network") + t.Fatal("incongruent EnableICC in bridge network") } if !nw.config.EnableIPMasquerade { - t.Fatalf("incongruent EnableIPMasquerade in bridge network") + t.Fatal("incongruent EnableIPMasquerade in bridge network") } bndIP := net.ParseIP(bndIPs) @@ -371,10 +371,10 @@ func TestCreate(t *testing.T) { err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil) if err == nil { - t.Fatalf("Expected bridge driver to refuse creation of second network with default name") + t.Fatal("Expected bridge driver to refuse creation of second network with default name") } if _, ok := err.(types.ForbiddenError); !ok { - t.Fatalf("Creation of second network with default name failed with unexpected error type") + t.Fatal("Creation of second network with default name failed with unexpected error type") } } @@ -662,18 +662,18 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) { } pmd, ok := data[netlabel.PortMap] if !ok { - t.Fatalf("Endpoint operational data does not contain port mapping data") + t.Fatal("Endpoint operational data does not contain port mapping data") } pm, ok := pmd.([]types.PortBinding) if !ok { - t.Fatalf("Unexpected format for port mapping in endpoint operational data") + t.Fatal("Unexpected format for port mapping in endpoint operational data") } if len(ep.portMapping) != len(pm) { - t.Fatalf("Incomplete data for port mapping in endpoint operational data") + t.Fatal("Incomplete data for port mapping in endpoint operational data") } for i, pb := range ep.portMapping { if !pb.Equal(&pm[i]) { - t.Fatalf("Unexpected data for port mapping in endpoint operational data") + t.Fatal("Unexpected data for port mapping in endpoint operational data") } } @@ -757,7 +757,7 @@ func TestLinkContainers(t *testing.T) { addr1 := te1.iface.addr if addr1.IP.To4() == nil { - t.Fatalf("No Ipv4 address assigned to the endpoint: ep1") + t.Fatal("No Ipv4 address assigned to the endpoint: ep1") } te2 := newTestEndpoint(ipdList[0].Pool, 22) @@ -768,7 +768,7 @@ func TestLinkContainers(t *testing.T) { addr2 := te2.iface.addr if addr2.IP.To4() == nil { - t.Fatalf("No Ipv4 address assigned to the endpoint: ep2") + t.Fatal("No Ipv4 address assigned to the endpoint: ep2") } sbOptions = make(map[string]interface{}) @@ -778,7 +778,7 @@ func TestLinkContainers(t *testing.T) { err = d.Join("net1", "ep2", "", te2, sbOptions) if err != nil { - t.Fatalf("Failed to link ep1 and ep2") + t.Fatal("Failed to link ep1 and ep2") } err = d.ProgramExternalConnectivity("net1", "ep2", sbOptions) @@ -809,7 +809,7 @@ func TestLinkContainers(t *testing.T) { err = d.Leave("net1", "ep2") if err != nil { - t.Fatalf("Failed to unlink ep1 and ep2") + t.Fatal("Failed to unlink ep1 and ep2") } out, err = iptables.Raw("-L", DockerChain) @@ -856,7 +856,7 @@ func TestLinkContainers(t *testing.T) { } } } else { - t.Fatalf("Expected Join to fail given link conditions are not satisfied") + t.Fatal("Expected Join to fail given link conditions are not satisfied") } } @@ -869,13 +869,13 @@ func TestValidateConfig(t *testing.T) { c := networkConfiguration{Mtu: -2} err := c.Validate() if err == nil { - t.Fatalf("Failed to detect invalid MTU number") + t.Fatal("Failed to detect invalid MTU number") } c.Mtu = 9000 err = c.Validate() if err != nil { - t.Fatalf("unexpected validation error on MTU number") + t.Fatal("unexpected validation error on MTU number") } // Bridge network @@ -893,13 +893,13 @@ func TestValidateConfig(t *testing.T) { c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234") err = c.Validate() if err == nil { - t.Fatalf("Failed to detect invalid default gateway") + t.Fatal("Failed to detect invalid default gateway") } c.DefaultGatewayIPv4 = net.ParseIP("172.28.30.234") err = c.Validate() if err != nil { - t.Fatalf("Unexpected validation error on default gateway") + t.Fatal("Unexpected validation error on default gateway") } // Test v6 gw @@ -911,25 +911,25 @@ func TestValidateConfig(t *testing.T) { } err = c.Validate() if err == nil { - t.Fatalf("Failed to detect invalid v6 default gateway") + t.Fatal("Failed to detect invalid v6 default gateway") } c.DefaultGatewayIPv6 = net.ParseIP("2001:db8:ae:b004::bad:a55") err = c.Validate() if err != nil { - t.Fatalf("Unexpected validation error on v6 default gateway") + t.Fatal("Unexpected validation error on v6 default gateway") } c.AddressIPv6 = nil err = c.Validate() if err == nil { - t.Fatalf("Failed to detect invalid v6 default gateway") + t.Fatal("Failed to detect invalid v6 default gateway") } c.AddressIPv6 = nil err = c.Validate() if err == nil { - t.Fatalf("Failed to detect invalid v6 default gateway") + t.Fatal("Failed to detect invalid v6 default gateway") } } @@ -1068,6 +1068,6 @@ func TestCreateWithExistingBridge(t *testing.T) { } if _, err := netlink.LinkByName(brName); err != nil { - t.Fatalf("Deleting bridge network that using existing bridge interface unexpectedly deleted the bridge interface") + t.Fatal("Deleting bridge network that using existing bridge interface unexpectedly deleted the bridge interface") } } diff --git a/drivers/bridge/network_test.go b/drivers/bridge/network_test.go index ca632e4c31..fbe177c173 100644 --- a/drivers/bridge/network_test.go +++ b/drivers/bridge/network_test.go @@ -39,7 +39,7 @@ func TestLinkCreate(t *testing.T) { t.Fatalf("Failed with a wrong error :%s", err.Error()) } } else { - t.Fatalf("Failed to detect invalid config") + t.Fatal("Failed to detect invalid config") } // Good endpoint creation @@ -59,7 +59,7 @@ func TestLinkCreate(t *testing.T) { t.Fatal(err) } if mtu != sboxLnk.Attrs().MTU { - t.Fatalf("Sandbox endpoint interface did not inherit bridge interface MTU config") + t.Fatal("Sandbox endpoint interface did not inherit bridge interface MTU config") } // TODO: if we could get peer name from (sboxLnk.(*netlink.Veth)).PeerName // then we could check the MTU on hostLnk as well. @@ -67,7 +67,7 @@ func TestLinkCreate(t *testing.T) { te1 := newTestEndpoint(ipdList[0].Pool, 11) err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil) if err == nil { - t.Fatalf("Failed to detect duplicate endpoint id on same network") + t.Fatal("Failed to detect duplicate endpoint id on same network") } if te.iface.dstName == "" { @@ -137,7 +137,7 @@ func TestLinkCreateTwo(t *testing.T) { t.Fatalf("Failed with a wrong error: %s", err.Error()) } } else { - t.Fatalf("Expected to fail while trying to add same endpoint twice") + t.Fatal("Expected to fail while trying to add same endpoint twice") } } @@ -207,7 +207,7 @@ func TestLinkDelete(t *testing.T) { t.Fatalf("Failed with a wrong error :%s", err.Error()) } } else { - t.Fatalf("Failed to detect invalid config") + t.Fatal("Failed to detect invalid config") } err = d.DeleteEndpoint("dummy", "ep1") diff --git a/drivers/bridge/port_mapping_test.go b/drivers/bridge/port_mapping_test.go index e4d342dd95..057ecfecb1 100644 --- a/drivers/bridge/port_mapping_test.go +++ b/drivers/bridge/port_mapping_test.go @@ -74,11 +74,11 @@ func TestPortMappingConfig(t *testing.T) { } if ep.portMapping[0].Proto != binding1.Proto || ep.portMapping[0].Port != binding1.Port || ep.portMapping[1].Proto != binding2.Proto || ep.portMapping[1].Port != binding2.Port { - t.Fatalf("bridgeEndpoint has incorrect port mapping values") + t.Fatal("bridgeEndpoint has incorrect port mapping values") } if ep.portMapping[0].HostIP == nil || ep.portMapping[0].HostPort == 0 || ep.portMapping[1].HostIP == nil || ep.portMapping[1].HostPort == 0 { - t.Fatalf("operational port mapping data not found on bridgeEndpoint") + t.Fatal("operational port mapping data not found on bridgeEndpoint") } // release host mapped ports diff --git a/drivers/bridge/setup_bridgenetfiltering.go b/drivers/bridge/setup_bridgenetfiltering.go index aa6c8eba4c..884c7115ec 100644 --- a/drivers/bridge/setup_bridgenetfiltering.go +++ b/drivers/bridge/setup_bridgenetfiltering.go @@ -1,6 +1,7 @@ package bridge import ( + "errors" "fmt" "io/ioutil" "os" @@ -37,7 +38,7 @@ func setupBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) e logrus.Warnf("running inside docker container, ignoring missing kernel params: %v", err) err = nil } else { - err = fmt.Errorf("please ensure that br_netfilter kernel module is loaded") + err = errors.New("please ensure that br_netfilter kernel module is loaded") } } } diff --git a/drivers/bridge/setup_device_test.go b/drivers/bridge/setup_device_test.go index aeb2c3fde3..85741995bd 100644 --- a/drivers/bridge/setup_device_test.go +++ b/drivers/bridge/setup_device_test.go @@ -32,7 +32,7 @@ func TestSetupNewBridge(t *testing.T) { t.Fatalf("Failed to retrieve bridge device: %v", err) } if br.Link.Attrs().Flags&net.FlagUp == net.FlagUp { - t.Fatalf("bridgeInterface should be created down") + t.Fatal("bridgeInterface should be created down") } } @@ -79,7 +79,7 @@ func TestSetupDeviceUp(t *testing.T) { lnk, _ := nh.LinkByName(DefaultBridgeName) if lnk.Attrs().Flags&net.FlagUp != net.FlagUp { - t.Fatalf("bridgeInterface should be up") + t.Fatal("bridgeInterface should be up") } } diff --git a/drivers/bridge/setup_ip_forwarding_test.go b/drivers/bridge/setup_ip_forwarding_test.go index c6b88c89d4..da9c4f48d5 100644 --- a/drivers/bridge/setup_ip_forwarding_test.go +++ b/drivers/bridge/setup_ip_forwarding_test.go @@ -24,7 +24,7 @@ func TestSetupIPForwarding(t *testing.T) { // Read new setting procSetting = readCurrentIPForwardingSetting(t) if bytes.Compare(procSetting, []byte("1\n")) != 0 { - t.Fatalf("Failed to effectively setup IP forwarding") + t.Fatal("Failed to effectively setup IP forwarding") } } diff --git a/drivers/bridge/setup_ip_tables.go b/drivers/bridge/setup_ip_tables.go index 862d9e4491..43327a19cc 100644 --- a/drivers/bridge/setup_ip_tables.go +++ b/drivers/bridge/setup_ip_tables.go @@ -1,6 +1,7 @@ package bridge import ( + "errors" "fmt" "net" @@ -17,7 +18,7 @@ const ( func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) { // Sanity check. if config.EnableIPTables == false { - return nil, nil, nil, fmt.Errorf("cannot create new chains, EnableIPTable is disabled") + return nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled") } hairpinMode := !config.EnableUserlandProxy @@ -68,7 +69,7 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt // Sanity check. if driverConfig.EnableIPTables == false { - return fmt.Errorf("Cannot program chains, EnableIPTable is disabled") + return errors.New("Cannot program chains, EnableIPTable is disabled") } // Pickup this configuraton option from driver diff --git a/drivers/bridge/setup_ipv4.go b/drivers/bridge/setup_ipv4.go index 772b40eed3..7f8707266d 100644 --- a/drivers/bridge/setup_ipv4.go +++ b/drivers/bridge/setup_ipv4.go @@ -1,6 +1,7 @@ package bridge import ( + "errors" "fmt" "io/ioutil" "net" @@ -13,7 +14,7 @@ import ( func selectIPv4Address(addresses []netlink.Addr, selector *net.IPNet) (netlink.Addr, error) { if len(addresses) == 0 { - return netlink.Addr{}, fmt.Errorf("unable to select an address as the address pool is empty") + return netlink.Addr{}, errors.New("unable to select an address as the address pool is empty") } if selector != nil { for _, addr := range addresses { diff --git a/drivers/host/host_test.go b/drivers/host/host_test.go index 8f6f3535f6..75b23b3a0b 100644 --- a/drivers/host/host_test.go +++ b/drivers/host/host_test.go @@ -11,7 +11,7 @@ func TestDriver(t *testing.T) { d := &driver{} if d.Type() != networkType { - t.Fatalf("Unexpected network type returned by driver") + t.Fatal("Unexpected network type returned by driver") } err := d.CreateNetwork("first", nil, nil, nil, nil) @@ -20,31 +20,31 @@ func TestDriver(t *testing.T) { } if d.network != "first" { - t.Fatalf("Unexpected network id stored") + t.Fatal("Unexpected network id stored") } err = d.CreateNetwork("second", nil, nil, nil, nil) if err == nil { - t.Fatalf("Second network creation should fail on this driver") + t.Fatal("Second network creation should fail on this driver") } if _, ok := err.(types.ForbiddenError); !ok { - t.Fatalf("Second network creation failed with unexpected error type") + t.Fatal("Second network creation failed with unexpected error type") } err = d.DeleteNetwork("first") if err == nil { - t.Fatalf("network deletion should fail on this driver") + t.Fatal("network deletion should fail on this driver") } if _, ok := err.(types.ForbiddenError); !ok { - t.Fatalf("network deletion failed with unexpected error type") + t.Fatal("network deletion failed with unexpected error type") } // we don't really check if it is there or not, delete is not allowed for this driver, period. err = d.DeleteNetwork("unknown") if err == nil { - t.Fatalf("any network deletion should fail on this driver") + t.Fatal("any network deletion should fail on this driver") } if _, ok := err.(types.ForbiddenError); !ok { - t.Fatalf("any network deletion failed with unexpected error type") + t.Fatal("any network deletion failed with unexpected error type") } } diff --git a/drivers/remote/driver.go b/drivers/remote/driver.go index 04be60124f..c079b046bf 100644 --- a/drivers/remote/driver.go +++ b/drivers/remote/driver.go @@ -1,6 +1,7 @@ package remote import ( + "errors" "fmt" "net" @@ -125,7 +126,7 @@ func (d *driver) DeleteNetwork(nid string) error { func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { if ifInfo == nil { - return fmt.Errorf("must not be called with nil InterfaceInfo") + return errors.New("must not be called with nil InterfaceInfo") } reqIface := &api.EndpointInterface{} diff --git a/drivers/remote/driver_test.go b/drivers/remote/driver_test.go index 6440de77e5..e559a61299 100644 --- a/drivers/remote/driver_test.go +++ b/drivers/remote/driver_test.go @@ -3,6 +3,7 @@ package remote import ( "bytes" "encoding/json" + "errors" "fmt" "io" "io/ioutil" @@ -472,7 +473,7 @@ func TestDriverError(t *testing.T) { driver := newDriver(plugin, p.Client()) if err := driver.CreateEndpoint("dummy", "dummy", &testEndpoint{t: t}, map[string]interface{}{}); err == nil { - t.Fatalf("Expected error from driver") + t.Fatal("Expected error from driver") } } @@ -528,11 +529,11 @@ func (r *rollbackEndpoint) AddressIPv6() *net.IPNet { } func (r *rollbackEndpoint) SetMacAddress(mac net.HardwareAddr) error { - return fmt.Errorf("invalid mac") + return errors.New("invalid mac") } func (r *rollbackEndpoint) SetIPAddress(ip *net.IPNet) error { - return fmt.Errorf("invalid ip") + return errors.New("invalid ip") } func TestRollback(t *testing.T) { @@ -567,9 +568,9 @@ func TestRollback(t *testing.T) { ep := &rollbackEndpoint{} if err := driver.CreateEndpoint("dummy", "dummy", ep.Interface(), map[string]interface{}{}); err == nil { - t.Fatalf("Expected error from driver") + t.Fatal("Expected error from driver") } if !rolledback { - t.Fatalf("Expected to have had DeleteEndpoint called") + t.Fatal("Expected to have had DeleteEndpoint called") } } diff --git a/drvregistry/drvregistry.go b/drvregistry/drvregistry.go index a9a7368025..0c25dfe120 100644 --- a/drvregistry/drvregistry.go +++ b/drvregistry/drvregistry.go @@ -1,6 +1,7 @@ package drvregistry import ( + "errors" "fmt" "strings" "sync" @@ -160,7 +161,7 @@ func (r *DrvRegistry) GetPluginGetter() plugingetter.PluginGetter { // RegisterDriver registers the network driver when it gets discovered. func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capability driverapi.Capability) error { if strings.TrimSpace(ntype) == "" { - return fmt.Errorf("network type string cannot be empty") + return errors.New("network type string cannot be empty") } r.Lock() @@ -188,7 +189,7 @@ func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capa func (r *DrvRegistry) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error { if strings.TrimSpace(name) == "" { - return fmt.Errorf("ipam driver name string cannot be empty") + return errors.New("ipam driver name string cannot be empty") } r.Lock() diff --git a/hostdiscovery/hostdiscovery_test.go b/hostdiscovery/hostdiscovery_test.go index 417e27d9a1..9afb3c3b46 100644 --- a/hostdiscovery/hostdiscovery_test.go +++ b/hostdiscovery/hostdiscovery_test.go @@ -46,7 +46,7 @@ func TestAddedCallback(t *testing.T) { removed := false hd.processCallback(update, func() {}, func(hosts []net.IP) { added = true }, func(hosts []net.IP) { removed = true }) if !added { - t.Fatalf("Expecting an Added callback notification. But none received") + t.Fatal("Expecting an Added callback notification. But none received") } } @@ -59,7 +59,7 @@ func TestRemovedCallback(t *testing.T) { removed := false hd.processCallback(update, func() {}, func(hosts []net.IP) { added = true }, func(hosts []net.IP) { removed = true }) if !removed { - t.Fatalf("Expecting a Removed callback notification. But none received") + t.Fatal("Expecting a Removed callback notification. But none received") } } @@ -72,6 +72,6 @@ func TestNoCallback(t *testing.T) { removed := false hd.processCallback(update, func() {}, func(hosts []net.IP) { added = true }, func(hosts []net.IP) { removed = true }) if added || removed { - t.Fatalf("Not expecting any callback notification. But received a callback") + t.Fatal("Not expecting any callback notification. But received a callback") } } diff --git a/idm/idm.go b/idm/idm.go index 84839c1c9b..38472a4249 100644 --- a/idm/idm.go +++ b/idm/idm.go @@ -2,6 +2,7 @@ package idm import ( + "errors" "fmt" "github.com/docker/libnetwork/bitseq" @@ -18,7 +19,7 @@ type Idm struct { // New returns an instance of id manager for a set of [start-end] numerical ids func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) { if id == "" { - return nil, fmt.Errorf("Invalid id") + return nil, errors.New("Invalid id") } if end <= start { return nil, fmt.Errorf("Invalid set range: [%d, %d]", start, end) @@ -35,7 +36,7 @@ func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) { // GetID returns the first available id in the set func (i *Idm) GetID() (uint64, error) { if i.handle == nil { - return 0, fmt.Errorf("ID set is not initialized") + return 0, errors.New("ID set is not initialized") } ordinal, err := i.handle.SetAny() return i.start + ordinal, err @@ -44,11 +45,11 @@ func (i *Idm) GetID() (uint64, error) { // GetSpecificID tries to reserve the specified id func (i *Idm) GetSpecificID(id uint64) error { if i.handle == nil { - return fmt.Errorf("ID set is not initialized") + return errors.New("ID set is not initialized") } if id < i.start || id > i.end { - return fmt.Errorf("Requested id does not belong to the set") + return errors.New("Requested id does not belong to the set") } return i.handle.Set(id - i.start) @@ -57,11 +58,11 @@ func (i *Idm) GetSpecificID(id uint64) error { // GetIDInRange returns the first available id in the set within a range func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) { if i.handle == nil { - return 0, fmt.Errorf("ID set is not initialized") + return 0, errors.New("ID set is not initialized") } if start < i.start || end > i.end { - return 0, fmt.Errorf("Requested range does not belong to the set") + return 0, errors.New("Requested range does not belong to the set") } return i.handle.SetAnyInRange(start, end-start) diff --git a/idm/idm_test.go b/idm/idm_test.go index 658755c93f..aa4099e8c4 100644 --- a/idm/idm_test.go +++ b/idm/idm_test.go @@ -9,12 +9,12 @@ import ( func TestNew(t *testing.T) { _, err := New(nil, "", 0, 1) if err == nil { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } _, err = New(nil, "myset", 1<<10, 0) if err == nil { - t.Fatalf("Expected failure, but succeeded") + t.Fatal("Expected failure, but succeeded") } i, err := New(nil, "myset", 0, 10) @@ -22,13 +22,13 @@ func TestNew(t *testing.T) { t.Fatalf("Unexpected failure: %v", err) } if i.handle == nil { - t.Fatalf("set is not initialized") + t.Fatal("set is not initialized") } if i.start != 0 { - t.Fatalf("unexpected start") + t.Fatal("unexpected start") } if i.end != 10 { - t.Fatalf("unexpected end") + t.Fatal("unexpected end") } } @@ -39,11 +39,11 @@ func TestAllocate(t *testing.T) { } if err = i.GetSpecificID(49); err == nil { - t.Fatalf("Expected failure but succeeded") + t.Fatal("Expected failure but succeeded") } if err = i.GetSpecificID(53); err == nil { - t.Fatalf("Expected failure but succeeded") + t.Fatal("Expected failure but succeeded") } o, err := i.GetID() @@ -87,7 +87,7 @@ func TestAllocate(t *testing.T) { t.Fatal(err) } if o != 50 { - t.Fatalf("Unexpected id returned") + t.Fatal("Unexpected id returned") } i.Release(52) @@ -101,10 +101,10 @@ func TestUninitialized(t *testing.T) { i := &Idm{} if _, err := i.GetID(); err == nil { - t.Fatalf("Expected failure but succeeded") + t.Fatal("Expected failure but succeeded") } if err := i.GetSpecificID(44); err == nil { - t.Fatalf("Expected failure but succeeded") + t.Fatal("Expected failure but succeeded") } } diff --git a/ipam/allocator_test.go b/ipam/allocator_test.go index c7f84a6122..1e1355f223 100644 --- a/ipam/allocator_test.go +++ b/ipam/allocator_test.go @@ -76,16 +76,16 @@ func TestInt2IP2IntConversion(t *testing.T) { func TestGetAddressVersion(t *testing.T) { if v4 != getAddressVersion(net.ParseIP("172.28.30.112")) { - t.Fatalf("Failed to detect IPv4 version") + t.Fatal("Failed to detect IPv4 version") } if v4 != getAddressVersion(net.ParseIP("0.0.0.1")) { - t.Fatalf("Failed to detect IPv4 version") + t.Fatal("Failed to detect IPv4 version") } if v6 != getAddressVersion(net.ParseIP("ff01::1")) { - t.Fatalf("Failed to detect IPv6 version") + t.Fatal("Failed to detect IPv6 version") } if v6 != getAddressVersion(net.ParseIP("2001:db8::76:51")) { - t.Fatalf("Failed to detect IPv6 version") + t.Fatal("Failed to detect IPv6 version") } } @@ -165,7 +165,7 @@ func TestPoolDataMarshal(t *testing.T) { } if q.Range != nil { - t.Fatalf("Unexpected Range") + t.Fatal("Unexpected Range") } } @@ -225,7 +225,7 @@ func TestAddSubnets(t *testing.T) { pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) if err != nil { - t.Fatalf("Unexpected failure in adding subnet") + t.Fatal("Unexpected failure in adding subnet") } pid1, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false) @@ -234,7 +234,7 @@ func TestAddSubnets(t *testing.T) { } if pid0 == pid1 { - t.Fatalf("returned same pool id for same subnets in different namespaces") + t.Fatal("returned same pool id for same subnets in different namespaces") } pid, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false) @@ -242,12 +242,12 @@ func TestAddSubnets(t *testing.T) { t.Fatalf("Unexpected failure requesting existing subnet: %v", err) } if pid != pid1 { - t.Fatalf("returned different pool id for same subnet requests") + t.Fatal("returned different pool id for same subnet requests") } _, _, _, err = a.RequestPool("abc", "10.128.0.0/9", "", nil, false) if err == nil { - t.Fatalf("Expected failure on adding overlapping base subnet") + t.Fatal("Expected failure on adding overlapping base subnet") } pid2, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false) @@ -259,17 +259,17 @@ func TestAddSubnets(t *testing.T) { t.Fatalf("Unexpected failure on adding overlapping sub pool: %v", err) } if pid2 != pid3 { - t.Fatalf("returned different pool id for same sub pool requests") + t.Fatal("returned different pool id for same sub pool requests") } pid, _, _, err = a.RequestPool(localAddressSpace, "10.20.2.0/24", "", nil, false) if err == nil { - t.Fatalf("Failed to detect overlapping subnets") + t.Fatal("Failed to detect overlapping subnets") } _, _, _, err = a.RequestPool(localAddressSpace, "10.128.0.0/9", "", nil, false) if err == nil { - t.Fatalf("Failed to detect overlapping subnets") + t.Fatal("Failed to detect overlapping subnets") } _, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3:4:5:6::/112", "", nil, false) @@ -279,7 +279,7 @@ func TestAddSubnets(t *testing.T) { _, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3::/64", "", nil, false) if err == nil { - t.Fatalf("Failed to detect overlapping v6 subnet") + t.Fatal("Failed to detect overlapping v6 subnet") } } @@ -299,7 +299,7 @@ func TestAddReleasePoolID(t *testing.T) { subnets := aSpace.subnets pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) if err != nil { - t.Fatalf("Unexpected failure in adding pool") + t.Fatal("Unexpected failure in adding pool") } if err := k0.FromString(pid0); err != nil { t.Fatal(err) @@ -318,7 +318,7 @@ func TestAddReleasePoolID(t *testing.T) { pid1, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false) if err != nil { - t.Fatalf("Unexpected failure in adding sub pool") + t.Fatal("Unexpected failure in adding sub pool") } if err := k1.FromString(pid1); err != nil { t.Fatal(err) @@ -336,7 +336,7 @@ func TestAddReleasePoolID(t *testing.T) { pid2, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false) if err != nil { - t.Fatalf("Unexpected failure in adding sub pool") + t.Fatal("Unexpected failure in adding sub pool") } if pid0 == pid1 || pid0 == pid2 || pid1 != pid2 { t.Fatalf("Incorrect poolIDs returned %s, %s, %s", pid0, pid1, pid2) @@ -388,10 +388,10 @@ func TestAddReleasePoolID(t *testing.T) { pid00, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) if err != nil { - t.Fatalf("Unexpected failure in adding pool") + t.Fatal("Unexpected failure in adding pool") } if pid00 != pid0 { - t.Fatalf("main pool should still exist") + t.Fatal("main pool should still exist") } aSpace, err = a.getAddrSpace(localAddressSpace) @@ -434,7 +434,7 @@ func TestAddReleasePoolID(t *testing.T) { _, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) if err != nil { - t.Fatalf("Unexpected failure in adding pool") + t.Fatal("Unexpected failure in adding pool") } aSpace, err = a.getAddrSpace(localAddressSpace) @@ -455,7 +455,7 @@ func TestPredefinedPool(t *testing.T) { } if _, err := a.getPredefinedPool("blue", false); err == nil { - t.Fatalf("Expected failure for non default addr space") + t.Fatal("Expected failure for non default addr space") } pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false) @@ -729,17 +729,17 @@ func TestRequestSyntaxCheck(t *testing.T) { _, _, _, err = a.RequestPool("", pool, "", nil, false) if err == nil { - t.Fatalf("Failed to detect wrong request: empty address space") + t.Fatal("Failed to detect wrong request: empty address space") } _, _, _, err = a.RequestPool("", pool, subPool, nil, false) if err == nil { - t.Fatalf("Failed to detect wrong request: empty address space") + t.Fatal("Failed to detect wrong request: empty address space") } _, _, _, err = a.RequestPool(as, "", subPool, nil, false) if err == nil { - t.Fatalf("Failed to detect wrong request: subPool specified and no pool") + t.Fatal("Failed to detect wrong request: subPool specified and no pool") } pid, _, _, err := a.RequestPool(as, pool, subPool, nil, false) @@ -749,13 +749,13 @@ func TestRequestSyntaxCheck(t *testing.T) { _, _, err = a.RequestAddress("", nil, nil) if err == nil { - t.Fatalf("Failed to detect wrong request: no pool id specified") + t.Fatal("Failed to detect wrong request: no pool id specified") } ip := net.ParseIP("172.17.0.23") _, _, err = a.RequestAddress(pid, ip, nil) if err == nil { - t.Fatalf("Failed to detect wrong request: requested IP from different subnet") + t.Fatal("Failed to detect wrong request: requested IP from different subnet") } ip = net.ParseIP("192.168.0.50") @@ -766,12 +766,12 @@ func TestRequestSyntaxCheck(t *testing.T) { err = a.ReleaseAddress("", ip) if err == nil { - t.Fatalf("Failed to detect wrong request: no pool id specified") + t.Fatal("Failed to detect wrong request: no pool id specified") } err = a.ReleaseAddress(pid, nil) if err == nil { - t.Fatalf("Failed to detect wrong request: no pool id specified") + t.Fatal("Failed to detect wrong request: no pool id specified") } err = a.ReleaseAddress(pid, ip) diff --git a/ipams/builtin/builtin_unix.go b/ipams/builtin/builtin_unix.go index 5baf515534..321448a344 100644 --- a/ipams/builtin/builtin_unix.go +++ b/ipams/builtin/builtin_unix.go @@ -3,7 +3,7 @@ package builtin import ( - "fmt" + "errors" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/ipam" @@ -20,13 +20,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error { if l != nil { if localDs, ok = l.(datastore.DataStore); !ok { - return fmt.Errorf("incorrect local datastore passed to built-in ipam init") + return errors.New("incorrect local datastore passed to built-in ipam init") } } if g != nil { if globalDs, ok = g.(datastore.DataStore); !ok { - return fmt.Errorf("incorrect global datastore passed to built-in ipam init") + return errors.New("incorrect global datastore passed to built-in ipam init") } } diff --git a/ipams/builtin/builtin_windows.go b/ipams/builtin/builtin_windows.go index 155c046875..7805e6a1d7 100644 --- a/ipams/builtin/builtin_windows.go +++ b/ipams/builtin/builtin_windows.go @@ -3,7 +3,7 @@ package builtin import ( - "fmt" + "errors" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/ipam" @@ -22,13 +22,13 @@ func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error { if l != nil { if localDs, ok = l.(datastore.DataStore); !ok { - return fmt.Errorf("incorrect local datastore passed to built-in ipam init") + return errors.New("incorrect local datastore passed to built-in ipam init") } } if g != nil { if globalDs, ok = g.(datastore.DataStore); !ok { - return fmt.Errorf("incorrect global datastore passed to built-in ipam init") + return errors.New("incorrect global datastore passed to built-in ipam init") } } diff --git a/ipams/null/null_test.go b/ipams/null/null_test.go index d56135e9a5..79b31d50de 100644 --- a/ipams/null/null_test.go +++ b/ipams/null/null_test.go @@ -23,22 +23,22 @@ func TestPoolRequest(t *testing.T) { _, _, _, err = a.RequestPool("default", "", "", nil, false) if err == nil { - t.Fatalf("Unexpected success") + t.Fatal("Unexpected success") } _, _, _, err = a.RequestPool(defaultAS, "192.168.0.0/16", "", nil, false) if err == nil { - t.Fatalf("Unexpected success") + t.Fatal("Unexpected success") } _, _, _, err = a.RequestPool(defaultAS, "", "192.168.0.0/24", nil, false) if err == nil { - t.Fatalf("Unexpected success") + t.Fatal("Unexpected success") } _, _, _, err = a.RequestPool(defaultAS, "", "", nil, true) if err == nil { - t.Fatalf("Unexpected success") + t.Fatal("Unexpected success") } } @@ -55,7 +55,7 @@ func TestOtherRequests(t *testing.T) { _, _, err = a.RequestAddress("anypid", nil, nil) if err == nil { - t.Fatalf("Unexpected success") + t.Fatal("Unexpected success") } } diff --git a/ipams/remote/remote_test.go b/ipams/remote/remote_test.go index ed393735ac..3e03683471 100644 --- a/ipams/remote/remote_test.go +++ b/ipams/remote/remote_test.go @@ -179,14 +179,14 @@ func TestRemoteDriver(t *testing.T) { handle(t, mux, "ReleasePool", func(msg map[string]interface{}) interface{} { if _, ok := msg["PoolID"]; !ok { - t.Fatalf("Missing PoolID in Release request") + t.Fatal("Missing PoolID in Release request") } return map[string]interface{}{} }) handle(t, mux, "RequestAddress", func(msg map[string]interface{}) interface{} { if _, ok := msg["PoolID"]; !ok { - t.Fatalf("Missing PoolID in address request") + t.Fatal("Missing PoolID in address request") } prefAddr := "" if v, ok := msg["Address"]; ok { @@ -204,10 +204,10 @@ func TestRemoteDriver(t *testing.T) { handle(t, mux, "ReleaseAddress", func(msg map[string]interface{}) interface{} { if _, ok := msg["PoolID"]; !ok { - t.Fatalf("Missing PoolID in address request") + t.Fatal("Missing PoolID in address request") } if _, ok := msg["Address"]; !ok { - t.Fatalf("Missing Address in release address request") + t.Fatal("Missing Address in release address request") } return map[string]interface{}{} }) @@ -251,7 +251,7 @@ func TestRemoteDriver(t *testing.T) { t.Fatalf("Unexpected pool: %s", pool2) } if dns, ok := ops["DNS"]; !ok || dns != "8.8.8.8" { - t.Fatalf("Missing options") + t.Fatal("Missing options") } // Request specific pool and subpool diff --git a/iptables/firewalld_test.go b/iptables/firewalld_test.go index 1ac11a9adf..bf36077476 100644 --- a/iptables/firewalld_test.go +++ b/iptables/firewalld_test.go @@ -52,7 +52,7 @@ func TestReloaded(t *testing.T) { "-j", "ACCEPT"} if !Exists(fwdChain.Table, fwdChain.Name, rule1...) { - t.Fatalf("rule1 does not exist") + t.Fatal("rule1 does not exist") } // flush all rules @@ -62,7 +62,7 @@ func TestReloaded(t *testing.T) { // make sure the rules have been recreated if !Exists(fwdChain.Table, fwdChain.Name, rule1...) { - t.Fatalf("rule1 hasn't been recreated") + t.Fatal("rule1 hasn't been recreated") } } @@ -79,7 +79,7 @@ func TestPassthrough(t *testing.T) { t.Fatal(err) } if !Exists(Filter, "INPUT", rule1...) { - t.Fatalf("rule1 does not exist") + t.Fatal("rule1 does not exist") } } diff --git a/iptables/iptables.go b/iptables/iptables.go index 3884257361..187e8c18e3 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -130,7 +130,7 @@ func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) { // ProgramChain is used to add rules to a chain func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error { if c.Name == "" { - return fmt.Errorf("Could not program chain, missing chain name") + return errors.New("Could not program chain, missing chain name") } switch c.Table { diff --git a/iptables/iptables_test.go b/iptables/iptables_test.go index 324d123da1..7c12404c19 100644 --- a/iptables/iptables_test.go +++ b/iptables/iptables_test.go @@ -57,7 +57,7 @@ func TestForward(t *testing.T) { } if !Exists(natChain.Table, natChain.Name, dnatRule...) { - t.Fatalf("DNAT rule does not exist") + t.Fatal("DNAT rule does not exist") } filterRule := []string{ @@ -70,7 +70,7 @@ func TestForward(t *testing.T) { } if !Exists(filterChain.Table, filterChain.Name, filterRule...) { - t.Fatalf("filter rule does not exist") + t.Fatal("filter rule does not exist") } masqRule := []string{ @@ -82,7 +82,7 @@ func TestForward(t *testing.T) { } if !Exists(natChain.Table, "POSTROUTING", masqRule...) { - t.Fatalf("MASQUERADE rule does not exist") + t.Fatal("MASQUERADE rule does not exist") } } @@ -110,7 +110,7 @@ func TestLink(t *testing.T) { "-j", "ACCEPT"} if !Exists(filterChain.Table, filterChain.Name, rule1...) { - t.Fatalf("rule1 does not exist") + t.Fatal("rule1 does not exist") } rule2 := []string{ @@ -123,7 +123,7 @@ func TestLink(t *testing.T) { "-j", "ACCEPT"} if !Exists(filterChain.Table, filterChain.Name, rule2...) { - t.Fatalf("rule2 does not exist") + t.Fatal("rule2 does not exist") } } @@ -138,7 +138,7 @@ func TestPrerouting(t *testing.T) { } if !Exists(natChain.Table, "PREROUTING", args...) { - t.Fatalf("rule does not exist") + t.Fatal("rule does not exist") } delRule := append([]string{"-D", "PREROUTING", "-t", string(Nat)}, args...) @@ -158,7 +158,7 @@ func TestOutput(t *testing.T) { } if !Exists(natChain.Table, "OUTPUT", args...) { - t.Fatalf("rule does not exist") + t.Fatal("rule does not exist") } delRule := append([]string{"-D", "OUTPUT", "-t", @@ -285,7 +285,7 @@ func TestExistsRaw(t *testing.T) { func TestGetVersion(t *testing.T) { mj, mn, mc := parseVersionNumbers("iptables v1.4.19.1-alpha") if mj != 1 || mn != 4 || mc != 19 { - t.Fatalf("Failed to parse version numbers") + t.Fatal("Failed to parse version numbers") } } diff --git a/netutils/utils.go b/netutils/utils.go index 65449d3dee..7de98f6b07 100644 --- a/netutils/utils.go +++ b/netutils/utils.go @@ -173,7 +173,7 @@ func ReverseIP(IP string) string { // ParseAlias parses and validates the specified string as an alias format (name:alias) func ParseAlias(val string) (string, string, error) { if val == "" { - return "", "", fmt.Errorf("empty string specified for alias") + return "", "", errors.New("empty string specified for alias") } arr := strings.Split(val, ":") if len(arr) > 2 { diff --git a/netutils/utils_test.go b/netutils/utils_test.go index 272c53e1f7..9413452025 100644 --- a/netutils/utils_test.go +++ b/netutils/utils_test.go @@ -61,7 +61,7 @@ func TestCheckRouteOverlaps(t *testing.T) { _, netX, _ = net.ParseCIDR("10.0.2.0/24") if err := CheckRouteOverlaps(netX); err == nil { - t.Fatalf("10.0.2.0/24 and 10.0.2.0 should overlap but it doesn't") + t.Fatal("10.0.2.0/24 and 10.0.2.0 should overlap but it doesn't") } } @@ -279,11 +279,11 @@ func TestElectInterfaceAddressMultipleAddresses(t *testing.T) { } if len(ipv4NwList) == 0 { - t.Fatalf("unexpected empty ipv4 network addresses") + t.Fatal("unexpected empty ipv4 network addresses") } if len(ipv6NwList) == 0 { - t.Fatalf("unexpected empty ipv6 network addresses") + t.Fatal("unexpected empty ipv6 network addresses") } nwList := []string{} @@ -316,11 +316,11 @@ func TestElectInterfaceAddress(t *testing.T) { } if len(ipv4Nw) == 0 { - t.Fatalf("unexpected empty ipv4 network addresses") + t.Fatal("unexpected empty ipv4 network addresses") } if len(ipv6Nw) == 0 { - t.Fatalf("unexpected empty ipv6 network addresses") + t.Fatal("unexpected empty ipv6 network addresses") } if nws != ipv4Nw[0].String() { diff --git a/networkdb/broadcast.go b/networkdb/broadcast.go index faaf642948..a9330cb3a2 100644 --- a/networkdb/broadcast.go +++ b/networkdb/broadcast.go @@ -1,7 +1,7 @@ package networkdb import ( - "fmt" + "errors" "time" "github.com/hashicorp/memberlist" @@ -90,7 +90,7 @@ func (nDB *NetworkDB) sendNodeEvent(event NodeEvent_Type) error { select { case <-notifyCh: case <-time.After(broadcastTimeout): - return fmt.Errorf("timed out broadcasting node event") + return errors.New("timed out broadcasting node event") } return nil diff --git a/networkdb/networkdb_test.go b/networkdb/networkdb_test.go index bdcb6c51a5..8099b344d2 100644 --- a/networkdb/networkdb_test.go +++ b/networkdb/networkdb_test.go @@ -426,6 +426,6 @@ func TestNetworkDBCRUDMediumCluster(t *testing.T) { dbs[i].verifyEntryExistence(t, "test_table", "network1", "test_key", "", false) } - log.Printf("Closing DB instances...") + log.Print("Closing DB instances...") closeNetworkDBInstances(dbs) } From 9136387b770a3489ff054ea341e3f78577e0cd2c Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 21 Nov 2016 22:02:07 -0800 Subject: [PATCH 163/799] Fix xtables_lock message probe - iptables pkg functions are coded to discard the xtables_lock error message about acquiring the lock, because all the calls are done with the wait logic. But the error message has slightly changed between iptables 1.4.x and 1.6. This lead to false positives causing docker network create to fil in presence of concurrent calls. - Fixed message mark to be common among the two main versions. Signed-off-by: Alessandro Boch --- iptables/iptables.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iptables/iptables.go b/iptables/iptables.go index 3884257361..e3a41b5564 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -45,6 +45,7 @@ var ( iptablesPath string supportsXlock = false supportsCOpt = false + xLockWaitMsg = "Another app is currently holding the xtables lock; waiting" // used to lock iptables commands if xtables lock is not supported bestEffortLock sync.Mutex // ErrIptablesNotFound is returned when the rule is not found. @@ -402,7 +403,7 @@ func raw(args ...string) ([]byte, error) { } // ignore iptables' message about xtables lock - if strings.Contains(string(output), "waiting for it to exit") { + if strings.Contains(string(output), xLockWaitMsg) { output = []byte("") } From 947eb35392384a5b01ff5d10f70de4207b107cb7 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 23 Feb 2016 13:28:14 -0800 Subject: [PATCH 164/799] Control IPv6 on container's interface - Disable ipv6 on all interface by default at sandbox creation. Enable IPv6 per interface basis if the interface has an IPv6 address. In case sandbox has an IPv6 interface, also enable IPv6 on loopback interface. Signed-off-by: Alessandro Boch --- cmd/proxy/network_proxy_test.go | 2 + networkdb/networkdb_test.go | 2 + osl/interface_linux.go | 7 +++ osl/namespace_linux.go | 98 +++++++++++++++++++++++++++++++++ osl/sandbox_linux_test.go | 49 +++++++++++++---- 5 files changed, 148 insertions(+), 10 deletions(-) diff --git a/cmd/proxy/network_proxy_test.go b/cmd/proxy/network_proxy_test.go index b3379dabb3..7f036b537f 100644 --- a/cmd/proxy/network_proxy_test.go +++ b/cmd/proxy/network_proxy_test.go @@ -130,6 +130,7 @@ func TestTCP4Proxy(t *testing.T) { } func TestTCP6Proxy(t *testing.T) { + t.Skip("Need to start CI docker with --ipv6") backend := NewEchoServer(t, "tcp", "[::1]:0") defer backend.Close() backend.Run() @@ -173,6 +174,7 @@ func TestUDP4Proxy(t *testing.T) { } func TestUDP6Proxy(t *testing.T) { + t.Skip("Need to start CI docker with --ipv6") backend := NewEchoServer(t, "udp", "[::1]:0") defer backend.Close() backend.Run() diff --git a/networkdb/networkdb_test.go b/networkdb/networkdb_test.go index bdcb6c51a5..c9bd6fb125 100644 --- a/networkdb/networkdb_test.go +++ b/networkdb/networkdb_test.go @@ -3,6 +3,7 @@ package networkdb import ( "flag" "fmt" + "io/ioutil" "log" "os" "sync/atomic" @@ -21,6 +22,7 @@ var ( ) func TestMain(m *testing.M) { + ioutil.WriteFile("/proc/sys/net/ipv6/conf/lo/disable_ipv6", []byte{'0', '\n'}, 0644) logrus.SetLevel(logrus.ErrorLevel) os.Exit(m.Run()) } diff --git a/osl/interface_linux.go b/osl/interface_linux.go index 2be99d72ea..d76966200a 100644 --- a/osl/interface_linux.go +++ b/osl/interface_linux.go @@ -179,6 +179,8 @@ func (i *nwIface) Remove() error { } n.Unlock() + n.checkLoV6() + return nil } @@ -318,6 +320,8 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If n.iFaces = append(n.iFaces, i) n.Unlock() + n.checkLoV6() + return nil } @@ -378,6 +382,9 @@ func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil { return err } + if err := setIPv6(i.ns.path, i.DstName(), true); err != nil { + return fmt.Errorf("failed to enable ipv6: %v", err) + } ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD} return nlh.AddrAdd(iface, ipAddr) } diff --git a/osl/namespace_linux.go b/osl/namespace_linux.go index fe8065a31e..b714ccf9fa 100644 --- a/osl/namespace_linux.go +++ b/osl/namespace_linux.go @@ -24,6 +24,10 @@ import ( const defaultPrefix = "/var/run/docker" +func init() { + reexec.Register("set-ipv6", reexecSetIPv6) +} + var ( once sync.Once garbagePathMap = make(map[string]bool) @@ -47,6 +51,7 @@ type networkNamespace struct { nextIfIndex int isDefault bool nlHandle *netlink.Handle + loV6Enabled bool sync.Mutex } @@ -216,6 +221,12 @@ func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) { logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err) } + // As starting point, disable IPv6 on all interfaces + err = setIPv6(n.path, "all", false) + if err != nil { + logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err) + } + if err = n.loopbackUp(); err != nil { n.nlHandle.Delete() return nil, err @@ -263,6 +274,12 @@ func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) { logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err) } + // As starting point, disable IPv6 on all interfaces + err = setIPv6(n.path, "all", false) + if err != nil { + logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err) + } + if err = n.loopbackUp(); err != nil { n.nlHandle.Delete() return nil, err @@ -508,3 +525,84 @@ func (n *networkNamespace) Restore(ifsopt map[string][]IfaceOption, routes []*ty return nil } + +// Checks whether IPv6 needs to be enabled/disabled on the loopback interface +func (n *networkNamespace) checkLoV6() { + var ( + enable = false + action = "disable" + ) + + n.Lock() + for _, iface := range n.iFaces { + if iface.AddressIPv6() != nil { + enable = true + action = "enable" + break + } + } + n.Unlock() + + if n.loV6Enabled == enable { + return + } + + if err := setIPv6(n.path, "lo", enable); err != nil { + logrus.Warnf("Failed to %s IPv6 on loopback interface on network namespace %q: %v", action, n.path, err) + } + + n.loV6Enabled = enable +} + +func reexecSetIPv6() { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if len(os.Args) < 3 { + logrus.Errorf("invalid number of arguments for %s", os.Args[0]) + os.Exit(1) + } + + ns, err := netns.GetFromPath(os.Args[1]) + if err != nil { + logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err) + os.Exit(2) + } + defer ns.Close() + + if err = netns.Set(ns); err != nil { + logrus.Errorf("setting into container netns %q failed: %v", os.Args[1], err) + os.Exit(3) + } + + var ( + action = "disable" + value = byte('1') + path = fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", os.Args[2]) + ) + + if os.Args[3] == "true" { + action = "enable" + value = byte('0') + } + + if err = ioutil.WriteFile(path, []byte{value, '\n'}, 0644); err != nil { + logrus.Errorf("failed to %s IPv6 forwarding for container's interface %s: %v", action, os.Args[2], err) + os.Exit(4) + } + + os.Exit(0) +} + +func setIPv6(path, iface string, enable bool) error { + cmd := &exec.Cmd{ + Path: reexec.Self(), + Args: append([]string{"set-ipv6"}, path, iface, strconv.FormatBool(enable)), + Stdout: os.Stdout, + Stderr: os.Stderr, + } + if err := cmd.Run(); err != nil { + return fmt.Errorf("reexec to set IPv6 failed: %v", err) + } + return nil +} diff --git a/osl/sandbox_linux_test.go b/osl/sandbox_linux_test.go index d71e24a21d..45345aa9f0 100644 --- a/osl/sandbox_linux_test.go +++ b/osl/sandbox_linux_test.go @@ -7,6 +7,7 @@ import ( "net" "os" "path/filepath" + "runtime" "strings" "syscall" "testing" @@ -190,17 +191,32 @@ func TestDisableIPv6DAD(t *testing.T) { defer testutils.SetupTestOSContext(t)() + key, err := newKey(t) + if err != nil { + t.Fatalf("Failed to obtain a key: %v", err) + } + + s, err := NewSandbox(key, true, false) + if err != nil { + t.Fatalf("Failed to create a new sandbox: %v", err) + } + runtime.LockOSThread() + defer s.Destroy() + + n, ok := s.(*networkNamespace) + if !ok { + t.Fatal(ok) + } + nlh := n.nlHandle + ipv6, _ := types.ParseCIDR("2001:db8::44/64") - iface := &nwIface{addressIPv6: ipv6} + iface := &nwIface{addressIPv6: ipv6, ns: n, dstName: "sideA"} veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: "sideA"}, PeerName: "sideB", } - nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE) - if err != nil { - t.Fatal(err) - } + err = nlh.LinkAdd(veth) if err != nil { t.Fatal(err) @@ -229,14 +245,27 @@ func TestDisableIPv6DAD(t *testing.T) { func TestSetInterfaceIP(t *testing.T) { defer testutils.SetupTestOSContext(t)() - ipv4, _ := types.ParseCIDR("172.30.0.33/24") - ipv6, _ := types.ParseCIDR("2001:db8::44/64") - iface := &nwIface{address: ipv4, addressIPv6: ipv6} + key, err := newKey(t) + if err != nil { + t.Fatalf("Failed to obtain a key: %v", err) + } - nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE) + s, err := NewSandbox(key, true, false) if err != nil { - t.Fatal(err) + t.Fatalf("Failed to create a new sandbox: %v", err) } + runtime.LockOSThread() + defer s.Destroy() + + n, ok := s.(*networkNamespace) + if !ok { + t.Fatal(ok) + } + nlh := n.nlHandle + + ipv4, _ := types.ParseCIDR("172.30.0.33/24") + ipv6, _ := types.ParseCIDR("2001:db8::44/64") + iface := &nwIface{address: ipv4, addressIPv6: ipv6, ns: n, dstName: "sideA"} if err := nlh.LinkAdd(&netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: "sideA"}, From df661396d15df44e72de06c6bfcf6116580e3b71 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Fri, 25 Nov 2016 13:02:03 -0800 Subject: [PATCH 165/799] Create vxlan-id space from 0 instead of starting from 1 With the introduction of GetIDInRange function in IDM and using it in ovmanager, the idm.New was modified to start from 1. But that causes issues when the network is removed which results in releasing the vxlan-id from IDM. With the offset of 1, the Release call incorrectly releases a bit which could be in use by another network and this results in the infamous "error creating vxlan interface: file exists" errors when another network is created with this freed bit. Signed-off-by: Madhu Venugopal --- drivers/overlay/ovmanager/ovmanager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/overlay/ovmanager/ovmanager.go b/drivers/overlay/ovmanager/ovmanager.go index 2f69083f25..aaf94e586f 100644 --- a/drivers/overlay/ovmanager/ovmanager.go +++ b/drivers/overlay/ovmanager/ovmanager.go @@ -57,7 +57,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { config: config, } - d.vxlanIdm, err = idm.New(nil, "vxlan-id", 1, vxlanIDEnd) + d.vxlanIdm, err = idm.New(nil, "vxlan-id", 0, vxlanIDEnd) if err != nil { return fmt.Errorf("failed to initialize vxlan id manager: %v", err) } From d55c701e0cc7fceac1410de570fe3de97690f615 Mon Sep 17 00:00:00 2001 From: Daehyeok Mun Date: Mon, 28 Nov 2016 11:44:45 -0700 Subject: [PATCH 166/799] Fixed misspelling Signed-off-by: Daehyeok Mun --- bitseq/sequence.go | 2 +- controller.go | 4 ++-- drivers/bridge/setup_ip_tables.go | 2 +- drivers/overlay/overlay.go | 2 +- drivers/solaris/bridge/bridge.go | 2 +- ipvs/ipvs.go | 2 +- network_windows.go | 2 +- networkdb/networkdb.go | 10 +++++----- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bitseq/sequence.go b/bitseq/sequence.go index 9c815e5e3c..a67999313c 100644 --- a/bitseq/sequence.go +++ b/bitseq/sequence.go @@ -1,5 +1,5 @@ // Package bitseq provides a structure and utilities for representing long bitmask -// as sequence of run-lenght encoded blocks. It operates direclty on the encoded +// as sequence of run-length encoded blocks. It operates directly on the encoded // representation, it does not decode/encode. package bitseq diff --git a/controller.go b/controller.go index 6eaa1c6638..2e620a4e1b 100644 --- a/controller.go +++ b/controller.go @@ -305,7 +305,7 @@ func (c *controller) clusterAgentInit() { c.clusterConfigAvailable = true keys := c.keys c.Unlock() - // agent initialization needs encyrption keys and bind/remote IP which + // agent initialization needs encryption keys and bind/remote IP which // comes from the daemon cluster events if len(keys) > 0 { c.agentSetup() @@ -779,7 +779,7 @@ func (c *controller) reservePools() { } for _, ep := range epl { if err := ep.assignAddress(ipam, true, ep.Iface().AddressIPv6() != nil); err != nil { - logrus.Warnf("Failed to reserve current adress for endpoint %q (%s) on network %q (%s)", + logrus.Warnf("Failed to reserve current address for endpoint %q (%s) on network %q (%s)", ep.Name(), ep.ID(), n.Name(), n.ID()) } } diff --git a/drivers/bridge/setup_ip_tables.go b/drivers/bridge/setup_ip_tables.go index 862d9e4491..9df4cdc6c6 100644 --- a/drivers/bridge/setup_ip_tables.go +++ b/drivers/bridge/setup_ip_tables.go @@ -71,7 +71,7 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt return fmt.Errorf("Cannot program chains, EnableIPTable is disabled") } - // Pickup this configuraton option from driver + // Pickup this configuration option from driver hairpinMode := !driverConfig.EnableUserlandProxy maskedAddrv4 := &net.IPNet{ diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index c1c87461a7..e3c1f7b899 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -99,7 +99,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { // outside of the restore path can potentially fix the network join and succeed. for nid, n := range d.networks { if n.initErr != nil { - logrus.Infof("resetting init error and once variable for network %s after unsuccesful endpoint restore: %v", nid, n.initErr) + logrus.Infof("resetting init error and once variable for network %s after unsuccessful endpoint restore: %v", nid, n.initErr) n.initErr = nil n.once = &sync.Once{} } diff --git a/drivers/solaris/bridge/bridge.go b/drivers/solaris/bridge/bridge.go index 82d0e8c44c..97180fbbd3 100644 --- a/drivers/solaris/bridge/bridge.go +++ b/drivers/solaris/bridge/bridge.go @@ -993,7 +993,7 @@ func (c *networkConfiguration) Conflicts(o *networkConfiguration) error { return fmt.Errorf("same configuration") } - // Also empty, becasue only one network with empty name is allowed + // Also empty, because only one network with empty name is allowed if c.BridgeName == o.BridgeName { return fmt.Errorf("networks have same bridge name") } diff --git a/ipvs/ipvs.go b/ipvs/ipvs.go index d98acd4055..9b44159d5d 100644 --- a/ipvs/ipvs.go +++ b/ipvs/ipvs.go @@ -47,7 +47,7 @@ type Handle struct { // New provides a new ipvs handle in the namespace pointed to by the // passed path. It will return a valid handle or an error in case an -// error occured while creating the handle. +// error occurred while creating the handle. func New(path string) (*Handle, error) { setup() diff --git a/network_windows.go b/network_windows.go index 7ae7a68798..07a1c1d424 100644 --- a/network_windows.go +++ b/network_windows.go @@ -54,7 +54,7 @@ func (n *network) startResolver() { logrus.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err) time.Sleep(1 * time.Second) } else { - logrus.Debugf("Resolver bound successfuly for network %s", n.Name()) + logrus.Debugf("Resolver bound successfully for network %s", n.Name()) n.resolver = append(n.resolver, resolver) break } diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 71a4e2b9ee..8ff8afad66 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -244,7 +244,7 @@ func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) { // CreateEntry creates a table entry in NetworkDB for given (network, // table, key) tuple and if the NetworkDB is part of the cluster -// propogates this event to the cluster. It is an error to create an +// propagates this event to the cluster. It is an error to create an // entry for the same tuple for which there is already an existing // entry unless the current entry is deleting state. func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error { @@ -279,7 +279,7 @@ func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error { // UpdateEntry updates a table entry in NetworkDB for given (network, // table, key) tuple and if the NetworkDB is part of the cluster -// propogates this event to the cluster. It is an error to update a +// propagates this event to the cluster. It is an error to update a // non-existent entry. func (nDB *NetworkDB) UpdateEntry(tname, nid, key string, value []byte) error { if _, err := nDB.GetEntry(tname, nid, key); err != nil { @@ -307,7 +307,7 @@ func (nDB *NetworkDB) UpdateEntry(tname, nid, key string, value []byte) error { // DeleteEntry deletes a table entry in NetworkDB for given (network, // table, key) tuple and if the NetworkDB is part of the cluster -// propogates this event to the cluster. +// propagates this event to the cluster. func (nDB *NetworkDB) DeleteEntry(tname, nid, key string) error { value, err := nDB.GetEntry(tname, nid, key) if err != nil { @@ -408,7 +408,7 @@ func (nDB *NetworkDB) WalkTable(tname string, fn func(string, string, []byte) bo return nil } -// JoinNetwork joins this node to a given network and propogates this +// JoinNetwork joins this node to a given network and propagates this // event across the cluster. This triggers this node joining the // sub-cluster of this network and participates in the network-scoped // gossip and bulk sync for this network. @@ -447,7 +447,7 @@ func (nDB *NetworkDB) JoinNetwork(nid string) error { return nil } -// LeaveNetwork leaves this node from a given network and propogates +// LeaveNetwork leaves this node from a given network and propagates // this event across the cluster. This triggers this node leaving the // sub-cluster of this network and as a result will no longer // participate in the network-scoped gossip and bulk sync for this From 8515b6ec5ca13d81c4fd6b7b1f204b692b168f3b Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 28 Nov 2016 11:27:21 -0800 Subject: [PATCH 167/799] Fix a bug in idm.GetIDInRange() Signed-off-by: Alessandro Boch --- idm/idm.go | 8 +-- idm/idm_test.go | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 3 deletions(-) diff --git a/idm/idm.go b/idm/idm.go index 84839c1c9b..20be113c83 100644 --- a/idm/idm.go +++ b/idm/idm.go @@ -15,7 +15,7 @@ type Idm struct { handle *bitseq.Handle } -// New returns an instance of id manager for a set of [start-end] numerical ids +// New returns an instance of id manager for a [start,end] set of numerical ids func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) { if id == "" { return nil, fmt.Errorf("Invalid id") @@ -54,7 +54,7 @@ func (i *Idm) GetSpecificID(id uint64) error { return i.handle.Set(id - i.start) } -// GetIDInRange returns the first available id in the set within a range +// GetIDInRange returns the first available id in the set within a [start,end] range func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) { if i.handle == nil { return 0, fmt.Errorf("ID set is not initialized") @@ -64,7 +64,9 @@ func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) { return 0, fmt.Errorf("Requested range does not belong to the set") } - return i.handle.SetAnyInRange(start, end-start) + ordinal, err := i.handle.SetAnyInRange(start-i.start, end-i.start) + + return i.start + ordinal, err } // Release releases the specified id diff --git a/idm/idm_test.go b/idm/idm_test.go index 658755c93f..2100943a55 100644 --- a/idm/idm_test.go +++ b/idm/idm_test.go @@ -108,3 +108,129 @@ func TestUninitialized(t *testing.T) { t.Fatalf("Expected failure but succeeded") } } + +func TestAllocateInRange(t *testing.T) { + i, err := New(nil, "myset", 5, 10) + if err != nil { + t.Fatal(err) + } + + o, err := i.GetIDInRange(6, 6) + if err != nil { + t.Fatal(err) + } + if o != 6 { + t.Fatalf("Unexpected id returned. Expected: 6. Got: %d", o) + } + + if err = i.GetSpecificID(6); err == nil { + t.Fatalf("Expected failure but succeeded") + } + + o, err = i.GetID() + if err != nil { + t.Fatal(err) + } + if o != 5 { + t.Fatalf("Unexpected id returned. Expected: 5. Got: %d", o) + } + + i.Release(6) + + o, err = i.GetID() + if err != nil { + t.Fatal(err) + } + if o != 6 { + t.Fatalf("Unexpected id returned. Expected: 6. Got: %d", o) + } + + for n := 7; n <= 10; n++ { + o, err := i.GetIDInRange(7, 10) + if err != nil { + t.Fatal(err) + } + if o != uint64(n) { + t.Fatalf("Unexpected id returned. Expected: %d. Got: %d", n, o) + } + } + + if err = i.GetSpecificID(7); err == nil { + t.Fatalf("Expected failure but succeeded") + } + + if err = i.GetSpecificID(10); err == nil { + t.Fatalf("Expected failure but succeeded") + } + + i.Release(10) + + o, err = i.GetIDInRange(5, 10) + if err != nil { + t.Fatal(err) + } + if o != 10 { + t.Fatalf("Unexpected id returned. Expected: 10. Got: %d", o) + } + + i.Release(5) + + o, err = i.GetIDInRange(5, 10) + if err != nil { + t.Fatal(err) + } + if o != 5 { + t.Fatalf("Unexpected id returned. Expected: 5. Got: %d", o) + } + + for n := 5; n <= 10; n++ { + i.Release(uint64(n)) + } + + for n := 5; n <= 10; n++ { + o, err := i.GetIDInRange(5, 10) + if err != nil { + t.Fatal(err) + } + if o != uint64(n) { + t.Fatalf("Unexpected id returned. Expected: %d. Got: %d", n, o) + } + } + + for n := 5; n <= 10; n++ { + if err = i.GetSpecificID(uint64(n)); err == nil { + t.Fatalf("Expected failure but succeeded for id: %d", n) + } + } + + // New larger set + ul := uint64((1 << 24) - 1) + i, err = New(nil, "newset", 0, ul) + if err != nil { + t.Fatal(err) + } + + o, err = i.GetIDInRange(4096, ul) + if err != nil { + t.Fatal(err) + } + if o != 4096 { + t.Fatalf("Unexpected id returned. Expected: 4096. Got: %d", o) + } + + o, err = i.GetIDInRange(4096, ul) + if err != nil { + t.Fatal(err) + } + if o != 4097 { + t.Fatalf("Unexpected id returned. Expected: 4097. Got: %d", o) + } + + o, err = i.GetIDInRange(4096, ul) + if err != nil { + t.Fatal(err) + } + if o != 4098 { + t.Fatalf("Unexpected id returned. Expected: 4098. Got: %d", o) + } +} From 38b0775dafd1d5c2ed061adbd72288fd4c5d6877 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 29 Nov 2016 10:42:20 -0800 Subject: [PATCH 168/799] Fix incorrect debug message Signed-off-by: Santhosh Manohar --- resolver.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/resolver.go b/resolver.go index 68e4831d53..ca3850c58e 100644 --- a/resolver.go +++ b/resolver.go @@ -418,8 +418,12 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { } execErr := r.backend.ExecFunc(extConnect) - if execErr != nil || err != nil { - logrus.Debugf("Connect failed, %s", err) + if execErr != nil { + logrus.Warn(execErr) + continue + } + if err != nil { + logrus.Warnf("Connect failed: %s", err) continue } logrus.Debugf("Query %s[%d] from %s, forwarding to %s:%s", name, query.Question[0].Qtype, From 8dcf9960aa81767376e580f20d9ecea3e68f62ad Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 21 Nov 2016 23:38:03 -0800 Subject: [PATCH 169/799] Add missing locks in agent and service code Signed-off-by: Alessandro Boch --- agent.go | 137 +++++++++++++++++++++++++++---------------- controller.go | 11 +++- network.go | 13 ++-- networkdb/cluster.go | 6 ++ service_common.go | 5 +- service_linux.go | 2 +- 6 files changed, 110 insertions(+), 64 deletions(-) diff --git a/agent.go b/agent.go index c4f18ba9a8..540aa79cf8 100644 --- a/agent.go +++ b/agent.go @@ -7,6 +7,7 @@ import ( "net" "os" "sort" + "sync" "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/stringid" @@ -39,6 +40,7 @@ type agent struct { advertiseAddr string epTblCancel func() driverCancelFuncs map[string][]func() + sync.Mutex } func getBindAddr(ifaceName string) (string, error) { @@ -86,9 +88,16 @@ func resolveAddr(addrOrInterface string) (string, error) { func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { drvEnc := discoverapi.DriverEncryptionUpdate{} - a := c.agent + a := c.getAgent() + if a == nil { + logrus.Debug("Skipping key change as agent is nil") + return nil + } + // Find the deleted key. If the deleted key was the primary key, // a new primary key should be set before removing if from keyring. + c.Lock() + added := []byte{} deleted := []byte{} j := len(c.keys) for i := 0; i < j; { @@ -127,7 +136,7 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { if !same { c.keys = append(c.keys, key) if key.Subsystem == subsysGossip { - a.networkDB.SetKey(key.Key) + added = key.Key } if key.Subsystem == subsysIPSec { @@ -136,6 +145,11 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { } } } + c.Unlock() + + if len(added) > 0 { + a.networkDB.SetKey(added) + } key, tag, err := c.getPrimaryKeyTag(subsysGossip) if err != nil { @@ -166,8 +180,10 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { } func (c *controller) agentSetup() error { + c.Lock() clusterProvider := c.cfg.Daemon.ClusterProvider - + agent := c.agent + c.Unlock() bindAddr := clusterProvider.GetLocalAddress() advAddr := clusterProvider.GetAdvertiseAddress() remote := clusterProvider.GetRemoteAddress() @@ -176,7 +192,7 @@ func (c *controller) agentSetup() error { listenAddr, _, _ := net.SplitHostPort(listen) logrus.Infof("Initializing Libnetwork Agent Listen-Addr=%s Local-addr=%s Adv-addr=%s Remote-addr =%s", listenAddr, bindAddr, advAddr, remoteAddr) - if advAddr != "" && c.agent == nil { + if advAddr != "" && agent == nil { if err := c.agentInit(listenAddr, bindAddr, advAddr); err != nil { logrus.Errorf("Error in agentInit : %v", err) } else { @@ -208,6 +224,9 @@ func (c *controller) agentSetup() error { // For a given subsystem getKeys sorts the keys by lamport time and returns // slice of keys and lamport time which can used as a unique tag for the keys func (c *controller) getKeys(subsys string) ([][]byte, []uint64) { + c.Lock() + defer c.Unlock() + sort.Sort(ByTime(c.keys)) keys := [][]byte{} @@ -227,6 +246,8 @@ func (c *controller) getKeys(subsys string) ([][]byte, []uint64) { // getPrimaryKeyTag returns the primary key for a given subsystem from the // list of sorted key and the associated tag func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64, error) { + c.Lock() + defer c.Unlock() sort.Sort(ByTime(c.keys)) keys := []*types.EncryptionKey{} for _, key := range c.keys { @@ -265,6 +286,7 @@ func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr st ch, cancel := nDB.Watch("endpoint_table", "", "") + c.Lock() c.agent = &agent{ networkDB: nDB, bindAddr: bindAddr, @@ -272,6 +294,7 @@ func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr st epTblCancel: cancel, driverCancelFuncs: make(map[string][]func()), } + c.Unlock() go c.handleTableEvents(ch, c.handleEpTableEvent) @@ -294,21 +317,22 @@ func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr st } func (c *controller) agentJoin(remote string) error { - if c.agent == nil { + agent := c.getAgent() + if agent == nil { return nil } - - return c.agent.networkDB.Join([]string{remote}) + return agent.networkDB.Join([]string{remote}) } func (c *controller) agentDriverNotify(d driverapi.Driver) { - if c.agent == nil { + agent := c.getAgent() + if agent == nil { return } d.DiscoverNew(discoverapi.NodeDiscovery, discoverapi.NodeDiscoveryData{ - Address: c.agent.advertiseAddr, - BindAddress: c.agent.bindAddr, + Address: agent.advertiseAddr, + BindAddress: agent.bindAddr, Self: true, }) @@ -339,11 +363,19 @@ func (c *controller) agentClose() { return } + var cancelList []func() + + agent.Lock() for _, cancelFuncs := range agent.driverCancelFuncs { for _, cancel := range cancelFuncs { - cancel() + cancelList = append(cancelList, cancel) } } + agent.Unlock() + + for _, cancel := range cancelList { + cancel() + } agent.epTblCancel() @@ -354,13 +386,7 @@ func (n *network) isClusterEligible() bool { if n.driverScope() != datastore.GlobalScope { return false } - - c := n.getController() - if c.agent == nil { - return false - } - - return true + return n.getController().getAgent() != nil } func (n *network) joinCluster() error { @@ -368,8 +394,12 @@ func (n *network) joinCluster() error { return nil } - c := n.getController() - return c.agent.networkDB.JoinNetwork(n.ID()) + agent := n.getController().getAgent() + if agent == nil { + return nil + } + + return agent.networkDB.JoinNetwork(n.ID()) } func (n *network) leaveCluster() error { @@ -377,8 +407,12 @@ func (n *network) leaveCluster() error { return nil } - c := n.getController() - return c.agent.networkDB.LeaveNetwork(n.ID()) + agent := n.getController().getAgent() + if agent == nil { + return nil + } + + return agent.networkDB.LeaveNetwork(n.ID()) } func (ep *endpoint) addDriverInfoToCluster() error { @@ -390,10 +424,7 @@ func (ep *endpoint) addDriverInfoToCluster() error { return nil } - ctrlr := n.ctrlr - ctrlr.Lock() - agent := ctrlr.agent - ctrlr.Unlock() + agent := n.getController().getAgent() if agent == nil { return nil } @@ -415,10 +446,7 @@ func (ep *endpoint) deleteDriverInfoFromCluster() error { return nil } - ctrlr := n.ctrlr - ctrlr.Lock() - agent := ctrlr.agent - ctrlr.Unlock() + agent := n.getController().getAgent() if agent == nil { return nil } @@ -438,6 +466,7 @@ func (ep *endpoint) addServiceInfoToCluster() error { } c := n.getController() + agent := c.getAgent() if !ep.isAnonymous() && ep.Iface().Address() != nil { var ingressPorts []*PortConfig if ep.svcID != "" { @@ -466,8 +495,10 @@ func (ep *endpoint) addServiceInfoToCluster() error { return err } - if err := c.agent.networkDB.CreateEntry("endpoint_table", n.ID(), ep.ID(), buf); err != nil { - return err + if agent != nil { + if err := agent.networkDB.CreateEntry("endpoint_table", n.ID(), ep.ID(), buf); err != nil { + return err + } } } @@ -481,6 +512,8 @@ func (ep *endpoint) deleteServiceInfoFromCluster() error { } c := n.getController() + agent := c.getAgent() + if !ep.isAnonymous() { if ep.svcID != "" && ep.Iface().Address() != nil { var ingressPorts []*PortConfig @@ -492,9 +525,10 @@ func (ep *endpoint) deleteServiceInfoFromCluster() error { return err } } - - if err := c.agent.networkDB.DeleteEntry("endpoint_table", n.ID(), ep.ID()); err != nil { - return err + if agent != nil { + if err := agent.networkDB.DeleteEntry("endpoint_table", n.ID(), ep.ID()); err != nil { + return err + } } } return nil @@ -506,16 +540,15 @@ func (n *network) addDriverWatches() { } c := n.getController() + agent := c.getAgent() + if agent == nil { + return + } for _, tableName := range n.driverTables { - c.Lock() - if c.agent == nil { - c.Unlock() - return - } - ch, cancel := c.agent.networkDB.Watch(tableName, n.ID(), "") - c.agent.driverCancelFuncs[n.ID()] = append(c.agent.driverCancelFuncs[n.ID()], cancel) - c.Unlock() - + ch, cancel := agent.networkDB.Watch(tableName, n.ID(), "") + agent.Lock() + agent.driverCancelFuncs[n.ID()] = append(agent.driverCancelFuncs[n.ID()], cancel) + agent.Unlock() go c.handleTableEvents(ch, n.handleDriverTableEvent) d, err := n.driver(false) if err != nil { @@ -523,7 +556,7 @@ func (n *network) addDriverWatches() { return } - c.agent.networkDB.WalkTable(tableName, func(nid, key string, value []byte) bool { + agent.networkDB.WalkTable(tableName, func(nid, key string, value []byte) bool { if nid == n.ID() { d.EventNotify(driverapi.Create, nid, tableName, key, value) } @@ -538,11 +571,15 @@ func (n *network) cancelDriverWatches() { return } - c := n.getController() - c.Lock() - cancelFuncs := c.agent.driverCancelFuncs[n.ID()] - delete(c.agent.driverCancelFuncs, n.ID()) - c.Unlock() + agent := n.getController().getAgent() + if agent == nil { + return + } + + agent.Lock() + cancelFuncs := agent.driverCancelFuncs[n.ID()] + delete(agent.driverCancelFuncs, n.ID()) + agent.Unlock() for _, cancel := range cancelFuncs { cancel() diff --git a/controller.go b/controller.go index 6eaa1c6638..68bccf074b 100644 --- a/controller.go +++ b/controller.go @@ -237,12 +237,13 @@ func New(cfgOptions ...config.Option) (NetworkController, error) { func (c *controller) SetClusterProvider(provider cluster.Provider) { c.Lock() - defer c.Unlock() c.cfg.Daemon.ClusterProvider = provider + disableProviderCh := c.cfg.Daemon.DisableProvider + c.Unlock() if provider != nil { go c.clusterAgentInit() } else { - c.cfg.Daemon.DisableProvider <- struct{}{} + disableProviderCh <- struct{}{} } } @@ -295,6 +296,12 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error { return c.handleKeyChange(keys) } +func (c *controller) getAgent() *agent { + c.Lock() + defer c.Unlock() + return c.agent +} + func (c *controller) clusterAgentInit() { clusterProvider := c.cfg.Daemon.ClusterProvider for { diff --git a/network.go b/network.go index ef40ea2bcc..79e7e49a95 100644 --- a/network.go +++ b/network.go @@ -1485,17 +1485,12 @@ func (n *network) Peers() []networkdb.PeerInfo { return []networkdb.PeerInfo{} } - var nDB *networkdb.NetworkDB - n.ctrlr.Lock() - if n.ctrlr.agentInitDone == nil && n.ctrlr.agent != nil { - nDB = n.ctrlr.agent.networkDB + agent := n.getController().getAgent() + if agent == nil { + return []networkdb.PeerInfo{} } - n.ctrlr.Unlock() - if nDB != nil { - return n.ctrlr.agent.networkDB.Peers(n.id) - } - return []networkdb.PeerInfo{} + return agent.networkDB.Peers(n.ID()) } func (n *network) DriverOptions() map[string]string { diff --git a/networkdb/cluster.go b/networkdb/cluster.go index c871d92f44..2c1a438c54 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -45,6 +45,8 @@ func (l *logWriter) Write(p []byte) (int, error) { // SetKey adds a new key to the key ring func (nDB *NetworkDB) SetKey(key []byte) { logrus.Debugf("Adding key %s", hex.EncodeToString(key)[0:5]) + nDB.Lock() + defer nDB.Unlock() for _, dbKey := range nDB.config.Keys { if bytes.Equal(key, dbKey) { return @@ -60,6 +62,8 @@ func (nDB *NetworkDB) SetKey(key []byte) { // been added apriori through SetKey func (nDB *NetworkDB) SetPrimaryKey(key []byte) { logrus.Debugf("Primary Key %s", hex.EncodeToString(key)[0:5]) + nDB.RLock() + defer nDB.RUnlock() for _, dbKey := range nDB.config.Keys { if bytes.Equal(key, dbKey) { if nDB.keyring != nil { @@ -74,6 +78,8 @@ func (nDB *NetworkDB) SetPrimaryKey(key []byte) { // can't be the primary key func (nDB *NetworkDB) RemoveKey(key []byte) { logrus.Debugf("Remove Key %s", hex.EncodeToString(key)[0:5]) + nDB.Lock() + defer nDB.Unlock() for i, dbKey := range nDB.config.Keys { if bytes.Equal(key, dbKey) { nDB.config.Keys = append(nDB.config.Keys[:i], nDB.config.Keys[i+1:]...) diff --git a/service_common.go b/service_common.go index a0172f5944..b43c6403f9 100644 --- a/service_common.go +++ b/service_common.go @@ -156,11 +156,10 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in c.Lock() s, ok := c.serviceBindings[skey] + c.Unlock() if !ok { - c.Unlock() return nil } - c.Unlock() s.Lock() lb, ok := s.loadBalancers[nid] @@ -188,7 +187,9 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in if len(s.loadBalancers) == 0 { // All loadbalancers for the service removed. Time to // remove the service itself. + c.Lock() delete(c.serviceBindings, skey) + c.Unlock() } // Remove loadbalancer service(if needed) and backend in all diff --git a/service_linux.go b/service_linux.go index be8dc84d3e..fbcc89d22e 100644 --- a/service_linux.go +++ b/service_linux.go @@ -34,8 +34,8 @@ func init() { func (n *network) connectedLoadbalancers() []*loadBalancer { c := n.getController() - serviceBindings := make([]*service, 0, len(c.serviceBindings)) c.Lock() + serviceBindings := make([]*service, 0, len(c.serviceBindings)) for _, s := range c.serviceBindings { serviceBindings = append(serviceBindings, s) } From 47bf4eb93770614b256afb622fb1a988c6ba38a0 Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Thu, 1 Dec 2016 19:08:07 -0800 Subject: [PATCH 170/799] networkdb: Properly format memberlist logs Right now, items logged by memberlist end up as a complete log line embedded inside another log line, like the following: Nov 22 16:34:16 hostname dockerd: time="2016-11-22T16:34:16.802103258-08:00" level=info msg="2016/11/22 16:34:16 [INFO] memberlist: Marking xyz-1d1ec2dfa053 as failed, suspect timeout reached\n" This has two time and date stamps, and an escaped newline inside the "msg" field of the outer log message. To fix this, define a custom logger that only prints the message itself. Capture this message in logWriter, strip off the log level (added directly by memberlist), and route to the appropriate logrus method. Signed-off-by: Aaron Lehmann --- networkdb/cluster.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/networkdb/cluster.go b/networkdb/cluster.go index 2c1a438c54..62d05c0aea 100644 --- a/networkdb/cluster.go +++ b/networkdb/cluster.go @@ -5,6 +5,7 @@ import ( "crypto/rand" "encoding/hex" "fmt" + "log" "math/big" rnd "math/rand" "net" @@ -27,15 +28,20 @@ type logWriter struct{} func (l *logWriter) Write(p []byte) (int, error) { str := string(p) + str = strings.TrimSuffix(str, "\n") switch { - case strings.Contains(str, "[WARN]"): + case strings.HasPrefix(str, "[WARN] "): + str = strings.TrimPrefix(str, "[WARN] ") logrus.Warn(str) - case strings.Contains(str, "[DEBUG]"): + case strings.HasPrefix(str, "[DEBUG] "): + str = strings.TrimPrefix(str, "[DEBUG] ") logrus.Debug(str) - case strings.Contains(str, "[INFO]"): + case strings.HasPrefix(str, "[INFO] "): + str = strings.TrimPrefix(str, "[INFO] ") logrus.Info(str) - case strings.Contains(str, "[ERR]"): + case strings.HasPrefix(str, "[ERR] "): + str = strings.TrimPrefix(str, "[ERR] ") logrus.Warn(str) } @@ -104,7 +110,9 @@ func (nDB *NetworkDB) clusterInit() error { config.ProtocolVersion = memberlist.ProtocolVersionMax config.Delegate = &delegate{nDB: nDB} config.Events = &eventDelegate{nDB: nDB} - config.LogOutput = &logWriter{} + // custom logger that does not add time or date, so they are not + // duplicated by logrus + config.Logger = log.New(&logWriter{}, "", 0) var err error if len(nDB.config.Keys) > 0 { From 3830f32f8bb47f5ad05634be4a041247714e4e42 Mon Sep 17 00:00:00 2001 From: Ke Li Date: Sat, 3 Dec 2016 13:22:42 +0800 Subject: [PATCH 171/799] fix review comments Signed-off-by: Ke Li --- cmd/dnet/cmd.go | 4 ++-- cmd/proxy/proxy.go | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/dnet/cmd.go b/cmd/dnet/cmd.go index c9ec2d2b1d..428b433bab 100644 --- a/cmd/dnet/cmd.go +++ b/cmd/dnet/cmd.go @@ -44,7 +44,7 @@ var ( func runContainerCreate(c *cli.Context) { if len(c.Args()) == 0 { - fmt.Print("Please provide container id argument\n") + fmt.Println("Please provide container id argument") os.Exit(1) } @@ -70,7 +70,7 @@ func runContainerRm(c *cli.Context) { var sbList []*client.SandboxResource if len(c.Args()) == 0 { - fmt.Print("Please provide container id argument\n") + fmt.Println("Please provide container id argument") os.Exit(1) } diff --git a/cmd/proxy/proxy.go b/cmd/proxy/proxy.go index b846905316..67574afa5e 100644 --- a/cmd/proxy/proxy.go +++ b/cmd/proxy/proxy.go @@ -3,7 +3,6 @@ package main import ( - "errors" "net" ) @@ -32,6 +31,6 @@ func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) { case *net.TCPAddr: return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr)) default: - panic(errors.New("Unsupported protocol")) + panic("Unsupported protocol") } } From b2a41c17d96d361900a19ef24875d393fe6fcac7 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Mon, 5 Dec 2016 00:58:59 -0800 Subject: [PATCH 172/799] Check for node's presence in networkDB's node map before accessing. Signed-off-by: Santhosh Manohar --- networkdb/networkdb.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/networkdb/networkdb.go b/networkdb/networkdb.go index 8ff8afad66..c3aab99335 100644 --- a/networkdb/networkdb.go +++ b/networkdb/networkdb.go @@ -211,10 +211,12 @@ func (nDB *NetworkDB) Peers(nid string) []PeerInfo { defer nDB.RUnlock() peers := make([]PeerInfo, 0, len(nDB.networkNodes[nid])) for _, nodeName := range nDB.networkNodes[nid] { - peers = append(peers, PeerInfo{ - Name: nDB.nodes[nodeName].Name, - IP: nDB.nodes[nodeName].Addr.String(), - }) + if node, ok := nDB.nodes[nodeName]; ok { + peers = append(peers, PeerInfo{ + Name: node.Name, + IP: node.Addr.String(), + }) + } } return peers } From cb53b5a4539b0beb55ac3de701ae4ca7c1a17d0c Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Fri, 9 Dec 2016 11:00:32 -0800 Subject: [PATCH 173/799] Correct regexp to match v6 addresses with zone ID Signed-off-by: Santhosh Manohar --- resolvconf/resolvconf.go | 2 +- resolvconf/resolvconf_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/resolvconf/resolvconf.go b/resolvconf/resolvconf.go index e1db6191e4..41c9af7cca 100644 --- a/resolvconf/resolvconf.go +++ b/resolvconf/resolvconf.go @@ -25,7 +25,7 @@ var ( // -- e.g. other link-local types -- either won't work in containers or are unnecessary. // For readability and sufficiency for Docker purposes this seemed more reasonable than a // 1000+ character regexp with exact and complete IPv6 validation - ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})` + ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})(%\w+)?` localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + dns.IPLocalhost + `\s*\n*`) nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`) diff --git a/resolvconf/resolvconf_test.go b/resolvconf/resolvconf_test.go index 218191396b..5282353521 100644 --- a/resolvconf/resolvconf_test.go +++ b/resolvconf/resolvconf_test.go @@ -271,6 +271,14 @@ func TestFilterResolvDns(t *testing.T) { } } + // with IPv6 disabled (false param), the IPv6 link-local nameserver with zone ID should be removed + ns1 = "nameserver 10.16.60.14\nnameserver FE80::BB1%1\nnameserver FE80::BB1%eth0\nnameserver 10.16.60.21\n" + if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { + if ns0 != string(result.Content) { + t.Fatalf("Failed Localhost+IPv6 off: expected \n<%s> got \n<%s>", ns0, string(result.Content)) + } + } + // with IPv6 enabled, the IPv6 nameserver should be preserved ns0 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\n" ns1 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1" From 95d72ecfa89f80f0f5f5fe34135b59a58c48a3b1 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 9 Dec 2016 14:25:46 +0100 Subject: [PATCH 174/799] Fix fqdn hostnames not added to /etc/hosts This fixes an issue where using a fqdn as hostname not being added to /etc/hosts. The etchosts.Build() function was never called with an IP-address, therefore the fqdn was not added. The subsequent updateHostsFile() was not updated to support fqdn's as hostname, and not adding the record correctly to /etc/hosts. This patch implements the functionality in updateHostsFile() Signed-off-by: Sebastiaan van Stijn --- sandbox_dns_unix.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sandbox_dns_unix.go b/sandbox_dns_unix.go index f4d1fad605..d40197e53c 100644 --- a/sandbox_dns_unix.go +++ b/sandbox_dns_unix.go @@ -100,8 +100,6 @@ func (sb *sandbox) buildHostsFile() error { } func (sb *sandbox) updateHostsFile(ifaceIP string) error { - var mhost string - if ifaceIP == "" { return nil } @@ -110,11 +108,17 @@ func (sb *sandbox) updateHostsFile(ifaceIP string) error { return nil } + // User might have provided a FQDN in hostname or split it across hostname + // and domainname. We want the FQDN and the bare hostname. + fqdn := sb.config.hostName + mhost := sb.config.hostName if sb.config.domainName != "" { - mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName, - sb.config.hostName) - } else { - mhost = sb.config.hostName + fqdn = fmt.Sprintf("%s.%s", fqdn, sb.config.domainName) + } + + parts := strings.SplitN(fqdn, ".", 2) + if len(parts) == 2 { + mhost = fmt.Sprintf("%s %s", fqdn, parts[0]) } extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}} From 14b2be6d747f1948f8e5fedf8795e9ee9ff751e1 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Tue, 13 Dec 2016 13:22:55 -0800 Subject: [PATCH 175/799] Handling the new experimental daemon flag related to https://github.com/docker/docker/issues/29368 Signed-off-by: Madhu Venugopal --- config/config.go | 9 +++++++++ controller.go | 4 ++-- drivers_experimental_linux.go | 2 -- drivers_freebsd.go | 2 +- drivers_linux.go | 6 ++++-- drivers_solaris.go | 2 +- drivers_stub_linux.go | 7 ------- drivers_windows.go | 2 +- 8 files changed, 18 insertions(+), 16 deletions(-) delete mode 100644 drivers_stub_linux.go diff --git a/config/config.go b/config/config.go index 6e29563df6..171f1852c0 100644 --- a/config/config.go +++ b/config/config.go @@ -35,6 +35,7 @@ type Config struct { // DaemonCfg represents libnetwork core configuration type DaemonCfg struct { Debug bool + Experimental bool DataDir string DefaultNetwork string DefaultDriver string @@ -222,6 +223,14 @@ func OptionPluginGetter(pg plugingetter.PluginGetter) Option { } } +// OptionExperimental function returns an option setter for experimental daemon +func OptionExperimental(exp bool) Option { + return func(c *Config) { + logrus.Debugf("Option Experimental: %v", exp) + c.Daemon.Experimental = exp + } +} + // ProcessOptions processes options and stores it in config func (c *Config) ProcessOptions(options ...Option) { for _, opt := range options { diff --git a/controller.go b/controller.go index 154b337a94..b551230baf 100644 --- a/controller.go +++ b/controller.go @@ -188,7 +188,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) { return nil, err } - for _, i := range getInitializers() { + for _, i := range getInitializers(c.cfg.Daemon.Experimental) { var dcfg map[string]interface{} // External plugins don't need config passed through daemon. They can @@ -476,7 +476,7 @@ func (c *controller) ID() string { func (c *controller) BuiltinDrivers() []string { drivers := []string{} - for _, i := range getInitializers() { + for _, i := range getInitializers(c.cfg.Daemon.Experimental) { if i.ntype == "remote" { continue } diff --git a/drivers_experimental_linux.go b/drivers_experimental_linux.go index ca7c9f9b0e..4f540d4a87 100644 --- a/drivers_experimental_linux.go +++ b/drivers_experimental_linux.go @@ -1,5 +1,3 @@ -// +build experimental - package libnetwork import "github.com/docker/libnetwork/drivers/ipvlan" diff --git a/drivers_freebsd.go b/drivers_freebsd.go index 416bba04d8..d117c25780 100644 --- a/drivers_freebsd.go +++ b/drivers_freebsd.go @@ -5,7 +5,7 @@ import ( "github.com/docker/libnetwork/drivers/remote" ) -func getInitializers() []initializer { +func getInitializers(experimental bool) []initializer { return []initializer{ {null.Init, "null"}, {remote.Init, "remote"}, diff --git a/drivers_linux.go b/drivers_linux.go index 50416512f3..c53d516fa6 100644 --- a/drivers_linux.go +++ b/drivers_linux.go @@ -9,7 +9,7 @@ import ( "github.com/docker/libnetwork/drivers/remote" ) -func getInitializers() []initializer { +func getInitializers(experimental bool) []initializer { in := []initializer{ {bridge.Init, "bridge"}, {host.Init, "host"}, @@ -19,6 +19,8 @@ func getInitializers() []initializer { {overlay.Init, "overlay"}, } - in = append(in, additionalDrivers()...) + if experimental { + in = append(in, additionalDrivers()...) + } return in } diff --git a/drivers_solaris.go b/drivers_solaris.go index ad5184a3fc..c4fcd96b7e 100644 --- a/drivers_solaris.go +++ b/drivers_solaris.go @@ -6,7 +6,7 @@ import ( "github.com/docker/libnetwork/drivers/solaris/overlay" ) -func getInitializers() []initializer { +func getInitializers(experimental bool) []initializer { return []initializer{ {overlay.Init, "overlay"}, {bridge.Init, "bridge"}, diff --git a/drivers_stub_linux.go b/drivers_stub_linux.go deleted file mode 100644 index e20428c72f..0000000000 --- a/drivers_stub_linux.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !experimental - -package libnetwork - -func additionalDrivers() []initializer { - return nil -} diff --git a/drivers_windows.go b/drivers_windows.go index 87705e7652..384d855cb8 100644 --- a/drivers_windows.go +++ b/drivers_windows.go @@ -7,7 +7,7 @@ import ( "github.com/docker/libnetwork/drivers/windows/overlay" ) -func getInitializers() []initializer { +func getInitializers(experimental bool) []initializer { return []initializer{ {null.Init, "null"}, {overlay.Init, "overlay"}, From 119c5ba3bcc6fc330634ed089d23b862c5492383 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 15 Dec 2016 18:34:50 -0800 Subject: [PATCH 176/799] Handle the case of registering active plugins during remote init With Plugin-V2, plugins can get activated before remote driver is Initialized. Those plugins fails to get registered with drvRegistry. This fix handles that scenario Signed-off-by: Madhu Venugopal --- drivers/remote/driver.go | 21 ++++++++++++++------- ipams/remote/remote.go | 20 +++++++++++++------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/remote/driver.go b/drivers/remote/driver.go index 04be60124f..209a28be52 100644 --- a/drivers/remote/driver.go +++ b/drivers/remote/driver.go @@ -29,12 +29,7 @@ func newDriver(name string, client *plugins.Client) driverapi.Driver { // Init makes sure a remote driver is registered when a network driver // plugin is activated. func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { - // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. - handleFunc := plugins.Handle - if pg := dc.GetPluginGetter(); pg != nil { - handleFunc = pg.Handle - } - handleFunc(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) { + newPluginHandler := func(name string, client *plugins.Client) { // negotiate driver capability with client d := newDriver(name, client) c, err := d.(*driver).getCapabilities() @@ -45,7 +40,19 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { if err = dc.RegisterDriver(name, d, *c); err != nil { logrus.Errorf("error registering driver for %s due to %v", name, err) } - }) + } + + // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. + handleFunc := plugins.Handle + if pg := dc.GetPluginGetter(); pg != nil { + handleFunc = pg.Handle + activePlugins, _ := pg.GetAllByCap(driverapi.NetworkPluginEndpointType) + for _, ap := range activePlugins { + newPluginHandler(ap.Name(), ap.Client()) + } + } + handleFunc(driverapi.NetworkPluginEndpointType, newPluginHandler) + return nil } diff --git a/ipams/remote/remote.go b/ipams/remote/remote.go index b23c52a6d0..ecaf10c2f1 100644 --- a/ipams/remote/remote.go +++ b/ipams/remote/remote.go @@ -31,12 +31,7 @@ func newAllocator(name string, client *plugins.Client) ipamapi.Ipam { // Init registers a remote ipam when its plugin is activated func Init(cb ipamapi.Callback, l, g interface{}) error { - // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. - handleFunc := plugins.Handle - if pg := cb.GetPluginGetter(); pg != nil { - handleFunc = pg.Handle - } - handleFunc(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) { + newPluginHandler := func(name string, client *plugins.Client) { a := newAllocator(name, client) if cps, err := a.(*allocator).getCapabilities(); err == nil { if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil { @@ -49,7 +44,18 @@ func Init(cb ipamapi.Callback, l, g interface{}) error { logrus.Errorf("error registering remote ipam driver %s due to %v", name, err) } } - }) + } + + // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. + handleFunc := plugins.Handle + if pg := cb.GetPluginGetter(); pg != nil { + handleFunc = pg.Handle + activePlugins, _ := pg.GetAllByCap(ipamapi.PluginEndpointType) + for _, ap := range activePlugins { + newPluginHandler(ap.Name(), ap.Client()) + } + } + handleFunc(ipamapi.PluginEndpointType, newPluginHandler) return nil } From fb8744be86f04056bd88ea3f1638fe0f56f208a9 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Sun, 18 Dec 2016 19:56:34 -0800 Subject: [PATCH 177/799] Internal interface to differentiate built-in drivers from remote Signed-off-by: Madhu Venugopal --- controller.go | 24 +++++++++++++++---- driverapi/driverapi.go | 3 +++ drivers/bridge/bridge.go | 4 ++++ drivers/host/host.go | 4 ++++ drivers/ipvlan/ipvlan.go | 4 ++++ drivers/macvlan/macvlan.go | 4 ++++ drivers/null/null.go | 4 ++++ drivers/overlay/overlay.go | 4 ++++ drivers/overlay/ovmanager/ovmanager.go | 4 ++++ drivers/remote/driver.go | 4 ++++ drivers/solaris/bridge/bridge.go | 4 ++++ drivers/solaris/overlay/overlay.go | 4 ++++ .../solaris/overlay/ovmanager/ovmanager.go | 4 ++++ drivers/windows/overlay/overlay_windows.go | 4 ++++ drivers/windows/windows.go | 4 ++++ ipam/allocator.go | 5 ++++ ipamapi/contract.go | 3 +++ ipams/null/null.go | 4 ++++ ipams/remote/remote.go | 4 ++++ ipams/windowsipam/windowsipam.go | 4 ++++ libnetwork_internal_test.go | 3 +++ 21 files changed, 97 insertions(+), 5 deletions(-) diff --git a/controller.go b/controller.go index b551230baf..aa92b88f6b 100644 --- a/controller.go +++ b/controller.go @@ -79,6 +79,9 @@ type NetworkController interface { // BuiltinDrivers returns list of builtin drivers BuiltinDrivers() []string + // BuiltinIPAMDrivers returns list of builtin ipam drivers + BuiltinIPAMDrivers() []string + // Config method returns the bootup configuration for the controller Config() config.Config @@ -476,12 +479,23 @@ func (c *controller) ID() string { func (c *controller) BuiltinDrivers() []string { drivers := []string{} - for _, i := range getInitializers(c.cfg.Daemon.Experimental) { - if i.ntype == "remote" { - continue + c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { + if driver.IsBuiltIn() { + drivers = append(drivers, name) } - drivers = append(drivers, i.ntype) - } + return false + }) + return drivers +} + +func (c *controller) BuiltinIPAMDrivers() []string { + drivers := []string{} + c.drvRegistry.WalkIPAMs(func(name string, driver ipamapi.Ipam, cap *ipamapi.Capability) bool { + if driver.IsBuiltIn() { + drivers = append(drivers, name) + } + return false + }) return drivers } diff --git a/driverapi/driverapi.go b/driverapi/driverapi.go index 98bc60ac9d..6e66ea221e 100644 --- a/driverapi/driverapi.go +++ b/driverapi/driverapi.go @@ -74,6 +74,9 @@ type Driver interface { // Type returns the the type of this driver, the network type this driver manages Type() string + + // IsBuiltIn returns true if it is a built-in driver + IsBuiltIn() bool } // NetworkInfo provides a go interface for drivers to provide network diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index f6cbe07783..ec999731cd 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -1424,6 +1424,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { return nil diff --git a/drivers/host/host.go b/drivers/host/host.go index bec64465a0..3bc9099761 100644 --- a/drivers/host/host.go +++ b/drivers/host/host.go @@ -86,6 +86,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { return nil diff --git a/drivers/ipvlan/ipvlan.go b/drivers/ipvlan/ipvlan.go index aacea3df80..cd0c830f79 100644 --- a/drivers/ipvlan/ipvlan.go +++ b/drivers/ipvlan/ipvlan.go @@ -84,6 +84,10 @@ func (d *driver) Type() string { return ipvlanType } +func (d *driver) IsBuiltIn() bool { + return true +} + func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { return nil } diff --git a/drivers/macvlan/macvlan.go b/drivers/macvlan/macvlan.go index b89b4b7845..23fa850edc 100644 --- a/drivers/macvlan/macvlan.go +++ b/drivers/macvlan/macvlan.go @@ -86,6 +86,10 @@ func (d *driver) Type() string { return macvlanType } +func (d *driver) IsBuiltIn() bool { + return true +} + func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { return nil } diff --git a/drivers/null/null.go b/drivers/null/null.go index a137b000fa..03f9777040 100644 --- a/drivers/null/null.go +++ b/drivers/null/null.go @@ -86,6 +86,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { return nil diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index e3c1f7b899..7f20840db2 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -211,6 +211,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + func validateSelf(node string) error { advIP := net.ParseIP(node) if advIP == nil { diff --git a/drivers/overlay/ovmanager/ovmanager.go b/drivers/overlay/ovmanager/ovmanager.go index aaf94e586f..2c4c771e58 100644 --- a/drivers/overlay/ovmanager/ovmanager.go +++ b/drivers/overlay/ovmanager/ovmanager.go @@ -229,6 +229,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { return types.NotImplementedErrorf("not implemented") diff --git a/drivers/remote/driver.go b/drivers/remote/driver.go index 209a28be52..12a8fb0cdb 100644 --- a/drivers/remote/driver.go +++ b/drivers/remote/driver.go @@ -312,6 +312,10 @@ func (d *driver) Type() string { return d.networkType } +func (d *driver) IsBuiltIn() bool { + return false +} + // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { if dType != discoverapi.NodeDiscovery { diff --git a/drivers/solaris/bridge/bridge.go b/drivers/solaris/bridge/bridge.go index 97180fbbd3..53092efeeb 100644 --- a/drivers/solaris/bridge/bridge.go +++ b/drivers/solaris/bridge/bridge.go @@ -916,6 +916,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { return nil diff --git a/drivers/solaris/overlay/overlay.go b/drivers/solaris/overlay/overlay.go index b48cfe7e76..b001f58af7 100644 --- a/drivers/solaris/overlay/overlay.go +++ b/drivers/solaris/overlay/overlay.go @@ -200,6 +200,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + func validateSelf(node string) error { advIP := net.ParseIP(node) if advIP == nil { diff --git a/drivers/solaris/overlay/ovmanager/ovmanager.go b/drivers/solaris/overlay/ovmanager/ovmanager.go index 78a586e08e..a756990acb 100644 --- a/drivers/solaris/overlay/ovmanager/ovmanager.go +++ b/drivers/solaris/overlay/ovmanager/ovmanager.go @@ -229,6 +229,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { return types.NotImplementedErrorf("not implemented") diff --git a/drivers/windows/overlay/overlay_windows.go b/drivers/windows/overlay/overlay_windows.go index 7ebc16eebd..c3028d7636 100644 --- a/drivers/windows/overlay/overlay_windows.go +++ b/drivers/windows/overlay/overlay_windows.go @@ -176,6 +176,10 @@ func (d *driver) Type() string { return networkType } +func (d *driver) IsBuiltIn() bool { + return true +} + func validateSelf(node string) error { advIP := net.ParseIP(node) if advIP == nil { diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index 7ce7fa8f81..b054898afe 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -698,6 +698,10 @@ func (d *driver) Type() string { return d.name } +func (d *driver) IsBuiltIn() bool { + return true +} + // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { return nil diff --git a/ipam/allocator.go b/ipam/allocator.go index bd00a14700..4243d57a74 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -594,3 +594,8 @@ func (a *Allocator) DumpDatabase() string { return s } + +// IsBuiltIn returns true for builtin drivers +func (a *Allocator) IsBuiltIn() bool { + return true +} diff --git a/ipamapi/contract.go b/ipamapi/contract.go index 090205e11f..7f967863d8 100644 --- a/ipamapi/contract.go +++ b/ipamapi/contract.go @@ -80,6 +80,9 @@ type Ipam interface { RequestAddress(string, net.IP, map[string]string) (*net.IPNet, map[string]string, error) // Release the address from the specified pool ID ReleaseAddress(string, net.IP) error + + //IsBuiltIn returns true if it is a built-in driver. + IsBuiltIn() bool } // Capability represents the requirements and capabilities of the IPAM driver diff --git a/ipams/null/null.go b/ipams/null/null.go index 60119a36ab..339b5308d1 100644 --- a/ipams/null/null.go +++ b/ipams/null/null.go @@ -65,6 +65,10 @@ func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interfa return nil } +func (a *allocator) IsBuiltIn() bool { + return true +} + // Init registers a remote ipam when its plugin is activated func Init(ic ipamapi.Callback, l, g interface{}) error { return ic.RegisterIpamDriver(ipamapi.NullIPAM, &allocator{}) diff --git a/ipams/remote/remote.go b/ipams/remote/remote.go index ecaf10c2f1..3da05260e6 100644 --- a/ipams/remote/remote.go +++ b/ipams/remote/remote.go @@ -149,3 +149,7 @@ func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{ func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { return nil } + +func (a *allocator) IsBuiltIn() bool { + return false +} diff --git a/ipams/windowsipam/windowsipam.go b/ipams/windowsipam/windowsipam.go index 1b9cd5a983..6b124d40d2 100644 --- a/ipams/windowsipam/windowsipam.go +++ b/ipams/windowsipam/windowsipam.go @@ -101,3 +101,7 @@ func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{ func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { return nil } + +func (a *allocator) IsBuiltIn() bool { + return true +} diff --git a/libnetwork_internal_test.go b/libnetwork_internal_test.go index e4e90151f5..9d4d562d0d 100644 --- a/libnetwork_internal_test.go +++ b/libnetwork_internal_test.go @@ -544,6 +544,9 @@ func (b *badDriver) DiscoverDelete(dType discoverapi.DiscoveryType, data interfa func (b *badDriver) Type() string { return badDriverName } +func (b *badDriver) IsBuiltIn() bool { + return false +} func (b *badDriver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { return nil } From d25f9d1c1381658c6841240df3b9880fc217c16f Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Sun, 18 Dec 2016 20:01:09 -0800 Subject: [PATCH 178/799] drvregistry to allow overriding plugin drvRegistry isnt aware if a plugin is v1 or v2. Plugin-v2 provides a way for user to disable and remove plugins. But unfortunately, there isnt any api to advertise the removal to drvRegistry. Hence there is no way to handle "docker plugin rm" of installed plugin. In order to support the case of "docker plugin install x" followed by "docker plugin rm x" followed by reinstalling of plugin x "docker plugin install x", drvRegistry must allow overriding any existing plugin with the same name. The protection in plugin infra will prevent willful override of existing plugin. Signed-off-by: Madhu Venugopal --- drvregistry/drvregistry.go | 8 ++++---- drvregistry/drvregistry_test.go | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drvregistry/drvregistry.go b/drvregistry/drvregistry.go index a9a7368025..a1cf88fc03 100644 --- a/drvregistry/drvregistry.go +++ b/drvregistry/drvregistry.go @@ -164,10 +164,10 @@ func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capa } r.Lock() - _, ok := r.drivers[ntype] + dd, ok := r.drivers[ntype] r.Unlock() - if ok { + if ok && dd.driver.IsBuiltIn() { return driverapi.ErrActiveRegistration(ntype) } @@ -192,9 +192,9 @@ func (r *DrvRegistry) registerIpamDriver(name string, driver ipamapi.Ipam, caps } r.Lock() - _, ok := r.ipamDrivers[name] + dd, ok := r.ipamDrivers[name] r.Unlock() - if ok { + if ok && dd.driver.IsBuiltIn() { return types.ForbiddenErrorf("ipam driver %q already registered", name) } diff --git a/drvregistry/drvregistry_test.go b/drvregistry/drvregistry_test.go index e52e28c28b..c5113ca28b 100644 --- a/drvregistry/drvregistry_test.go +++ b/drvregistry/drvregistry_test.go @@ -68,6 +68,10 @@ func (m *mockDriver) Type() string { return mockDriverName } +func (m *mockDriver) IsBuiltIn() bool { + return true +} + func (m *mockDriver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { return nil } From 805efb18435db6605f9d1e3a818f52b53c60c6b3 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 6 Dec 2016 14:56:24 -0800 Subject: [PATCH 179/799] Defer PTR queries to external servers based on A/AAAA response Signed-off-by: Santhosh Manohar --- libnetwork_internal_test.go | 2 +- network.go | 55 +++++++++++++++++++++++++------------ resolver.go | 18 ++++++++++-- sandbox.go | 7 +++++ 4 files changed, 62 insertions(+), 20 deletions(-) diff --git a/libnetwork_internal_test.go b/libnetwork_internal_test.go index e4e90151f5..e5dcfd8b35 100644 --- a/libnetwork_internal_test.go +++ b/libnetwork_internal_test.go @@ -380,7 +380,7 @@ func TestSRVServiceQuery(t *testing.T) { sr := svcInfo{ svcMap: make(map[string][]net.IP), svcIPv6Map: make(map[string][]net.IP), - ipMap: make(map[string]string), + ipMap: make(map[string]*ipInfo), service: make(map[string][]servicePorts), } // backing container for the service diff --git a/network.go b/network.go index 79e7e49a95..e966dae001 100644 --- a/network.go +++ b/network.go @@ -80,10 +80,18 @@ type NetworkInfo interface { // When the function returns true, the walk will stop. type EndpointWalker func(ep Endpoint) bool +// ipInfo is the reverse mapping from IP to service name to serve the PTR query. +// extResolver is set if an externl server resolves a service name to this IP. +// Its an indication to defer PTR queries also to that external server. +type ipInfo struct { + name string + extResolver bool +} + type svcInfo struct { svcMap map[string][]net.IP svcIPv6Map map[string][]net.IP - ipMap map[string]string + ipMap map[string]*ipInfo service map[string][]servicePorts } @@ -1070,10 +1078,12 @@ func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool } } -func addIPToName(ipMap map[string]string, name string, ip net.IP) { +func addIPToName(ipMap map[string]*ipInfo, name string, ip net.IP) { reverseIP := netutils.ReverseIP(ip.String()) if _, ok := ipMap[reverseIP]; !ok { - ipMap[reverseIP] = name + ipMap[reverseIP] = &ipInfo{ + name: name, + } } } @@ -1117,7 +1127,7 @@ func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUp sr = svcInfo{ svcMap: make(map[string][]net.IP), svcIPv6Map: make(map[string][]net.IP), - ipMap: make(map[string]string), + ipMap: make(map[string]*ipInfo), } c.svcRecords[n.ID()] = sr } @@ -1612,8 +1622,8 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) { c := n.getController() c.Lock() + defer c.Unlock() sr, ok := c.svcRecords[n.ID()] - c.Unlock() if !ok { return nil, false @@ -1621,7 +1631,6 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) { req = strings.TrimSuffix(req, ".") var ip []net.IP - n.Lock() ip, ok = sr.svcMap[req] if ipType == types.IPv6 { @@ -1634,7 +1643,6 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) { } ip = sr.svcIPv6Map[req] } - n.Unlock() if ip != nil { return ip, false @@ -1643,13 +1651,28 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) { return nil, ipv6Miss } -func (n *network) ResolveIP(ip string) string { - var svc string +func (n *network) HandleQueryResp(name string, ip net.IP) { + c := n.getController() + c.Lock() + defer c.Unlock() + sr, ok := c.svcRecords[n.ID()] + if !ok { + return + } + + ipStr := netutils.ReverseIP(ip.String()) + + if ipInfo, ok := sr.ipMap[ipStr]; ok { + ipInfo.extResolver = true + } +} + +func (n *network) ResolveIP(ip string) string { c := n.getController() c.Lock() + defer c.Unlock() sr, ok := c.svcRecords[n.ID()] - c.Unlock() if !ok { return "" @@ -1657,15 +1680,13 @@ func (n *network) ResolveIP(ip string) string { nwName := n.Name() - n.Lock() - defer n.Unlock() - svc, ok = sr.ipMap[ip] + ipInfo, ok := sr.ipMap[ip] - if ok { - return svc + "." + nwName + if !ok || ipInfo.extResolver { + return "" } - return svc + return ipInfo.name + "." + nwName } func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) { @@ -1689,8 +1710,8 @@ func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) { svcName := strings.Join(parts[2:], ".") c.Lock() + defer c.Unlock() sr, ok := c.svcRecords[n.ID()] - c.Unlock() if !ok { return nil, nil diff --git a/resolver.go b/resolver.go index ca3850c58e..1fb816c8aa 100644 --- a/resolver.go +++ b/resolver.go @@ -54,6 +54,9 @@ type DNSBackend interface { ExecFunc(f func()) error //NdotsSet queries the backends ndots dns option settings NdotsSet() bool + // HandleQueryResp passes the name & IP from a response to the backend. backend + // can use it to maintain any required state about the resolution + HandleQueryResp(name string, ip net.IP) } const ( @@ -462,9 +465,20 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { logrus.Debugf("Read from DNS server failed, %s", err) continue } - r.forwardQueryEnd() - + if resp != nil { + for _, rr := range resp.Answer { + h := rr.Header() + switch h.Rrtype { + case dns.TypeA: + ip := rr.(*dns.A).A + r.backend.HandleQueryResp(h.Name, ip) + case dns.TypeAAAA: + ip := rr.(*dns.AAAA).AAAA + r.backend.HandleQueryResp(h.Name, ip) + } + } + } resp.Compress = true break } diff --git a/sandbox.go b/sandbox.go index 1fd585cd28..a3e890503a 100644 --- a/sandbox.go +++ b/sandbox.go @@ -411,6 +411,13 @@ func (sb *sandbox) updateGateway(ep *endpoint) error { return nil } +func (sb *sandbox) HandleQueryResp(name string, ip net.IP) { + for _, ep := range sb.getConnectedEndpoints() { + n := ep.getNetwork() + n.HandleQueryResp(name, ip) + } +} + func (sb *sandbox) ResolveIP(ip string) string { var svc string logrus.Debugf("IP To resolve %v", ip) From 14ae4337e1b88e93fec1c69359425ff514e0ce80 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Sun, 18 Dec 2016 18:27:13 -0800 Subject: [PATCH 180/799] Add embedded DNS server support for host loopback resolver Signed-off-by: Santhosh Manohar --- controller.go | 1 + resolvconf/dns/resolvconf.go | 11 ++++++++++- resolver.go | 23 ++++++++++++++--------- sandbox.go | 2 +- sandbox_dns_unix.go | 33 ++++++++++++++++++++++++++++----- sandbox_store.go | 2 +- 6 files changed, 55 insertions(+), 17 deletions(-) diff --git a/controller.go b/controller.go index 154b337a94..3fad7c4f61 100644 --- a/controller.go +++ b/controller.go @@ -918,6 +918,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s populatedEndpoints: map[string]struct{}{}, config: containerConfig{}, controller: c, + extDNS: []extDNSEntry{}, } } sBox = sb diff --git a/resolvconf/dns/resolvconf.go b/resolvconf/dns/resolvconf.go index 6c6dac589f..e348bc57f5 100644 --- a/resolvconf/dns/resolvconf.go +++ b/resolvconf/dns/resolvconf.go @@ -4,10 +4,14 @@ import ( "regexp" ) -// IPLocalhost is a regex patter for localhost IP address range. +// IPLocalhost is a regex pattern for IPv4 or IPv6 loopback range. const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)` +// IPv4Localhost is a regex pattern for IPv4 localhost address range. +const IPv4Localhost = `(127\.([0-9]{1,3}\.){2}[0-9]{1,3})` + var localhostIPRegexp = regexp.MustCompile(IPLocalhost) +var localhostIPv4Regexp = regexp.MustCompile(IPv4Localhost) // IsLocalhost returns true if ip matches the localhost IP regular expression. // Used for determining if nameserver settings are being passed which are @@ -15,3 +19,8 @@ var localhostIPRegexp = regexp.MustCompile(IPLocalhost) func IsLocalhost(ip string) bool { return localhostIPRegexp.MatchString(ip) } + +// IsIPv4Localhost returns true if ip matches the IPv4 localhost regular expression. +func IsIPv4Localhost(ip string) bool { + return localhostIPv4Regexp.MatchString(ip) +} diff --git a/resolver.go b/resolver.go index ca3850c58e..fd8a9a909d 100644 --- a/resolver.go +++ b/resolver.go @@ -29,7 +29,7 @@ type Resolver interface { NameServer() string // SetExtServers configures the external nameservers the resolver // should use to forward queries - SetExtServers([]string) + SetExtServers([]extDNSEntry) // ResolverOptions returns resolv.conf options that should be set ResolverOptions() []string } @@ -69,7 +69,8 @@ const ( ) type extDNSEntry struct { - ipStr string + ipStr string + hostLoopback bool } // resolver implements the Resolver interface @@ -182,13 +183,13 @@ func (r *resolver) Stop() { r.queryLock = sync.Mutex{} } -func (r *resolver) SetExtServers(dns []string) { - l := len(dns) +func (r *resolver) SetExtServers(extDNS []extDNSEntry) { + l := len(extDNS) if l > maxExtDNS { l = maxExtDNS } for i := 0; i < l; i++ { - r.extDNSList[i].ipStr = dns[i] + r.extDNSList[i] = extDNS[i] } } @@ -417,10 +418,14 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { extConn, err = net.DialTimeout(proto, addr, extIOTimeout) } - execErr := r.backend.ExecFunc(extConnect) - if execErr != nil { - logrus.Warn(execErr) - continue + if extDNS.hostLoopback { + extConnect() + } else { + execErr := r.backend.ExecFunc(extConnect) + if execErr != nil { + logrus.Warn(execErr) + continue + } } if err != nil { logrus.Warnf("Connect failed: %s", err) diff --git a/sandbox.go b/sandbox.go index 1fd585cd28..9067ddc9e0 100644 --- a/sandbox.go +++ b/sandbox.go @@ -69,7 +69,7 @@ type sandbox struct { id string containerID string config containerConfig - extDNS []string + extDNS []extDNSEntry osSbox osl.Sandbox controller *controller resolver Resolver diff --git a/sandbox_dns_unix.go b/sandbox_dns_unix.go index f4d1fad605..4ea0c23771 100644 --- a/sandbox_dns_unix.go +++ b/sandbox_dns_unix.go @@ -14,6 +14,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/etchosts" "github.com/docker/libnetwork/resolvconf" + "github.com/docker/libnetwork/resolvconf/dns" "github.com/docker/libnetwork/types" ) @@ -161,6 +162,20 @@ func (sb *sandbox) restorePath() { } } +func (sb *sandbox) setExternalResolvers(content []byte, addrType int, checkLoopback bool) { + servers := resolvconf.GetNameservers(content, addrType) + for _, ip := range servers { + hostLoopback := false + if checkLoopback { + hostLoopback = dns.IsIPv4Localhost(ip) + } + sb.extDNS = append(sb.extDNS, extDNSEntry{ + ipStr: ip, + hostLoopback: hostLoopback, + }) + } +} + func (sb *sandbox) setupDNS() error { var newRC *resolvconf.File @@ -208,7 +223,17 @@ func (sb *sandbox) setupDNS() error { if err != nil { return err } + // After building the resolv.conf from the user config save the + // external resolvers in the sandbox. Note that --dns 127.0.0.x + // config refers to the loopback in the container namespace + sb.setExternalResolvers(newRC.Content, types.IPv4, false) } else { + // If the host resolv.conf file has 127.0.0.x container should + // use the host restolver for queries. This is supported by the + // docker embedded DNS server. Hence save the external resolvers + // before filtering it out. + sb.setExternalResolvers(currRC.Content, types.IPv4, true) + // Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true) if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil { return err @@ -297,7 +322,6 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error { // Embedded DNS server has to be enabled for this sandbox. Rebuild the container's // resolv.conf by doing the following -// - Save the external name servers in resolv.conf in the sandbox // - Add only the embedded server's IP to container's resolv.conf // - If the embedded server needs any resolv.conf options add it to the current list func (sb *sandbox) rebuildDNS() error { @@ -306,10 +330,9 @@ func (sb *sandbox) rebuildDNS() error { return err } - // localhost entries have already been filtered out from the list - // retain only the v4 servers in sb for forwarding the DNS queries - sb.extDNS = resolvconf.GetNameservers(currRC.Content, types.IPv4) - + if len(sb.extDNS) == 0 { + sb.setExternalResolvers(currRC.Content, types.IPv4, false) + } var ( dnsList = []string{sb.resolver.NameServer()} dnsOptionsList = resolvconf.GetOptions(currRC.Content) diff --git a/sandbox_store.go b/sandbox_store.go index 8b36d688a1..d50163ded5 100644 --- a/sandbox_store.go +++ b/sandbox_store.go @@ -27,7 +27,7 @@ type sbState struct { dbExists bool Eps []epState EpPriority map[string]int - ExtDNS []string + ExtDNS []extDNSEntry } func (sbs *sbState) Key() []string { From d94f688dec818a9416a2a5629e2fb82fc8a64e77 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Thu, 22 Dec 2016 04:30:40 +0000 Subject: [PATCH 181/799] proxy: fix an issue about half-closing net.TCPConn after io.Copy() Fix docker/docker#27539 After io.Copy(to, from), we should call to.CloseWrite(), not to.CloseRead(). Without this fix, TestTCP4ProxyHalfClose (newly added in this commit) fails as follows: --- FAIL: TestTCP4ProxyHalfClose (0.00s) network_proxy_test.go:135: EOF Signed-off-by: Akihiro Suda --- cmd/proxy/network_proxy_test.go | 74 ++++++++++++++++++++++++--------- cmd/proxy/tcp_proxy.go | 3 +- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/cmd/proxy/network_proxy_test.go b/cmd/proxy/network_proxy_test.go index 7f036b537f..be7f8754ce 100644 --- a/cmd/proxy/network_proxy_test.go +++ b/cmd/proxy/network_proxy_test.go @@ -5,6 +5,7 @@ import ( "flag" "fmt" "io" + "io/ioutil" "net" "strings" "testing" @@ -22,9 +23,14 @@ type EchoServer interface { LocalAddr() net.Addr } +type EchoServerOptions struct { + TCPHalfClose bool +} + type TCPEchoServer struct { listener net.Listener testCtx *testing.T + opts EchoServerOptions } type UDPEchoServer struct { @@ -32,15 +38,18 @@ type UDPEchoServer struct { testCtx *testing.T } -func NewEchoServer(t *testing.T, proto, address string) EchoServer { +func NewEchoServer(t *testing.T, proto, address string, opts EchoServerOptions) EchoServer { var server EchoServer if strings.HasPrefix(proto, "tcp") { listener, err := net.Listen(proto, address) if err != nil { t.Fatal(err) } - server = &TCPEchoServer{listener: listener, testCtx: t} + server = &TCPEchoServer{listener: listener, testCtx: t, opts: opts} } else { + if opts.TCPHalfClose { + t.Fatalf("TCPHalfClose is not supported for %s", proto) + } socket, err := net.ListenPacket(proto, address) if err != nil { t.Fatal(err) @@ -58,10 +67,21 @@ func (server *TCPEchoServer) Run() { return } go func(client net.Conn) { - if _, err := io.Copy(client, client); err != nil { - server.testCtx.Logf("can't echo to the client: %v\n", err.Error()) + if server.opts.TCPHalfClose { + data, err := ioutil.ReadAll(client) + if err != nil { + server.testCtx.Logf("io.ReadAll() failed for the client: %v\n", err.Error()) + } + if _, err := client.Write(data); err != nil { + server.testCtx.Logf("can't echo to the client: %v\n", err.Error()) + } + client.(*net.TCPConn).CloseWrite() + } else { + if _, err := io.Copy(client, client); err != nil { + server.testCtx.Logf("can't echo to the client: %v\n", err.Error()) + } + client.Close() } - client.Close() }(client) } }() @@ -92,7 +112,7 @@ func (server *UDPEchoServer) Run() { func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() } func (server *UDPEchoServer) Close() { server.conn.Close() } -func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) { +func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string, halfClose bool) { defer proxy.Close() go proxy.Run() client, err := net.Dial(proto, addr) @@ -104,6 +124,12 @@ func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) { if _, err = client.Write(testBuf); err != nil { t.Fatal(err) } + if halfClose { + if proto != "tcp" { + t.Fatalf("halfClose is not supported for %s", proto) + } + client.(*net.TCPConn).CloseWrite() + } recvBuf := make([]byte, testBufSize) if _, err = client.Read(recvBuf); err != nil { t.Fatal(err) @@ -113,12 +139,12 @@ func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) { } } -func testProxy(t *testing.T, proto string, proxy Proxy) { - testProxyAt(t, proto, proxy, proxy.FrontendAddr().String()) +func testProxy(t *testing.T, proto string, proxy Proxy, halfClose bool) { + testProxyAt(t, proto, proxy, proxy.FrontendAddr().String(), halfClose) } -func TestTCP4Proxy(t *testing.T) { - backend := NewEchoServer(t, "tcp", "127.0.0.1:0") +func testTCP4Proxy(t *testing.T, halfClose bool) { + backend := NewEchoServer(t, "tcp", "127.0.0.1:0", EchoServerOptions{TCPHalfClose: halfClose}) defer backend.Close() backend.Run() frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} @@ -126,12 +152,20 @@ func TestTCP4Proxy(t *testing.T) { if err != nil { t.Fatal(err) } - testProxy(t, "tcp", proxy) + testProxy(t, "tcp", proxy, halfClose) +} + +func TestTCP4Proxy(t *testing.T) { + testTCP4Proxy(t, false) +} + +func TestTCP4ProxyHalfClose(t *testing.T) { + testTCP4Proxy(t, true) } func TestTCP6Proxy(t *testing.T) { t.Skip("Need to start CI docker with --ipv6") - backend := NewEchoServer(t, "tcp", "[::1]:0") + backend := NewEchoServer(t, "tcp", "[::1]:0", EchoServerOptions{}) defer backend.Close() backend.Run() frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0} @@ -139,14 +173,14 @@ func TestTCP6Proxy(t *testing.T) { if err != nil { t.Fatal(err) } - testProxy(t, "tcp", proxy) + testProxy(t, "tcp", proxy, false) } func TestTCPDualStackProxy(t *testing.T) { // If I understand `godoc -src net favoriteAddrFamily` (used by the // net.Listen* functions) correctly this should work, but it doesn't. t.Skip("No support for dual stack yet") - backend := NewEchoServer(t, "tcp", "[::1]:0") + backend := NewEchoServer(t, "tcp", "[::1]:0", EchoServerOptions{}) defer backend.Close() backend.Run() frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0} @@ -158,11 +192,11 @@ func TestTCPDualStackProxy(t *testing.T) { IP: net.IPv4(127, 0, 0, 1), Port: proxy.FrontendAddr().(*net.TCPAddr).Port, } - testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String()) + testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String(), false) } func TestUDP4Proxy(t *testing.T) { - backend := NewEchoServer(t, "udp", "127.0.0.1:0") + backend := NewEchoServer(t, "udp", "127.0.0.1:0", EchoServerOptions{}) defer backend.Close() backend.Run() frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} @@ -170,12 +204,12 @@ func TestUDP4Proxy(t *testing.T) { if err != nil { t.Fatal(err) } - testProxy(t, "udp", proxy) + testProxy(t, "udp", proxy, false) } func TestUDP6Proxy(t *testing.T) { t.Skip("Need to start CI docker with --ipv6") - backend := NewEchoServer(t, "udp", "[::1]:0") + backend := NewEchoServer(t, "udp", "[::1]:0", EchoServerOptions{}) defer backend.Close() backend.Run() frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0} @@ -183,7 +217,7 @@ func TestUDP6Proxy(t *testing.T) { if err != nil { t.Fatal(err) } - testProxy(t, "udp", proxy) + testProxy(t, "udp", proxy, false) } func TestUDPWriteError(t *testing.T) { @@ -204,7 +238,7 @@ func TestUDPWriteError(t *testing.T) { // Make sure the proxy doesn't stop when there is no actual backend: client.Write(testBuf) client.Write(testBuf) - backend := NewEchoServer(t, "udp", "127.0.0.1:25587") + backend := NewEchoServer(t, "udp", "127.0.0.1:25587", EchoServerOptions{}) defer backend.Close() backend.Run() client.SetDeadline(time.Now().Add(10 * time.Second)) diff --git a/cmd/proxy/tcp_proxy.go b/cmd/proxy/tcp_proxy.go index 1c713105db..700054af99 100644 --- a/cmd/proxy/tcp_proxy.go +++ b/cmd/proxy/tcp_proxy.go @@ -48,7 +48,8 @@ func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) { from.CloseWrite() } } - to.CloseRead() + from.CloseRead() + to.CloseWrite() wg.Done() } From 85949f610e2d4929de6d783dc7dda7de5eb9cec6 Mon Sep 17 00:00:00 2001 From: allencloud Date: Tue, 27 Dec 2016 19:46:10 +0800 Subject: [PATCH 182/799] make network connect error message readable Signed-off-by: allencloud --- network.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network.go b/network.go index e966dae001..7b6f519d15 100644 --- a/network.go +++ b/network.go @@ -885,7 +885,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi } if _, err = n.EndpointByName(name); err == nil { - return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name) + return nil, types.ForbiddenErrorf("endpoint with name %s already exists in network %s", name, n.Name()) } ep := &endpoint{name: name, generic: make(map[string]interface{}), iface: &endpointInterface{}} From c1865b811b6247cc0a52c4f7a253fc05372b3d89 Mon Sep 17 00:00:00 2001 From: allencloud Date: Tue, 27 Dec 2016 19:42:32 +0800 Subject: [PATCH 183/799] fix nits in comments Signed-off-by: allencloud --- controller.go | 6 +++--- docs/macvlan.md | 4 ++-- driverapi/driverapi.go | 4 ++-- drivers/windows/overlay/peerdb_windows.go | 2 +- libnetwork_linux_test.go | 2 +- sandbox.go | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/controller.go b/controller.go index aa92b88f6b..23510dcef4 100644 --- a/controller.go +++ b/controller.go @@ -273,7 +273,7 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error { } for s, count := range subsysKeys { if count != keyringSize { - return fmt.Errorf("incorrect number of keys for susbsystem %v", s) + return fmt.Errorf("incorrect number of keys for subsystem %v", s) } } @@ -582,7 +582,7 @@ func (c *controller) pushNodeDiscovery(d driverapi.Driver, cap driverapi.Capabil err = d.DiscoverDelete(discoverapi.NodeDiscovery, nodeData) } if err != nil { - logrus.Debugf("discovery notification error : %v", err) + logrus.Debugf("discovery notification error: %v", err) } } } @@ -997,7 +997,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s err = sb.storeUpdate() if err != nil { - return nil, fmt.Errorf("updating the store state of sandbox failed: %v", err) + return nil, fmt.Errorf("failed to update the store state of sandbox: %v", err) } return sb, nil diff --git a/docs/macvlan.md b/docs/macvlan.md index 9193220e5e..b6b02fd2fb 100644 --- a/docs/macvlan.md +++ b/docs/macvlan.md @@ -38,7 +38,7 @@ There are positive performance implication as a result of bypassing the Linux br - The driver limits one network per parent interface. The driver does however accommodate secondary subnets to be allocated in a single Docker network for a multi-subnet requirement. The upstream router is responsible for proxy-arping between the two subnets. -- Any Macvlan container sharing the same subnet can communicate via IP to any other container in the same subnet without a gateway. It is important to note, that the parent will go into promiscuous mode when a container is attached to the parent since each container has a unique MAC address. Alternatively, Ipvlan which is currently a experimental driver uses the same MAC address as the parent interface and thus precluding the need for the parent being promiscuous. +- Any Macvlan container sharing the same subnet can communicate via IP to any other container in the same subnet without a gateway. It is important to note, that the parent will go into promiscuous mode when a container is attached to the parent since each container has a unique MAC address. Alternatively, Ipvlan which is currently an experimental driver uses the same MAC address as the parent interface and thus precluding the need for the parent being promiscuous. In the following example, `eth0` on the docker host has an IP on the `172.16.86.0/24` network and a default gateway of `172.16.86.1`. The gateway is an external router with an address of `172.16.86.1`. An IP address is not required on the Docker host interface `eth0` in `bridge` mode, it merely needs to be on the proper upstream network to get forwarded by a network switch or network router. @@ -150,7 +150,7 @@ In the case of a host reboot, instead of needing to modify often complex network The same holds true if the network is deleted `docker network rm`. If driver created the sub-interface with `docker network create` it will remove the sub-interface link for the operator. -If the user doesn't want Docker to create and delete the `-o parent` sub-interface, then you simply pass a interface that already exists as the parent link. Parent interfaces such as `eth0` are not deleted, only interfaces that are slave links. +If the user doesn't want Docker to create and delete the `-o parent` sub-interface, then you simply pass an interface that already exists as the parent link. Parent interfaces such as `eth0` are not deleted, only interfaces that are slave links. For the driver to add/delete the vlan sub-interfaces the format needs to be `-o parent interface_name.vlan_tag`. diff --git a/driverapi/driverapi.go b/driverapi/driverapi.go index 6e66ea221e..7fe6f611a4 100644 --- a/driverapi/driverapi.go +++ b/driverapi/driverapi.go @@ -62,7 +62,7 @@ type Driver interface { // programming to allow the external connectivity dictated by the passed options ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error - // RevokeExternalConnectivity aks the driver to remove any external connectivity + // RevokeExternalConnectivity asks the driver to remove any external connectivity // programming that was done so far RevokeExternalConnectivity(nid, eid string) error @@ -72,7 +72,7 @@ type Driver interface { // only invoked for the global scope driver. EventNotify(event EventType, nid string, tableName string, key string, value []byte) - // Type returns the the type of this driver, the network type this driver manages + // Type returns the type of this driver, the network type this driver manages Type() string // IsBuiltIn returns true if it is a built-in driver diff --git a/drivers/windows/overlay/peerdb_windows.go b/drivers/windows/overlay/peerdb_windows.go index 47f4bfbcc4..20f190f86e 100644 --- a/drivers/windows/overlay/peerdb_windows.go +++ b/drivers/windows/overlay/peerdb_windows.go @@ -81,7 +81,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, return err } - // Temp: We have to create a endpoint object to keep track of the HNS ID for + // Temp: We have to create an endpoint object to keep track of the HNS ID for // this endpoint so that we can retrieve it later when the endpoint is deleted. // This seems unnecessary when we already have dockers EID. See if we can pass // the global EID to HNS to use as it's ID, rather than having each HNS assign diff --git a/libnetwork_linux_test.go b/libnetwork_linux_test.go index 2cbc00ec75..db1eee1c89 100644 --- a/libnetwork_linux_test.go +++ b/libnetwork_linux_test.go @@ -318,7 +318,7 @@ func TestEndpointJoin(t *testing.T) { } if info.Sandbox() == nil { - t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key") + t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found an empty sandbox key") } // Check endpoint provided container information diff --git a/sandbox.go b/sandbox.go index a3e890503a..48b95f66e1 100644 --- a/sandbox.go +++ b/sandbox.go @@ -45,7 +45,7 @@ type Sandbox interface { // EnableService makes a managed container's service available by adding the // endpoint to the service load balancer and service discovery EnableService() error - // DisableService removes a managed contianer's endpoints from the load balancer + // DisableService removes a managed container's endpoints from the load balancer // and service discovery DisableService() error } From fd0448a568ee80e838d7369c63a30133da58a321 Mon Sep 17 00:00:00 2001 From: yupeng Date: Wed, 28 Dec 2016 15:46:22 +0800 Subject: [PATCH 184/799] fix typos Signed-off-by: yupeng --- docs/remote.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/remote.md b/docs/remote.md index d7a49e3276..bedbd676de 100644 --- a/docs/remote.md +++ b/docs/remote.md @@ -31,7 +31,7 @@ The remote driver protocol is a set of RPCs, issued as HTTP POSTs with JSON payl If the remote process cannot decode, or otherwise detects a syntactic problem with the HTTP request or payload, it must respond with an HTTP error status (4xx or 5xx). -If the remote process http server receives a request for an unknown URI, it should respond with the HTTP StatusCode `404 Not Found`. This allows libnetwork to detect when a remote driver does not implement yet a newly added method, therefore not to deem the request as failed. +If the remote process http server receives a request for an unknown URI, it should respond with the HTTP StatusCode `404 Not Found`. This allows LibNetwork to detect when a remote driver does not implement yet a newly added method, therefore not to deem the request as failed. If the remote process can decode the request, but cannot complete the operation, it must send a response in the form @@ -101,7 +101,7 @@ When the proxy is asked to create a network, the remote process shall receive a * `IPv4Data` and `IPv6Data` are the ip-addressing data configured by the user and managed by IPAM driver. The network driver is expected to honor the ip-addressing data supplied by IPAM driver. The data include, * `AddressSpace` : A unique string represents an isolated space for IP Addressing * `Pool` : A range of IP Addresses represted in CIDR format address/mask. Since, the IPAM driver is responsible for allocating container ip-addresses, the network driver can make use of this information for the network plumbing purposes. -* `Gateway` : Optionally, the IPAM driver may provide a Gateway for the subnet represented by the Pool. the network driver can make use of this information for the network plumbing purposes. +* `Gateway` : Optionally, the IPAM driver may provide a Gateway for the subnet represented by the Pool. The network driver can make use of this information for the network plumbing purposes. * `AuxAddresses` : A list of pre-allocated ip-addresses with an associated identifier as provided by the user to assist network driver if it requires specific ip-addresses for its operation. The response indicating success is empty: @@ -224,7 +224,7 @@ The entries in `"StaticRoutes"` represent routes that should be added to an inte Routes are either given a `RouteType` of `0` and a value for `NextHop`; or, a `RouteType` of `1` and no value for `NextHop`, meaning a connected route. -If no gateway and no default static route is set by the driver in the Join response, libnetwork will add an additional interface to the sandbox connecting to a default gateway network (a bridge network named *docker_gwbridge*) and program the default gateway into the sandbox accordingly, pointing to the interface address of the bridge *docker_gwbridge*. +If no gateway and no default static route is set by the driver in the Join response, LibNetwork will add an additional interface to the sandbox connecting to a default gateway network (a bridge network named *docker_gwbridge*) and program the default gateway into the sandbox accordingly, pointing to the interface address of the bridge *docker_gwbridge*. ### Leave @@ -241,7 +241,7 @@ where `NetworkID` and `EndpointID` have meanings as above. The success response ### DiscoverNew Notification -libnetwork listens to inbuilt docker discovery notifications and passes it along to the interested drivers. +LibNetwork listens to inbuilt docker discovery notifications and passes it along to the interested drivers. When the proxy receives a DiscoverNew notification, the remote process shall receive a POST to the URL `/NetworkDriver.DiscoverNew` of the form From 6c0e2b449923f19cda2487b95b4368dcadd0e2a7 Mon Sep 17 00:00:00 2001 From: Yi EungJun Date: Tue, 9 Aug 2016 14:34:36 +0900 Subject: [PATCH 185/799] docs/remote.md: Remove unnecessary backquote Signed-off-by: Yi EungJun --- docs/remote.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/remote.md b/docs/remote.md index d7a49e3276..aa75f0c92d 100644 --- a/docs/remote.md +++ b/docs/remote.md @@ -106,7 +106,7 @@ When the proxy is asked to create a network, the remote process shall receive a The response indicating success is empty: - `{}` + {} ### Delete network @@ -257,7 +257,7 @@ When the proxy receives a DiscoverNew notification, the remote process shall rec The response indicating success is empty: - `{}` + {} * Node Discovery @@ -287,7 +287,7 @@ When the proxy receives a DiscoverDelete notification, the remote process shall The response indicating success is empty: - `{}` + {} * Node Discovery From b643d27cbab01bbe34076e3769db8f939c8bf52f Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Thu, 29 Dec 2016 11:33:25 -0800 Subject: [PATCH 186/799] ResolveName should return copy of IPs Signed-off-by: Santhosh Manohar --- network.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/network.go b/network.go index e966dae001..a388829c8e 100644 --- a/network.go +++ b/network.go @@ -1645,7 +1645,9 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) { } if ip != nil { - return ip, false + ipLocal := make([]net.IP, len(ip)) + copy(ipLocal, ip) + return ipLocal, false } return nil, ipv6Miss From f774a9e5754d9b593c7dada223dc59528fc17615 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 3 Jan 2017 11:39:04 -0800 Subject: [PATCH 187/799] Prioritize nw endpoint which can provide both v4 and v6 connectivity - when selecting sandbox's default gw Signed-off-by: Alessandro Boch --- sandbox.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sandbox.go b/sandbox.go index 48b95f66e1..6767026369 100644 --- a/sandbox.go +++ b/sandbox.go @@ -1174,6 +1174,17 @@ func (eh epHeap) Less(i, j int) bool { return true } + if epi.joinInfo != nil && epj.joinInfo != nil { + if (epi.joinInfo.gw != nil && epi.joinInfo.gw6 != nil) && + (epj.joinInfo.gw == nil || epj.joinInfo.gw6 == nil) { + return true + } + if (epj.joinInfo.gw != nil && epj.joinInfo.gw6 != nil) && + (epi.joinInfo.gw == nil || epi.joinInfo.gw6 == nil) { + return false + } + } + if ci != nil { cip, ok = ci.epPriority[eh[i].ID()] if !ok { From a14b145b0248c5991ee4ed7f2792bc7599f9a209 Mon Sep 17 00:00:00 2001 From: Xianjie Date: Mon, 26 Sep 2016 18:37:24 +0800 Subject: [PATCH 188/799] fix json Signed-off-by: user.name Signed-off-by: datastream --- docs/ipam.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ipam.md b/docs/ipam.md index 8de0abbe44..7eeada0b94 100644 --- a/docs/ipam.md +++ b/docs/ipam.md @@ -212,8 +212,8 @@ A successful response is in the form: { - Address: string - Data: map[string]string + "Address": string + "Data": map[string]string } @@ -230,7 +230,7 @@ For this API, the remote driver will receive a POST message to the URL `/IpamDri { "PoolID": string - "Address: string + "Address": string } Where: From 8bfb39f1e67a1579a0381011aaafc09ce1becd2f Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 22 Dec 2016 14:19:31 -0800 Subject: [PATCH 189/799] Updating Godeps to pull in plugingetter dependancy Signed-off-by: Madhu Venugopal --- Godeps/Godeps.json | 4 ++-- .../docker/docker/pkg/plugingetter/getter.go | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index e5d0df3bbf..1df58416ab 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -143,8 +143,8 @@ }, { "ImportPath": "github.com/docker/docker/pkg/plugingetter", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" + "Comment": "docs-v1.12.0-rc4-2016-07-15-4185-ge4512d2", + "Rev": "e4512d264741e83e954a19f9ef5e3cb06c5856b6" }, { "ImportPath": "github.com/docker/docker/pkg/plugins", diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go index cd8214cae9..6c2c82c670 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go @@ -5,22 +5,31 @@ import "github.com/docker/docker/pkg/plugins" const ( // LOOKUP doesn't update RefCount LOOKUP = 0 - // CREATE increments RefCount - CREATE = 1 - // REMOVE decrements RefCount - REMOVE = -1 + // ACQUIRE increments RefCount + ACQUIRE = 1 + // RELEASE decrements RefCount + RELEASE = -1 ) -// CompatPlugin is a abstraction to handle both v2(new) and v1(legacy) plugins. +// CompatPlugin is an abstraction to handle both v2(new) and v1(legacy) plugins. type CompatPlugin interface { Client() *plugins.Client Name() string + BasePath() string IsV1() bool } +// CountedPlugin is a plugin which is reference counted. +type CountedPlugin interface { + Acquire() + Release() + CompatPlugin +} + // PluginGetter is the interface implemented by Store type PluginGetter interface { Get(name, capability string, mode int) (CompatPlugin, error) GetAllByCap(capability string) ([]CompatPlugin, error) + GetAllManagedPluginsByCap(capability string) []CompatPlugin Handle(capability string, callback func(string, *plugins.Client)) } From a4e5218e6387393104c8860b135af3f9f0f4aa31 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 22 Dec 2016 13:46:19 -0800 Subject: [PATCH 190/799] Make use of GetAllManagedPluginsForCap to avoid loading v1-plugins Read this for more details : https://github.com/docker/docker/pull/29665 Signed-off-by: Madhu Venugopal --- drivers/remote/driver.go | 2 +- ipams/remote/remote.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/remote/driver.go b/drivers/remote/driver.go index 12a8fb0cdb..f35a941f09 100644 --- a/drivers/remote/driver.go +++ b/drivers/remote/driver.go @@ -46,7 +46,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { handleFunc := plugins.Handle if pg := dc.GetPluginGetter(); pg != nil { handleFunc = pg.Handle - activePlugins, _ := pg.GetAllByCap(driverapi.NetworkPluginEndpointType) + activePlugins := pg.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType) for _, ap := range activePlugins { newPluginHandler(ap.Name(), ap.Client()) } diff --git a/ipams/remote/remote.go b/ipams/remote/remote.go index 3da05260e6..d2e2b4f3c8 100644 --- a/ipams/remote/remote.go +++ b/ipams/remote/remote.go @@ -50,7 +50,7 @@ func Init(cb ipamapi.Callback, l, g interface{}) error { handleFunc := plugins.Handle if pg := cb.GetPluginGetter(); pg != nil { handleFunc = pg.Handle - activePlugins, _ := pg.GetAllByCap(ipamapi.PluginEndpointType) + activePlugins := pg.GetAllManagedPluginsByCap(ipamapi.PluginEndpointType) for _, ap := range activePlugins { newPluginHandler(ap.Name(), ap.Client()) } From 287d14c9e0508bc65da30989732ad8f257f0f123 Mon Sep 17 00:00:00 2001 From: realityone Date: Mon, 24 Oct 2016 15:52:48 +0800 Subject: [PATCH 191/799] return an error on overlay subnet is overlapped with hosts Signed-off-by: realityone --- drivers/overlay/ov_network.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/overlay/ov_network.go b/drivers/overlay/ov_network.go index 703d13f9a5..122c3f6b1b 100644 --- a/drivers/overlay/ov_network.go +++ b/drivers/overlay/ov_network.go @@ -402,7 +402,7 @@ func (n *network) getBridgeNamePrefix(s *subnet) string { return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s)) } -func isOverlap(nw *net.IPNet) bool { +func checkOverlap(nw *net.IPNet) error { var nameservers []string if rc, err := resolvconf.Get(); err == nil { @@ -410,14 +410,14 @@ func isOverlap(nw *net.IPNet) bool { } if err := netutils.CheckNameserverOverlaps(nameservers, nw); err != nil { - return true + return fmt.Errorf("overlay subnet %s failed check with nameserver: %v: %v", nw.String(), nameservers, err) } if err := netutils.CheckRouteOverlaps(nw); err != nil { - return true + return fmt.Errorf("overlay subnet %s failed check with host route table: %v", nw.String(), err) } - return false + return nil } func (n *network) restoreSubnetSandbox(s *subnet, brName, vxlanName string) error { @@ -456,8 +456,8 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error // Try to delete the vxlan interface by vni if already present deleteVxlanByVNI("", n.vxlanID(s)) - if isOverlap(s.subnetIP) { - return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String()) + if err := checkOverlap(s.subnetIP); err != nil { + return err } } From 6f43b46432050dfe23e91cff65e30c61591ca427 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 10 Jan 2017 13:11:48 -0800 Subject: [PATCH 192/799] Godep update for docker plugingetter pkg Signed-off-by: Santhosh Manohar --- Godeps/Godeps.json | 4 ++-- .../docker/docker/pkg/plugingetter/getter.go | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 1df58416ab..8430829943 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -143,8 +143,8 @@ }, { "ImportPath": "github.com/docker/docker/pkg/plugingetter", - "Comment": "docs-v1.12.0-rc4-2016-07-15-4185-ge4512d2", - "Rev": "e4512d264741e83e954a19f9ef5e3cb06c5856b6" + "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-g9c96768", + "Rev": "9c96768eae4b3a65147b47a55c850c103ab8972d" }, { "ImportPath": "github.com/docker/docker/pkg/plugins", diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go index 6c2c82c670..b04b7bc828 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/plugingetter/getter.go @@ -3,12 +3,12 @@ package plugingetter import "github.com/docker/docker/pkg/plugins" const ( - // LOOKUP doesn't update RefCount - LOOKUP = 0 - // ACQUIRE increments RefCount - ACQUIRE = 1 - // RELEASE decrements RefCount - RELEASE = -1 + // Lookup doesn't update RefCount + Lookup = 0 + // Acquire increments RefCount + Acquire = 1 + // Release decrements RefCount + Release = -1 ) // CompatPlugin is an abstraction to handle both v2(new) and v1(legacy) plugins. From ec570ad8c6fc1fd7ba18326cc2c1611d2db8625e Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Tue, 10 Jan 2017 13:17:15 -0800 Subject: [PATCH 193/799] carry docker/docker #29564 Signed-off-by: Santhosh Manohar --- controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller.go b/controller.go index b82d59b3df..24d71e4325 100644 --- a/controller.go +++ b/controller.go @@ -1088,7 +1088,7 @@ func (c *controller) loadDriver(networkType string) error { var err error if pg := c.GetPluginGetter(); pg != nil { - _, err = pg.Get(networkType, driverapi.NetworkPluginEndpointType, plugingetter.LOOKUP) + _, err = pg.Get(networkType, driverapi.NetworkPluginEndpointType, plugingetter.Lookup) } else { _, err = plugins.Get(networkType, driverapi.NetworkPluginEndpointType) } @@ -1107,7 +1107,7 @@ func (c *controller) loadIPAMDriver(name string) error { var err error if pg := c.GetPluginGetter(); pg != nil { - _, err = pg.Get(name, ipamapi.PluginEndpointType, plugingetter.LOOKUP) + _, err = pg.Get(name, ipamapi.PluginEndpointType, plugingetter.Lookup) } else { _, err = plugins.Get(name, ipamapi.PluginEndpointType) } From 54b97aee7814c57789f666c60eb8521b9ee61e92 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Wed, 11 Jan 2017 00:21:56 -0800 Subject: [PATCH 194/799] Use vndr for managing libnetwork dependencies Signed-off-by: Santhosh Manohar --- Godeps/Godeps.json | 444 - Godeps/Readme | 5 - Godeps/_workspace/.gitignore | 2 - .../github.com/Azure/go-ansiterm/README.md | 9 - .../src/github.com/BurntSushi/toml/.gitignore | 5 - .../github.com/BurntSushi/toml/.travis.yml | 12 - .../src/github.com/BurntSushi/toml/COMPATIBLE | 3 - .../src/github.com/BurntSushi/toml/Makefile | 19 - .../src/github.com/BurntSushi/toml/README.md | 220 - .../github.com/BurntSushi/toml/session.vim | 1 - .../github.com/Microsoft/go-winio/.gitignore | 1 - .../github.com/Microsoft/go-winio/README.md | 22 - .../github.com/Microsoft/hcsshim/README.md | 12 - .../src/github.com/Sirupsen/logrus/.gitignore | 1 - .../github.com/Sirupsen/logrus/.travis.yml | 9 - .../github.com/Sirupsen/logrus/CHANGELOG.md | 66 - .../src/github.com/Sirupsen/logrus/README.md | 388 - .../github.com/armon/go-metrics/.gitignore | 22 - .../src/github.com/armon/go-metrics/README.md | 68 - .../src/github.com/armon/go-radix/.gitignore | 22 - .../src/github.com/armon/go-radix/.travis.yml | 3 - .../src/github.com/armon/go-radix/README.md | 36 - .../src/github.com/boltdb/bolt/.gitignore | 4 - .../src/github.com/boltdb/bolt/Makefile | 18 - .../src/github.com/boltdb/bolt/README.md | 844 - .../src/github.com/boltdb/bolt/appveyor.yml | 18 - .../github.com/codegangsta/cli/.travis.yml | 13 - .../src/github.com/codegangsta/cli/README.md | 316 - .../github.com/coreos/etcd/client/README.md | 94 - .../coreos/etcd/client/cancelreq_go14.go | 17 - .../coreos/etcd/client/keys.generated.go | 891 - .../github.com/deckarep/golang-set/.gitignore | 22 - .../deckarep/golang-set/.travis.yml | 9 - .../github.com/deckarep/golang-set/README.md | 94 - .../docker/api/types/versions/README.md | 14 - .../docker/docker/pkg/discovery/README.md | 41 - .../docker/docker/pkg/locker/README.md | 65 - .../docker/docker/pkg/mflag/LICENSE | 27 - .../docker/docker/pkg/mflag/README.md | 40 - .../docker/docker/pkg/mflag/flag.go | 1280 - .../docker/docker/pkg/reexec/README.md | 5 - .../docker/docker/pkg/signal/README.md | 1 - .../docker/docker/pkg/stringid/README.md | 1 - .../docker/docker/pkg/symlink/LICENSE.APACHE | 191 - .../docker/docker/pkg/symlink/LICENSE.BSD | 27 - .../docker/docker/pkg/symlink/README.md | 6 - .../docker/docker/pkg/system/filesys.go | 19 - .../docker/pkg/system/filesys_windows.go | 82 - .../src/github.com/docker/engine-api/LICENSE | 191 - .../docker/go-connections/sockets/README.md | 0 .../github.com/docker/go-events/.gitignore | 24 - .../src/github.com/docker/go-events/README.md | 112 - .../docker/go-units/CONTRIBUTING.md | 67 - .../github.com/docker/go-units/LICENSE.code | 191 - .../github.com/docker/go-units/LICENSE.docs | 425 - .../github.com/docker/go-units/MAINTAINERS | 27 - .../src/github.com/docker/go-units/README.md | 18 - .../src/github.com/docker/go-units/circle.yml | 11 - .../src/github.com/docker/libkv/.travis.yml | 31 - .../src/github.com/docker/libkv/LICENSE.code | 191 - .../src/github.com/docker/libkv/LICENSE.docs | 425 - .../src/github.com/docker/libkv/MAINTAINERS | 40 - .../src/github.com/docker/libkv/README.md | 107 - .../github.com/godbus/dbus/CONTRIBUTING.md | 50 - .../src/github.com/godbus/dbus/MAINTAINERS | 2 - .../github.com/godbus/dbus/README.markdown | 41 - .../gogo/protobuf/gogoproto/Makefile | 36 - .../gogo/protobuf/gogoproto/gogo.pb.golden | 45 - .../github.com/gogo/protobuf/proto/Makefile | 43 - .../protoc-gen-gogo/descriptor/Makefile | 33 - .../github.com/golang/protobuf/proto/Makefile | 43 - .../github.com/gorilla/context/.travis.yml | 9 - .../src/github.com/gorilla/context/README.md | 7 - .../src/github.com/gorilla/mux/.travis.yml | 7 - .../src/github.com/gorilla/mux/README.md | 7 - .../github.com/hashicorp/consul/api/README.md | 39 - .../hashicorp/go-msgpack/codec/README.md | 174 - .../go-msgpack/codec/msgpack_test.py | 110 - .../hashicorp/go-multierror/README.md | 91 - .../hashicorp/memberlist/.gitignore | 25 - .../github.com/hashicorp/memberlist/Makefile | 14 - .../github.com/hashicorp/memberlist/README.md | 144 - .../github.com/hashicorp/memberlist/todo.md | 6 - .../mattn/go-shellwords/.travis.yml | 8 - .../github.com/mattn/go-shellwords/README.md | 47 - .../src/github.com/miekg/dns/.gitignore | 4 - .../src/github.com/miekg/dns/.travis.yml | 7 - .../src/github.com/miekg/dns/AUTHORS | 1 - .../src/github.com/miekg/dns/CONTRIBUTORS | 9 - .../src/github.com/miekg/dns/COPYRIGHT | 9 - .../src/github.com/miekg/dns/README.md | 153 - .../runc/libcontainer/README.md | 152 - .../opencontainers/runc/libcontainer/SPEC.md | 334 - .../runc/libcontainer/criurpc/Makefile | 2 - .../runc/libcontainer/user/MAINTAINERS | 2 - .../seccomp/libseccomp-golang/README | 26 - .../github.com/stretchr/testify/LICENCE.txt | 9 - .../src/github.com/ugorji/go/codec/README.md | 148 - .../ugorji/go/codec/fast-path.go.tmpl | 442 - .../ugorji/go/codec/gen-dec-array.go.tmpl | 80 - .../ugorji/go/codec/gen-dec-map.go.tmpl | 46 - .../ugorji/go/codec/gen-helper.generated.go | 102 - .../ugorji/go/codec/gen.generated.go | 139 - .../src/github.com/ugorji/go/codec/noop.go | 164 - .../github.com/ugorji/go/codec/prebuild.sh | 193 - .../ugorji/go/codec/test-cbor-goldens.json | 639 - .../src/github.com/ugorji/go/codec/test.py | 119 - .../vishvananda/netlink/.travis.yml | 8 - .../github.com/vishvananda/netlink/Makefile | 29 - .../github.com/vishvananda/netlink/README.md | 89 - .../github.com/vishvananda/netns/README.md | 49 - .../src/golang.org/x/sys/unix/.gitignore | 1 - .../src/golang.org/x/sys/unix/mkall.sh | 274 - .../src/golang.org/x/sys/unix/mkerrors.sh | 476 - .../src/golang.org/x/sys/unix/mksyscall.pl | 323 - .../x/sys/unix/mksyscall_solaris.pl | 294 - .../golang.org/x/sys/unix/mksysctl_openbsd.pl | 264 - .../golang.org/x/sys/unix/mksysnum_darwin.pl | 39 - .../x/sys/unix/mksysnum_dragonfly.pl | 50 - .../golang.org/x/sys/unix/mksysnum_freebsd.pl | 63 - .../golang.org/x/sys/unix/mksysnum_linux.pl | 58 - .../golang.org/x/sys/unix/mksysnum_netbsd.pl | 58 - .../golang.org/x/sys/unix/mksysnum_openbsd.pl | 50 - .../x/sys/unix/syscall_dragonfly_386.go | 63 - .../x/sys/unix/zerrors_dragonfly_386.go | 1530 - .../x/sys/unix/zsysnum_dragonfly_386.go | 304 - .../x/sys/unix/ztypes_dragonfly_386.go | 437 - .../src/golang.org/x/sys/windows/asm.s | 8 - Makefile | 18 +- vendor.conf | 42 + .../github.com/Azure/go-ansiterm/LICENSE | 0 .../github.com/Azure/go-ansiterm/constants.go | 0 .../github.com/Azure/go-ansiterm/context.go | 0 .../Azure/go-ansiterm/csi_entry_state.go | 0 .../Azure/go-ansiterm/csi_param_state.go | 0 .../go-ansiterm/escape_intermediate_state.go | 0 .../Azure/go-ansiterm/escape_state.go | 0 .../Azure/go-ansiterm/event_handler.go | 0 .../Azure/go-ansiterm/ground_state.go | 0 .../Azure/go-ansiterm/osc_string_state.go | 0 .../github.com/Azure/go-ansiterm/parser.go | 0 .../go-ansiterm/parser_action_helpers.go | 0 .../Azure/go-ansiterm/parser_actions.go | 0 .../github.com/Azure/go-ansiterm/states.go | 0 .../github.com/Azure/go-ansiterm/utilities.go | 0 .../Azure/go-ansiterm/winterm/ansi.go | 0 .../Azure/go-ansiterm/winterm/api.go | 0 .../go-ansiterm/winterm/attr_translation.go | 0 .../go-ansiterm/winterm/cursor_helpers.go | 0 .../go-ansiterm/winterm/erase_helpers.go | 0 .../go-ansiterm/winterm/scroll_helper.go | 0 .../Azure/go-ansiterm/winterm/utilities.go | 0 .../go-ansiterm/winterm/win_event_handler.go | 0 .../github.com/BurntSushi/toml/COPYING | 0 .../github.com/BurntSushi/toml/decode.go | 0 .../github.com/BurntSushi/toml/decode_meta.go | 0 .../github.com/BurntSushi/toml/doc.go | 0 .../github.com/BurntSushi/toml/encode.go | 0 .../BurntSushi/toml/encoding_types.go | 0 .../BurntSushi/toml/encoding_types_1.1.go | 0 .../github.com/BurntSushi/toml/lex.go | 0 .../github.com/BurntSushi/toml/parse.go | 0 .../github.com/BurntSushi/toml/type_check.go | 0 .../github.com/BurntSushi/toml/type_fields.go | 0 .../github.com/Microsoft/go-winio/LICENSE | 0 .../github.com/Microsoft/go-winio/backup.go | 0 .../github.com/Microsoft/go-winio/file.go | 0 .../github.com/Microsoft/go-winio/fileinfo.go | 0 .../github.com/Microsoft/go-winio/pipe.go | 0 .../Microsoft/go-winio/privilege.go | 0 .../github.com/Microsoft/go-winio/reparse.go | 0 .../github.com/Microsoft/go-winio/sd.go | 0 .../github.com/Microsoft/go-winio/syscall.go | 0 .../github.com/Microsoft/go-winio/zsyscall.go | 0 .../github.com/Microsoft/hcsshim/LICENSE | 0 .../Microsoft/hcsshim/activatelayer.go | 0 .../github.com/Microsoft/hcsshim/baselayer.go | 0 .../github.com/Microsoft/hcsshim/callback.go | 0 .../github.com/Microsoft/hcsshim/cgo.go | 0 .../github.com/Microsoft/hcsshim/container.go | 0 .../Microsoft/hcsshim/createlayer.go | 0 .../Microsoft/hcsshim/createsandboxlayer.go | 0 .../Microsoft/hcsshim/deactivatelayer.go | 0 .../Microsoft/hcsshim/destroylayer.go | 0 .../github.com/Microsoft/hcsshim/errors.go | 0 .../Microsoft/hcsshim/expandsandboxsize.go | 0 .../Microsoft/hcsshim/exportlayer.go | 0 .../Microsoft/hcsshim/getlayermountpath.go | 0 .../Microsoft/hcsshim/getsharedbaseimages.go | 0 .../github.com/Microsoft/hcsshim/guid.go | 0 .../github.com/Microsoft/hcsshim/hcsshim.go | 0 .../github.com/Microsoft/hcsshim/hnsfuncs.go | 0 .../Microsoft/hcsshim/importlayer.go | 0 .../github.com/Microsoft/hcsshim/interface.go | 0 .../Microsoft/hcsshim/layerexists.go | 0 .../Microsoft/hcsshim/layerutils.go | 0 .../github.com/Microsoft/hcsshim/legacy.go | 0 .../Microsoft/hcsshim/mksyscall_windows.go | 0 .../Microsoft/hcsshim/nametoguid.go | 0 .../Microsoft/hcsshim/preparelayer.go | 0 .../github.com/Microsoft/hcsshim/process.go | 0 .../Microsoft/hcsshim/processimage.go | 0 .../Microsoft/hcsshim/unpreparelayer.go | 0 .../github.com/Microsoft/hcsshim/utils.go | 0 .../github.com/Microsoft/hcsshim/version.go | 0 .../Microsoft/hcsshim/waithelper.go | 0 .../github.com/Microsoft/hcsshim/zhcsshim.go | 0 .../github.com/Sirupsen/logrus/LICENSE | 0 .../github.com/Sirupsen/logrus/doc.go | 0 .../github.com/Sirupsen/logrus/entry.go | 0 .../github.com/Sirupsen/logrus/exported.go | 0 .../github.com/Sirupsen/logrus/formatter.go | 0 .../github.com/Sirupsen/logrus/hooks.go | 0 .../Sirupsen/logrus/json_formatter.go | 0 .../github.com/Sirupsen/logrus/logger.go | 0 .../github.com/Sirupsen/logrus/logrus.go | 0 .../Sirupsen/logrus/terminal_bsd.go | 0 .../Sirupsen/logrus/terminal_linux.go | 0 .../Sirupsen/logrus/terminal_notwindows.go | 0 .../Sirupsen/logrus/terminal_solaris.go | 0 .../Sirupsen/logrus/terminal_windows.go | 0 .../Sirupsen/logrus/text_formatter.go | 0 .../github.com/Sirupsen/logrus/writer.go | 0 .../github.com/armon/go-metrics/LICENSE | 0 .../github.com/armon/go-metrics/const_unix.go | 0 .../armon/go-metrics/const_windows.go | 0 .../github.com/armon/go-metrics/inmem.go | 0 .../armon/go-metrics/inmem_signal.go | 0 .../github.com/armon/go-metrics/metrics.go | 0 .../github.com/armon/go-metrics/sink.go | 0 .../github.com/armon/go-metrics/start.go | 0 .../github.com/armon/go-metrics/statsd.go | 0 .../github.com/armon/go-metrics/statsite.go | 0 .../github.com/armon/go-radix/LICENSE | 0 .../github.com/armon/go-radix/radix.go | 0 .../github.com/boltdb/bolt/LICENSE | 0 .../github.com/boltdb/bolt/bolt_386.go | 0 .../github.com/boltdb/bolt/bolt_amd64.go | 0 .../github.com/boltdb/bolt/bolt_arm.go | 0 .../github.com/boltdb/bolt/bolt_arm64.go | 0 .../github.com/boltdb/bolt/bolt_linux.go | 0 .../github.com/boltdb/bolt/bolt_openbsd.go | 0 .../github.com/boltdb/bolt/bolt_ppc.go | 0 .../github.com/boltdb/bolt/bolt_ppc64.go | 0 .../github.com/boltdb/bolt/bolt_ppc64le.go | 0 .../github.com/boltdb/bolt/bolt_s390x.go | 0 .../github.com/boltdb/bolt/bolt_unix.go | 0 .../boltdb/bolt/bolt_unix_solaris.go | 0 .../github.com/boltdb/bolt/bolt_windows.go | 0 .../github.com/boltdb/bolt/boltsync_unix.go | 0 .../github.com/boltdb/bolt/bucket.go | 0 .../github.com/boltdb/bolt/cursor.go | 0 .../github.com/boltdb/bolt/db.go | 0 .../github.com/boltdb/bolt/doc.go | 0 .../github.com/boltdb/bolt/errors.go | 0 .../github.com/boltdb/bolt/freelist.go | 0 .../github.com/boltdb/bolt/node.go | 0 .../github.com/boltdb/bolt/page.go | 0 .../github.com/boltdb/bolt/tx.go | 0 .../github.com/codegangsta/cli/LICENSE | 0 .../github.com/codegangsta/cli/app.go | 0 .../github.com/codegangsta/cli/cli.go | 0 .../github.com/codegangsta/cli/command.go | 0 .../github.com/codegangsta/cli/context.go | 0 .../github.com/codegangsta/cli/flag.go | 0 .../github.com/codegangsta/cli/help.go | 0 .../github.com/coreos/etcd/LICENSE | 0 .../github.com/coreos/etcd/NOTICE | 0 .../coreos/etcd/client/auth_role.go | 36 +- .../coreos/etcd/client/auth_user.go | 69 +- .../coreos/etcd/client/cancelreq.go | 2 - .../github.com/coreos/etcd/client/client.go | 208 +- .../coreos/etcd/client/cluster_error.go | 8 +- .../github.com/coreos/etcd/client/curl.go | 2 +- .../github.com/coreos/etcd/client/discover.go | 4 +- .../github.com/coreos/etcd/client/doc.go | 4 +- .../coreos/etcd/client/keys.generated.go | 1087 + .../github.com/coreos/etcd/client/keys.go | 68 +- .../github.com/coreos/etcd/client/members.go | 34 +- .../github.com/coreos/etcd/client/srv.go | 8 +- vendor/github.com/coreos/etcd/client/util.go | 53 + .../coreos/etcd/pkg/pathutil/path.go | 2 + .../github.com/coreos/etcd/pkg/types/doc.go | 17 + .../github.com/coreos/etcd/pkg/types/id.go | 2 +- .../github.com/coreos/etcd/pkg/types/set.go | 2 +- .../github.com/coreos/etcd/pkg/types/slice.go | 2 +- .../github.com/coreos/etcd/pkg/types/urls.go | 14 +- .../coreos/etcd/pkg/types/urlsmap.go | 58 +- .../github.com/coreos/go-systemd/LICENSE | 0 .../github.com/coreos/go-systemd/dbus/dbus.go | 0 .../coreos/go-systemd/dbus/methods.go | 0 .../coreos/go-systemd/dbus/properties.go | 0 .../github.com/coreos/go-systemd/dbus/set.go | 0 .../coreos/go-systemd/dbus/subscription.go | 0 .../go-systemd/dbus/subscription_set.go | 0 .../github.com/coreos/go-systemd/util/util.go | 0 .../github.com/deckarep/golang-set/LICENSE | 0 .../github.com/deckarep/golang-set/set.go | 0 .../deckarep/golang-set/threadsafe.go | 0 .../deckarep/golang-set/threadunsafe.go | 0 .../github.com/docker/docker/LICENSE | 0 .../github.com/docker/docker/NOTICE | 0 .../docker/docker/api/types/auth.go | 22 + .../docker/docker/api/types/blkiodev/blkio.go | 23 + .../docker/docker/api/types/client.go | 378 + .../docker/docker/api/types/configs.go | 69 + .../docker/api/types/container/config.go | 62 + .../api/types/container/container_create.go | 21 + .../api/types/container/container_update.go | 17 + .../api/types/container/container_wait.go | 17 + .../docker/api/types/container/host_config.go | 333 + .../api/types/container/hostconfig_unix.go | 81 + .../api/types/container/hostconfig_windows.go | 87 + .../docker/docker/api/types/error_response.go | 13 + .../docker/docker/api/types/filters/parse.go | 5 +- .../docker/docker/api/types/id_response.go | 13 + .../docker/docker/api/types/image_summary.go | 49 + .../docker/docker/api/types/mount/mount.go | 113 + .../docker/api/types/network/network.go | 6 + .../docker/docker/api/types/plugin.go | 186 + .../docker/docker/api/types/plugin_device.go | 25 + .../docker/docker/api/types/plugin_env.go | 25 + .../docker/api/types/plugin_interface_type.go | 21 + .../docker/docker/api/types/plugin_mount.go | 37 + .../docker/api/types/plugin_responses.go | 64 + .../docker/docker/api/types/port.go | 23 + .../docker/api/types/registry/authenticate.go | 21 + .../docker/api/types/registry/registry.go | 104 + .../docker/docker/api/types/seccomp.go | 93 + .../api/types/service_update_response.go | 12 + .../docker/docker/api/types/stats.go | 178 + .../docker/api/types/strslice/strslice.go | 30 + .../docker/docker/api/types/swarm/common.go | 27 + .../docker/api/types/swarm/container.go | 46 + .../docker/docker/api/types/swarm/network.go | 111 + .../docker/docker/api/types/swarm/node.go | 114 + .../docker/docker/api/types/swarm/secret.go | 31 + .../docker/docker/api/types/swarm/service.go | 105 + .../docker/docker/api/types/swarm/swarm.go | 197 + .../docker/docker/api/types/swarm/task.go | 128 + .../docker/docker/api/types/types.go | 558 + .../docker/api/types/versions/compare.go | 0 .../docker/docker/api/types/volume.go | 58 + vendor/github.com/docker/docker/opts/env.go | 46 + .../github.com/docker/docker/opts/hosts.go | 18 +- .../docker/docker/opts/hosts_unix.go | 0 .../docker/docker/opts/hosts_windows.go | 0 .../github.com/docker/docker/opts/ip.go | 0 vendor/github.com/docker/docker/opts/mount.go | 171 + .../github.com/docker/docker/opts/opts.go | 83 + .../docker/docker/opts/opts_unix.go | 2 +- .../docker/docker/opts/opts_windows.go | 2 +- vendor/github.com/docker/docker/opts/port.go | 146 + .../docker/docker/opts/quotedstring.go | 37 + .../github.com/docker/docker/opts/runtime.go | 79 + .../github.com/docker/docker/opts/secret.go | 107 + .../docker/docker/opts/throttledevice.go | 111 + .../github.com/docker/docker/opts/ulimit.go | 57 + .../docker/docker/opts/weightdevice.go | 89 + .../docker/docker/pkg/discovery/backends.go | 4 +- .../docker/docker/pkg/discovery/discovery.go | 0 .../docker/docker/pkg/discovery/entry.go | 0 .../docker/docker/pkg/discovery/generator.go | 0 .../docker/docker/pkg/discovery/kv/kv.go | 4 +- .../docker/docker/pkg/homedir/homedir.go | 0 .../docker/pkg/homedir/homedir_linux.go | 23 + .../docker/pkg/homedir/homedir_others.go | 13 + .../docker/docker/pkg/idtools/idtools.go | 197 + .../docker/docker/pkg/idtools/idtools_unix.go | 204 + .../docker/pkg/idtools/idtools_windows.go | 25 + .../docker/pkg/idtools/usergroupadd_linux.go | 164 + .../pkg/idtools/usergroupadd_unsupported.go | 12 + .../docker/docker/pkg/idtools/utils_unix.go | 32 + .../docker/docker/pkg/ioutils/buffer.go | 0 .../docker/docker/pkg/ioutils/bytespipe.go | 0 .../docker/docker/pkg/ioutils/fmt.go | 0 .../docker/docker/pkg/ioutils/fswriters.go | 0 .../docker/docker/pkg/ioutils/multireader.go | 8 +- .../docker/docker/pkg/ioutils/readers.go | 0 .../docker/docker/pkg/ioutils/temp_unix.go | 0 .../docker/docker/pkg/ioutils/temp_windows.go | 0 .../docker/docker/pkg/ioutils/writeflusher.go | 0 .../docker/docker/pkg/ioutils/writers.go | 0 .../docker/docker/pkg/locker/locker.go | 0 .../docker/docker/pkg/longpath/longpath.go | 0 .../docker/docker/pkg/mount/flags.go | 0 .../docker/docker/pkg/mount/flags_freebsd.go | 0 .../docker/docker/pkg/mount/flags_linux.go | 0 .../docker/pkg/mount/flags_unsupported.go | 0 .../docker/docker/pkg/mount/mount.go | 0 .../docker/pkg/mount/mounter_freebsd.go | 0 .../docker/docker/pkg/mount/mounter_linux.go | 0 .../docker/pkg/mount/mounter_solaris.go | 0 .../docker/pkg/mount/mounter_unsupported.go | 0 .../docker/docker/pkg/mount/mountinfo.go | 0 .../docker/pkg/mount/mountinfo_freebsd.go | 0 .../docker/pkg/mount/mountinfo_linux.go | 0 .../docker/pkg/mount/mountinfo_solaris.go | 0 .../docker/pkg/mount/mountinfo_unsupported.go | 0 .../docker/pkg/mount/mountinfo_windows.go | 0 .../docker/pkg/mount/sharedsubtree_linux.go | 0 .../docker/pkg/mount/sharedsubtree_solaris.go | 58 + .../docker/pkg/parsers/kernel/kernel.go | 0 .../pkg/parsers/kernel/kernel_darwin.go | 0 .../docker/pkg/parsers/kernel/kernel_unix.go | 0 .../pkg/parsers/kernel/kernel_windows.go | 0 .../docker/pkg/parsers/kernel/uname_linux.go | 0 .../pkg/parsers/kernel/uname_solaris.go | 0 .../pkg/parsers/kernel/uname_unsupported.go | 0 .../docker/docker/pkg/plugingetter/getter.go | 0 .../docker/docker/pkg/plugins/client.go | 29 +- .../docker/docker/pkg/plugins/discovery.go | 0 .../docker/pkg/plugins/discovery_unix.go | 0 .../docker/pkg/plugins/discovery_windows.go | 0 .../docker/docker/pkg/plugins/errors.go | 0 .../docker/docker/pkg/plugins/plugins.go | 105 +- .../docker/pkg/plugins/transport/http.go | 0 .../docker/pkg/plugins/transport/transport.go | 0 .../docker/docker/pkg/random/random.go | 0 .../docker/docker/pkg/reexec/command_linux.go | 0 .../docker/docker/pkg/reexec/command_unix.go | 0 .../docker/pkg/reexec/command_unsupported.go | 0 .../docker/pkg/reexec/command_windows.go | 0 .../docker/docker/pkg/reexec/reexec.go | 0 .../docker/docker/pkg/signal/signal.go | 0 .../docker/docker/pkg/signal/signal_darwin.go | 0 .../docker/pkg/signal/signal_freebsd.go | 0 .../docker/docker/pkg/signal/signal_linux.go | 0 .../docker/pkg/signal/signal_solaris.go | 0 .../docker/docker/pkg/signal/signal_unix.go | 0 .../docker/pkg/signal/signal_unsupported.go | 0 .../docker/pkg/signal/signal_windows.go | 0 .../docker/docker/pkg/signal/trap.go | 47 +- .../docker/docker/pkg/stringid/stringid.go | 14 +- .../docker/docker/pkg/symlink/fs.go | 0 .../docker/docker/pkg/symlink/fs_unix.go | 0 .../docker/docker/pkg/symlink/fs_windows.go | 0 .../docker/docker/pkg/system/chtimes.go | 0 .../docker/docker/pkg/system/chtimes_unix.go | 0 .../docker/pkg/system/chtimes_windows.go | 0 .../docker/docker/pkg/system/errors.go | 0 .../docker/pkg/system/events_windows.go | 4 +- .../docker/docker/pkg/system/exitcode.go | 33 + .../docker/docker/pkg/system/filesys.go | 54 + .../docker/pkg/system/filesys_windows.go | 236 + .../docker/docker/pkg/system/lstat.go | 0 .../docker/docker/pkg/system/lstat_windows.go | 0 .../docker/docker/pkg/system/meminfo.go | 0 .../docker/docker/pkg/system/meminfo_linux.go | 0 .../docker/pkg/system/meminfo_solaris.go | 2 +- .../docker/pkg/system/meminfo_unsupported.go | 0 .../docker/pkg/system/meminfo_windows.go | 5 +- .../docker/docker/pkg/system/mknod.go | 0 .../docker/docker/pkg/system/mknod_windows.go | 0 .../docker/docker/pkg/system/path_unix.go | 0 .../docker/docker/pkg/system/path_windows.go | 0 .../docker/docker/pkg/system/process_unix.go | 22 + .../docker/pkg/system/process_windows.go | 20 + .../docker/docker/pkg/system/stat.go | 0 .../docker/docker/pkg/system/stat_darwin.go | 0 .../docker/docker/pkg/system/stat_freebsd.go | 0 .../docker/docker/pkg/system/stat_linux.go | 0 .../docker/docker/pkg/system/stat_openbsd.go | 0 .../docker/docker/pkg/system/stat_solaris.go | 0 .../docker/pkg/system/stat_unsupported.go | 0 .../docker/docker/pkg/system/stat_windows.go | 0 .../docker/docker/pkg/system/syscall_unix.go | 0 .../docker/pkg/system/syscall_windows.go | 2 + .../docker/docker/pkg/system/umask.go | 0 .../docker/docker/pkg/system/umask_windows.go | 0 .../docker/pkg/system/utimes_freebsd.go | 0 .../docker/docker/pkg/system/utimes_linux.go | 0 .../docker/pkg/system/utimes_unsupported.go | 0 .../docker/docker/pkg/system/xattrs_linux.go | 0 .../docker/pkg/system/xattrs_unsupported.go | 0 .../docker/docker/pkg/term/ascii.go | 0 .../docker/docker/pkg/term/tc_linux_cgo.go | 0 .../docker/docker/pkg/term/tc_other.go | 0 .../docker/docker/pkg/term/tc_solaris_cgo.go | 0 .../github.com/docker/docker/pkg/term/term.go | 0 .../docker/docker/pkg/term/term_solaris.go | 0 .../docker/docker/pkg/term/term_unix.go | 0 .../docker/docker/pkg/term/term_windows.go | 0 .../docker/docker/pkg/term/termios_darwin.go | 0 .../docker/docker/pkg/term/termios_freebsd.go | 0 .../docker/docker/pkg/term/termios_linux.go | 0 .../docker/docker/pkg/term/termios_openbsd.go | 0 .../docker/pkg/term/windows/ansi_reader.go | 4 +- .../docker/pkg/term/windows/ansi_writer.go | 0 .../docker/docker/pkg/term/windows/console.go | 0 .../docker/docker/pkg/term/windows/windows.go | 0 .../github.com/docker/go-connections/LICENSE | 0 .../docker/go-connections/nat/nat.go | 223 + .../docker/go-connections/nat/parse.go | 56 + .../docker/go-connections/nat/sort.go | 96 + .../go-connections/sockets/inmem_socket.go | 0 .../docker/go-connections/sockets/proxy.go | 0 .../docker/go-connections/sockets/sockets.go | 0 .../go-connections/sockets/sockets_unix.go | 0 .../go-connections/sockets/sockets_windows.go | 0 .../go-connections/sockets/tcp_socket.go | 0 .../go-connections/sockets/unix_socket.go | 0 .../docker/go-connections/tlsconfig/config.go | 0 .../tlsconfig/config_client_ciphers.go | 0 .../tlsconfig/config_legacy_client_ciphers.go | 0 .../github.com/docker/go-events/LICENSE | 0 .../github.com/docker/go-events/broadcast.go | 0 .../github.com/docker/go-events/channel.go | 0 .../github.com/docker/go-events/errors.go | 0 .../github.com/docker/go-events/event.go | 0 .../github.com/docker/go-events/filter.go | 0 .../github.com/docker/go-events/queue.go | 0 .../github.com/docker/go-events/retry.go | 0 .../github.com/docker/go-units/duration.go | 0 .../github.com/docker/go-units/size.go | 0 .../github.com/docker/go-units/ulimit.go | 0 .../github.com/docker/libkv/libkv.go | 0 .../docker/libkv/store/boltdb/boltdb.go | 0 .../docker/libkv/store/consul/consul.go | 0 .../docker/libkv/store/etcd/etcd.go | 0 .../github.com/docker/libkv/store/helpers.go | 0 .../github.com/docker/libkv/store/store.go | 0 .../docker/libkv/store/zookeeper/zookeeper.go | 0 .../github.com/godbus/dbus/LICENSE | 0 .../github.com/godbus/dbus/auth.go | 0 .../github.com/godbus/dbus/auth_external.go | 0 .../github.com/godbus/dbus/auth_sha1.go | 0 .../github.com/godbus/dbus/call.go | 0 .../github.com/godbus/dbus/conn.go | 0 .../github.com/godbus/dbus/conn_darwin.go | 0 .../github.com/godbus/dbus/conn_other.go | 0 .../github.com/godbus/dbus/dbus.go | 0 .../github.com/godbus/dbus/decoder.go | 0 .../github.com/godbus/dbus/doc.go | 0 .../github.com/godbus/dbus/encoder.go | 0 .../github.com/godbus/dbus/export.go | 0 .../github.com/godbus/dbus/homedir.go | 0 .../github.com/godbus/dbus/homedir_dynamic.go | 0 .../github.com/godbus/dbus/homedir_static.go | 0 .../github.com/godbus/dbus/message.go | 0 .../github.com/godbus/dbus/object.go | 0 .../github.com/godbus/dbus/sig.go | 0 .../godbus/dbus/transport_darwin.go | 0 .../godbus/dbus/transport_generic.go | 0 .../github.com/godbus/dbus/transport_tcp.go | 0 .../github.com/godbus/dbus/transport_unix.go | 0 .../dbus/transport_unixcred_dragonfly.go | 0 .../godbus/dbus/transport_unixcred_linux.go | 0 .../github.com/godbus/dbus/variant.go | 0 .../github.com/godbus/dbus/variant_lexer.go | 0 .../github.com/godbus/dbus/variant_parser.go | 0 .../github.com/gogo/protobuf/LICENSE | 0 .../github.com/gogo/protobuf/gogoproto/doc.go | 0 .../gogo/protobuf/gogoproto/gogo.pb.go | 0 .../gogo/protobuf/gogoproto/gogo.proto | 0 .../gogo/protobuf/gogoproto/helper.go | 0 .../github.com/gogo/protobuf/proto/clone.go | 0 .../github.com/gogo/protobuf/proto/decode.go | 0 .../gogo/protobuf/proto/decode_gogo.go | 0 .../github.com/gogo/protobuf/proto/encode.go | 0 .../gogo/protobuf/proto/encode_gogo.go | 0 .../github.com/gogo/protobuf/proto/equal.go | 0 .../gogo/protobuf/proto/extensions.go | 0 .../gogo/protobuf/proto/extensions_gogo.go | 0 .../github.com/gogo/protobuf/proto/lib.go | 0 .../gogo/protobuf/proto/lib_gogo.go | 0 .../gogo/protobuf/proto/message_set.go | 0 .../gogo/protobuf/proto/pointer_reflect.go | 0 .../gogo/protobuf/proto/pointer_unsafe.go | 0 .../protobuf/proto/pointer_unsafe_gogo.go | 0 .../gogo/protobuf/proto/properties.go | 0 .../gogo/protobuf/proto/properties_gogo.go | 0 .../gogo/protobuf/proto/skip_gogo.go | 0 .../github.com/gogo/protobuf/proto/text.go | 0 .../gogo/protobuf/proto/text_gogo.go | 0 .../gogo/protobuf/proto/text_parser.go | 0 .../google/protobuf/compiler/plugin.proto | 150 + .../protobuf/google/protobuf/descriptor.proto | 779 + .../descriptor/descriptor.pb.go | 0 .../protoc-gen-gogo/descriptor/gostring.go | 0 .../protoc-gen-gogo/descriptor/helper.go | 0 .../github.com/golang/protobuf/LICENSE | 0 .../github.com/golang/protobuf/proto/clone.go | 0 .../golang/protobuf/proto/decode.go | 0 .../golang/protobuf/proto/encode.go | 0 .../github.com/golang/protobuf/proto/equal.go | 0 .../golang/protobuf/proto/extensions.go | 0 .../github.com/golang/protobuf/proto/lib.go | 0 .../golang/protobuf/proto/message_set.go | 0 .../golang/protobuf/proto/pointer_reflect.go | 0 .../golang/protobuf/proto/pointer_unsafe.go | 0 .../golang/protobuf/proto/properties.go | 0 .../github.com/golang/protobuf/proto/text.go | 0 .../golang/protobuf/proto/text_parser.go | 0 .../github.com/gorilla/context/LICENSE | 0 .../github.com/gorilla/context/context.go | 0 .../github.com/gorilla/context/doc.go | 0 .../github.com/gorilla/mux/LICENSE | 0 .../github.com/gorilla/mux/doc.go | 0 .../github.com/gorilla/mux/mux.go | 0 .../github.com/gorilla/mux/regexp.go | 0 .../github.com/gorilla/mux/route.go | 0 .../github.com/hashicorp/consul/LICENSE | 0 .../github.com/hashicorp/consul/api/acl.go | 0 .../github.com/hashicorp/consul/api/agent.go | 0 .../github.com/hashicorp/consul/api/api.go | 0 .../hashicorp/consul/api/catalog.go | 0 .../github.com/hashicorp/consul/api/event.go | 0 .../github.com/hashicorp/consul/api/health.go | 0 .../github.com/hashicorp/consul/api/kv.go | 0 .../github.com/hashicorp/consul/api/lock.go | 0 .../hashicorp/consul/api/semaphore.go | 0 .../hashicorp/consul/api/session.go | 0 .../github.com/hashicorp/consul/api/status.go | 0 .../github.com/hashicorp/go-msgpack/LICENSE | 0 .../hashicorp/go-msgpack/codec/0doc.go | 0 .../hashicorp/go-msgpack/codec/binc.go | 0 .../hashicorp/go-msgpack/codec/decode.go | 0 .../hashicorp/go-msgpack/codec/encode.go | 0 .../hashicorp/go-msgpack/codec/helper.go | 0 .../go-msgpack/codec/helper_internal.go | 0 .../hashicorp/go-msgpack/codec/msgpack.go | 0 .../hashicorp/go-msgpack/codec/rpc.go | 0 .../hashicorp/go-msgpack/codec/simple.go | 0 .../hashicorp/go-msgpack/codec/time.go | 0 .../hashicorp/go-multierror/LICENSE | 0 .../hashicorp/go-multierror/append.go | 0 .../hashicorp/go-multierror/format.go | 0 .../hashicorp/go-multierror/multierror.go | 0 .../github.com/hashicorp/memberlist/LICENSE | 0 .../hashicorp/memberlist/alive_delegate.go | 0 .../hashicorp/memberlist/broadcast.go | 0 .../github.com/hashicorp/memberlist/config.go | 0 .../hashicorp/memberlist/conflict_delegate.go | 0 .../hashicorp/memberlist/delegate.go | 0 .../hashicorp/memberlist/event_delegate.go | 0 .../hashicorp/memberlist/keyring.go | 0 .../hashicorp/memberlist/logging.go | 0 .../hashicorp/memberlist/memberlist.go | 0 .../hashicorp/memberlist/merge_delegate.go | 0 .../github.com/hashicorp/memberlist/net.go | 0 .../hashicorp/memberlist/ping_delegate.go | 0 .../github.com/hashicorp/memberlist/queue.go | 0 .../hashicorp/memberlist/security.go | 0 .../github.com/hashicorp/memberlist/state.go | 0 .../github.com/hashicorp/memberlist/util.go | 0 .../github.com/hashicorp/serf/LICENSE | 0 .../hashicorp/serf/coordinate/client.go | 0 .../hashicorp/serf/coordinate/config.go | 0 .../hashicorp/serf/coordinate/coordinate.go | 0 .../hashicorp/serf/coordinate/phantom.go | 0 .../hashicorp/serf/serf/broadcast.go | 0 .../hashicorp/serf/serf/coalesce.go | 0 .../hashicorp/serf/serf/coalesce_member.go | 0 .../hashicorp/serf/serf/coalesce_user.go | 0 .../github.com/hashicorp/serf/serf/config.go | 0 .../hashicorp/serf/serf/conflict_delegate.go | 0 .../hashicorp/serf/serf/delegate.go | 0 .../github.com/hashicorp/serf/serf/event.go | 0 .../hashicorp/serf/serf/event_delegate.go | 0 .../hashicorp/serf/serf/internal_query.go | 0 .../hashicorp/serf/serf/keymanager.go | 0 .../github.com/hashicorp/serf/serf/lamport.go | 0 .../hashicorp/serf/serf/merge_delegate.go | 0 .../hashicorp/serf/serf/messages.go | 0 .../hashicorp/serf/serf/ping_delegate.go | 0 .../github.com/hashicorp/serf/serf/query.go | 0 .../github.com/hashicorp/serf/serf/serf.go | 0 .../hashicorp/serf/serf/snapshot.go | 0 .../mattn/go-shellwords/shellwords.go | 0 .../mattn/go-shellwords/util_posix.go | 0 .../mattn/go-shellwords/util_windows.go | 0 .../github.com/miekg/dns/LICENSE | 0 .../github.com/miekg/dns/client.go | 0 .../github.com/miekg/dns/clientconfig.go | 0 .../github.com/miekg/dns/defaults.go | 0 .../github.com/miekg/dns/dns.go | 0 .../github.com/miekg/dns/dnssec.go | 0 .../github.com/miekg/dns/dnssec_keygen.go | 0 .../github.com/miekg/dns/dnssec_keyscan.go | 0 .../github.com/miekg/dns/dnssec_privkey.go | 0 .../github.com/miekg/dns/doc.go | 0 .../github.com/miekg/dns/edns.go | 0 .../github.com/miekg/dns/format.go | 0 .../github.com/miekg/dns/labels.go | 0 .../github.com/miekg/dns/msg.go | 0 .../github.com/miekg/dns/nsecx.go | 0 .../github.com/miekg/dns/privaterr.go | 0 .../github.com/miekg/dns/rawmsg.go | 0 .../github.com/miekg/dns/sanitize.go | 0 .../github.com/miekg/dns/scanner.go | 0 .../github.com/miekg/dns/server.go | 0 .../github.com/miekg/dns/sig0.go | 0 .../github.com/miekg/dns/singleinflight.go | 0 .../github.com/miekg/dns/tlsa.go | 0 .../github.com/miekg/dns/tsig.go | 0 .../github.com/miekg/dns/types.go | 0 .../github.com/miekg/dns/types_generate.go | 0 .../github.com/miekg/dns/udp.go | 0 .../github.com/miekg/dns/udp_linux.go | 0 .../github.com/miekg/dns/udp_other.go | 0 .../github.com/miekg/dns/udp_windows.go | 0 .../github.com/miekg/dns/update.go | 0 .../github.com/miekg/dns/xfr.go | 0 .../github.com/miekg/dns/zgenerate.go | 0 .../github.com/miekg/dns/zscan.go | 0 .../github.com/miekg/dns/zscan_rr.go | 0 .../github.com/miekg/dns/ztypes.go | 0 .../github.com/opencontainers/runc/LICENSE | 0 .../github.com/opencontainers/runc/NOTICE | 0 .../runc/libcontainer/apparmor/apparmor.go | 0 .../apparmor/apparmor_disabled.go | 0 .../runc/libcontainer/capabilities_linux.go | 0 .../runc/libcontainer/cgroups/cgroups.go | 0 .../cgroups/cgroups_unsupported.go | 0 .../runc/libcontainer/cgroups/fs/apply_raw.go | 0 .../runc/libcontainer/cgroups/fs/blkio.go | 0 .../runc/libcontainer/cgroups/fs/cpu.go | 0 .../runc/libcontainer/cgroups/fs/cpuacct.go | 0 .../runc/libcontainer/cgroups/fs/cpuset.go | 0 .../runc/libcontainer/cgroups/fs/devices.go | 0 .../runc/libcontainer/cgroups/fs/freezer.go | 0 .../libcontainer/cgroups/fs/fs_unsupported.go | 0 .../runc/libcontainer/cgroups/fs/hugetlb.go | 0 .../runc/libcontainer/cgroups/fs/memory.go | 0 .../runc/libcontainer/cgroups/fs/name.go | 0 .../runc/libcontainer/cgroups/fs/net_cls.go | 0 .../runc/libcontainer/cgroups/fs/net_prio.go | 0 .../libcontainer/cgroups/fs/perf_event.go | 0 .../runc/libcontainer/cgroups/fs/utils.go | 0 .../runc/libcontainer/cgroups/stats.go | 0 .../cgroups/systemd/apply_nosystemd.go | 0 .../cgroups/systemd/apply_systemd.go | 0 .../runc/libcontainer/cgroups/utils.go | 0 .../runc/libcontainer/compat_1.5_linux.go | 0 .../runc/libcontainer/configs/blkio_device.go | 0 .../runc/libcontainer/configs/cgroup_unix.go | 0 .../configs/cgroup_unsupported.go | 0 .../libcontainer/configs/cgroup_windows.go | 0 .../runc/libcontainer/configs/config.go | 0 .../runc/libcontainer/configs/config_unix.go | 0 .../runc/libcontainer/configs/device.go | 0 .../libcontainer/configs/device_defaults.go | 0 .../libcontainer/configs/hugepage_limit.go | 0 .../configs/interface_priority_map.go | 0 .../runc/libcontainer/configs/mount.go | 0 .../runc/libcontainer/configs/namespaces.go | 0 .../configs/namespaces_syscall.go | 0 .../configs/namespaces_syscall_unsupported.go | 0 .../libcontainer/configs/namespaces_unix.go | 0 .../configs/namespaces_unsupported.go | 0 .../runc/libcontainer/configs/network.go | 0 .../libcontainer/configs/validate/config.go | 0 .../runc/libcontainer/console.go | 0 .../runc/libcontainer/console_freebsd.go | 0 .../runc/libcontainer/console_linux.go | 0 .../runc/libcontainer/console_windows.go | 0 .../runc/libcontainer/container.go | 0 .../runc/libcontainer/container_linux.go | 0 .../libcontainer/container_nouserns_linux.go | 0 .../libcontainer/container_userns_linux.go | 0 .../runc/libcontainer/container_windows.go | 0 .../runc/libcontainer/criu_opts_unix.go | 0 .../runc/libcontainer/criu_opts_windows.go | 0 .../runc/libcontainer/criurpc/criurpc.pb.go | 0 .../runc/libcontainer/criurpc/criurpc.proto | 0 .../opencontainers/runc/libcontainer/error.go | 0 .../runc/libcontainer/factory.go | 0 .../runc/libcontainer/factory_linux.go | 0 .../runc/libcontainer/generic_error.go | 0 .../runc/libcontainer/init_linux.go | 0 .../runc/libcontainer/label/label.go | 0 .../runc/libcontainer/label/label_selinux.go | 0 .../runc/libcontainer/message_linux.go | 0 .../runc/libcontainer/network_linux.go | 0 .../runc/libcontainer/notify_linux.go | 0 .../runc/libcontainer/process.go | 0 .../runc/libcontainer/process_linux.go | 0 .../runc/libcontainer/restored_process.go | 0 .../runc/libcontainer/rootfs_linux.go | 0 .../runc/libcontainer/seccomp/config.go | 0 .../libcontainer/seccomp/seccomp_linux.go | 0 .../seccomp/seccomp_unsupported.go | 0 .../runc/libcontainer/selinux/selinux.go | 0 .../runc/libcontainer/setgroups_linux.go | 0 .../runc/libcontainer/setns_init_linux.go | 0 .../runc/libcontainer/stacktrace/capture.go | 0 .../runc/libcontainer/stacktrace/frame.go | 0 .../libcontainer/stacktrace/stacktrace.go | 0 .../runc/libcontainer/standard_init_linux.go | 0 .../opencontainers/runc/libcontainer/stats.go | 0 .../runc/libcontainer/stats_freebsd.go | 0 .../runc/libcontainer/stats_linux.go | 0 .../runc/libcontainer/stats_windows.go | 0 .../runc/libcontainer/system/linux.go | 0 .../runc/libcontainer/system/proc.go | 0 .../runc/libcontainer/system/setns_linux.go | 0 .../libcontainer/system/syscall_linux_386.go | 0 .../libcontainer/system/syscall_linux_64.go | 0 .../libcontainer/system/syscall_linux_arm.go | 0 .../runc/libcontainer/system/sysconfig.go | 0 .../libcontainer/system/sysconfig_notcgo.go | 0 .../runc/libcontainer/system/xattrs_linux.go | 0 .../runc/libcontainer/user/lookup.go | 0 .../runc/libcontainer/user/lookup_unix.go | 0 .../libcontainer/user/lookup_unsupported.go | 0 .../runc/libcontainer/user/user.go | 0 .../runc/libcontainer/utils/utils.go | 0 .../runc/libcontainer/utils/utils_unix.go | 0 vendor/github.com/pkg/errors/LICENSE | 23 + vendor/github.com/pkg/errors/errors.go | 269 + vendor/github.com/pkg/errors/stack.go | 178 + .../github.com/samuel/go-zookeeper/LICENSE | 0 .../github.com/samuel/go-zookeeper/zk/conn.go | 0 .../samuel/go-zookeeper/zk/constants.go | 0 .../github.com/samuel/go-zookeeper/zk/flw.go | 0 .../github.com/samuel/go-zookeeper/zk/lock.go | 0 .../samuel/go-zookeeper/zk/server_help.go | 0 .../samuel/go-zookeeper/zk/server_java.go | 0 .../samuel/go-zookeeper/zk/structs.go | 0 .../samuel/go-zookeeper/zk/tracer.go | 0 .../github.com/samuel/go-zookeeper/zk/util.go | 0 .../seccomp/libseccomp-golang/LICENSE | 0 .../seccomp/libseccomp-golang/seccomp.go | 0 .../libseccomp-golang/seccomp_internal.go | 0 .../stretchr/testify/assert/assertions.go | 0 .../github.com/stretchr/testify/assert/doc.go | 0 .../stretchr/testify/assert/errors.go | 0 .../testify/assert/forward_assertions.go | 0 .../testify/assert/http_assertions.go | 0 .../stretchr/testify/require/doc.go | 0 .../testify/require/forward_requirements.go | 0 .../stretchr/testify/require/requirements.go | 0 .../github.com/syndtr/gocapability/LICENSE | 0 .../gocapability/capability/capability.go | 0 .../capability/capability_linux.go | 0 .../capability/capability_noop.go | 0 .../syndtr/gocapability/capability/enum.go | 0 .../gocapability/capability/enum_gen.go | 0 .../gocapability/capability/syscall_linux.go | 0 .../github.com/ugorji/go/LICENSE | 0 .../github.com/ugorji/go/codec/0doc.go | 45 +- .../github.com/ugorji/go/codec/binc.go | 151 +- .../github.com/ugorji/go/codec/cbor.go | 130 +- .../github.com/ugorji/go/codec/decode.go | 1371 +- .../github.com/ugorji/go/codec/encode.go | 929 +- .../ugorji/go/codec/fast-path.generated.go | 30947 +++++++++++----- .../ugorji/go/codec/fast-path.not.go | 32 + .../ugorji/go/codec/gen-helper.generated.go | 261 +- .../ugorji/go/codec/gen.generated.go | 172 + .../github.com/ugorji/go/codec/gen.go | 800 +- .../github.com/ugorji/go/codec/helper.go | 425 +- .../ugorji/go/codec/helper_internal.go | 91 + .../ugorji/go/codec/helper_not_unsafe.go | 0 .../ugorji/go/codec/helper_unsafe.go | 6 + .../github.com/ugorji/go/codec/json.go | 560 +- .../github.com/ugorji/go/codec/msgpack.go | 169 +- vendor/github.com/ugorji/go/codec/noop.go | 213 + .../github.com/ugorji/go/codec/prebuild.go | 0 .../github.com/ugorji/go/codec/rpc.go | 0 .../github.com/ugorji/go/codec/simple.go | 119 +- .../github.com/ugorji/go/codec/time.go | 29 + .../github.com/vishvananda/netlink/LICENSE | 0 .../github.com/vishvananda/netlink/addr.go | 0 .../vishvananda/netlink/addr_linux.go | 0 .../vishvananda/netlink/bpf_linux.go | 0 .../github.com/vishvananda/netlink/class.go | 0 .../vishvananda/netlink/class_linux.go | 0 .../github.com/vishvananda/netlink/filter.go | 0 .../vishvananda/netlink/filter_linux.go | 0 .../vishvananda/netlink/handle_linux.go | 0 .../github.com/vishvananda/netlink/link.go | 0 .../vishvananda/netlink/link_linux.go | 0 .../vishvananda/netlink/link_tuntap_linux.go | 0 .../github.com/vishvananda/netlink/neigh.go | 0 .../vishvananda/netlink/neigh_linux.go | 0 .../github.com/vishvananda/netlink/netlink.go | 0 .../vishvananda/netlink/netlink_linux.go | 0 .../netlink/netlink_unspecified.go | 0 .../vishvananda/netlink/nl/addr_linux.go | 0 .../vishvananda/netlink/nl/link_linux.go | 0 .../vishvananda/netlink/nl/nl_linux.go | 0 .../vishvananda/netlink/nl/route_linux.go | 0 .../vishvananda/netlink/nl/syscall.go | 0 .../vishvananda/netlink/nl/tc_linux.go | 0 .../vishvananda/netlink/nl/xfrm_linux.go | 0 .../netlink/nl/xfrm_policy_linux.go | 0 .../netlink/nl/xfrm_state_linux.go | 0 .../vishvananda/netlink/protinfo.go | 0 .../vishvananda/netlink/protinfo_linux.go | 0 .../github.com/vishvananda/netlink/qdisc.go | 0 .../vishvananda/netlink/qdisc_linux.go | 0 .../github.com/vishvananda/netlink/route.go | 0 .../vishvananda/netlink/route_linux.go | 0 .../vishvananda/netlink/route_unspecified.go | 0 .../github.com/vishvananda/netlink/rule.go | 0 .../vishvananda/netlink/rule_linux.go | 0 .../github.com/vishvananda/netlink/xfrm.go | 0 .../vishvananda/netlink/xfrm_policy.go | 0 .../vishvananda/netlink/xfrm_policy_linux.go | 0 .../vishvananda/netlink/xfrm_state.go | 0 .../vishvananda/netlink/xfrm_state_linux.go | 0 .../github.com/vishvananda/netns/LICENSE | 0 .../github.com/vishvananda/netns/netns.go | 0 .../vishvananda/netns/netns_linux.go | 0 .../vishvananda/netns/netns_linux_386.go | 0 .../vishvananda/netns/netns_linux_amd64.go | 0 .../vishvananda/netns/netns_linux_arm.go | 0 .../vishvananda/netns/netns_linux_arm64.go | 0 .../vishvananda/netns/netns_linux_ppc64le.go | 0 .../vishvananda/netns/netns_linux_s390x.go | 0 .../vishvananda/netns/netns_unspecified.go | 0 .../src => vendor}/golang.org/x/net/LICENSE | 0 .../src => vendor}/golang.org/x/net/PATENTS | 0 .../golang.org/x/net/context/context.go | 2 +- .../golang.org/x/net/proxy/direct.go | 0 .../golang.org/x/net/proxy/per_host.go | 0 .../golang.org/x/net/proxy/proxy.go | 2 +- .../golang.org/x/net/proxy/socks5.go | 0 .../src => vendor}/golang.org/x/sys/LICENSE | 0 .../src => vendor}/golang.org/x/sys/PATENTS | 0 .../golang.org/x/sys/unix/asm.s | 0 .../golang.org/x/sys/unix/asm_darwin_386.s | 0 .../golang.org/x/sys/unix/asm_darwin_amd64.s | 0 .../golang.org/x/sys/unix/asm_darwin_arm.s | 0 .../golang.org/x/sys/unix/asm_darwin_arm64.s | 0 .../x/sys/unix/asm_dragonfly_amd64.s | 0 .../golang.org/x/sys/unix/asm_freebsd_386.s | 0 .../golang.org/x/sys/unix/asm_freebsd_amd64.s | 0 .../golang.org/x/sys/unix/asm_freebsd_arm.s | 0 .../golang.org/x/sys/unix/asm_linux_386.s | 0 .../golang.org/x/sys/unix/asm_linux_amd64.s | 0 .../golang.org/x/sys/unix/asm_linux_arm.s | 0 .../golang.org/x/sys/unix/asm_linux_arm64.s | 0 .../golang.org/x/sys/unix/asm_linux_mips64x.s | 17 +- .../golang.org/x/sys/unix/asm_linux_ppc64x.s | 0 .../golang.org/x/sys/unix/asm_linux_s390x.s | 28 + .../golang.org/x/sys/unix/asm_netbsd_386.s | 0 .../golang.org/x/sys/unix/asm_netbsd_amd64.s | 0 .../golang.org/x/sys/unix/asm_netbsd_arm.s | 0 .../golang.org/x/sys/unix/asm_openbsd_386.s | 0 .../golang.org/x/sys/unix/asm_openbsd_amd64.s | 0 .../golang.org/x/sys/unix/asm_solaris_amd64.s | 0 .../golang.org/x/sys/unix/bluetooth_linux.go | 35 + .../golang.org/x/sys/unix/constants.go | 0 .../golang.org/x/sys/unix/env_unix.go | 0 .../golang.org/x/sys/unix/env_unset.go | 0 .../golang.org/x/sys/unix/flock.go | 0 .../x/sys/unix/flock_linux_32bit.go | 0 .../golang.org/x/sys/unix/gccgo.go | 0 .../golang.org/x/sys/unix/gccgo_c.c | 0 .../x/sys/unix/gccgo_linux_amd64.go | 0 vendor/golang.org/x/sys/unix/mkpost.go | 62 + .../golang.org/x/sys/unix/race.go | 0 .../golang.org/x/sys/unix/race0.go | 0 .../golang.org/x/sys/unix/sockcmsg_linux.go | 0 .../golang.org/x/sys/unix/sockcmsg_unix.go | 2 +- .../golang.org/x/sys/unix/str.go | 0 .../golang.org/x/sys/unix/syscall.go | 4 +- .../golang.org/x/sys/unix/syscall_bsd.go | 0 .../golang.org/x/sys/unix/syscall_darwin.go | 2 + .../x/sys/unix/syscall_darwin_386.go | 2 - .../x/sys/unix/syscall_darwin_amd64.go | 2 - .../x/sys/unix/syscall_darwin_arm.go | 2 - .../x/sys/unix/syscall_darwin_arm64.go | 2 - .../x/sys/unix/syscall_dragonfly.go | 1 + .../x/sys/unix/syscall_dragonfly_amd64.go | 2 - .../golang.org/x/sys/unix/syscall_freebsd.go | 1 + .../x/sys/unix/syscall_freebsd_386.go | 2 - .../x/sys/unix/syscall_freebsd_amd64.go | 2 - .../x/sys/unix/syscall_freebsd_arm.go | 2 - .../golang.org/x/sys/unix/syscall_linux.go | 45 +- .../x/sys/unix/syscall_linux_386.go | 15 +- .../x/sys/unix/syscall_linux_amd64.go | 15 +- .../x/sys/unix/syscall_linux_arm.go | 34 +- .../x/sys/unix/syscall_linux_arm64.go | 48 +- .../x/sys/unix/syscall_linux_mips64x.go | 215 + .../x/sys/unix/syscall_linux_ppc64x.go | 43 +- .../x/sys/unix/syscall_linux_s390x.go | 329 + .../golang.org/x/sys/unix/syscall_netbsd.go | 0 .../x/sys/unix/syscall_netbsd_386.go | 2 - .../x/sys/unix/syscall_netbsd_amd64.go | 2 - .../x/sys/unix/syscall_netbsd_arm.go | 2 - .../golang.org/x/sys/unix/syscall_no_getwd.go | 0 .../golang.org/x/sys/unix/syscall_openbsd.go | 1 + .../x/sys/unix/syscall_openbsd_386.go | 2 - .../x/sys/unix/syscall_openbsd_amd64.go | 2 - .../golang.org/x/sys/unix/syscall_solaris.go | 46 +- .../x/sys/unix/syscall_solaris_amd64.go | 2 - .../golang.org/x/sys/unix/syscall_unix.go | 0 .../golang.org/x/sys/unix/types_darwin.go | 0 .../golang.org/x/sys/unix/types_dragonfly.go | 0 .../golang.org/x/sys/unix/types_freebsd.go | 0 .../golang.org/x/sys/unix/types_linux.go | 46 +- .../golang.org/x/sys/unix/types_netbsd.go | 0 .../golang.org/x/sys/unix/types_openbsd.go | 0 .../golang.org/x/sys/unix/types_solaris.go | 2 + .../x/sys/unix/zerrors_darwin_386.go | 0 .../x/sys/unix/zerrors_darwin_amd64.go | 0 .../x/sys/unix/zerrors_darwin_arm.go | 0 .../x/sys/unix/zerrors_darwin_arm64.go | 0 .../x/sys/unix/zerrors_dragonfly_amd64.go | 0 .../x/sys/unix/zerrors_freebsd_386.go | 0 .../x/sys/unix/zerrors_freebsd_amd64.go | 0 .../x/sys/unix/zerrors_freebsd_arm.go | 0 .../x/sys/unix/zerrors_linux_386.go | 2 + .../x/sys/unix/zerrors_linux_amd64.go | 2 + .../x/sys/unix/zerrors_linux_arm.go | 1 + .../x/sys/unix/zerrors_linux_arm64.go | 1 + .../x/sys/unix/zerrors_linux_mips64.go | 1917 + .../x/sys/unix/zerrors_linux_mips64le.go | 1917 + .../x/sys/unix/zerrors_linux_ppc64.go | 1 + .../x/sys/unix/zerrors_linux_ppc64le.go | 1 + .../x/sys/unix/zerrors_linux_s390x.go | 2027 + .../x/sys/unix/zerrors_netbsd_386.go | 0 .../x/sys/unix/zerrors_netbsd_amd64.go | 0 .../x/sys/unix/zerrors_netbsd_arm.go | 0 .../x/sys/unix/zerrors_openbsd_386.go | 0 .../x/sys/unix/zerrors_openbsd_amd64.go | 0 .../x/sys/unix/zerrors_solaris_amd64.go | 0 .../x/sys/unix/zsyscall_darwin_386.go | 1 + .../x/sys/unix/zsyscall_darwin_amd64.go | 1 + .../x/sys/unix/zsyscall_darwin_arm.go | 1 + .../x/sys/unix/zsyscall_darwin_arm64.go | 1 + .../x/sys/unix/zsyscall_dragonfly_amd64.go | 1 + .../x/sys/unix/zsyscall_freebsd_386.go | 1 + .../x/sys/unix/zsyscall_freebsd_amd64.go | 1 + .../x/sys/unix/zsyscall_freebsd_arm.go | 1 + .../x/sys/unix/zsyscall_linux_386.go | 120 +- .../x/sys/unix/zsyscall_linux_amd64.go | 120 +- .../x/sys/unix/zsyscall_linux_arm.go | 101 +- .../x/sys/unix/zsyscall_linux_arm64.go | 94 +- .../x/sys/unix/zsyscall_linux_mips64.go | 1803 + .../x/sys/unix/zsyscall_linux_mips64le.go | 1803 + .../x/sys/unix/zsyscall_linux_ppc64.go | 161 +- .../x/sys/unix/zsyscall_linux_ppc64le.go | 161 +- .../x/sys/unix/zsyscall_linux_s390x.go | 1139 +- .../x/sys/unix/zsyscall_netbsd_386.go | 1 + .../x/sys/unix/zsyscall_netbsd_amd64.go | 1 + .../x/sys/unix/zsyscall_netbsd_arm.go | 1 + .../x/sys/unix/zsyscall_openbsd_386.go | 1 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 1 + .../x/sys/unix/zsyscall_solaris_amd64.go | 40 + .../golang.org/x/sys/unix/zsysctl_openbsd.go | 0 .../x/sys/unix/zsysnum_darwin_386.go | 0 .../x/sys/unix/zsysnum_darwin_amd64.go | 0 .../x/sys/unix/zsysnum_darwin_arm.go | 0 .../x/sys/unix/zsysnum_darwin_arm64.go | 0 .../x/sys/unix/zsysnum_dragonfly_amd64.go | 0 .../x/sys/unix/zsysnum_freebsd_386.go | 0 .../x/sys/unix/zsysnum_freebsd_amd64.go | 0 .../x/sys/unix/zsysnum_freebsd_arm.go | 0 .../x/sys/unix/zsysnum_linux_386.go | 0 .../x/sys/unix/zsysnum_linux_amd64.go | 0 .../x/sys/unix/zsysnum_linux_arm.go | 0 .../x/sys/unix/zsysnum_linux_arm64.go | 0 .../x/sys/unix/zsysnum_linux_mips64.go | 327 + .../x/sys/unix/zsysnum_linux_mips64le.go | 327 + .../x/sys/unix/zsysnum_linux_ppc64.go | 0 .../x/sys/unix/zsysnum_linux_ppc64le.go | 0 .../x/sys/unix/zsysnum_linux_s390x.go | 328 + .../x/sys/unix/zsysnum_netbsd_386.go | 0 .../x/sys/unix/zsysnum_netbsd_amd64.go | 0 .../x/sys/unix/zsysnum_netbsd_arm.go | 0 .../x/sys/unix/zsysnum_openbsd_386.go | 0 .../x/sys/unix/zsysnum_openbsd_amd64.go | 0 .../x/sys/unix/zsysnum_solaris_amd64.go | 0 .../x/sys/unix/ztypes_darwin_386.go | 0 .../x/sys/unix/ztypes_darwin_amd64.go | 0 .../x/sys/unix/ztypes_darwin_arm.go | 0 .../x/sys/unix/ztypes_darwin_arm64.go | 0 .../x/sys/unix/ztypes_dragonfly_amd64.go | 0 .../x/sys/unix/ztypes_freebsd_386.go | 0 .../x/sys/unix/ztypes_freebsd_amd64.go | 0 .../x/sys/unix/ztypes_freebsd_arm.go | 0 .../golang.org/x/sys/unix/ztypes_linux_386.go | 39 +- .../x/sys/unix/ztypes_linux_amd64.go | 39 +- .../golang.org/x/sys/unix/ztypes_linux_arm.go | 30 +- .../x/sys/unix/ztypes_linux_arm64.go | 29 + .../x/sys/unix/ztypes_linux_mips64.go | 627 + .../x/sys/unix/ztypes_linux_mips64le.go | 627 + .../x/sys/unix/ztypes_linux_ppc64.go | 35 +- .../x/sys/unix/ztypes_linux_ppc64le.go | 35 +- .../x/sys/unix/ztypes_linux_s390x.go | 649 + .../x/sys/unix/ztypes_netbsd_386.go | 0 .../x/sys/unix/ztypes_netbsd_amd64.go | 0 .../x/sys/unix/ztypes_netbsd_arm.go | 0 .../x/sys/unix/ztypes_openbsd_386.go | 0 .../x/sys/unix/ztypes_openbsd_amd64.go | 0 .../x/sys/unix/ztypes_solaris_amd64.go | 3 +- .../x/sys/windows/asm_windows_386.s | 0 .../x/sys/windows/asm_windows_amd64.s | 0 .../golang.org/x/sys/windows/dll_windows.go | 135 +- .../golang.org/x/sys/windows/env_unset.go | 1 + .../golang.org/x/sys/windows/env_windows.go | 0 .../golang.org/x/sys/windows/eventlog.go | 0 .../golang.org/x/sys/windows/exec_windows.go | 0 vendor/golang.org/x/sys/windows/mksyscall.go | 7 + .../golang.org/x/sys/windows/race.go | 0 .../golang.org/x/sys/windows/race0.go | 0 .../x/sys/windows/security_windows.go | 0 .../golang.org/x/sys/windows/service.go | 0 .../golang.org/x/sys/windows/str.go | 0 .../golang.org/x/sys/windows/syscall.go | 8 +- .../x/sys/windows/syscall_windows.go | 3 +- .../x/sys/windows/zsyscall_windows.go | 51 +- .../x/sys/windows/ztypes_windows.go | 0 .../x/sys/windows/ztypes_windows_386.go | 0 .../x/sys/windows/ztypes_windows_amd64.go | 0 1109 files changed, 48440 insertions(+), 28640 deletions(-) delete mode 100644 Godeps/Godeps.json delete mode 100644 Godeps/Readme delete mode 100644 Godeps/_workspace/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/Azure/go-ansiterm/README.md delete mode 100644 Godeps/_workspace/src/github.com/BurntSushi/toml/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/BurntSushi/toml/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/BurntSushi/toml/COMPATIBLE delete mode 100644 Godeps/_workspace/src/github.com/BurntSushi/toml/Makefile delete mode 100644 Godeps/_workspace/src/github.com/BurntSushi/toml/README.md delete mode 100644 Godeps/_workspace/src/github.com/BurntSushi/toml/session.vim delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/go-winio/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md delete mode 100644 Godeps/_workspace/src/github.com/Microsoft/hcsshim/README.md delete mode 100644 Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/Sirupsen/logrus/CHANGELOG.md delete mode 100644 Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md delete mode 100755 Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/armon/go-metrics/README.md delete mode 100644 Godeps/_workspace/src/github.com/armon/go-radix/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/armon/go-radix/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/armon/go-radix/README.md delete mode 100644 Godeps/_workspace/src/github.com/boltdb/bolt/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/boltdb/bolt/Makefile delete mode 100644 Godeps/_workspace/src/github.com/boltdb/bolt/README.md delete mode 100644 Godeps/_workspace/src/github.com/boltdb/bolt/appveyor.yml delete mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/README.md delete mode 100644 Godeps/_workspace/src/github.com/coreos/etcd/client/README.md delete mode 100644 Godeps/_workspace/src/github.com/coreos/etcd/client/cancelreq_go14.go delete mode 100644 Godeps/_workspace/src/github.com/coreos/etcd/client/keys.generated.go delete mode 100644 Godeps/_workspace/src/github.com/deckarep/golang-set/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/deckarep/golang-set/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/deckarep/golang-set/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/api/types/versions/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/locker/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/LICENSE delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/flag.go delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/signal/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/stringid/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.APACHE delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.BSD delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/system/filesys.go delete mode 100644 Godeps/_workspace/src/github.com/docker/docker/pkg/system/filesys_windows.go delete mode 100644 Godeps/_workspace/src/github.com/docker/engine-api/LICENSE delete mode 100644 Godeps/_workspace/src/github.com/docker/go-connections/sockets/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/go-events/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/docker/go-events/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/go-units/CONTRIBUTING.md delete mode 100644 Godeps/_workspace/src/github.com/docker/go-units/LICENSE.code delete mode 100644 Godeps/_workspace/src/github.com/docker/go-units/LICENSE.docs delete mode 100644 Godeps/_workspace/src/github.com/docker/go-units/MAINTAINERS delete mode 100644 Godeps/_workspace/src/github.com/docker/go-units/README.md delete mode 100644 Godeps/_workspace/src/github.com/docker/go-units/circle.yml delete mode 100644 Godeps/_workspace/src/github.com/docker/libkv/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/docker/libkv/LICENSE.code delete mode 100644 Godeps/_workspace/src/github.com/docker/libkv/LICENSE.docs delete mode 100644 Godeps/_workspace/src/github.com/docker/libkv/MAINTAINERS delete mode 100644 Godeps/_workspace/src/github.com/docker/libkv/README.md delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/CONTRIBUTING.md delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/MAINTAINERS delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/README.markdown delete mode 100644 Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/Makefile delete mode 100644 Godeps/_workspace/src/github.com/gogo/protobuf/gogoproto/gogo.pb.golden delete mode 100644 Godeps/_workspace/src/github.com/gogo/protobuf/proto/Makefile delete mode 100644 Godeps/_workspace/src/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/Makefile delete mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/Makefile delete mode 100644 Godeps/_workspace/src/github.com/gorilla/context/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/gorilla/context/README.md delete mode 100644 Godeps/_workspace/src/github.com/gorilla/mux/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/gorilla/mux/README.md delete mode 100644 Godeps/_workspace/src/github.com/hashicorp/consul/api/README.md delete mode 100644 Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/README.md delete mode 100755 Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/msgpack_test.py delete mode 100644 Godeps/_workspace/src/github.com/hashicorp/go-multierror/README.md delete mode 100644 Godeps/_workspace/src/github.com/hashicorp/memberlist/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/hashicorp/memberlist/Makefile delete mode 100644 Godeps/_workspace/src/github.com/hashicorp/memberlist/README.md delete mode 100644 Godeps/_workspace/src/github.com/hashicorp/memberlist/todo.md delete mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/mattn/go-shellwords/README.md delete mode 100644 Godeps/_workspace/src/github.com/miekg/dns/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/miekg/dns/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/miekg/dns/AUTHORS delete mode 100644 Godeps/_workspace/src/github.com/miekg/dns/CONTRIBUTORS delete mode 100644 Godeps/_workspace/src/github.com/miekg/dns/COPYRIGHT delete mode 100644 Godeps/_workspace/src/github.com/miekg/dns/README.md delete mode 100644 Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/README.md delete mode 100644 Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/SPEC.md delete mode 100644 Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/criurpc/Makefile delete mode 100644 Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/user/MAINTAINERS delete mode 100644 Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/README delete mode 100644 Godeps/_workspace/src/github.com/stretchr/testify/LICENCE.txt delete mode 100644 Godeps/_workspace/src/github.com/ugorji/go/codec/README.md delete mode 100644 Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.go.tmpl delete mode 100644 Godeps/_workspace/src/github.com/ugorji/go/codec/gen-dec-array.go.tmpl delete mode 100644 Godeps/_workspace/src/github.com/ugorji/go/codec/gen-dec-map.go.tmpl delete mode 100644 Godeps/_workspace/src/github.com/ugorji/go/codec/gen-helper.generated.go delete mode 100644 Godeps/_workspace/src/github.com/ugorji/go/codec/gen.generated.go delete mode 100644 Godeps/_workspace/src/github.com/ugorji/go/codec/noop.go delete mode 100755 Godeps/_workspace/src/github.com/ugorji/go/codec/prebuild.sh delete mode 100644 Godeps/_workspace/src/github.com/ugorji/go/codec/test-cbor-goldens.json delete mode 100755 Godeps/_workspace/src/github.com/ugorji/go/codec/test.py delete mode 100644 Godeps/_workspace/src/github.com/vishvananda/netlink/.travis.yml delete mode 100644 Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile delete mode 100644 Godeps/_workspace/src/github.com/vishvananda/netlink/README.md delete mode 100644 Godeps/_workspace/src/github.com/vishvananda/netns/README.md delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/unix/.gitignore delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mkall.sh delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mkerrors.sh delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksyscall.pl delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksyscall_solaris.pl delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysctl_openbsd.pl delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_darwin.pl delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_dragonfly.pl delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_freebsd.pl delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_linux.pl delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_netbsd.pl delete mode 100755 Godeps/_workspace/src/golang.org/x/sys/unix/mksysnum_openbsd.pl delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/unix/syscall_dragonfly_386.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/unix/zerrors_dragonfly_386.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/unix/zsysnum_dragonfly_386.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/unix/ztypes_dragonfly_386.go delete mode 100644 Godeps/_workspace/src/golang.org/x/sys/windows/asm.s create mode 100644 vendor.conf rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/constants.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/context.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/csi_entry_state.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/csi_param_state.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/escape_intermediate_state.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/escape_state.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/event_handler.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/ground_state.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/osc_string_state.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/parser.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/parser_action_helpers.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/parser_actions.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/states.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/utilities.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/winterm/ansi.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/winterm/api.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/winterm/attr_translation.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/winterm/erase_helpers.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/winterm/scroll_helper.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/winterm/utilities.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Azure/go-ansiterm/winterm/win_event_handler.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/COPYING (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/decode.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/decode_meta.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/encode.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/encoding_types.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/encoding_types_1.1.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/lex.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/parse.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/type_check.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/BurntSushi/toml/type_fields.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/backup.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/file.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/fileinfo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/pipe.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/privilege.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/reparse.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/sd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/syscall.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/go-winio/zsyscall.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/activatelayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/baselayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/callback.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/cgo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/container.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/createlayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/createsandboxlayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/deactivatelayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/destroylayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/errors.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/expandsandboxsize.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/exportlayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/getlayermountpath.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/getsharedbaseimages.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/guid.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/hcsshim.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/hnsfuncs.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/importlayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/interface.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/layerexists.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/layerutils.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/legacy.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/mksyscall_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/nametoguid.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/preparelayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/process.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/processimage.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/unpreparelayer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/utils.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/version.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/waithelper.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Microsoft/hcsshim/zhcsshim.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/entry.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/exported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/formatter.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/hooks.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/json_formatter.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/logger.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/logrus.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/terminal_bsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/terminal_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/terminal_notwindows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/terminal_solaris.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/terminal_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/text_formatter.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/Sirupsen/logrus/writer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/const_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/const_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/inmem.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/inmem_signal.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/metrics.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/sink.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/start.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/statsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-metrics/statsite.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-radix/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/armon/go-radix/radix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_386.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_arm.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_arm64.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_openbsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_ppc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_ppc64.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_ppc64le.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_s390x.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_unix_solaris.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bolt_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/boltsync_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/bucket.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/cursor.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/db.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/errors.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/freelist.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/node.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/page.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/boltdb/bolt/tx.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/codegangsta/cli/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/codegangsta/cli/app.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/codegangsta/cli/cli.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/codegangsta/cli/command.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/codegangsta/cli/context.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/codegangsta/cli/flag.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/codegangsta/cli/help.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/NOTICE (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/auth_role.go (86%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/auth_user.go (80%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/cancelreq.go (95%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/client.go (70%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/cluster_error.go (83%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/curl.go (97%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/discover.go (88%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/doc.go (94%) create mode 100644 vendor/github.com/coreos/etcd/client/keys.generated.go rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/keys.go (90%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/members.go (88%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/client/srv.go (86%) create mode 100644 vendor/github.com/coreos/etcd/client/util.go rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/pkg/pathutil/path.go (90%) create mode 100644 vendor/github.com/coreos/etcd/pkg/types/doc.go rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/pkg/types/id.go (97%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/pkg/types/set.go (99%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/pkg/types/slice.go (95%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/pkg/types/urls.go (83%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/etcd/pkg/types/urlsmap.go (58%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/go-systemd/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/go-systemd/dbus/dbus.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/go-systemd/dbus/methods.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/go-systemd/dbus/properties.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/go-systemd/dbus/set.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/go-systemd/dbus/subscription.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/go-systemd/dbus/subscription_set.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/coreos/go-systemd/util/util.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/deckarep/golang-set/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/deckarep/golang-set/set.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/deckarep/golang-set/threadsafe.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/deckarep/golang-set/threadunsafe.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/NOTICE (100%) create mode 100644 vendor/github.com/docker/docker/api/types/auth.go create mode 100644 vendor/github.com/docker/docker/api/types/blkiodev/blkio.go create mode 100644 vendor/github.com/docker/docker/api/types/client.go create mode 100644 vendor/github.com/docker/docker/api/types/configs.go create mode 100644 vendor/github.com/docker/docker/api/types/container/config.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_create.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_update.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_wait.go create mode 100644 vendor/github.com/docker/docker/api/types/container/host_config.go create mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go create mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go create mode 100644 vendor/github.com/docker/docker/api/types/error_response.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/api/types/filters/parse.go (98%) create mode 100644 vendor/github.com/docker/docker/api/types/id_response.go create mode 100644 vendor/github.com/docker/docker/api/types/image_summary.go create mode 100644 vendor/github.com/docker/docker/api/types/mount/mount.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/api/types/network/network.go (93%) create mode 100644 vendor/github.com/docker/docker/api/types/plugin.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_device.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_env.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_interface_type.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_mount.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_responses.go create mode 100644 vendor/github.com/docker/docker/api/types/port.go create mode 100644 vendor/github.com/docker/docker/api/types/registry/authenticate.go create mode 100644 vendor/github.com/docker/docker/api/types/registry/registry.go create mode 100644 vendor/github.com/docker/docker/api/types/seccomp.go create mode 100644 vendor/github.com/docker/docker/api/types/service_update_response.go create mode 100644 vendor/github.com/docker/docker/api/types/stats.go create mode 100644 vendor/github.com/docker/docker/api/types/strslice/strslice.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/common.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/container.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/network.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/node.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/secret.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/service.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/swarm.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/task.go create mode 100644 vendor/github.com/docker/docker/api/types/types.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/api/types/versions/compare.go (100%) create mode 100644 vendor/github.com/docker/docker/api/types/volume.go create mode 100644 vendor/github.com/docker/docker/opts/env.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/opts/hosts.go (88%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/opts/hosts_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/opts/hosts_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/opts/ip.go (100%) create mode 100644 vendor/github.com/docker/docker/opts/mount.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/opts/opts.go (78%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/opts/opts_unix.go (73%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/opts/opts_windows.go (98%) create mode 100644 vendor/github.com/docker/docker/opts/port.go create mode 100644 vendor/github.com/docker/docker/opts/quotedstring.go create mode 100644 vendor/github.com/docker/docker/opts/runtime.go create mode 100644 vendor/github.com/docker/docker/opts/secret.go create mode 100644 vendor/github.com/docker/docker/opts/throttledevice.go create mode 100644 vendor/github.com/docker/docker/opts/ulimit.go create mode 100644 vendor/github.com/docker/docker/opts/weightdevice.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/discovery/backends.go (95%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/discovery/discovery.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/discovery/entry.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/discovery/generator.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/discovery/kv/kv.go (97%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/homedir/homedir.go (100%) create mode 100644 vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/homedir/homedir_others.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/idtools.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/utils_unix.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/buffer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/bytespipe.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/fmt.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/fswriters.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/multireader.go (97%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/readers.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/temp_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/temp_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/writeflusher.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/ioutils/writers.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/locker/locker.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/longpath/longpath.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/flags.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/flags_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/flags_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/flags_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mount.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mounter_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mounter_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mounter_solaris.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mounter_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mountinfo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mountinfo_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mountinfo_solaris.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/mountinfo_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go (100%) create mode 100644 vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/parsers/kernel/kernel.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/parsers/kernel/kernel_darwin.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/parsers/kernel/kernel_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/parsers/kernel/kernel_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/parsers/kernel/uname_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/parsers/kernel/uname_solaris.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugingetter/getter.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugins/client.go (84%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugins/discovery.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugins/discovery_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugins/discovery_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugins/errors.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugins/plugins.go (72%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugins/transport/http.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/plugins/transport/transport.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/random/random.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/reexec/command_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/reexec/command_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/reexec/command_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/reexec/command_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/reexec/reexec.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/signal.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/signal_darwin.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/signal_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/signal_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/signal_solaris.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/signal_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/signal_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/signal_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/signal/trap.go (62%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/stringid/stringid.go (83%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/symlink/fs.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/symlink/fs_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/symlink/fs_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/chtimes.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/chtimes_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/chtimes_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/errors.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/events_windows.go (96%) create mode 100644 vendor/github.com/docker/docker/pkg/system/exitcode.go create mode 100644 vendor/github.com/docker/docker/pkg/system/filesys.go create mode 100644 vendor/github.com/docker/docker/pkg/system/filesys_windows.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/lstat.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/lstat_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/meminfo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/meminfo_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/meminfo_solaris.go (98%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/meminfo_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/meminfo_windows.go (92%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/mknod.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/mknod_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/path_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/path_windows.go (100%) create mode 100644 vendor/github.com/docker/docker/pkg/system/process_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/system/process_windows.go rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/stat.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/stat_darwin.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/stat_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/stat_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/stat_openbsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/stat_solaris.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/stat_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/stat_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/syscall_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/syscall_windows.go (95%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/umask.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/umask_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/utimes_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/utimes_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/utimes_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/xattrs_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/system/xattrs_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/ascii.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/tc_linux_cgo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/tc_other.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/tc_solaris_cgo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/term.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/term_solaris.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/term_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/term_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/termios_darwin.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/termios_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/termios_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/termios_openbsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/windows/ansi_reader.go (98%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/windows/ansi_writer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/windows/console.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/docker/pkg/term/windows/windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/LICENSE (100%) create mode 100644 vendor/github.com/docker/go-connections/nat/nat.go create mode 100644 vendor/github.com/docker/go-connections/nat/parse.go create mode 100644 vendor/github.com/docker/go-connections/nat/sort.go rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/sockets/inmem_socket.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/sockets/proxy.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/sockets/sockets.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/sockets/sockets_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/sockets/sockets_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/sockets/tcp_socket.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/sockets/unix_socket.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/tlsconfig/config.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-events/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-events/broadcast.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-events/channel.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-events/errors.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-events/event.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-events/filter.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-events/queue.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-events/retry.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-units/duration.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-units/size.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/go-units/ulimit.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/libkv/libkv.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/libkv/store/boltdb/boltdb.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/libkv/store/consul/consul.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/libkv/store/etcd/etcd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/libkv/store/helpers.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/libkv/store/store.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/docker/libkv/store/zookeeper/zookeeper.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/auth.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/auth_external.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/auth_sha1.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/call.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/conn.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/conn_darwin.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/conn_other.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/dbus.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/decoder.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/encoder.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/export.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/homedir.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/homedir_dynamic.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/homedir_static.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/message.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/object.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/sig.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/transport_darwin.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/transport_generic.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/transport_tcp.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/transport_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/transport_unixcred_dragonfly.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/transport_unixcred_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/variant.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/variant_lexer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/godbus/dbus/variant_parser.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/gogoproto/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/gogoproto/gogo.pb.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/gogoproto/gogo.proto (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/gogoproto/helper.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/clone.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/decode.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/decode_gogo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/encode.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/encode_gogo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/equal.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/extensions.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/extensions_gogo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/lib.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/lib_gogo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/message_set.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/pointer_reflect.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/pointer_unsafe.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/properties.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/properties_gogo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/skip_gogo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/text.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/text_gogo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/proto/text_parser.go (100%) create mode 100644 vendor/github.com/gogo/protobuf/protobuf/google/protobuf/compiler/plugin.proto create mode 100644 vendor/github.com/gogo/protobuf/protobuf/google/protobuf/descriptor.proto rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/descriptor.pb.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/gostring.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gogo/protobuf/protoc-gen-gogo/descriptor/helper.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/clone.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/decode.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/encode.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/equal.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/extensions.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/lib.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/message_set.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/pointer_reflect.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/pointer_unsafe.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/properties.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/text.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/golang/protobuf/proto/text_parser.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gorilla/context/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/gorilla/context/context.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gorilla/context/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gorilla/mux/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/gorilla/mux/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gorilla/mux/mux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gorilla/mux/regexp.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/gorilla/mux/route.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/acl.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/agent.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/api.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/catalog.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/event.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/health.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/kv.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/lock.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/semaphore.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/session.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/consul/api/status.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/0doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/binc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/decode.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/encode.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/helper.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/helper_internal.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/msgpack.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/rpc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/simple.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-msgpack/codec/time.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-multierror/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-multierror/append.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-multierror/format.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/go-multierror/multierror.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/alive_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/broadcast.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/config.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/conflict_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/event_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/keyring.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/logging.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/memberlist.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/merge_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/net.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/ping_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/queue.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/security.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/state.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/memberlist/util.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/coordinate/client.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/coordinate/config.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/coordinate/coordinate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/coordinate/phantom.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/broadcast.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/coalesce.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/coalesce_member.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/coalesce_user.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/config.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/conflict_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/event.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/event_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/internal_query.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/keymanager.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/lamport.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/merge_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/messages.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/ping_delegate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/query.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/serf.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/hashicorp/serf/serf/snapshot.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/mattn/go-shellwords/shellwords.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/mattn/go-shellwords/util_posix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/mattn/go-shellwords/util_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/client.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/clientconfig.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/defaults.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/dns.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/dnssec.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/dnssec_keygen.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/dnssec_keyscan.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/dnssec_privkey.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/edns.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/format.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/labels.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/msg.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/nsecx.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/privaterr.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/rawmsg.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/sanitize.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/scanner.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/server.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/sig0.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/singleinflight.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/tlsa.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/tsig.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/types.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/types_generate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/udp.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/udp_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/udp_other.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/udp_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/update.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/xfr.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/zgenerate.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/zscan.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/zscan_rr.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/miekg/dns/ztypes.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/NOTICE (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_disabled.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/capabilities_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/stats.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_nosystemd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/cgroups/utils.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/config.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/config_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/device.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/hugepage_limit.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/interface_priority_map.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/mount.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/namespaces.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/network.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/configs/validate/config.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/console.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/console_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/console_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/console_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/container.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/container_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/container_nouserns_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/container_userns_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/container_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/criu_opts_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/criu_opts_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/criurpc/criurpc.pb.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/criurpc/criurpc.proto (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/error.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/factory.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/factory_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/generic_error.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/init_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/label/label.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/label/label_selinux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/message_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/network_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/notify_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/process.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/process_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/restored_process.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/rootfs_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/seccomp/config.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/selinux/selinux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/setgroups_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/setns_init_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/standard_init_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/stats.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/stats_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/stats_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/stats_windows.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/proc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/setns_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/syscall_linux_386.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/syscall_linux_arm.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/sysconfig.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/sysconfig_notcgo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/user/lookup.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/user/user.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/utils/utils.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go (100%) create mode 100644 vendor/github.com/pkg/errors/LICENSE create mode 100644 vendor/github.com/pkg/errors/errors.go create mode 100644 vendor/github.com/pkg/errors/stack.go rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/conn.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/constants.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/flw.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/lock.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/server_help.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/server_java.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/structs.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/tracer.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/samuel/go-zookeeper/zk/util.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/seccomp/libseccomp-golang/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/seccomp/libseccomp-golang/seccomp.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/seccomp/libseccomp-golang/seccomp_internal.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/stretchr/testify/assert/assertions.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/stretchr/testify/assert/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/stretchr/testify/assert/errors.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/stretchr/testify/assert/forward_assertions.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/stretchr/testify/assert/http_assertions.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/stretchr/testify/require/doc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/stretchr/testify/require/forward_requirements.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/stretchr/testify/require/requirements.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/syndtr/gocapability/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/syndtr/gocapability/capability/capability.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/syndtr/gocapability/capability/capability_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/syndtr/gocapability/capability/capability_noop.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/syndtr/gocapability/capability/enum.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/syndtr/gocapability/capability/enum_gen.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/syndtr/gocapability/capability/syscall_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/0doc.go (72%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/binc.go (89%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/cbor.go (86%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/decode.go (50%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/encode.go (57%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/fast-path.generated.go (53%) create mode 100644 vendor/github.com/ugorji/go/codec/fast-path.not.go rename Godeps/_workspace/src/github.com/ugorji/go/codec/gen-helper.go.tmpl => vendor/github.com/ugorji/go/codec/gen-helper.generated.go (50%) create mode 100644 vendor/github.com/ugorji/go/codec/gen.generated.go rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/gen.go (70%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/helper.go (66%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/helper_internal.go (61%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/helper_not_unsafe.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/helper_unsafe.go (93%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/json.go (64%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/msgpack.go (88%) create mode 100644 vendor/github.com/ugorji/go/codec/noop.go rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/prebuild.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/rpc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/simple.go (86%) rename {Godeps/_workspace/src => vendor}/github.com/ugorji/go/codec/time.go (90%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/addr.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/addr_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/bpf_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/class.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/class_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/filter.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/filter_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/handle_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/link.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/link_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/link_tuntap_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/neigh.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/neigh_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/netlink.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/netlink_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/netlink_unspecified.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/addr_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/link_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/nl_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/route_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/syscall.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/tc_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/xfrm_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/nl/xfrm_state_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/protinfo.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/protinfo_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/qdisc.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/qdisc_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/route.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/route_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/route_unspecified.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/rule.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/rule_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/xfrm.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/xfrm_policy.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/xfrm_policy_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/xfrm_state.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netlink/xfrm_state_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns_linux.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns_linux_386.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns_linux_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns_linux_arm.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns_linux_arm64.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns_linux_ppc64le.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns_linux_s390x.go (100%) rename {Godeps/_workspace/src => vendor}/github.com/vishvananda/netns/netns_unspecified.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/net/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/net/PATENTS (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/net/context/context.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/net/proxy/direct.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/net/proxy/per_host.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/net/proxy/proxy.go (97%) rename {Godeps/_workspace/src => vendor}/golang.org/x/net/proxy/socks5.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/LICENSE (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/PATENTS (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_darwin_386.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_darwin_amd64.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_darwin_arm.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_darwin_arm64.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_dragonfly_amd64.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_freebsd_386.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_freebsd_amd64.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_freebsd_arm.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_linux_386.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_linux_amd64.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_linux_arm.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_linux_arm64.s (100%) rename Godeps/_workspace/src/golang.org/x/sys/unix/asm_dragonfly_386.s => vendor/golang.org/x/sys/unix/asm_linux_mips64x.s (56%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_linux_ppc64x.s (100%) create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_s390x.s rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_netbsd_386.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_netbsd_amd64.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_netbsd_arm.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_openbsd_386.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_openbsd_amd64.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/asm_solaris_amd64.s (100%) create mode 100644 vendor/golang.org/x/sys/unix/bluetooth_linux.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/constants.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/env_unix.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/env_unset.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/flock.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/flock_linux_32bit.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/gccgo.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/gccgo_c.c (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/gccgo_linux_amd64.go (100%) create mode 100644 vendor/golang.org/x/sys/unix/mkpost.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/race.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/race0.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/sockcmsg_linux.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/sockcmsg_unix.go (97%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/str.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall.go (94%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_bsd.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_darwin.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_darwin_386.go (95%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_darwin_amd64.go (95%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_darwin_arm.go (95%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_darwin_arm64.go (95%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_dragonfly.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_dragonfly_amd64.go (94%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_freebsd.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_freebsd_386.go (94%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_freebsd_amd64.go (94%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_freebsd_arm.go (94%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_linux.go (96%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_linux_386.go (96%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_linux_amd64.go (92%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_linux_arm.go (91%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_linux_arm64.go (85%) create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_linux_ppc64x.go (82%) create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_s390x.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_netbsd.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_netbsd_386.go (91%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_netbsd_amd64.go (91%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_netbsd_arm.go (91%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_no_getwd.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_openbsd.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_openbsd_386.go (91%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_openbsd_amd64.go (91%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_solaris.go (96%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_solaris_amd64.go (90%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/syscall_unix.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/types_darwin.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/types_dragonfly.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/types_freebsd.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/types_linux.go (90%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/types_netbsd.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/types_openbsd.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/types_solaris.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_darwin_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_darwin_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_darwin_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_darwin_arm64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_freebsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_freebsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_freebsd_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_linux_386.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_linux_amd64.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_linux_arm.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_linux_arm64.go (99%) create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_linux_ppc64.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_linux_ppc64le.go (99%) create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_netbsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_netbsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_netbsd_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_openbsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_openbsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zerrors_solaris_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_darwin_386.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_darwin_amd64.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_darwin_arm.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_darwin_arm64.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_freebsd_386.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_freebsd_arm.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_linux_386.go (97%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_linux_amd64.go (97%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_linux_arm.go (98%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_linux_arm64.go (98%) create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_linux_ppc64.go (95%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go (95%) rename Godeps/_workspace/src/golang.org/x/sys/unix/zsyscall_dragonfly_386.go => vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go (57%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_netbsd_386.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_netbsd_arm.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_openbsd_386.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsyscall_solaris_amd64.go (97%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysctl_openbsd.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_darwin_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_darwin_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_darwin_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_darwin_arm64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_freebsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_freebsd_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_linux_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_linux_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_linux_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_linux_arm64.go (100%) create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_linux_ppc64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go (100%) create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_netbsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_netbsd_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_openbsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/zsysnum_solaris_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_darwin_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_darwin_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_darwin_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_darwin_arm64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_freebsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_freebsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_freebsd_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_linux_386.go (94%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_linux_amd64.go (95%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_linux_arm.go (96%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_linux_arm64.go (96%) create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_linux_ppc64.go (95%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_linux_ppc64le.go (95%) create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_netbsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_netbsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_netbsd_arm.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_openbsd_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_openbsd_amd64.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/unix/ztypes_solaris_amd64.go (98%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/asm_windows_386.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/asm_windows_amd64.s (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/dll_windows.go (69%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/env_unset.go (94%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/env_windows.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/eventlog.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/exec_windows.go (100%) create mode 100644 vendor/golang.org/x/sys/windows/mksyscall.go rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/race.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/race0.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/security_windows.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/service.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/str.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/syscall.go (92%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/syscall_windows.go (99%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/zsyscall_windows.go (98%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/ztypes_windows.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/ztypes_windows_386.go (100%) rename {Godeps/_workspace/src => vendor}/golang.org/x/sys/windows/ztypes_windows_amd64.go (100%) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json deleted file mode 100644 index 8430829943..0000000000 --- a/Godeps/Godeps.json +++ /dev/null @@ -1,444 +0,0 @@ -{ - "ImportPath": "github.com/docker/libnetwork", - "GoVersion": "go1.7", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "github.com/Azure/go-ansiterm", - "Rev": "04b7f292a41fcb5da32dda536c0807fc13e8351c" - }, - { - "ImportPath": "github.com/Azure/go-ansiterm/winterm", - "Rev": "04b7f292a41fcb5da32dda536c0807fc13e8351c" - }, - { - "ImportPath": "github.com/BurntSushi/toml", - "Comment": "v0.1.0-16-gf706d00", - "Rev": "f706d00e3de6abe700c994cdd545a1a4915af060" - }, - { - "ImportPath": "github.com/Microsoft/go-winio", - "Comment": "v0.3.5-2-gce2922f", - "Rev": "ce2922f643c8fd76b46cadc7f404a06282678b34" - }, - { - "ImportPath": "github.com/Microsoft/hcsshim", - "Comment": "v0.5.6", - "Rev": "e439b7d2b63f036d3a50c93a9e0b154a0d50e788" - }, - { - "ImportPath": "github.com/Sirupsen/logrus", - "Comment": "v0.10.0", - "Rev": "4b6ea7319e214d98c938f12692336f7ca9348d6b" - }, - { - "ImportPath": "github.com/armon/go-metrics", - "Rev": "eb0af217e5e9747e41dd5303755356b62d28e3ec" - }, - { - "ImportPath": "github.com/armon/go-radix", - "Rev": "e39d623f12e8e41c7b5529e9a9dd67a1e2261f80" - }, - { - "ImportPath": "github.com/boltdb/bolt", - "Comment": "v1.2.0", - "Rev": "c6ba97b89e0454fec9aa92e1d33a4e2c5fc1f631" - }, - { - "ImportPath": "github.com/codegangsta/cli", - "Comment": "v1.9.0", - "Rev": "a65b733b303f0055f8d324d805f393cd3e7a7904" - }, - { - "ImportPath": "github.com/coreos/etcd/client", - "Comment": "v2.2.0", - "Rev": "e4561dd8cfb1163fb51afceca9c78aa89398e731" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/pathutil", - "Comment": "v2.2.0", - "Rev": "e4561dd8cfb1163fb51afceca9c78aa89398e731" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/types", - "Comment": "v2.2.0", - "Rev": "e4561dd8cfb1163fb51afceca9c78aa89398e731" - }, - { - "ImportPath": "github.com/coreos/go-systemd/dbus", - "Comment": "v4", - "Rev": "b4a58d95188dd092ae20072bac14cece0e67c388" - }, - { - "ImportPath": "github.com/coreos/go-systemd/util", - "Comment": "v4", - "Rev": "b4a58d95188dd092ae20072bac14cece0e67c388" - }, - { - "ImportPath": "github.com/deckarep/golang-set", - "Comment": "v1-26-gef32fa3", - "Rev": "ef32fa3046d9f249d399f98ebaf9be944430fd1d" - }, - { - "ImportPath": "github.com/docker/docker/api/types/filters", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/api/types/network", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/api/types/versions", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/opts", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/discovery", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/discovery/kv", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/homedir", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/ioutils", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/locker", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/longpath", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/mount", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/parsers/kernel", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/plugingetter", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-g9c96768", - "Rev": "9c96768eae4b3a65147b47a55c850c103ab8972d" - }, - { - "ImportPath": "github.com/docker/docker/pkg/plugins", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/plugins/transport", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/random", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/reexec", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/signal", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/stringid", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/symlink", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/system", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/term", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/docker/pkg/term/windows", - "Comment": "docs-v1.12.0-rc4-2016-07-15-1985-gfebf53d", - "Rev": "febf53d91a43fe13fbb802d9e6b7b6732183cf21" - }, - { - "ImportPath": "github.com/docker/go-connections/sockets", - "Comment": "v0.2.0", - "Rev": "34b5052da6b11e27f5f2e357b38b571ddddd3928" - }, - { - "ImportPath": "github.com/docker/go-connections/tlsconfig", - "Comment": "v0.2.0", - "Rev": "34b5052da6b11e27f5f2e357b38b571ddddd3928" - }, - { - "ImportPath": "github.com/docker/go-events", - "Rev": "2e7d352816128aa84f4d29b2a21d400133701a0d" - }, - { - "ImportPath": "github.com/docker/go-units", - "Comment": "v0.1.0-16-g8e2d452", - "Rev": "8e2d4523730c73120e10d4652f36ad6010998f4e" - }, - { - "ImportPath": "github.com/docker/libkv", - "Comment": "v0.2.1-5-g1d84310", - "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" - }, - { - "ImportPath": "github.com/docker/libkv/store", - "Comment": "v0.2.1-5-g1d84310", - "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" - }, - { - "ImportPath": "github.com/docker/libkv/store/boltdb", - "Comment": "v0.2.1-5-g1d84310", - "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" - }, - { - "ImportPath": "github.com/docker/libkv/store/consul", - "Comment": "v0.2.1-5-g1d84310", - "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" - }, - { - "ImportPath": "github.com/docker/libkv/store/etcd", - "Comment": "v0.2.1-5-g1d84310", - "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" - }, - { - "ImportPath": "github.com/docker/libkv/store/zookeeper", - "Comment": "v0.2.1-5-g1d84310", - "Rev": "1d8431073ae03cdaedb198a89722f3aab6d418ef" - }, - { - "ImportPath": "github.com/godbus/dbus", - "Comment": "v4.0.0", - "Rev": "5f6efc7ef2759c81b7ba876593971bfce311eab3" - }, - { - "ImportPath": "github.com/gogo/protobuf/gogoproto", - "Comment": "v0.2-55-ge33835a", - "Rev": "e33835a643a970c11ac74f6333f5f6866387a101" - }, - { - "ImportPath": "github.com/gogo/protobuf/proto", - "Comment": "v0.2-55-ge33835a", - "Rev": "e33835a643a970c11ac74f6333f5f6866387a101" - }, - { - "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/descriptor", - "Comment": "v0.2-55-ge33835a", - "Rev": "e33835a643a970c11ac74f6333f5f6866387a101" - }, - { - "ImportPath": "github.com/golang/protobuf/proto", - "Rev": "f7137ae6b19afbfd61a94b746fda3b3fe0491874" - }, - { - "ImportPath": "github.com/gorilla/context", - "Rev": "215affda49addc4c8ef7e2534915df2c8c35c6cd" - }, - { - "ImportPath": "github.com/gorilla/mux", - "Rev": "8096f47503459bcc74d1f4c487b7e6e42e5746b5" - }, - { - "ImportPath": "github.com/hashicorp/consul/api", - "Comment": "v0.5.0rc1-66-g954aec6", - "Rev": "954aec66231b79c161a4122b023fbcad13047f79" - }, - { - "ImportPath": "github.com/hashicorp/go-msgpack/codec", - "Rev": "71c2886f5a673a35f909803f38ece5810165097b" - }, - { - "ImportPath": "github.com/hashicorp/go-multierror", - "Rev": "2167c8ec40776024589f483a6b836489e47e1049" - }, - { - "ImportPath": "github.com/hashicorp/memberlist", - "Rev": "88ac4de0d1a0ca6def284b571342db3b777a4c37" - }, - { - "ImportPath": "github.com/hashicorp/serf/coordinate", - "Comment": "v0.7.0-47-g598c548", - "Rev": "598c54895cc5a7b1a24a398d635e8c0ea0959870" - }, - { - "ImportPath": "github.com/hashicorp/serf/serf", - "Comment": "v0.7.0-47-g598c548", - "Rev": "598c54895cc5a7b1a24a398d635e8c0ea0959870" - }, - { - "ImportPath": "github.com/mattn/go-shellwords", - "Comment": "v1.0.0-1-g525bede", - "Rev": "525bedee691b5a8df547cb5cf9f86b7fb1883e24" - }, - { - "ImportPath": "github.com/miekg/dns", - "Rev": "d27455715200c7d3e321a1e5cadb27c9ee0b0f02" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/apparmor", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/fs", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/systemd", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/configs", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/configs/validate", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/criurpc", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/label", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/seccomp", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/selinux", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/stacktrace", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/system", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/user", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/utils", - "Comment": "v0.0.6-6-gba1568d", - "Rev": "ba1568de399395774ad84c2ace65937814c542ed" - }, - { - "ImportPath": "github.com/samuel/go-zookeeper/zk", - "Rev": "d0e0d8e11f318e000a8cc434616d69e329edc374" - }, - { - "ImportPath": "github.com/seccomp/libseccomp-golang", - "Rev": "1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1" - }, - { - "ImportPath": "github.com/stretchr/testify/assert", - "Rev": "dab07ac62d4905d3e48d17dc549c684ac3b7c15a" - }, - { - "ImportPath": "github.com/stretchr/testify/require", - "Rev": "dab07ac62d4905d3e48d17dc549c684ac3b7c15a" - }, - { - "ImportPath": "github.com/syndtr/gocapability/capability", - "Rev": "2c00daeb6c3b45114c80ac44119e7b8801fdd852" - }, - { - "ImportPath": "github.com/ugorji/go/codec", - "Rev": "5abd4e96a45c386928ed2ca2a7ef63e2533e18ec" - }, - { - "ImportPath": "github.com/vishvananda/netlink", - "Rev": "17ea11b5a11c5614597c65a671105e8ee58c4d04" - }, - { - "ImportPath": "github.com/vishvananda/netlink/nl", - "Rev": "17ea11b5a11c5614597c65a671105e8ee58c4d04" - }, - { - "ImportPath": "github.com/vishvananda/netns", - "Rev": "604eaf189ee867d8c147fafc28def2394e878d25" - }, - { - "ImportPath": "golang.org/x/net/context", - "Rev": "9dd48c277bcb2bb2cc3eb6a6368a486a567d3562" - }, - { - "ImportPath": "golang.org/x/net/proxy", - "Rev": "9dd48c277bcb2bb2cc3eb6a6368a486a567d3562" - }, - { - "ImportPath": "golang.org/x/sys/unix", - "Rev": "5eaf0df67e70d6997a9fe0ed24383fa1b01638d3" - }, - { - "ImportPath": "golang.org/x/sys/windows", - "Rev": "5eaf0df67e70d6997a9fe0ed24383fa1b01638d3" - } - ] -} diff --git a/Godeps/Readme b/Godeps/Readme deleted file mode 100644 index 4cdaa53d56..0000000000 --- a/Godeps/Readme +++ /dev/null @@ -1,5 +0,0 @@ -This directory tree is generated automatically by godep. - -Please do not edit. - -See https://github.com/tools/godep for more information. diff --git a/Godeps/_workspace/.gitignore b/Godeps/_workspace/.gitignore deleted file mode 100644 index f037d684ef..0000000000 --- a/Godeps/_workspace/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/pkg -/bin diff --git a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/README.md b/Godeps/_workspace/src/github.com/Azure/go-ansiterm/README.md deleted file mode 100644 index e25e382101..0000000000 --- a/Godeps/_workspace/src/github.com/Azure/go-ansiterm/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# go-ansiterm - -This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent. - -For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position. - -The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go). - -See parser_test.go for examples exercising the state machine and generating appropriate function calls. diff --git a/Godeps/_workspace/src/github.com/BurntSushi/toml/.gitignore b/Godeps/_workspace/src/github.com/BurntSushi/toml/.gitignore deleted file mode 100644 index 0cd3800377..0000000000 --- a/Godeps/_workspace/src/github.com/BurntSushi/toml/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -TAGS -tags -.*.swp -tomlcheck/tomlcheck -toml.test diff --git a/Godeps/_workspace/src/github.com/BurntSushi/toml/.travis.yml b/Godeps/_workspace/src/github.com/BurntSushi/toml/.travis.yml deleted file mode 100644 index 43caf6d021..0000000000 --- a/Godeps/_workspace/src/github.com/BurntSushi/toml/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: go -go: - - 1.1 - - 1.2 - - tip -install: - - go install ./... - - go get github.com/BurntSushi/toml-test -script: - - export PATH="$PATH:$HOME/gopath/bin" - - make test - diff --git a/Godeps/_workspace/src/github.com/BurntSushi/toml/COMPATIBLE b/Godeps/_workspace/src/github.com/BurntSushi/toml/COMPATIBLE deleted file mode 100644 index 21e0938cae..0000000000 --- a/Godeps/_workspace/src/github.com/BurntSushi/toml/COMPATIBLE +++ /dev/null @@ -1,3 +0,0 @@ -Compatible with TOML version -[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md) - diff --git a/Godeps/_workspace/src/github.com/BurntSushi/toml/Makefile b/Godeps/_workspace/src/github.com/BurntSushi/toml/Makefile deleted file mode 100644 index 3600848d33..0000000000 --- a/Godeps/_workspace/src/github.com/BurntSushi/toml/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -install: - go install ./... - -test: install - go test -v - toml-test toml-test-decoder - toml-test -encoder toml-test-encoder - -fmt: - gofmt -w *.go */*.go - colcheck *.go */*.go - -tags: - find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS - -push: - git push origin master - git push github master - diff --git a/Godeps/_workspace/src/github.com/BurntSushi/toml/README.md b/Godeps/_workspace/src/github.com/BurntSushi/toml/README.md deleted file mode 100644 index e861c0ca7b..0000000000 --- a/Godeps/_workspace/src/github.com/BurntSushi/toml/README.md +++ /dev/null @@ -1,220 +0,0 @@ -## TOML parser and encoder for Go with reflection - -TOML stands for Tom's Obvious, Minimal Language. This Go package provides a -reflection interface similar to Go's standard library `json` and `xml` -packages. This package also supports the `encoding.TextUnmarshaler` and -`encoding.TextMarshaler` interfaces so that you can define custom data -representations. (There is an example of this below.) - -Spec: https://github.com/mojombo/toml - -Compatible with TOML version -[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md) - -Documentation: http://godoc.org/github.com/BurntSushi/toml - -Installation: - -```bash -go get github.com/BurntSushi/toml -``` - -Try the toml validator: - -```bash -go get github.com/BurntSushi/toml/cmd/tomlv -tomlv some-toml-file.toml -``` - -[![Build status](https://api.travis-ci.org/BurntSushi/toml.png)](https://travis-ci.org/BurntSushi/toml) - - -### Testing - -This package passes all tests in -[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder -and the encoder. - -### Examples - -This package works similarly to how the Go standard library handles `XML` -and `JSON`. Namely, data is loaded into Go values via reflection. - -For the simplest example, consider some TOML file as just a list of keys -and values: - -```toml -Age = 25 -Cats = [ "Cauchy", "Plato" ] -Pi = 3.14 -Perfection = [ 6, 28, 496, 8128 ] -DOB = 1987-07-05T05:45:00Z -``` - -Which could be defined in Go as: - -```go -type Config struct { - Age int - Cats []string - Pi float64 - Perfection []int - DOB time.Time // requires `import time` -} -``` - -And then decoded with: - -```go -var conf Config -if _, err := toml.Decode(tomlData, &conf); err != nil { - // handle error -} -``` - -You can also use struct tags if your struct field name doesn't map to a TOML -key value directly: - -```toml -some_key_NAME = "wat" -``` - -```go -type TOML struct { - ObscureKey string `toml:"some_key_NAME"` -} -``` - -### Using the `encoding.TextUnmarshaler` interface - -Here's an example that automatically parses duration strings into -`time.Duration` values: - -```toml -[[song]] -name = "Thunder Road" -duration = "4m49s" - -[[song]] -name = "Stairway to Heaven" -duration = "8m03s" -``` - -Which can be decoded with: - -```go -type song struct { - Name string - Duration duration -} -type songs struct { - Song []song -} -var favorites songs -if _, err := toml.Decode(blob, &favorites); err != nil { - log.Fatal(err) -} - -for _, s := range favorites.Song { - fmt.Printf("%s (%s)\n", s.Name, s.Duration) -} -``` - -And you'll also need a `duration` type that satisfies the -`encoding.TextUnmarshaler` interface: - -```go -type duration struct { - time.Duration -} - -func (d *duration) UnmarshalText(text []byte) error { - var err error - d.Duration, err = time.ParseDuration(string(text)) - return err -} -``` - -### More complex usage - -Here's an example of how to load the example from the official spec page: - -```toml -# This is a TOML document. Boom. - -title = "TOML Example" - -[owner] -name = "Tom Preston-Werner" -organization = "GitHub" -bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." -dob = 1979-05-27T07:32:00Z # First class dates? Why not? - -[database] -server = "192.168.1.1" -ports = [ 8001, 8001, 8002 ] -connection_max = 5000 -enabled = true - -[servers] - - # You can indent as you please. Tabs or spaces. TOML don't care. - [servers.alpha] - ip = "10.0.0.1" - dc = "eqdc10" - - [servers.beta] - ip = "10.0.0.2" - dc = "eqdc10" - -[clients] -data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it - -# Line breaks are OK when inside arrays -hosts = [ - "alpha", - "omega" -] -``` - -And the corresponding Go types are: - -```go -type tomlConfig struct { - Title string - Owner ownerInfo - DB database `toml:"database"` - Servers map[string]server - Clients clients -} - -type ownerInfo struct { - Name string - Org string `toml:"organization"` - Bio string - DOB time.Time -} - -type database struct { - Server string - Ports []int - ConnMax int `toml:"connection_max"` - Enabled bool -} - -type server struct { - IP string - DC string -} - -type clients struct { - Data [][]interface{} - Hosts []string -} -``` - -Note that a case insensitive match will be tried if an exact match can't be -found. - -A working example of the above can be found in `_examples/example.{go,toml}`. - diff --git a/Godeps/_workspace/src/github.com/BurntSushi/toml/session.vim b/Godeps/_workspace/src/github.com/BurntSushi/toml/session.vim deleted file mode 100644 index 562164be06..0000000000 --- a/Godeps/_workspace/src/github.com/BurntSushi/toml/session.vim +++ /dev/null @@ -1 +0,0 @@ -au BufWritePost *.go silent!make tags > /dev/null 2>&1 diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/.gitignore b/Godeps/_workspace/src/github.com/Microsoft/go-winio/.gitignore deleted file mode 100644 index b883f1fdc6..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/go-winio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.exe diff --git a/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md b/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md deleted file mode 100644 index 5680010575..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# go-winio - -This repository contains utilities for efficiently performing Win32 IO operations in -Go. Currently, this is focused on accessing named pipes and other file handles, and -for using named pipes as a net transport. - -This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go -to reuse the thread to schedule another goroutine. This limits support to Windows Vista and -newer operating systems. This is similar to the implementation of network sockets in Go's net -package. - -Please see the LICENSE file for licensing information. - -This project has adopted the [Microsoft Open Source Code of -Conduct](https://opensource.microsoft.com/codeofconduct/). For more information -see the [Code of Conduct -FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact -[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional -questions or comments. - -Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe -for another named pipe implementation. diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/README.md b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/README.md deleted file mode 100644 index 30991a12e4..0000000000 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# hcsshim - -This package supports launching Windows Server containers from Go. It is -primarily used in the [Docker Engine](https://github.com/docker/docker) project, -but it can be freely used by other projects as well. - -This project has adopted the [Microsoft Open Source Code of -Conduct](https://opensource.microsoft.com/codeofconduct/). For more information -see the [Code of Conduct -FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact -[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional -questions or comments. diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore b/Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore deleted file mode 100644 index 66be63a005..0000000000 --- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore +++ /dev/null @@ -1 +0,0 @@ -logrus diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml b/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml deleted file mode 100644 index ff23150dc3..0000000000 --- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - 1.3 - - 1.4 - - 1.5 - - tip -install: - - go get -t ./... -script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./... diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/CHANGELOG.md b/Godeps/_workspace/src/github.com/Sirupsen/logrus/CHANGELOG.md deleted file mode 100644 index f2c2bc2111..0000000000 --- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/CHANGELOG.md +++ /dev/null @@ -1,66 +0,0 @@ -# 0.10.0 - -* feature: Add a test hook (#180) -* feature: `ParseLevel` is now case-insensitive (#326) -* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) -* performance: avoid re-allocations on `WithFields` (#335) - -# 0.9.0 - -* logrus/text_formatter: don't emit empty msg -* logrus/hooks/airbrake: move out of main repository -* logrus/hooks/sentry: move out of main repository -* logrus/hooks/papertrail: move out of main repository -* logrus/hooks/bugsnag: move out of main repository -* logrus/core: run tests with `-race` -* logrus/core: detect TTY based on `stderr` -* logrus/core: support `WithError` on logger -* logrus/core: Solaris support - -# 0.8.7 - -* logrus/core: fix possible race (#216) -* logrus/doc: small typo fixes and doc improvements - - -# 0.8.6 - -* hooks/raven: allow passing an initialized client - -# 0.8.5 - -* logrus/core: revert #208 - -# 0.8.4 - -* formatter/text: fix data race (#218) - -# 0.8.3 - -* logrus/core: fix entry log level (#208) -* logrus/core: improve performance of text formatter by 40% -* logrus/core: expose `LevelHooks` type -* logrus/core: add support for DragonflyBSD and NetBSD -* formatter/text: print structs more verbosely - -# 0.8.2 - -* logrus: fix more Fatal family functions - -# 0.8.1 - -* logrus: fix not exiting on `Fatalf` and `Fatalln` - -# 0.8.0 - -* logrus: defaults to stderr instead of stdout -* hooks/sentry: add special field for `*http.Request` -* formatter/text: ignore Windows for colors - -# 0.7.3 - -* formatter/\*: allow configuration of timestamp layout - -# 0.7.2 - -* formatter/text: Add configuration option for time format (#158) diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md b/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md deleted file mode 100644 index 6e1721a743..0000000000 --- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md +++ /dev/null @@ -1,388 +0,0 @@ -# Logrus :walrus: [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus) - -Logrus is a structured logger for Go (golang), completely API compatible with -the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not -yet stable (pre 1.0). Logrus itself is completely stable and has been used in -many large deployments. The core API is unlikely to change much but please -version control your Logrus to make sure you aren't fetching latest `master` on -every build.** - -Nicely color-coded in development (when a TTY is attached, otherwise just -plain text): - -![Colored](http://i.imgur.com/PY7qMwd.png) - -With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash -or Splunk: - -```json -{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the -ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} - -{"level":"warning","msg":"The group's number increased tremendously!", -"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} - -{"animal":"walrus","level":"info","msg":"A giant walrus appears!", -"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} - -{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", -"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} - -{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, -"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} -``` - -With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not -attached, the output is compatible with the -[logfmt](http://godoc.org/github.com/kr/logfmt) format: - -```text -time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 -time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 -time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true -time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 -time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 -time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true -exit status 1 -``` - -#### Example - -The simplest way to use Logrus is simply the package-level exported logger: - -```go -package main - -import ( - log "github.com/Sirupsen/logrus" -) - -func main() { - log.WithFields(log.Fields{ - "animal": "walrus", - }).Info("A walrus appears") -} -``` - -Note that it's completely api-compatible with the stdlib logger, so you can -replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"` -and you'll now have the flexibility of Logrus. You can customize it all you -want: - -```go -package main - -import ( - "os" - log "github.com/Sirupsen/logrus" -) - -func init() { - // Log as JSON instead of the default ASCII formatter. - log.SetFormatter(&log.JSONFormatter{}) - - // Output to stderr instead of stdout, could also be a file. - log.SetOutput(os.Stderr) - - // Only log the warning severity or above. - log.SetLevel(log.WarnLevel) -} - -func main() { - log.WithFields(log.Fields{ - "animal": "walrus", - "size": 10, - }).Info("A group of walrus emerges from the ocean") - - log.WithFields(log.Fields{ - "omg": true, - "number": 122, - }).Warn("The group's number increased tremendously!") - - log.WithFields(log.Fields{ - "omg": true, - "number": 100, - }).Fatal("The ice breaks!") - - // A common pattern is to re-use fields between logging statements by re-using - // the logrus.Entry returned from WithFields() - contextLogger := log.WithFields(log.Fields{ - "common": "this is a common field", - "other": "I also should be logged always", - }) - - contextLogger.Info("I'll be logged with common and other field") - contextLogger.Info("Me too") -} -``` - -For more advanced usage such as logging to multiple locations from the same -application, you can also create an instance of the `logrus` Logger: - -```go -package main - -import ( - "github.com/Sirupsen/logrus" -) - -// Create a new instance of the logger. You can have any number of instances. -var log = logrus.New() - -func main() { - // The API for setting attributes is a little different than the package level - // exported logger. See Godoc. - log.Out = os.Stderr - - log.WithFields(logrus.Fields{ - "animal": "walrus", - "size": 10, - }).Info("A group of walrus emerges from the ocean") -} -``` - -#### Fields - -Logrus encourages careful, structured logging though logging fields instead of -long, unparseable error messages. For example, instead of: `log.Fatalf("Failed -to send event %s to topic %s with key %d")`, you should log the much more -discoverable: - -```go -log.WithFields(log.Fields{ - "event": event, - "topic": topic, - "key": key, -}).Fatal("Failed to send event") -``` - -We've found this API forces you to think about logging in a way that produces -much more useful logging messages. We've been in countless situations where just -a single added field to a log statement that was already there would've saved us -hours. The `WithFields` call is optional. - -In general, with Logrus using any of the `printf`-family functions should be -seen as a hint you should add a field, however, you can still use the -`printf`-family functions with Logrus. - -#### Hooks - -You can add hooks for logging levels. For example to send errors to an exception -tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to -multiple places simultaneously, e.g. syslog. - -Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in -`init`: - -```go -import ( - log "github.com/Sirupsen/logrus" - "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake" - logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" - "log/syslog" -) - -func init() { - - // Use the Airbrake hook to report errors that have Error severity or above to - // an exception tracker. You can create custom hooks, see the Hooks section. - log.AddHook(airbrake.NewHook(123, "xyz", "production")) - - hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") - if err != nil { - log.Error("Unable to connect to local syslog daemon") - } else { - log.AddHook(hook) - } -} -``` -Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). - -| Hook | Description | -| ----- | ----------- | -| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. | -| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | -| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | -| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | -| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | -| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. | -| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | -| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | -| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | -| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | -| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) | -| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) | -| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | -| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | -| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | -| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar | -| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | -| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | -| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb | -| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | -| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | -| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) | -| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | -| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka | -| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | -| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| - - -#### Level logging - -Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. - -```go -log.Debug("Useful debugging information.") -log.Info("Something noteworthy happened!") -log.Warn("You should probably take a look at this.") -log.Error("Something failed but I'm not quitting.") -// Calls os.Exit(1) after logging -log.Fatal("Bye.") -// Calls panic() after logging -log.Panic("I'm bailing.") -``` - -You can set the logging level on a `Logger`, then it will only log entries with -that severity or anything above it: - -```go -// Will log anything that is info or above (warn, error, fatal, panic). Default. -log.SetLevel(log.InfoLevel) -``` - -It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose -environment if your application has that. - -#### Entries - -Besides the fields added with `WithField` or `WithFields` some fields are -automatically added to all logging events: - -1. `time`. The timestamp when the entry was created. -2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after - the `AddFields` call. E.g. `Failed to send event.` -3. `level`. The logging level. E.g. `info`. - -#### Environments - -Logrus has no notion of environment. - -If you wish for hooks and formatters to only be used in specific environments, -you should handle that yourself. For example, if your application has a global -variable `Environment`, which is a string representation of the environment you -could do: - -```go -import ( - log "github.com/Sirupsen/logrus" -) - -init() { - // do something here to set environment depending on an environment variable - // or command-line flag - if Environment == "production" { - log.SetFormatter(&log.JSONFormatter{}) - } else { - // The TextFormatter is default, you don't actually have to do this. - log.SetFormatter(&log.TextFormatter{}) - } -} -``` - -This configuration is how `logrus` was intended to be used, but JSON in -production is mostly only useful if you do log aggregation with tools like -Splunk or Logstash. - -#### Formatters - -The built-in logging formatters are: - -* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise - without colors. - * *Note:* to force colored output when there is no TTY, set the `ForceColors` - field to `true`. To force no colored output even if there is a TTY set the - `DisableColors` field to `true` -* `logrus.JSONFormatter`. Logs fields as JSON. -* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events. - - ```go - logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"}) - ``` - -Third party logging formatters: - -* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. -* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. - -You can define your formatter by implementing the `Formatter` interface, -requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a -`Fields` type (`map[string]interface{}`) with all your fields as well as the -default ones (see Entries section above): - -```go -type MyJSONFormatter struct { -} - -log.SetFormatter(new(MyJSONFormatter)) - -func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { - // Note this doesn't include Time, Level and Message which are available on - // the Entry. Consult `godoc` on information about those fields or read the - // source of the official loggers. - serialized, err := json.Marshal(entry.Data) - if err != nil { - return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) - } - return append(serialized, '\n'), nil -} -``` - -#### Logger as an `io.Writer` - -Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. - -```go -w := logger.Writer() -defer w.Close() - -srv := http.Server{ - // create a stdlib log.Logger that writes to - // logrus.Logger. - ErrorLog: log.New(w, "", 0), -} -``` - -Each line written to that writer will be printed the usual way, using formatters -and hooks. The level for those entries is `info`. - -#### Rotation - -Log rotation is not provided with Logrus. Log rotation should be done by an -external program (like `logrotate(8)`) that can compress and delete old log -entries. It should not be a feature of the application-level logger. - -#### Tools - -| Tool | Description | -| ---- | ----------- | -|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| - -#### Testing - -Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: - -* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook -* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): - -```go -logger, hook := NewNullLogger() -logger.Error("Hello error") - -assert.Equal(1, len(hook.Entries)) -assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) -assert.Equal("Hello error", hook.LastEntry().Message) - -hook.Reset() -assert.Nil(hook.LastEntry()) -``` diff --git a/Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore b/Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore deleted file mode 100755 index 00268614f0..0000000000 --- a/Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/Godeps/_workspace/src/github.com/armon/go-metrics/README.md b/Godeps/_workspace/src/github.com/armon/go-metrics/README.md deleted file mode 100644 index d9f46e85ba..0000000000 --- a/Godeps/_workspace/src/github.com/armon/go-metrics/README.md +++ /dev/null @@ -1,68 +0,0 @@ -go-metrics -========== - -This library provides a `metrics` package which can be used to instrument code, -expose application metrics, and profile runtime performance in a flexible manner. - -Sinks -===== - -The `metrics` package makes use of a `MetricSink` interface to support delivery -to any type of backend. Currently the following sinks are provided: - -* StatsiteSink : Sinks to a statsite instance (TCP) -* StatsdSink: Sinks to a statsd / statsite instance (UDP) -* InmemSink : Provides in-memory aggregation, can be used to export stats -* FanoutSink : Sinks to multiple sinks. Enables writing to multiple statsite instances for example. -* BlackholeSink : Sinks to nowhere - -In addition to the sinks, the `InmemSignal` can be used to catch a signal, -and dump a formatted output of recent metrics. For example, when a process gets -a SIGUSR1, it can dump to stderr recent performance metrics for debugging. - -Examples -======== - -Here is an example of using the package: - - func SlowMethod() { - // Profiling the runtime of a method - defer metrics.MeasureSince([]string{"SlowMethod"}, time.Now()) - } - - // Configure a statsite sink as the global metrics sink - sink, _ := metrics.NewStatsiteSink("statsite:8125") - metrics.NewGlobal(metrics.DefaultConfig("service-name"), sink) - - // Emit a Key/Value pair - metrics.EmitKey([]string{"questions", "meaning of life"}, 42) - - -Here is an example of setting up an signal handler: - - // Setup the inmem sink and signal handler - inm := NewInmemSink(10*time.Second, time.Minute) - sig := DefaultInmemSignal(inm) - metrics.NewGlobal(metrics.DefaultConfig("service-name"), inm) - - // Run some code - inm.SetGauge([]string{"foo"}, 42) - inm.EmitKey([]string{"bar"}, 30) - - inm.IncrCounter([]string{"baz"}, 42) - inm.IncrCounter([]string{"baz"}, 1) - inm.IncrCounter([]string{"baz"}, 80) - - inm.AddSample([]string{"method", "wow"}, 42) - inm.AddSample([]string{"method", "wow"}, 100) - inm.AddSample([]string{"method", "wow"}, 22) - - .... - -When a signal comes in, output like the following will be dumped to stderr: - - [2014-01-28 14:57:33.04 -0800 PST][G] 'foo': 42.000 - [2014-01-28 14:57:33.04 -0800 PST][P] 'bar': 30.000 - [2014-01-28 14:57:33.04 -0800 PST][C] 'baz': Count: 3 Min: 1.000 Mean: 41.000 Max: 80.000 Stddev: 39.509 - [2014-01-28 14:57:33.04 -0800 PST][S] 'method.wow': Count: 3 Min: 22.000 Mean: 54.667 Max: 100.000 Stddev: 40.513 - diff --git a/Godeps/_workspace/src/github.com/armon/go-radix/.gitignore b/Godeps/_workspace/src/github.com/armon/go-radix/.gitignore deleted file mode 100644 index 00268614f0..0000000000 --- a/Godeps/_workspace/src/github.com/armon/go-radix/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/Godeps/_workspace/src/github.com/armon/go-radix/.travis.yml b/Godeps/_workspace/src/github.com/armon/go-radix/.travis.yml deleted file mode 100644 index 1a0bbea6c7..0000000000 --- a/Godeps/_workspace/src/github.com/armon/go-radix/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: go -go: - - tip diff --git a/Godeps/_workspace/src/github.com/armon/go-radix/README.md b/Godeps/_workspace/src/github.com/armon/go-radix/README.md deleted file mode 100644 index c054fe86c0..0000000000 --- a/Godeps/_workspace/src/github.com/armon/go-radix/README.md +++ /dev/null @@ -1,36 +0,0 @@ -go-radix [![Build Status](https://travis-ci.org/armon/go-radix.png)](https://travis-ci.org/armon/go-radix) -========= - -Provides the `radix` package that implements a [radix tree](http://en.wikipedia.org/wiki/Radix_tree). -The package only provides a single `Tree` implementation, optimized for sparse nodes. - -As a radix tree, it provides the following: - * O(k) operations. In many cases, this can be faster than a hash table since - the hash function is an O(k) operation, and hash tables have very poor cache locality. - * Minimum / Maximum value lookups - * Ordered iteration - -Documentation -============= - -The full documentation is available on [Godoc](http://godoc.org/github.com/armon/go-radix). - -Example -======= - -Below is a simple example of usage - -```go -// Create a tree -r := radix.New() -r.Insert("foo", 1) -r.Insert("bar", 2) -r.Insert("foobar", 2) - -// Find the longest prefix match -m, _, _ := r.LongestPrefix("foozip") -if m != "foo" { - panic("should be foo") -} -``` - diff --git a/Godeps/_workspace/src/github.com/boltdb/bolt/.gitignore b/Godeps/_workspace/src/github.com/boltdb/bolt/.gitignore deleted file mode 100644 index c7bd2b7a5b..0000000000 --- a/Godeps/_workspace/src/github.com/boltdb/bolt/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.prof -*.test -*.swp -/bin/ diff --git a/Godeps/_workspace/src/github.com/boltdb/bolt/Makefile b/Godeps/_workspace/src/github.com/boltdb/bolt/Makefile deleted file mode 100644 index e035e63adc..0000000000 --- a/Godeps/_workspace/src/github.com/boltdb/bolt/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -BRANCH=`git rev-parse --abbrev-ref HEAD` -COMMIT=`git rev-parse --short HEAD` -GOLDFLAGS="-X main.branch $(BRANCH) -X main.commit $(COMMIT)" - -default: build - -race: - @go test -v -race -test.run="TestSimulate_(100op|1000op)" - -# go get github.com/kisielk/errcheck -errcheck: - @errcheck -ignorepkg=bytes -ignore=os:Remove github.com/boltdb/bolt - -test: - @go test -v -cover . - @go test -v ./cmd/bolt - -.PHONY: fmt test diff --git a/Godeps/_workspace/src/github.com/boltdb/bolt/README.md b/Godeps/_workspace/src/github.com/boltdb/bolt/README.md deleted file mode 100644 index 66b19ace8a..0000000000 --- a/Godeps/_workspace/src/github.com/boltdb/bolt/README.md +++ /dev/null @@ -1,844 +0,0 @@ -Bolt [![Build Status](https://drone.io/github.com/boltdb/bolt/status.png)](https://drone.io/github.com/boltdb/bolt/latest) [![Coverage Status](https://coveralls.io/repos/boltdb/bolt/badge.svg?branch=master)](https://coveralls.io/r/boltdb/bolt?branch=master) [![GoDoc](https://godoc.org/github.com/boltdb/bolt?status.svg)](https://godoc.org/github.com/boltdb/bolt) ![Version](https://img.shields.io/badge/version-1.0-green.svg) -==== - -Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas] -[LMDB project][lmdb]. The goal of the project is to provide a simple, -fast, and reliable database for projects that don't require a full database -server such as Postgres or MySQL. - -Since Bolt is meant to be used as such a low-level piece of functionality, -simplicity is key. The API will be small and only focus on getting values -and setting values. That's it. - -[hyc_symas]: https://twitter.com/hyc_symas -[lmdb]: http://symas.com/mdb/ - -## Project Status - -Bolt is stable and the API is fixed. Full unit test coverage and randomized -black box testing are used to ensure database consistency and thread safety. -Bolt is currently in high-load production environments serving databases as -large as 1TB. Many companies such as Shopify and Heroku use Bolt-backed -services every day. - -## Table of Contents - -- [Getting Started](#getting-started) - - [Installing](#installing) - - [Opening a database](#opening-a-database) - - [Transactions](#transactions) - - [Read-write transactions](#read-write-transactions) - - [Read-only transactions](#read-only-transactions) - - [Batch read-write transactions](#batch-read-write-transactions) - - [Managing transactions manually](#managing-transactions-manually) - - [Using buckets](#using-buckets) - - [Using key/value pairs](#using-keyvalue-pairs) - - [Autoincrementing integer for the bucket](#autoincrementing-integer-for-the-bucket) - - [Iterating over keys](#iterating-over-keys) - - [Prefix scans](#prefix-scans) - - [Range scans](#range-scans) - - [ForEach()](#foreach) - - [Nested buckets](#nested-buckets) - - [Database backups](#database-backups) - - [Statistics](#statistics) - - [Read-Only Mode](#read-only-mode) - - [Mobile Use (iOS/Android)](#mobile-use-iosandroid) -- [Resources](#resources) -- [Comparison with other databases](#comparison-with-other-databases) - - [Postgres, MySQL, & other relational databases](#postgres-mysql--other-relational-databases) - - [LevelDB, RocksDB](#leveldb-rocksdb) - - [LMDB](#lmdb) -- [Caveats & Limitations](#caveats--limitations) -- [Reading the Source](#reading-the-source) -- [Other Projects Using Bolt](#other-projects-using-bolt) - -## Getting Started - -### Installing - -To start using Bolt, install Go and run `go get`: - -```sh -$ go get github.com/boltdb/bolt/... -``` - -This will retrieve the library and install the `bolt` command line utility into -your `$GOBIN` path. - - -### Opening a database - -The top-level object in Bolt is a `DB`. It is represented as a single file on -your disk and represents a consistent snapshot of your data. - -To open your database, simply use the `bolt.Open()` function: - -```go -package main - -import ( - "log" - - "github.com/boltdb/bolt" -) - -func main() { - // Open the my.db data file in your current directory. - // It will be created if it doesn't exist. - db, err := bolt.Open("my.db", 0600, nil) - if err != nil { - log.Fatal(err) - } - defer db.Close() - - ... -} -``` - -Please note that Bolt obtains a file lock on the data file so multiple processes -cannot open the same database at the same time. Opening an already open Bolt -database will cause it to hang until the other process closes it. To prevent -an indefinite wait you can pass a timeout option to the `Open()` function: - -```go -db, err := bolt.Open("my.db", 0600, &bolt.Options{Timeout: 1 * time.Second}) -``` - - -### Transactions - -Bolt allows only one read-write transaction at a time but allows as many -read-only transactions as you want at a time. Each transaction has a consistent -view of the data as it existed when the transaction started. - -Individual transactions and all objects created from them (e.g. buckets, keys) -are not thread safe. To work with data in multiple goroutines you must start -a transaction for each one or use locking to ensure only one goroutine accesses -a transaction at a time. Creating transaction from the `DB` is thread safe. - -Read-only transactions and read-write transactions should not depend on one -another and generally shouldn't be opened simultaneously in the same goroutine. -This can cause a deadlock as the read-write transaction needs to periodically -re-map the data file but it cannot do so while a read-only transaction is open. - - -#### Read-write transactions - -To start a read-write transaction, you can use the `DB.Update()` function: - -```go -err := db.Update(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -Inside the closure, you have a consistent view of the database. You commit the -transaction by returning `nil` at the end. You can also rollback the transaction -at any point by returning an error. All database operations are allowed inside -a read-write transaction. - -Always check the return error as it will report any disk failures that can cause -your transaction to not complete. If you return an error within your closure -it will be passed through. - - -#### Read-only transactions - -To start a read-only transaction, you can use the `DB.View()` function: - -```go -err := db.View(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -You also get a consistent view of the database within this closure, however, -no mutating operations are allowed within a read-only transaction. You can only -retrieve buckets, retrieve values, and copy the database within a read-only -transaction. - - -#### Batch read-write transactions - -Each `DB.Update()` waits for disk to commit the writes. This overhead -can be minimized by combining multiple updates with the `DB.Batch()` -function: - -```go -err := db.Batch(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -Concurrent Batch calls are opportunistically combined into larger -transactions. Batch is only useful when there are multiple goroutines -calling it. - -The trade-off is that `Batch` can call the given -function multiple times, if parts of the transaction fail. The -function must be idempotent and side effects must take effect only -after a successful return from `DB.Batch()`. - -For example: don't display messages from inside the function, instead -set variables in the enclosing scope: - -```go -var id uint64 -err := db.Batch(func(tx *bolt.Tx) error { - // Find last key in bucket, decode as bigendian uint64, increment - // by one, encode back to []byte, and add new key. - ... - id = newValue - return nil -}) -if err != nil { - return ... -} -fmt.Println("Allocated ID %d", id) -``` - - -#### Managing transactions manually - -The `DB.View()` and `DB.Update()` functions are wrappers around the `DB.Begin()` -function. These helper functions will start the transaction, execute a function, -and then safely close your transaction if an error is returned. This is the -recommended way to use Bolt transactions. - -However, sometimes you may want to manually start and end your transactions. -You can use the `Tx.Begin()` function directly but **please** be sure to close -the transaction. - -```go -// Start a writable transaction. -tx, err := db.Begin(true) -if err != nil { - return err -} -defer tx.Rollback() - -// Use the transaction... -_, err := tx.CreateBucket([]byte("MyBucket")) -if err != nil { - return err -} - -// Commit the transaction and check for error. -if err := tx.Commit(); err != nil { - return err -} -``` - -The first argument to `DB.Begin()` is a boolean stating if the transaction -should be writable. - - -### Using buckets - -Buckets are collections of key/value pairs within the database. All keys in a -bucket must be unique. You can create a bucket using the `DB.CreateBucket()` -function: - -```go -db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("MyBucket")) - if err != nil { - return fmt.Errorf("create bucket: %s", err) - } - return nil -}) -``` - -You can also create a bucket only if it doesn't exist by using the -`Tx.CreateBucketIfNotExists()` function. It's a common pattern to call this -function for all your top-level buckets after you open your database so you can -guarantee that they exist for future transactions. - -To delete a bucket, simply call the `Tx.DeleteBucket()` function. - - -### Using key/value pairs - -To save a key/value pair to a bucket, use the `Bucket.Put()` function: - -```go -db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("MyBucket")) - err := b.Put([]byte("answer"), []byte("42")) - return err -}) -``` - -This will set the value of the `"answer"` key to `"42"` in the `MyBucket` -bucket. To retrieve this value, we can use the `Bucket.Get()` function: - -```go -db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("MyBucket")) - v := b.Get([]byte("answer")) - fmt.Printf("The answer is: %s\n", v) - return nil -}) -``` - -The `Get()` function does not return an error because its operation is -guaranteed to work (unless there is some kind of system failure). If the key -exists then it will return its byte slice value. If it doesn't exist then it -will return `nil`. It's important to note that you can have a zero-length value -set to a key which is different than the key not existing. - -Use the `Bucket.Delete()` function to delete a key from the bucket. - -Please note that values returned from `Get()` are only valid while the -transaction is open. If you need to use a value outside of the transaction -then you must use `copy()` to copy it to another byte slice. - - -### Autoincrementing integer for the bucket -By using the `NextSequence()` function, you can let Bolt determine a sequence -which can be used as the unique identifier for your key/value pairs. See the -example below. - -```go -// CreateUser saves u to the store. The new user ID is set on u once the data is persisted. -func (s *Store) CreateUser(u *User) error { - return s.db.Update(func(tx *bolt.Tx) error { - // Retrieve the users bucket. - // This should be created when the DB is first opened. - b := tx.Bucket([]byte("users")) - - // Generate ID for the user. - // This returns an error only if the Tx is closed or not writeable. - // That can't happen in an Update() call so I ignore the error check. - id, _ = b.NextSequence() - u.ID = int(id) - - // Marshal user data into bytes. - buf, err := json.Marshal(u) - if err != nil { - return err - } - - // Persist bytes to users bucket. - return b.Put(itob(u.ID), buf) - }) -} - -// itob returns an 8-byte big endian representation of v. -func itob(v int) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(v)) - return b -} - -type User struct { - ID int - ... -} -``` - -### Iterating over keys - -Bolt stores its keys in byte-sorted order within a bucket. This makes sequential -iteration over these keys extremely fast. To iterate over keys we'll use a -`Cursor`: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - b := tx.Bucket([]byte("MyBucket")) - - c := b.Cursor() - - for k, v := c.First(); k != nil; k, v = c.Next() { - fmt.Printf("key=%s, value=%s\n", k, v) - } - - return nil -}) -``` - -The cursor allows you to move to a specific point in the list of keys and move -forward or backward through the keys one at a time. - -The following functions are available on the cursor: - -``` -First() Move to the first key. -Last() Move to the last key. -Seek() Move to a specific key. -Next() Move to the next key. -Prev() Move to the previous key. -``` - -Each of those functions has a return signature of `(key []byte, value []byte)`. -When you have iterated to the end of the cursor then `Next()` will return a -`nil` key. You must seek to a position using `First()`, `Last()`, or `Seek()` -before calling `Next()` or `Prev()`. If you do not seek to a position then -these functions will return a `nil` key. - -During iteration, if the key is non-`nil` but the value is `nil`, that means -the key refers to a bucket rather than a value. Use `Bucket.Bucket()` to -access the sub-bucket. - - -#### Prefix scans - -To iterate over a key prefix, you can combine `Seek()` and `bytes.HasPrefix()`: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - c := tx.Bucket([]byte("MyBucket")).Cursor() - - prefix := []byte("1234") - for k, v := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, v = c.Next() { - fmt.Printf("key=%s, value=%s\n", k, v) - } - - return nil -}) -``` - -#### Range scans - -Another common use case is scanning over a range such as a time range. If you -use a sortable time encoding such as RFC3339 then you can query a specific -date range like this: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume our events bucket exists and has RFC3339 encoded time keys. - c := tx.Bucket([]byte("Events")).Cursor() - - // Our time range spans the 90's decade. - min := []byte("1990-01-01T00:00:00Z") - max := []byte("2000-01-01T00:00:00Z") - - // Iterate over the 90's. - for k, v := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, v = c.Next() { - fmt.Printf("%s: %s\n", k, v) - } - - return nil -}) -``` - - -#### ForEach() - -You can also use the function `ForEach()` if you know you'll be iterating over -all the keys in a bucket: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - b := tx.Bucket([]byte("MyBucket")) - - b.ForEach(func(k, v []byte) error { - fmt.Printf("key=%s, value=%s\n", k, v) - return nil - }) - return nil -}) -``` - - -### Nested buckets - -You can also store a bucket in a key to create nested buckets. The API is the -same as the bucket management API on the `DB` object: - -```go -func (*Bucket) CreateBucket(key []byte) (*Bucket, error) -func (*Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) -func (*Bucket) DeleteBucket(key []byte) error -``` - - -### Database backups - -Bolt is a single file so it's easy to backup. You can use the `Tx.WriteTo()` -function to write a consistent view of the database to a writer. If you call -this from a read-only transaction, it will perform a hot backup and not block -your other database reads and writes. - -By default, it will use a regular file handle which will utilize the operating -system's page cache. See the [`Tx`](https://godoc.org/github.com/boltdb/bolt#Tx) -documentation for information about optimizing for larger-than-RAM datasets. - -One common use case is to backup over HTTP so you can use tools like `cURL` to -do database backups: - -```go -func BackupHandleFunc(w http.ResponseWriter, req *http.Request) { - err := db.View(func(tx *bolt.Tx) error { - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", `attachment; filename="my.db"`) - w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size()))) - _, err := tx.WriteTo(w) - return err - }) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } -} -``` - -Then you can backup using this command: - -```sh -$ curl http://localhost/backup > my.db -``` - -Or you can open your browser to `http://localhost/backup` and it will download -automatically. - -If you want to backup to another file you can use the `Tx.CopyFile()` helper -function. - - -### Statistics - -The database keeps a running count of many of the internal operations it -performs so you can better understand what's going on. By grabbing a snapshot -of these stats at two points in time we can see what operations were performed -in that time range. - -For example, we could start a goroutine to log stats every 10 seconds: - -```go -go func() { - // Grab the initial stats. - prev := db.Stats() - - for { - // Wait for 10s. - time.Sleep(10 * time.Second) - - // Grab the current stats and diff them. - stats := db.Stats() - diff := stats.Sub(&prev) - - // Encode stats to JSON and print to STDERR. - json.NewEncoder(os.Stderr).Encode(diff) - - // Save stats for the next loop. - prev = stats - } -}() -``` - -It's also useful to pipe these stats to a service such as statsd for monitoring -or to provide an HTTP endpoint that will perform a fixed-length sample. - - -### Read-Only Mode - -Sometimes it is useful to create a shared, read-only Bolt database. To this, -set the `Options.ReadOnly` flag when opening your database. Read-only mode -uses a shared lock to allow multiple processes to read from the database but -it will block any processes from opening the database in read-write mode. - -```go -db, err := bolt.Open("my.db", 0666, &bolt.Options{ReadOnly: true}) -if err != nil { - log.Fatal(err) -} -``` - -### Mobile Use (iOS/Android) - -Bolt is able to run on mobile devices by leveraging the binding feature of the -[gomobile](https://github.com/golang/mobile) tool. Create a struct that will -contain your database logic and a reference to a `*bolt.DB` with a initializing -contstructor that takes in a filepath where the database file will be stored. -Neither Android nor iOS require extra permissions or cleanup from using this method. - -```go -func NewBoltDB(filepath string) *BoltDB { - db, err := bolt.Open(filepath+"/demo.db", 0600, nil) - if err != nil { - log.Fatal(err) - } - - return &BoltDB{db} -} - -type BoltDB struct { - db *bolt.DB - ... -} - -func (b *BoltDB) Path() string { - return b.db.Path() -} - -func (b *BoltDB) Close() { - b.db.Close() -} -``` - -Database logic should be defined as methods on this wrapper struct. - -To initialize this struct from the native language (both platforms now sync -their local storage to the cloud. These snippets disable that functionality for the -database file): - -#### Android - -```java -String path; -if (android.os.Build.VERSION.SDK_INT >=android.os.Build.VERSION_CODES.LOLLIPOP){ - path = getNoBackupFilesDir().getAbsolutePath(); -} else{ - path = getFilesDir().getAbsolutePath(); -} -Boltmobiledemo.BoltDB boltDB = Boltmobiledemo.NewBoltDB(path) -``` - -#### iOS - -```objc -- (void)demo { - NSString* path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, - NSUserDomainMask, - YES) objectAtIndex:0]; - GoBoltmobiledemoBoltDB * demo = GoBoltmobiledemoNewBoltDB(path); - [self addSkipBackupAttributeToItemAtPath:demo.path]; - //Some DB Logic would go here - [demo close]; -} - -- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString -{ - NSURL* URL= [NSURL fileURLWithPath: filePathString]; - assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]); - - NSError *error = nil; - BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES] - forKey: NSURLIsExcludedFromBackupKey error: &error]; - if(!success){ - NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error); - } - return success; -} - -``` - -## Resources - -For more information on getting started with Bolt, check out the following articles: - -* [Intro to BoltDB: Painless Performant Persistence](http://npf.io/2014/07/intro-to-boltdb-painless-performant-persistence/) by [Nate Finch](https://github.com/natefinch). -* [Bolt -- an embedded key/value database for Go](https://www.progville.com/go/bolt-embedded-db-golang/) by Progville - - -## Comparison with other databases - -### Postgres, MySQL, & other relational databases - -Relational databases structure data into rows and are only accessible through -the use of SQL. This approach provides flexibility in how you store and query -your data but also incurs overhead in parsing and planning SQL statements. Bolt -accesses all data by a byte slice key. This makes Bolt fast to read and write -data by key but provides no built-in support for joining values together. - -Most relational databases (with the exception of SQLite) are standalone servers -that run separately from your application. This gives your systems -flexibility to connect multiple application servers to a single database -server but also adds overhead in serializing and transporting data over the -network. Bolt runs as a library included in your application so all data access -has to go through your application's process. This brings data closer to your -application but limits multi-process access to the data. - - -### LevelDB, RocksDB - -LevelDB and its derivatives (RocksDB, HyperLevelDB) are similar to Bolt in that -they are libraries bundled into the application, however, their underlying -structure is a log-structured merge-tree (LSM tree). An LSM tree optimizes -random writes by using a write ahead log and multi-tiered, sorted files called -SSTables. Bolt uses a B+tree internally and only a single file. Both approaches -have trade-offs. - -If you require a high random write throughput (>10,000 w/sec) or you need to use -spinning disks then LevelDB could be a good choice. If your application is -read-heavy or does a lot of range scans then Bolt could be a good choice. - -One other important consideration is that LevelDB does not have transactions. -It supports batch writing of key/values pairs and it supports read snapshots -but it will not give you the ability to do a compare-and-swap operation safely. -Bolt supports fully serializable ACID transactions. - - -### LMDB - -Bolt was originally a port of LMDB so it is architecturally similar. Both use -a B+tree, have ACID semantics with fully serializable transactions, and support -lock-free MVCC using a single writer and multiple readers. - -The two projects have somewhat diverged. LMDB heavily focuses on raw performance -while Bolt has focused on simplicity and ease of use. For example, LMDB allows -several unsafe actions such as direct writes for the sake of performance. Bolt -opts to disallow actions which can leave the database in a corrupted state. The -only exception to this in Bolt is `DB.NoSync`. - -There are also a few differences in API. LMDB requires a maximum mmap size when -opening an `mdb_env` whereas Bolt will handle incremental mmap resizing -automatically. LMDB overloads the getter and setter functions with multiple -flags whereas Bolt splits these specialized cases into their own functions. - - -## Caveats & Limitations - -It's important to pick the right tool for the job and Bolt is no exception. -Here are a few things to note when evaluating and using Bolt: - -* Bolt is good for read intensive workloads. Sequential write performance is - also fast but random writes can be slow. You can use `DB.Batch()` or add a - write-ahead log to help mitigate this issue. - -* Bolt uses a B+tree internally so there can be a lot of random page access. - SSDs provide a significant performance boost over spinning disks. - -* Try to avoid long running read transactions. Bolt uses copy-on-write so - old pages cannot be reclaimed while an old transaction is using them. - -* Byte slices returned from Bolt are only valid during a transaction. Once the - transaction has been committed or rolled back then the memory they point to - can be reused by a new page or can be unmapped from virtual memory and you'll - see an `unexpected fault address` panic when accessing it. - -* Be careful when using `Bucket.FillPercent`. Setting a high fill percent for - buckets that have random inserts will cause your database to have very poor - page utilization. - -* Use larger buckets in general. Smaller buckets causes poor page utilization - once they become larger than the page size (typically 4KB). - -* Bulk loading a lot of random writes into a new bucket can be slow as the - page will not split until the transaction is committed. Randomly inserting - more than 100,000 key/value pairs into a single new bucket in a single - transaction is not advised. - -* Bolt uses a memory-mapped file so the underlying operating system handles the - caching of the data. Typically, the OS will cache as much of the file as it - can in memory and will release memory as needed to other processes. This means - that Bolt can show very high memory usage when working with large databases. - However, this is expected and the OS will release memory as needed. Bolt can - handle databases much larger than the available physical RAM, provided its - memory-map fits in the process virtual address space. It may be problematic - on 32-bits systems. - -* The data structures in the Bolt database are memory mapped so the data file - will be endian specific. This means that you cannot copy a Bolt file from a - little endian machine to a big endian machine and have it work. For most - users this is not a concern since most modern CPUs are little endian. - -* Because of the way pages are laid out on disk, Bolt cannot truncate data files - and return free pages back to the disk. Instead, Bolt maintains a free list - of unused pages within its data file. These free pages can be reused by later - transactions. This works well for many use cases as databases generally tend - to grow. However, it's important to note that deleting large chunks of data - will not allow you to reclaim that space on disk. - - For more information on page allocation, [see this comment][page-allocation]. - -[page-allocation]: https://github.com/boltdb/bolt/issues/308#issuecomment-74811638 - - -## Reading the Source - -Bolt is a relatively small code base (<3KLOC) for an embedded, serializable, -transactional key/value database so it can be a good starting point for people -interested in how databases work. - -The best places to start are the main entry points into Bolt: - -- `Open()` - Initializes the reference to the database. It's responsible for - creating the database if it doesn't exist, obtaining an exclusive lock on the - file, reading the meta pages, & memory-mapping the file. - -- `DB.Begin()` - Starts a read-only or read-write transaction depending on the - value of the `writable` argument. This requires briefly obtaining the "meta" - lock to keep track of open transactions. Only one read-write transaction can - exist at a time so the "rwlock" is acquired during the life of a read-write - transaction. - -- `Bucket.Put()` - Writes a key/value pair into a bucket. After validating the - arguments, a cursor is used to traverse the B+tree to the page and position - where they key & value will be written. Once the position is found, the bucket - materializes the underlying page and the page's parent pages into memory as - "nodes". These nodes are where mutations occur during read-write transactions. - These changes get flushed to disk during commit. - -- `Bucket.Get()` - Retrieves a key/value pair from a bucket. This uses a cursor - to move to the page & position of a key/value pair. During a read-only - transaction, the key and value data is returned as a direct reference to the - underlying mmap file so there's no allocation overhead. For read-write - transactions, this data may reference the mmap file or one of the in-memory - node values. - -- `Cursor` - This object is simply for traversing the B+tree of on-disk pages - or in-memory nodes. It can seek to a specific key, move to the first or last - value, or it can move forward or backward. The cursor handles the movement up - and down the B+tree transparently to the end user. - -- `Tx.Commit()` - Converts the in-memory dirty nodes and the list of free pages - into pages to be written to disk. Writing to disk then occurs in two phases. - First, the dirty pages are written to disk and an `fsync()` occurs. Second, a - new meta page with an incremented transaction ID is written and another - `fsync()` occurs. This two phase write ensures that partially written data - pages are ignored in the event of a crash since the meta page pointing to them - is never written. Partially written meta pages are invalidated because they - are written with a checksum. - -If you have additional notes that could be helpful for others, please submit -them via pull request. - - -## Other Projects Using Bolt - -Below is a list of public, open source projects that use Bolt: - -* [Operation Go: A Routine Mission](http://gocode.io) - An online programming game for Golang using Bolt for user accounts and a leaderboard. -* [Bazil](https://bazil.org/) - A file system that lets your data reside where it is most convenient for it to reside. -* [DVID](https://github.com/janelia-flyem/dvid) - Added Bolt as optional storage engine and testing it against Basho-tuned leveldb. -* [Skybox Analytics](https://github.com/skybox/skybox) - A standalone funnel analysis tool for web analytics. -* [Scuttlebutt](https://github.com/benbjohnson/scuttlebutt) - Uses Bolt to store and process all Twitter mentions of GitHub projects. -* [Wiki](https://github.com/peterhellberg/wiki) - A tiny wiki using Goji, BoltDB and Blackfriday. -* [ChainStore](https://github.com/pressly/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations. -* [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite. -* [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin". -* [event-shuttle](https://github.com/sclasen/event-shuttle) - A Unix system service to collect and reliably deliver messages to Kafka. -* [ipxed](https://github.com/kelseyhightower/ipxed) - Web interface and api for ipxed. -* [BoltStore](https://github.com/yosssi/boltstore) - Session store using Bolt. -* [photosite/session](https://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site. -* [LedisDB](https://github.com/siddontang/ledisdb) - A high performance NoSQL, using Bolt as optional storage. -* [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters. -* [cayley](https://github.com/google/cayley) - Cayley is an open-source graph database using Bolt as optional backend. -* [bleve](http://www.blevesearch.com/) - A pure Go search engine similar to ElasticSearch that uses Bolt as the default storage backend. -* [tentacool](https://github.com/optiflows/tentacool) - REST api server to manage system stuff (IP, DNS, Gateway...) on a linux server. -* [SkyDB](https://github.com/skydb/sky) - Behavioral analytics database. -* [Seaweed File System](https://github.com/chrislusf/seaweedfs) - Highly scalable distributed key~file system with O(1) disk read. -* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics. -* [Freehold](http://tshannon.bitbucket.org/freehold/) - An open, secure, and lightweight platform for your files and data. -* [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system. -* [Consul](https://github.com/hashicorp/consul) - Consul is service discovery and configuration made easy. Distributed, highly available, and datacenter-aware. -* [Kala](https://github.com/ajvb/kala) - Kala is a modern job scheduler optimized to run on a single node. It is persistent, JSON over HTTP API, ISO 8601 duration notation, and dependent jobs. -* [drive](https://github.com/odeke-em/drive) - drive is an unofficial Google Drive command line client for \*NIX operating systems. -* [stow](https://github.com/djherbis/stow) - a persistence manager for objects - backed by boltdb. -* [buckets](https://github.com/joyrexus/buckets) - a bolt wrapper streamlining - simple tx and key scans. -* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets. -* [Request Baskets](https://github.com/darklynx/request-baskets) - A web service to collect arbitrary HTTP requests and inspect them via REST API or simple web UI, similar to [RequestBin](http://requestb.in/) service -* [Go Report Card](https://goreportcard.com/) - Go code quality report cards as a (free and open source) service. -* [Boltdb Boilerplate](https://github.com/bobintornado/boltdb-boilerplate) - Boilerplate wrapper around bolt aiming to make simple calls one-liners. -* [lru](https://github.com/crowdriff/lru) - Easy to use Bolt-backed Least-Recently-Used (LRU) read-through cache with chainable remote stores. - -If you are using Bolt in a project please send a pull request to add it to the list. diff --git a/Godeps/_workspace/src/github.com/boltdb/bolt/appveyor.yml b/Godeps/_workspace/src/github.com/boltdb/bolt/appveyor.yml deleted file mode 100644 index 6e26e941d6..0000000000 --- a/Godeps/_workspace/src/github.com/boltdb/bolt/appveyor.yml +++ /dev/null @@ -1,18 +0,0 @@ -version: "{build}" - -os: Windows Server 2012 R2 - -clone_folder: c:\gopath\src\github.com\boltdb\bolt - -environment: - GOPATH: c:\gopath - -install: - - echo %PATH% - - echo %GOPATH% - - go version - - go env - - go get -v -t ./... - -build_script: - - go test -v ./... diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml deleted file mode 100644 index 34d39c871e..0000000000 --- a/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: go -sudo: false - -go: -- 1.0.3 -- 1.1.2 -- 1.2.2 -- 1.3.3 -- 1.4.2 - -script: -- go vet ./... -- go test -v ./... diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/README.md b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md deleted file mode 100644 index fa220e2991..0000000000 --- a/Godeps/_workspace/src/github.com/codegangsta/cli/README.md +++ /dev/null @@ -1,316 +0,0 @@ -[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli) - -# cli.go -`cli.go` is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way. - -You can view the API docs here: -http://godoc.org/github.com/codegangsta/cli - -## Overview -Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app. - -**This is where `cli.go` comes into play.** `cli.go` makes command line programming fun, organized, and expressive! - -## Installation -Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html). - -To install `cli.go`, simply run: -``` -$ go get github.com/codegangsta/cli -``` - -Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used: -``` -export PATH=$PATH:$GOPATH/bin -``` - -## Getting Started -One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`. - -``` go -package main - -import ( - "os" - "github.com/codegangsta/cli" -) - -func main() { - cli.NewApp().Run(os.Args) -} -``` - -This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation: - -``` go -package main - -import ( - "os" - "github.com/codegangsta/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "boom" - app.Usage = "make an explosive entrance" - app.Action = func(c *cli.Context) { - println("boom! I say!") - } - - app.Run(os.Args) -} -``` - -Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below. - -## Example - -Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness! - -Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it: - -``` go -package main - -import ( - "os" - "github.com/codegangsta/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "greet" - app.Usage = "fight the loneliness!" - app.Action = func(c *cli.Context) { - println("Hello friend!") - } - - app.Run(os.Args) -} -``` - -Install our command to the `$GOPATH/bin` directory: - -``` -$ go install -``` - -Finally run our new command: - -``` -$ greet -Hello friend! -``` - -`cli.go` also generates some bitchass help text: - -``` -$ greet help -NAME: - greet - fight the loneliness! - -USAGE: - greet [global options] command [command options] [arguments...] - -VERSION: - 0.0.0 - -COMMANDS: - help, h Shows a list of commands or help for one command - -GLOBAL OPTIONS - --version Shows version information -``` - -### Arguments -You can lookup arguments by calling the `Args` function on `cli.Context`. - -``` go -... -app.Action = func(c *cli.Context) { - println("Hello", c.Args()[0]) -} -... -``` - -### Flags -Setting and querying flags is simple. -``` go -... -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", - }, -} -app.Action = func(c *cli.Context) { - name := "someone" - if len(c.Args()) > 0 { - name = c.Args()[0] - } - if c.String("lang") == "spanish" { - println("Hola", name) - } else { - println("Hello", name) - } -} -... -``` - -See full list of flags at http://godoc.org/github.com/codegangsta/cli - -#### Alternate Names - -You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g. - -``` go -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - }, -} -``` - -That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error. - -#### Values from the Environment - -You can also have the default value set from the environment via `EnvVar`. e.g. - -``` go -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - EnvVar: "APP_LANG", - }, -} -``` - -The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default. - -``` go -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG", - }, -} -``` - -### Subcommands - -Subcommands can be defined for a more git-like command line app. -```go -... -app.Commands = []cli.Command{ - { - Name: "add", - Aliases: []string{"a"}, - Usage: "add a task to the list", - Action: func(c *cli.Context) { - println("added task: ", c.Args().First()) - }, - }, - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) { - println("completed task: ", c.Args().First()) - }, - }, - { - Name: "template", - Aliases: []string{"r"}, - Usage: "options for task templates", - Subcommands: []cli.Command{ - { - Name: "add", - Usage: "add a new template", - Action: func(c *cli.Context) { - println("new task template: ", c.Args().First()) - }, - }, - { - Name: "remove", - Usage: "remove an existing template", - Action: func(c *cli.Context) { - println("removed task template: ", c.Args().First()) - }, - }, - }, - }, -} -... -``` - -### Bash Completion - -You can enable completion commands by setting the `EnableBashCompletion` -flag on the `App` object. By default, this setting will only auto-complete to -show an app's subcommands, but you can write your own completion methods for -the App or its subcommands. -```go -... -var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"} -app := cli.NewApp() -app.EnableBashCompletion = true -app.Commands = []cli.Command{ - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) { - println("completed task: ", c.Args().First()) - }, - BashComplete: func(c *cli.Context) { - // This will complete if no args are passed - if len(c.Args()) > 0 { - return - } - for _, t := range tasks { - fmt.Println(t) - } - }, - } -} -... -``` - -#### To Enable - -Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while -setting the `PROG` variable to the name of your program: - -`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` - -#### To Distribute - -Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename -it to the name of the program you wish to add autocomplete support for (or -automatically install it there if you are distributing a package). Don't forget -to source the file to make it active in the current shell. - -``` - sudo cp src/bash_autocomplete /etc/bash_completion.d/ - source /etc/bash_completion.d/ -``` - -Alternatively, you can just document that users should source the generic -`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set -to the name of their program (as above). - -## Contribution Guidelines -Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch. - -If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together. - -If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out. diff --git a/Godeps/_workspace/src/github.com/coreos/etcd/client/README.md b/Godeps/_workspace/src/github.com/coreos/etcd/client/README.md deleted file mode 100644 index 672b8c13f0..0000000000 --- a/Godeps/_workspace/src/github.com/coreos/etcd/client/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# etcd/client - -etcd/client is the Go client library for etcd. - -[![GoDoc](https://godoc.org/github.com/coreos/etcd/client?status.png)](https://godoc.org/github.com/coreos/etcd/client) - -## Install - -```bash -go get github.com/coreos/etcd/client -``` - -## Usage - -```go -package main - -import ( - "log" - "time" - - "github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context" - "github.com/coreos/etcd/client" -) - -func main() { - cfg := client.Config{ - Endpoints: []string{"http://127.0.0.1:2379"}, - Transport: client.DefaultTransport, - // set timeout per request to fail fast when the target endpoint is unavailable - HeaderTimeoutPerRequest: time.Second, - } - c, err := client.New(cfg) - if err != nil { - log.Fatal(err) - } - kapi := client.NewKeysAPI(c) - resp, err := kapi.Set(context.Background(), "foo", "bar", nil) - if err != nil { - log.Fatal(err) - } -} -``` - -## Error Handling - -etcd client might return three types of errors. - -- context error - -Each API call has its first parameter as `context`. A context can be canceled or have an attached deadline. If the context is canceled or reaches its deadline, the responding context error will be returned no matter what internal errors the API call has already encountered. - -- cluster error - -Each API call tries to send request to the cluster endpoints one by one until it successfully gets a response. If a requests to an endpoint fails, due to exceeding per request timeout or connection issues, the error will be added into a list of errors. If all possible endpoints fail, a cluster error that includes all encountered errors will be returned. - -- response error - -If the response gets from the cluster is invalid, a plain string error will be returned. For example, it might be a invalid JSON error. - -Here is the example code to handle client errors: - -```go -cfg := client.Config{Endpoints: []string{"http://etcd1:2379,http://etcd2:2379,http://etcd3:2379"}} -c, err := client.New(cfg) -if err != nil { - log.Fatal(err) -} - -kapi := client.NewKeysAPI(c) -resp, err := kapi.Set(ctx, "test", "bar", nil) -if err != nil { - if err == context.Canceled { - // ctx is canceled by another routine - } else if err == context.DeadlineExceeded { - // ctx is attached with a deadline and it exceeded - } else if cerr, ok := err.(*client.ClusterError); ok { - // process (cerr.Errors) - } else { - // bad cluster endpoints, which are not etcd servers - } -} -``` - - -## Caveat - -1. etcd/client prefers to use the same endpoint as long as the endpoint continues to work well. This saves socket resources, and improves efficiency for both client and server side. This preference doesn't remove consistency from the data consumed by the client because data replicated to each etcd member has already passed through the consensus process. - -2. etcd/client does round-robin rotation on other available endpoints if the preferred endpoint isn't functioning properly. For example, if the member that etcd/client connects to is hard killed, etcd/client will fail on the first attempt with the killed member, and succeed on the second attempt with another member. If it fails to talk to all available endpoints, it will return all errors happened. - -3. Default etcd/client cannot handle the case that the remote server is SIGSTOPed now. TCP keepalive mechanism doesn't help in this scenario because operating system may still send TCP keep-alive packets. Over time we'd like to improve this functionality, but solving this issue isn't high priority because a real-life case in which a server is stopped, but the connection is kept alive, hasn't been brought to our attention. - -4. etcd/client cannot detect whether the member in use is healthy when doing read requests. If the member is isolated from the cluster, etcd/client may retrieve outdated data. As a workaround, users could monitor experimental /health endpoint for member healthy information. We are improving it at [#3265](https://github.com/coreos/etcd/issues/3265). diff --git a/Godeps/_workspace/src/github.com/coreos/etcd/client/cancelreq_go14.go b/Godeps/_workspace/src/github.com/coreos/etcd/client/cancelreq_go14.go deleted file mode 100644 index 2bed38a418..0000000000 --- a/Godeps/_workspace/src/github.com/coreos/etcd/client/cancelreq_go14.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// borrowed from golang/net/context/ctxhttp/cancelreq_go14.go - -// +build !go1.5 - -package client - -import "net/http" - -func requestCanceler(tr CancelableTransport, req *http.Request) func() { - return func() { - tr.CancelRequest(req) - } -} diff --git a/Godeps/_workspace/src/github.com/coreos/etcd/client/keys.generated.go b/Godeps/_workspace/src/github.com/coreos/etcd/client/keys.generated.go deleted file mode 100644 index a897261f48..0000000000 --- a/Godeps/_workspace/src/github.com/coreos/etcd/client/keys.generated.go +++ /dev/null @@ -1,891 +0,0 @@ -// ************************************************************ -// DO NOT EDIT. -// THIS FILE IS AUTO-GENERATED BY codecgen. -// ************************************************************ - -package client - -import ( - "errors" - "fmt" - codec1978 "github.com/ugorji/go/codec" - "reflect" - "runtime" - "time" -) - -const ( - codecSelferC_UTF85311 = 1 - codecSelferC_RAW5311 = 0 - codecSelverValueTypeArray5311 = 10 - codecSelverValueTypeMap5311 = 9 -) - -var ( - codecSelferBitsize5311 = uint8(reflect.TypeOf(uint(0)).Bits()) - codecSelferOnlyMapOrArrayEncodeToStructErr5311 = errors.New(`only encoded map or array can be decoded into a struct`) -) - -type codecSelfer5311 struct{} - -func init() { - if codec1978.GenVersion != 2 { - _, file, _, _ := runtime.Caller(0) - err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", - 2, codec1978.GenVersion, file) - panic(err) - } - if false { // reference the types, but skip this branch at build/run time - var v0 time.Time - _ = v0 - } -} - -func (x *Response) CodecEncodeSelf(e *codec1978.Encoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperEncoder(e) - _, _, _ = h, z, r - if x == nil { - r.EncodeNil() - } else { - yysep1 := !z.EncBinary() - yy2arr1 := z.EncBasicHandle().StructToArray - var yyfirst1 bool - var yyq1 [3]bool - _, _, _, _ = yysep1, yyfirst1, yyq1, yy2arr1 - const yyr1 bool = false - if yyr1 || yy2arr1 { - r.EncodeArrayStart(3) - } else { - var yynn1 int = 3 - for _, b := range yyq1 { - if b { - yynn1++ - } - } - r.EncodeMapStart(yynn1) - } - if yyr1 || yy2arr1 { - r.EncodeString(codecSelferC_UTF85311, string(x.Action)) - } else { - yyfirst1 = true - r.EncodeString(codecSelferC_UTF85311, string("action")) - if yysep1 { - r.EncodeMapKVSeparator() - } - r.EncodeString(codecSelferC_UTF85311, string(x.Action)) - } - if yyr1 || yy2arr1 { - if yysep1 { - r.EncodeArrayEntrySeparator() - } - if x.Node == nil { - r.EncodeNil() - } else { - x.Node.CodecEncodeSelf(e) - } - } else { - if yyfirst1 { - r.EncodeMapEntrySeparator() - } else { - yyfirst1 = true - } - r.EncodeString(codecSelferC_UTF85311, string("node")) - if yysep1 { - r.EncodeMapKVSeparator() - } - if x.Node == nil { - r.EncodeNil() - } else { - x.Node.CodecEncodeSelf(e) - } - } - if yyr1 || yy2arr1 { - if yysep1 { - r.EncodeArrayEntrySeparator() - } - if x.PrevNode == nil { - r.EncodeNil() - } else { - x.PrevNode.CodecEncodeSelf(e) - } - } else { - if yyfirst1 { - r.EncodeMapEntrySeparator() - } else { - yyfirst1 = true - } - r.EncodeString(codecSelferC_UTF85311, string("prevNode")) - if yysep1 { - r.EncodeMapKVSeparator() - } - if x.PrevNode == nil { - r.EncodeNil() - } else { - x.PrevNode.CodecEncodeSelf(e) - } - } - if yysep1 { - if yyr1 || yy2arr1 { - r.EncodeArrayEnd() - } else { - r.EncodeMapEnd() - } - } - } -} - -func (x *Response) CodecDecodeSelf(d *codec1978.Decoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - if r.IsContainerType(codecSelverValueTypeMap5311) { - yyl5 := r.ReadMapStart() - if yyl5 == 0 { - r.ReadMapEnd() - } else { - x.codecDecodeSelfFromMap(yyl5, d) - } - } else if r.IsContainerType(codecSelverValueTypeArray5311) { - yyl5 := r.ReadArrayStart() - if yyl5 == 0 { - r.ReadArrayEnd() - } else { - x.codecDecodeSelfFromArray(yyl5, d) - } - } else { - panic(codecSelferOnlyMapOrArrayEncodeToStructErr5311) - } -} - -func (x *Response) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - var yys6Slc = z.DecScratchBuffer() // default slice to decode into - _ = yys6Slc - var yyhl6 bool = l >= 0 - for yyj6 := 0; ; yyj6++ { - if yyhl6 { - if yyj6 >= l { - break - } - } else { - if r.CheckBreak() { - break - } - if yyj6 > 0 { - r.ReadMapEntrySeparator() - } - } - yys6Slc = r.DecodeBytes(yys6Slc, true, true) - yys6 := string(yys6Slc) - if !yyhl6 { - r.ReadMapKVSeparator() - } - switch yys6 { - case "action": - if r.TryDecodeAsNil() { - x.Action = "" - } else { - x.Action = string(r.DecodeString()) - } - case "node": - if r.TryDecodeAsNil() { - if x.Node != nil { - x.Node = nil - } - } else { - if x.Node == nil { - x.Node = new(Node) - } - x.Node.CodecDecodeSelf(d) - } - case "prevNode": - if r.TryDecodeAsNil() { - if x.PrevNode != nil { - x.PrevNode = nil - } - } else { - if x.PrevNode == nil { - x.PrevNode = new(Node) - } - x.PrevNode.CodecDecodeSelf(d) - } - default: - z.DecStructFieldNotFound(-1, yys6) - } // end switch yys6 - } // end for yyj6 - if !yyhl6 { - r.ReadMapEnd() - } -} - -func (x *Response) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - var yyj10 int - var yyb10 bool - var yyhl10 bool = l >= 0 - yyj10++ - if yyhl10 { - yyb10 = yyj10 > l - } else { - yyb10 = r.CheckBreak() - } - if yyb10 { - r.ReadArrayEnd() - return - } - if r.TryDecodeAsNil() { - x.Action = "" - } else { - x.Action = string(r.DecodeString()) - } - yyj10++ - if yyhl10 { - yyb10 = yyj10 > l - } else { - yyb10 = r.CheckBreak() - } - if yyb10 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - if x.Node != nil { - x.Node = nil - } - } else { - if x.Node == nil { - x.Node = new(Node) - } - x.Node.CodecDecodeSelf(d) - } - yyj10++ - if yyhl10 { - yyb10 = yyj10 > l - } else { - yyb10 = r.CheckBreak() - } - if yyb10 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - if x.PrevNode != nil { - x.PrevNode = nil - } - } else { - if x.PrevNode == nil { - x.PrevNode = new(Node) - } - x.PrevNode.CodecDecodeSelf(d) - } - for { - yyj10++ - if yyhl10 { - yyb10 = yyj10 > l - } else { - yyb10 = r.CheckBreak() - } - if yyb10 { - break - } - if yyj10 > 1 { - r.ReadArrayEntrySeparator() - } - z.DecStructFieldNotFound(yyj10-1, "") - } - r.ReadArrayEnd() -} - -func (x *Node) CodecEncodeSelf(e *codec1978.Encoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperEncoder(e) - _, _, _ = h, z, r - if x == nil { - r.EncodeNil() - } else { - yysep14 := !z.EncBinary() - yy2arr14 := z.EncBasicHandle().StructToArray - var yyfirst14 bool - var yyq14 [8]bool - _, _, _, _ = yysep14, yyfirst14, yyq14, yy2arr14 - const yyr14 bool = false - yyq14[1] = x.Dir != false - yyq14[6] = x.Expiration != nil - yyq14[7] = x.TTL != 0 - if yyr14 || yy2arr14 { - r.EncodeArrayStart(8) - } else { - var yynn14 int = 5 - for _, b := range yyq14 { - if b { - yynn14++ - } - } - r.EncodeMapStart(yynn14) - } - if yyr14 || yy2arr14 { - r.EncodeString(codecSelferC_UTF85311, string(x.Key)) - } else { - yyfirst14 = true - r.EncodeString(codecSelferC_UTF85311, string("key")) - if yysep14 { - r.EncodeMapKVSeparator() - } - r.EncodeString(codecSelferC_UTF85311, string(x.Key)) - } - if yyr14 || yy2arr14 { - if yysep14 { - r.EncodeArrayEntrySeparator() - } - if yyq14[1] { - r.EncodeBool(bool(x.Dir)) - } else { - r.EncodeBool(false) - } - } else { - if yyq14[1] { - if yyfirst14 { - r.EncodeMapEntrySeparator() - } else { - yyfirst14 = true - } - r.EncodeString(codecSelferC_UTF85311, string("dir")) - if yysep14 { - r.EncodeMapKVSeparator() - } - r.EncodeBool(bool(x.Dir)) - } - } - if yyr14 || yy2arr14 { - if yysep14 { - r.EncodeArrayEntrySeparator() - } - r.EncodeString(codecSelferC_UTF85311, string(x.Value)) - } else { - if yyfirst14 { - r.EncodeMapEntrySeparator() - } else { - yyfirst14 = true - } - r.EncodeString(codecSelferC_UTF85311, string("value")) - if yysep14 { - r.EncodeMapKVSeparator() - } - r.EncodeString(codecSelferC_UTF85311, string(x.Value)) - } - if yyr14 || yy2arr14 { - if yysep14 { - r.EncodeArrayEntrySeparator() - } - if x.Nodes == nil { - r.EncodeNil() - } else { - h.encSlicePtrtoNode(([]*Node)(x.Nodes), e) - } - } else { - if yyfirst14 { - r.EncodeMapEntrySeparator() - } else { - yyfirst14 = true - } - r.EncodeString(codecSelferC_UTF85311, string("nodes")) - if yysep14 { - r.EncodeMapKVSeparator() - } - if x.Nodes == nil { - r.EncodeNil() - } else { - h.encSlicePtrtoNode(([]*Node)(x.Nodes), e) - } - } - if yyr14 || yy2arr14 { - if yysep14 { - r.EncodeArrayEntrySeparator() - } - r.EncodeUint(uint64(x.CreatedIndex)) - } else { - if yyfirst14 { - r.EncodeMapEntrySeparator() - } else { - yyfirst14 = true - } - r.EncodeString(codecSelferC_UTF85311, string("createdIndex")) - if yysep14 { - r.EncodeMapKVSeparator() - } - r.EncodeUint(uint64(x.CreatedIndex)) - } - if yyr14 || yy2arr14 { - if yysep14 { - r.EncodeArrayEntrySeparator() - } - r.EncodeUint(uint64(x.ModifiedIndex)) - } else { - if yyfirst14 { - r.EncodeMapEntrySeparator() - } else { - yyfirst14 = true - } - r.EncodeString(codecSelferC_UTF85311, string("modifiedIndex")) - if yysep14 { - r.EncodeMapKVSeparator() - } - r.EncodeUint(uint64(x.ModifiedIndex)) - } - if yyr14 || yy2arr14 { - if yysep14 { - r.EncodeArrayEntrySeparator() - } - if yyq14[6] { - if x.Expiration == nil { - r.EncodeNil() - } else { - z.EncFallback(x.Expiration) - } - } else { - r.EncodeNil() - } - } else { - if yyq14[6] { - if yyfirst14 { - r.EncodeMapEntrySeparator() - } else { - yyfirst14 = true - } - r.EncodeString(codecSelferC_UTF85311, string("expiration")) - if yysep14 { - r.EncodeMapKVSeparator() - } - if x.Expiration == nil { - r.EncodeNil() - } else { - z.EncFallback(x.Expiration) - } - } - } - if yyr14 || yy2arr14 { - if yysep14 { - r.EncodeArrayEntrySeparator() - } - if yyq14[7] { - r.EncodeInt(int64(x.TTL)) - } else { - r.EncodeInt(0) - } - } else { - if yyq14[7] { - if yyfirst14 { - r.EncodeMapEntrySeparator() - } else { - yyfirst14 = true - } - r.EncodeString(codecSelferC_UTF85311, string("ttl")) - if yysep14 { - r.EncodeMapKVSeparator() - } - r.EncodeInt(int64(x.TTL)) - } - } - if yysep14 { - if yyr14 || yy2arr14 { - r.EncodeArrayEnd() - } else { - r.EncodeMapEnd() - } - } - } -} - -func (x *Node) CodecDecodeSelf(d *codec1978.Decoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - if r.IsContainerType(codecSelverValueTypeMap5311) { - yyl23 := r.ReadMapStart() - if yyl23 == 0 { - r.ReadMapEnd() - } else { - x.codecDecodeSelfFromMap(yyl23, d) - } - } else if r.IsContainerType(codecSelverValueTypeArray5311) { - yyl23 := r.ReadArrayStart() - if yyl23 == 0 { - r.ReadArrayEnd() - } else { - x.codecDecodeSelfFromArray(yyl23, d) - } - } else { - panic(codecSelferOnlyMapOrArrayEncodeToStructErr5311) - } -} - -func (x *Node) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - var yys24Slc = z.DecScratchBuffer() // default slice to decode into - _ = yys24Slc - var yyhl24 bool = l >= 0 - for yyj24 := 0; ; yyj24++ { - if yyhl24 { - if yyj24 >= l { - break - } - } else { - if r.CheckBreak() { - break - } - if yyj24 > 0 { - r.ReadMapEntrySeparator() - } - } - yys24Slc = r.DecodeBytes(yys24Slc, true, true) - yys24 := string(yys24Slc) - if !yyhl24 { - r.ReadMapKVSeparator() - } - switch yys24 { - case "key": - if r.TryDecodeAsNil() { - x.Key = "" - } else { - x.Key = string(r.DecodeString()) - } - case "dir": - if r.TryDecodeAsNil() { - x.Dir = false - } else { - x.Dir = bool(r.DecodeBool()) - } - case "value": - if r.TryDecodeAsNil() { - x.Value = "" - } else { - x.Value = string(r.DecodeString()) - } - case "nodes": - if r.TryDecodeAsNil() { - x.Nodes = nil - } else { - yyv28 := &x.Nodes - h.decSlicePtrtoNode((*[]*Node)(yyv28), d) - } - case "createdIndex": - if r.TryDecodeAsNil() { - x.CreatedIndex = 0 - } else { - x.CreatedIndex = uint64(r.DecodeUint(64)) - } - case "modifiedIndex": - if r.TryDecodeAsNil() { - x.ModifiedIndex = 0 - } else { - x.ModifiedIndex = uint64(r.DecodeUint(64)) - } - case "expiration": - if r.TryDecodeAsNil() { - if x.Expiration != nil { - x.Expiration = nil - } - } else { - if x.Expiration == nil { - x.Expiration = new(time.Time) - } - z.DecFallback(x.Expiration, false) - } - case "ttl": - if r.TryDecodeAsNil() { - x.TTL = 0 - } else { - x.TTL = int64(r.DecodeInt(64)) - } - default: - z.DecStructFieldNotFound(-1, yys24) - } // end switch yys24 - } // end for yyj24 - if !yyhl24 { - r.ReadMapEnd() - } -} - -func (x *Node) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - var yyj33 int - var yyb33 bool - var yyhl33 bool = l >= 0 - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - r.ReadArrayEnd() - return - } - if r.TryDecodeAsNil() { - x.Key = "" - } else { - x.Key = string(r.DecodeString()) - } - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - x.Dir = false - } else { - x.Dir = bool(r.DecodeBool()) - } - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - x.Value = "" - } else { - x.Value = string(r.DecodeString()) - } - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - x.Nodes = nil - } else { - yyv37 := &x.Nodes - h.decSlicePtrtoNode((*[]*Node)(yyv37), d) - } - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - x.CreatedIndex = 0 - } else { - x.CreatedIndex = uint64(r.DecodeUint(64)) - } - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - x.ModifiedIndex = 0 - } else { - x.ModifiedIndex = uint64(r.DecodeUint(64)) - } - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - if x.Expiration != nil { - x.Expiration = nil - } - } else { - if x.Expiration == nil { - x.Expiration = new(time.Time) - } - z.DecFallback(x.Expiration, false) - } - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - r.ReadArrayEnd() - return - } - r.ReadArrayEntrySeparator() - if r.TryDecodeAsNil() { - x.TTL = 0 - } else { - x.TTL = int64(r.DecodeInt(64)) - } - for { - yyj33++ - if yyhl33 { - yyb33 = yyj33 > l - } else { - yyb33 = r.CheckBreak() - } - if yyb33 { - break - } - if yyj33 > 1 { - r.ReadArrayEntrySeparator() - } - z.DecStructFieldNotFound(yyj33-1, "") - } - r.ReadArrayEnd() -} - -func (x codecSelfer5311) encSlicePtrtoNode(v []*Node, e *codec1978.Encoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperEncoder(e) - _, _, _ = h, z, r - r.EncodeArrayStart(len(v)) - yys42 := !z.EncBinary() - if yys42 { - for yyi42, yyv42 := range v { - if yyi42 > 0 { - r.EncodeArrayEntrySeparator() - } - if yyv42 == nil { - r.EncodeNil() - } else { - yyv42.CodecEncodeSelf(e) - } - } - r.EncodeArrayEnd() - } else { - for _, yyv42 := range v { - if yyv42 == nil { - r.EncodeNil() - } else { - yyv42.CodecEncodeSelf(e) - } - } - } -} - -func (x codecSelfer5311) decSlicePtrtoNode(v *[]*Node, d *codec1978.Decoder) { - var h codecSelfer5311 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - - yyv43 := *v - yyh43, yyl43 := z.DecSliceHelperStart() - - var yyc43 bool - _ = yyc43 - - if yyv43 == nil { - if yyl43 <= 0 { - yyv43 = make([]*Node, 0) - } else { - yyv43 = make([]*Node, yyl43) - } - yyc43 = true - } - - if yyl43 == 0 { - if len(yyv43) != 0 { - yyv43 = yyv43[:0] - yyc43 = true - } - } else if yyl43 > 0 { - - yyn43 := yyl43 - if yyl43 > cap(yyv43) { - yyv43 = make([]*Node, yyl43, yyl43) - yyc43 = true - - } else if yyl43 != len(yyv43) { - yyv43 = yyv43[:yyl43] - yyc43 = true - } - yyj43 := 0 - for ; yyj43 < yyn43; yyj43++ { - if r.TryDecodeAsNil() { - if yyv43[yyj43] != nil { - *yyv43[yyj43] = Node{} - } - } else { - if yyv43[yyj43] == nil { - yyv43[yyj43] = new(Node) - } - yyw44 := yyv43[yyj43] - yyw44.CodecDecodeSelf(d) - } - - } - - } else { - for yyj43 := 0; !r.CheckBreak(); yyj43++ { - if yyj43 >= len(yyv43) { - yyv43 = append(yyv43, nil) // var yyz43 *Node - yyc43 = true - } - if yyj43 > 0 { - yyh43.Sep(yyj43) - } - - if yyj43 < len(yyv43) { - if r.TryDecodeAsNil() { - if yyv43[yyj43] != nil { - *yyv43[yyj43] = Node{} - } - } else { - if yyv43[yyj43] == nil { - yyv43[yyj43] = new(Node) - } - yyw45 := yyv43[yyj43] - yyw45.CodecDecodeSelf(d) - } - - } else { - z.DecSwallow() - } - - } - yyh43.End() - } - if yyc43 { - *v = yyv43 - } - -} diff --git a/Godeps/_workspace/src/github.com/deckarep/golang-set/.gitignore b/Godeps/_workspace/src/github.com/deckarep/golang-set/.gitignore deleted file mode 100644 index 00268614f0..0000000000 --- a/Godeps/_workspace/src/github.com/deckarep/golang-set/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/Godeps/_workspace/src/github.com/deckarep/golang-set/.travis.yml b/Godeps/_workspace/src/github.com/deckarep/golang-set/.travis.yml deleted file mode 100644 index db1359c72e..0000000000 --- a/Godeps/_workspace/src/github.com/deckarep/golang-set/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.2 - -script: - - go test ./... - #- go test -race ./... - diff --git a/Godeps/_workspace/src/github.com/deckarep/golang-set/README.md b/Godeps/_workspace/src/github.com/deckarep/golang-set/README.md deleted file mode 100644 index 744b1841cd..0000000000 --- a/Godeps/_workspace/src/github.com/deckarep/golang-set/README.md +++ /dev/null @@ -1,94 +0,0 @@ -[![Build Status](https://travis-ci.org/deckarep/golang-set.png?branch=master)](https://travis-ci.org/deckarep/golang-set) -[![GoDoc](https://godoc.org/github.com/deckarep/golang-set?status.png)](http://godoc.org/github.com/deckarep/golang-set) - -## golang-set - - -The missing set collection for the Go language. Until Go has sets built-in...use this. - -Coming from Python one of the things I miss is the superbly wonderful set collection. This is my attempt to mimic the primary features of the set from Python. -You can of course argue that there is no need for a set in Go, otherwise the creators would have added one to the standard library. To those I say simply ignore this repository -and carry-on and to the rest that find this useful please contribute in helping me make it better by: - -* Helping to make more idiomatic improvements to the code. -* Helping to increase the performance of it. ~~(So far, no attempt has been made, but since it uses a map internally, I expect it to be mostly performant.)~~ -* Helping to make the unit-tests more robust and kick-ass. -* Helping to fill in the [documentation.](http://godoc.org/github.com/deckarep/golang-set) -* Simply offering feedback and suggestions. (Positive, constructive feedback is appreciated.) - -I have to give some credit for helping seed the idea with this post on [stackoverflow.](http://programmers.stackexchange.com/questions/177428/sets-data-structure-in-golang) - -*Update* - as of 3/9/2014, you can use a compile-time generic version of this package in the [gen](http://clipperhouse.github.io/gen/) framework. This framework allows you to use the golang-set in a completely generic and type-safe way by allowing you to generate a supporting .go file based on your custom types. - -## Features (as of 9/22/2014) - -* a CartesionProduct() method has been added with unit-tests: [Read more about the cartesion product](http://en.wikipedia.org/wiki/Cartesian_product) - -## Features (as of 9/15/2014) - -* a PowerSet() method has been added with unit-tests: [Read more about the Power set](http://en.wikipedia.org/wiki/Power_set) - -## Features (as of 4/22/2014) - -* One common interface to both implementations -* Two set implementations to choose from - * a thread-safe implementation designed for concurrent use - * a non-thread-safe implementation designed for performance -* 75 benchmarks for both implementations -* 35 unit tests for both implementations -* 14 concurrent tests for the thread-safe implementation - - - -Please see the unit test file for additional usage examples. The Python set documentation will also do a better job than I can of explaining how a set typically [works.](http://docs.python.org/2/library/sets.html) Please keep in mind -however that the Python set is a built-in type and supports additional features and syntax that make it awesome. - -## Examples but not exhaustive: - -```go -requiredClasses := mapset.NewSet() -requiredClasses.Add("Cooking") -requiredClasses.Add("English") -requiredClasses.Add("Math") -requiredClasses.Add("Biology") - -scienceSlice := []interface{}{"Biology", "Chemistry"} -scienceClasses := mapset.NewSetFromSlice(scienceSlice) - -electiveClasses := mapset.NewSet() -electiveClasses.Add("Welding") -electiveClasses.Add("Music") -electiveClasses.Add("Automotive") - -bonusClasses := mapset.NewSet() -bonusClasses.Add("Go Programming") -bonusClasses.Add("Python Programming") - -//Show me all the available classes I can take -allClasses := requiredClasses.Union(scienceClasses).Union(electiveClasses).Union(bonusClasses) -fmt.Println(allClasses) //Set{Cooking, English, Math, Chemistry, Welding, Biology, Music, Automotive, Go Programming, Python Programming} - - -//Is cooking considered a science class? -fmt.Println(scienceClasses.Contains("Cooking")) //false - -//Show me all classes that are not science classes, since I hate science. -fmt.Println(allClasses.Difference(scienceClasses)) //Set{Music, Automotive, Go Programming, Python Programming, Cooking, English, Math, Welding} - -//Which science classes are also required classes? -fmt.Println(scienceClasses.Intersect(requiredClasses)) //Set{Biology} - -//How many bonus classes do you offer? -fmt.Println(bonusClasses.Cardinality()) //2 - -//Do you have the following classes? Welding, Automotive and English? -fmt.Println(allClasses.IsSuperset(mapset.NewSetFromSlice([]interface{}{"Welding", "Automotive", "English"}))) //true -``` - -Thanks! - --Ralph - -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/deckarep/golang-set/trend.png)](https://bitdeli.com/free "Bitdeli Badge") - -[![Analytics](https://ga-beacon.appspot.com/UA-42584447-2/deckarep/golang-set)](https://github.com/igrigorik/ga-beacon) diff --git a/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/README.md b/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/README.md deleted file mode 100644 index cdac50a53c..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/api/types/versions/README.md +++ /dev/null @@ -1,14 +0,0 @@ -## Legacy API type versions - -This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`. - -Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`. - -### Package name conventions - -The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention: - -1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`. -2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`. - -For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`. diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md deleted file mode 100644 index 39777c2171..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -page_title: Docker discovery -page_description: discovery -page_keywords: docker, clustering, discovery ---- - -# Discovery - -Docker comes with multiple Discovery backends. - -## Backends - -### Using etcd - -Point your Docker Engine instances to a common etcd instance. You can specify -the address Docker uses to advertise the node using the `--cluster-advertise` -flag. - -```bash -$ docker daemon -H= --cluster-advertise= --cluster-store etcd://,/ -``` - -### Using consul - -Point your Docker Engine instances to a common Consul instance. You can specify -the address Docker uses to advertise the node using the `--cluster-advertise` -flag. - -```bash -$ docker daemon -H= --cluster-advertise= --cluster-store consul:/// -``` - -### Using zookeeper - -Point your Docker Engine instances to a common Zookeeper instance. You can specify -the address Docker uses to advertise the node using the `--cluster-advertise` -flag. - -```bash -$ docker daemon -H= --cluster-advertise= --cluster-store zk://,/ -``` diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/README.md deleted file mode 100644 index e84a815cc5..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/locker/README.md +++ /dev/null @@ -1,65 +0,0 @@ -Locker -===== - -locker provides a mechanism for creating finer-grained locking to help -free up more global locks to handle other tasks. - -The implementation looks close to a sync.Mutex, however the user must provide a -reference to use to refer to the underlying lock when locking and unlocking, -and unlock may generate an error. - -If a lock with a given name does not exist when `Lock` is called, one is -created. -Lock references are automatically cleaned up on `Unlock` if nothing else is -waiting for the lock. - - -## Usage - -```go -package important - -import ( - "sync" - "time" - - "github.com/docker/docker/pkg/locker" -) - -type important struct { - locks *locker.Locker - data map[string]interface{} - mu sync.Mutex -} - -func (i *important) Get(name string) interface{} { - i.locks.Lock(name) - defer i.locks.Unlock(name) - return data[name] -} - -func (i *important) Create(name string, data interface{}) { - i.locks.Lock(name) - defer i.locks.Unlock(name) - - i.createImportant(data) - - s.mu.Lock() - i.data[name] = data - s.mu.Unlock() -} - -func (i *important) createImportant(data interface{}) { - time.Sleep(10 * time.Second) -} -``` - -For functions dealing with a given name, always lock at the beginning of the -function (or before doing anything with the underlying state), this ensures any -other function that is dealing with the same name will block. - -When needing to modify the underlying data, use the global lock to ensure nothing -else is modfying it at the same time. -Since name lock is already in place, no reads will occur while the modification -is being performed. - diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/LICENSE b/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/LICENSE deleted file mode 100644 index 9b4f4a294e..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014-2016 The Docker & Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/README.md deleted file mode 100644 index da00efa336..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/README.md +++ /dev/null @@ -1,40 +0,0 @@ -Package mflag (aka multiple-flag) implements command-line flag parsing. -It's an **hacky** fork of the [official golang package](http://golang.org/pkg/flag/) - -It adds: - -* both short and long flag version -`./example -s red` `./example --string blue` - -* multiple names for the same option -``` -$>./example -h -Usage of example: - -s, --string="": a simple string -``` - -___ -It is very flexible on purpose, so you can do things like: -``` -$>./example -h -Usage of example: - -s, -string, --string="": a simple string -``` - -Or: -``` -$>./example -h -Usage of example: - -oldflag, --newflag="": a simple string -``` - -You can also hide some flags from the usage, so if we want only `--newflag`: -``` -$>./example -h -Usage of example: - --newflag="": a simple string -$>./example -oldflag str -str -``` - -See [example.go](example/example.go) for more details. diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/flag.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/flag.go deleted file mode 100644 index e2a0c42257..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/flag.go +++ /dev/null @@ -1,1280 +0,0 @@ -// Copyright 2014-2016 The Docker & Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package mflag implements command-line flag parsing. -// -// Usage: -// -// Define flags using flag.String(), Bool(), Int(), etc. -// -// This declares an integer flag, -f or --flagname, stored in the pointer ip, with type *int. -// import "flag /github.com/docker/docker/pkg/mflag" -// var ip = flag.Int([]string{"f", "-flagname"}, 1234, "help message for flagname") -// If you like, you can bind the flag to a variable using the Var() functions. -// var flagvar int -// func init() { -// // -flaghidden will work, but will be hidden from the usage -// flag.IntVar(&flagvar, []string{"f", "#flaghidden", "-flagname"}, 1234, "help message for flagname") -// } -// Or you can create custom flags that satisfy the Value interface (with -// pointer receivers) and couple them to flag parsing by -// flag.Var(&flagVal, []string{"name"}, "help message for flagname") -// For such flags, the default value is just the initial value of the variable. -// -// You can also add "deprecated" flags, they are still usable, but are not shown -// in the usage and will display a warning when you try to use them. `#` before -// an option means this option is deprecated, if there is an following option -// without `#` ahead, then that's the replacement, if not, it will just be removed: -// var ip = flag.Int([]string{"#f", "#flagname", "-flagname"}, 1234, "help message for flagname") -// this will display: `Warning: '-f' is deprecated, it will be replaced by '--flagname' soon. See usage.` or -// this will display: `Warning: '-flagname' is deprecated, it will be replaced by '--flagname' soon. See usage.` -// var ip = flag.Int([]string{"f", "#flagname"}, 1234, "help message for flagname") -// will display: `Warning: '-flagname' is deprecated, it will be removed soon. See usage.` -// so you can only use `-f`. -// -// You can also group one letter flags, bif you declare -// var v = flag.Bool([]string{"v", "-verbose"}, false, "help message for verbose") -// var s = flag.Bool([]string{"s", "-slow"}, false, "help message for slow") -// you will be able to use the -vs or -sv -// -// After all flags are defined, call -// flag.Parse() -// to parse the command line into the defined flags. -// -// Flags may then be used directly. If you're using the flags themselves, -// they are all pointers; if you bind to variables, they're values. -// fmt.Println("ip has value ", *ip) -// fmt.Println("flagvar has value ", flagvar) -// -// After parsing, the arguments after the flag are available as the -// slice flag.Args() or individually as flag.Arg(i). -// The arguments are indexed from 0 through flag.NArg()-1. -// -// Command line flag syntax: -// -flag -// -flag=x -// -flag="x" -// -flag='x' -// -flag x // non-boolean flags only -// One or two minus signs may be used; they are equivalent. -// The last form is not permitted for boolean flags because the -// meaning of the command -// cmd -x * -// will change if there is a file called 0, false, etc. You must -// use the -flag=false form to turn off a boolean flag. -// -// Flag parsing stops just before the first non-flag argument -// ("-" is a non-flag argument) or after the terminator "--". -// -// Integer flags accept 1234, 0664, 0x1234 and may be negative. -// Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False. -// Duration flags accept any input valid for time.ParseDuration. -// -// The default set of command-line flags is controlled by -// top-level functions. The FlagSet type allows one to define -// independent sets of flags, such as to implement subcommands -// in a command-line interface. The methods of FlagSet are -// analogous to the top-level functions for the command-line -// flag set. - -package mflag - -import ( - "errors" - "fmt" - "io" - "os" - "runtime" - "sort" - "strconv" - "strings" - "text/tabwriter" - "time" - - "github.com/docker/docker/pkg/homedir" -) - -// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. -var ErrHelp = errors.New("flag: help requested") - -// ErrRetry is the error returned if you need to try letter by letter -var ErrRetry = errors.New("flag: retry") - -// -- bool Value -type boolValue bool - -func newBoolValue(val bool, p *bool) *boolValue { - *p = val - return (*boolValue)(p) -} - -func (b *boolValue) Set(s string) error { - v, err := strconv.ParseBool(s) - *b = boolValue(v) - return err -} - -func (b *boolValue) Get() interface{} { return bool(*b) } - -func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) } - -func (b *boolValue) IsBoolFlag() bool { return true } - -// optional interface to indicate boolean flags that can be -// supplied without "=value" text -type boolFlag interface { - Value - IsBoolFlag() bool -} - -// -- int Value -type intValue int - -func newIntValue(val int, p *int) *intValue { - *p = val - return (*intValue)(p) -} - -func (i *intValue) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - *i = intValue(v) - return err -} - -func (i *intValue) Get() interface{} { return int(*i) } - -func (i *intValue) String() string { return fmt.Sprintf("%v", *i) } - -// -- int64 Value -type int64Value int64 - -func newInt64Value(val int64, p *int64) *int64Value { - *p = val - return (*int64Value)(p) -} - -func (i *int64Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - *i = int64Value(v) - return err -} - -func (i *int64Value) Get() interface{} { return int64(*i) } - -func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) } - -// -- uint Value -type uintValue uint - -func newUintValue(val uint, p *uint) *uintValue { - *p = val - return (*uintValue)(p) -} - -func (i *uintValue) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 64) - *i = uintValue(v) - return err -} - -func (i *uintValue) Get() interface{} { return uint(*i) } - -func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) } - -// -- uint64 Value -type uint64Value uint64 - -func newUint64Value(val uint64, p *uint64) *uint64Value { - *p = val - return (*uint64Value)(p) -} - -func (i *uint64Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 64) - *i = uint64Value(v) - return err -} - -func (i *uint64Value) Get() interface{} { return uint64(*i) } - -func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) } - -// -- uint16 Value -type uint16Value uint16 - -func newUint16Value(val uint16, p *uint16) *uint16Value { - *p = val - return (*uint16Value)(p) -} - -func (i *uint16Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 16) - *i = uint16Value(v) - return err -} - -func (i *uint16Value) Get() interface{} { return uint16(*i) } - -func (i *uint16Value) String() string { return fmt.Sprintf("%v", *i) } - -// -- string Value -type stringValue string - -func newStringValue(val string, p *string) *stringValue { - *p = val - return (*stringValue)(p) -} - -func (s *stringValue) Set(val string) error { - *s = stringValue(val) - return nil -} - -func (s *stringValue) Get() interface{} { return string(*s) } - -func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) } - -// -- float64 Value -type float64Value float64 - -func newFloat64Value(val float64, p *float64) *float64Value { - *p = val - return (*float64Value)(p) -} - -func (f *float64Value) Set(s string) error { - v, err := strconv.ParseFloat(s, 64) - *f = float64Value(v) - return err -} - -func (f *float64Value) Get() interface{} { return float64(*f) } - -func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) } - -// -- time.Duration Value -type durationValue time.Duration - -func newDurationValue(val time.Duration, p *time.Duration) *durationValue { - *p = val - return (*durationValue)(p) -} - -func (d *durationValue) Set(s string) error { - v, err := time.ParseDuration(s) - *d = durationValue(v) - return err -} - -func (d *durationValue) Get() interface{} { return time.Duration(*d) } - -func (d *durationValue) String() string { return (*time.Duration)(d).String() } - -// Value is the interface to the dynamic value stored in a flag. -// (The default value is represented as a string.) -// -// If a Value has an IsBoolFlag() bool method returning true, -// the command-line parser makes -name equivalent to -name=true -// rather than using the next command-line argument. -type Value interface { - String() string - Set(string) error -} - -// Getter is an interface that allows the contents of a Value to be retrieved. -// It wraps the Value interface, rather than being part of it, because it -// appeared after Go 1 and its compatibility rules. All Value types provided -// by this package satisfy the Getter interface. -type Getter interface { - Value - Get() interface{} -} - -// ErrorHandling defines how to handle flag parsing errors. -type ErrorHandling int - -// ErrorHandling strategies available when a flag parsing error occurs -const ( - ContinueOnError ErrorHandling = iota - ExitOnError - PanicOnError -) - -// A FlagSet represents a set of defined flags. The zero value of a FlagSet -// has no name and has ContinueOnError error handling. -type FlagSet struct { - // Usage is the function called when an error occurs while parsing flags. - // The field is a function (not a method) that may be changed to point to - // a custom error handler. - Usage func() - ShortUsage func() - - name string - parsed bool - actual map[string]*Flag - formal map[string]*Flag - args []string // arguments after flags - errorHandling ErrorHandling - output io.Writer // nil means stderr; use Out() accessor - nArgRequirements []nArgRequirement -} - -// A Flag represents the state of a flag. -type Flag struct { - Names []string // name as it appears on command line - Usage string // help message - Value Value // value as set - DefValue string // default value (as text); for usage message -} - -type flagSlice []string - -func (p flagSlice) Len() int { return len(p) } -func (p flagSlice) Less(i, j int) bool { - pi, pj := strings.TrimPrefix(p[i], "-"), strings.TrimPrefix(p[j], "-") - lpi, lpj := strings.ToLower(pi), strings.ToLower(pj) - if lpi != lpj { - return lpi < lpj - } - return pi < pj -} -func (p flagSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -// sortFlags returns the flags as a slice in lexicographical sorted order. -func sortFlags(flags map[string]*Flag) []*Flag { - var list flagSlice - - // The sorted list is based on the first name, when flag map might use the other names. - nameMap := make(map[string]string) - - for n, f := range flags { - fName := strings.TrimPrefix(f.Names[0], "#") - nameMap[fName] = n - if len(f.Names) == 1 { - list = append(list, fName) - continue - } - - found := false - for _, name := range list { - if name == fName { - found = true - break - } - } - if !found { - list = append(list, fName) - } - } - sort.Sort(list) - result := make([]*Flag, len(list)) - for i, name := range list { - result[i] = flags[nameMap[name]] - } - return result -} - -// Name returns the name of the FlagSet. -func (fs *FlagSet) Name() string { - return fs.name -} - -// Out returns the destination for usage and error messages. -func (fs *FlagSet) Out() io.Writer { - if fs.output == nil { - return os.Stderr - } - return fs.output -} - -// SetOutput sets the destination for usage and error messages. -// If output is nil, os.Stderr is used. -func (fs *FlagSet) SetOutput(output io.Writer) { - fs.output = output -} - -// VisitAll visits the flags in lexicographical order, calling fn for each. -// It visits all flags, even those not set. -func (fs *FlagSet) VisitAll(fn func(*Flag)) { - for _, flag := range sortFlags(fs.formal) { - fn(flag) - } -} - -// VisitAll visits the command-line flags in lexicographical order, calling -// fn for each. It visits all flags, even those not set. -func VisitAll(fn func(*Flag)) { - CommandLine.VisitAll(fn) -} - -// Visit visits the flags in lexicographical order, calling fn for each. -// It visits only those flags that have been set. -func (fs *FlagSet) Visit(fn func(*Flag)) { - for _, flag := range sortFlags(fs.actual) { - fn(flag) - } -} - -// Visit visits the command-line flags in lexicographical order, calling fn -// for each. It visits only those flags that have been set. -func Visit(fn func(*Flag)) { - CommandLine.Visit(fn) -} - -// Lookup returns the Flag structure of the named flag, returning nil if none exists. -func (fs *FlagSet) Lookup(name string) *Flag { - return fs.formal[name] -} - -// IsSet indicates whether the specified flag is set in the given FlagSet -func (fs *FlagSet) IsSet(name string) bool { - return fs.actual[name] != nil -} - -// Lookup returns the Flag structure of the named command-line flag, -// returning nil if none exists. -func Lookup(name string) *Flag { - return CommandLine.formal[name] -} - -// IsSet indicates whether the specified flag was specified at all on the cmd line. -func IsSet(name string) bool { - return CommandLine.IsSet(name) -} - -type nArgRequirementType int - -// Indicator used to pass to BadArgs function -const ( - Exact nArgRequirementType = iota - Max - Min -) - -type nArgRequirement struct { - Type nArgRequirementType - N int -} - -// Require adds a requirement about the number of arguments for the FlagSet. -// The first parameter can be Exact, Max, or Min to respectively specify the exact, -// the maximum, or the minimal number of arguments required. -// The actual check is done in FlagSet.CheckArgs(). -func (fs *FlagSet) Require(nArgRequirementType nArgRequirementType, nArg int) { - fs.nArgRequirements = append(fs.nArgRequirements, nArgRequirement{nArgRequirementType, nArg}) -} - -// CheckArgs uses the requirements set by FlagSet.Require() to validate -// the number of arguments. If the requirements are not met, -// an error message string is returned. -func (fs *FlagSet) CheckArgs() (message string) { - for _, req := range fs.nArgRequirements { - var arguments string - if req.N == 1 { - arguments = "1 argument" - } else { - arguments = fmt.Sprintf("%d arguments", req.N) - } - - str := func(kind string) string { - return fmt.Sprintf("%q requires %s%s", fs.name, kind, arguments) - } - - switch req.Type { - case Exact: - if fs.NArg() != req.N { - return str("") - } - case Max: - if fs.NArg() > req.N { - return str("a maximum of ") - } - case Min: - if fs.NArg() < req.N { - return str("a minimum of ") - } - } - } - return "" -} - -// Set sets the value of the named flag. -func (fs *FlagSet) Set(name, value string) error { - flag, ok := fs.formal[name] - if !ok { - return fmt.Errorf("no such flag -%v", name) - } - if err := flag.Value.Set(value); err != nil { - return err - } - if fs.actual == nil { - fs.actual = make(map[string]*Flag) - } - fs.actual[name] = flag - return nil -} - -// Set sets the value of the named command-line flag. -func Set(name, value string) error { - return CommandLine.Set(name, value) -} - -// isZeroValue guesses whether the string represents the zero -// value for a flag. It is not accurate but in practice works OK. -func isZeroValue(value string) bool { - switch value { - case "false": - return true - case "": - return true - case "0": - return true - } - return false -} - -// PrintDefaults prints, to standard error unless configured -// otherwise, the default values of all defined flags in the set. -func (fs *FlagSet) PrintDefaults() { - writer := tabwriter.NewWriter(fs.Out(), 20, 1, 3, ' ', 0) - home := homedir.Get() - - // Don't substitute when HOME is / - if runtime.GOOS != "windows" && home == "/" { - home = "" - } - - // Add a blank line between cmd description and list of options - if fs.FlagCount() > 0 { - fmt.Fprintln(writer, "") - } - - fs.VisitAll(func(flag *Flag) { - names := []string{} - for _, name := range flag.Names { - if name[0] != '#' { - names = append(names, name) - } - } - if len(names) > 0 && len(flag.Usage) > 0 { - val := flag.DefValue - - if home != "" && strings.HasPrefix(val, home) { - val = homedir.GetShortcutString() + val[len(home):] - } - - if isZeroValue(val) { - format := " -%s" - fmt.Fprintf(writer, format, strings.Join(names, ", -")) - } else { - format := " -%s=%s" - fmt.Fprintf(writer, format, strings.Join(names, ", -"), val) - } - for _, line := range strings.Split(flag.Usage, "\n") { - fmt.Fprintln(writer, "\t", line) - } - } - }) - writer.Flush() -} - -// PrintDefaults prints to standard error the default values of all defined command-line flags. -func PrintDefaults() { - CommandLine.PrintDefaults() -} - -// defaultUsage is the default function to print a usage message. -func defaultUsage(fs *FlagSet) { - if fs.name == "" { - fmt.Fprintf(fs.Out(), "Usage:\n") - } else { - fmt.Fprintf(fs.Out(), "Usage of %s:\n", fs.name) - } - fs.PrintDefaults() -} - -// NOTE: Usage is not just defaultUsage(CommandLine) -// because it serves (via godoc flag Usage) as the example -// for how to write your own usage function. - -// Usage prints to standard error a usage message documenting all defined command-line flags. -// The function is a variable that may be changed to point to a custom function. -var Usage = func() { - fmt.Fprintf(CommandLine.Out(), "Usage of %s:\n", os.Args[0]) - PrintDefaults() -} - -// ShortUsage prints to standard error a usage message documenting the standard command layout -// The function is a variable that may be changed to point to a custom function. -var ShortUsage = func() { - fmt.Fprintf(CommandLine.output, "Usage of %s:\n", os.Args[0]) -} - -// FlagCount returns the number of flags that have been defined. -func (fs *FlagSet) FlagCount() int { return len(sortFlags(fs.formal)) } - -// FlagCountUndeprecated returns the number of undeprecated flags that have been defined. -func (fs *FlagSet) FlagCountUndeprecated() int { - count := 0 - for _, flag := range sortFlags(fs.formal) { - for _, name := range flag.Names { - if name[0] != '#' { - count++ - break - } - } - } - return count -} - -// NFlag returns the number of flags that have been set. -func (fs *FlagSet) NFlag() int { return len(fs.actual) } - -// NFlag returns the number of command-line flags that have been set. -func NFlag() int { return len(CommandLine.actual) } - -// Arg returns the i'th argument. Arg(0) is the first remaining argument -// after flags have been processed. -func (fs *FlagSet) Arg(i int) string { - if i < 0 || i >= len(fs.args) { - return "" - } - return fs.args[i] -} - -// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument -// after flags have been processed. -func Arg(i int) string { - return CommandLine.Arg(i) -} - -// NArg is the number of arguments remaining after flags have been processed. -func (fs *FlagSet) NArg() int { return len(fs.args) } - -// NArg is the number of arguments remaining after flags have been processed. -func NArg() int { return len(CommandLine.args) } - -// Args returns the non-flag arguments. -func (fs *FlagSet) Args() []string { return fs.args } - -// Args returns the non-flag command-line arguments. -func Args() []string { return CommandLine.args } - -// BoolVar defines a bool flag with specified name, default value, and usage string. -// The argument p points to a bool variable in which to store the value of the flag. -func (fs *FlagSet) BoolVar(p *bool, names []string, value bool, usage string) { - fs.Var(newBoolValue(value, p), names, usage) -} - -// BoolVar defines a bool flag with specified name, default value, and usage string. -// The argument p points to a bool variable in which to store the value of the flag. -func BoolVar(p *bool, names []string, value bool, usage string) { - CommandLine.Var(newBoolValue(value, p), names, usage) -} - -// Bool defines a bool flag with specified name, default value, and usage string. -// The return value is the address of a bool variable that stores the value of the flag. -func (fs *FlagSet) Bool(names []string, value bool, usage string) *bool { - p := new(bool) - fs.BoolVar(p, names, value, usage) - return p -} - -// Bool defines a bool flag with specified name, default value, and usage string. -// The return value is the address of a bool variable that stores the value of the flag. -func Bool(names []string, value bool, usage string) *bool { - return CommandLine.Bool(names, value, usage) -} - -// IntVar defines an int flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -func (fs *FlagSet) IntVar(p *int, names []string, value int, usage string) { - fs.Var(newIntValue(value, p), names, usage) -} - -// IntVar defines an int flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -func IntVar(p *int, names []string, value int, usage string) { - CommandLine.Var(newIntValue(value, p), names, usage) -} - -// Int defines an int flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -func (fs *FlagSet) Int(names []string, value int, usage string) *int { - p := new(int) - fs.IntVar(p, names, value, usage) - return p -} - -// Int defines an int flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -func Int(names []string, value int, usage string) *int { - return CommandLine.Int(names, value, usage) -} - -// Int64Var defines an int64 flag with specified name, default value, and usage string. -// The argument p points to an int64 variable in which to store the value of the flag. -func (fs *FlagSet) Int64Var(p *int64, names []string, value int64, usage string) { - fs.Var(newInt64Value(value, p), names, usage) -} - -// Int64Var defines an int64 flag with specified name, default value, and usage string. -// The argument p points to an int64 variable in which to store the value of the flag. -func Int64Var(p *int64, names []string, value int64, usage string) { - CommandLine.Var(newInt64Value(value, p), names, usage) -} - -// Int64 defines an int64 flag with specified name, default value, and usage string. -// The return value is the address of an int64 variable that stores the value of the flag. -func (fs *FlagSet) Int64(names []string, value int64, usage string) *int64 { - p := new(int64) - fs.Int64Var(p, names, value, usage) - return p -} - -// Int64 defines an int64 flag with specified name, default value, and usage string. -// The return value is the address of an int64 variable that stores the value of the flag. -func Int64(names []string, value int64, usage string) *int64 { - return CommandLine.Int64(names, value, usage) -} - -// UintVar defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func (fs *FlagSet) UintVar(p *uint, names []string, value uint, usage string) { - fs.Var(newUintValue(value, p), names, usage) -} - -// UintVar defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func UintVar(p *uint, names []string, value uint, usage string) { - CommandLine.Var(newUintValue(value, p), names, usage) -} - -// Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func (fs *FlagSet) Uint(names []string, value uint, usage string) *uint { - p := new(uint) - fs.UintVar(p, names, value, usage) - return p -} - -// Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func Uint(names []string, value uint, usage string) *uint { - return CommandLine.Uint(names, value, usage) -} - -// Uint64Var defines a uint64 flag with specified name, default value, and usage string. -// The argument p points to a uint64 variable in which to store the value of the flag. -func (fs *FlagSet) Uint64Var(p *uint64, names []string, value uint64, usage string) { - fs.Var(newUint64Value(value, p), names, usage) -} - -// Uint64Var defines a uint64 flag with specified name, default value, and usage string. -// The argument p points to a uint64 variable in which to store the value of the flag. -func Uint64Var(p *uint64, names []string, value uint64, usage string) { - CommandLine.Var(newUint64Value(value, p), names, usage) -} - -// Uint64 defines a uint64 flag with specified name, default value, and usage string. -// The return value is the address of a uint64 variable that stores the value of the flag. -func (fs *FlagSet) Uint64(names []string, value uint64, usage string) *uint64 { - p := new(uint64) - fs.Uint64Var(p, names, value, usage) - return p -} - -// Uint64 defines a uint64 flag with specified name, default value, and usage string. -// The return value is the address of a uint64 variable that stores the value of the flag. -func Uint64(names []string, value uint64, usage string) *uint64 { - return CommandLine.Uint64(names, value, usage) -} - -// Uint16Var defines a uint16 flag with specified name, default value, and usage string. -// The argument p points to a uint16 variable in which to store the value of the flag. -func (fs *FlagSet) Uint16Var(p *uint16, names []string, value uint16, usage string) { - fs.Var(newUint16Value(value, p), names, usage) -} - -// Uint16Var defines a uint16 flag with specified name, default value, and usage string. -// The argument p points to a uint16 variable in which to store the value of the flag. -func Uint16Var(p *uint16, names []string, value uint16, usage string) { - CommandLine.Var(newUint16Value(value, p), names, usage) -} - -// Uint16 defines a uint16 flag with specified name, default value, and usage string. -// The return value is the address of a uint16 variable that stores the value of the flag. -func (fs *FlagSet) Uint16(names []string, value uint16, usage string) *uint16 { - p := new(uint16) - fs.Uint16Var(p, names, value, usage) - return p -} - -// Uint16 defines a uint16 flag with specified name, default value, and usage string. -// The return value is the address of a uint16 variable that stores the value of the flag. -func Uint16(names []string, value uint16, usage string) *uint16 { - return CommandLine.Uint16(names, value, usage) -} - -// StringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a string variable in which to store the value of the flag. -func (fs *FlagSet) StringVar(p *string, names []string, value string, usage string) { - fs.Var(newStringValue(value, p), names, usage) -} - -// StringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a string variable in which to store the value of the flag. -func StringVar(p *string, names []string, value string, usage string) { - CommandLine.Var(newStringValue(value, p), names, usage) -} - -// String defines a string flag with specified name, default value, and usage string. -// The return value is the address of a string variable that stores the value of the flag. -func (fs *FlagSet) String(names []string, value string, usage string) *string { - p := new(string) - fs.StringVar(p, names, value, usage) - return p -} - -// String defines a string flag with specified name, default value, and usage string. -// The return value is the address of a string variable that stores the value of the flag. -func String(names []string, value string, usage string) *string { - return CommandLine.String(names, value, usage) -} - -// Float64Var defines a float64 flag with specified name, default value, and usage string. -// The argument p points to a float64 variable in which to store the value of the flag. -func (fs *FlagSet) Float64Var(p *float64, names []string, value float64, usage string) { - fs.Var(newFloat64Value(value, p), names, usage) -} - -// Float64Var defines a float64 flag with specified name, default value, and usage string. -// The argument p points to a float64 variable in which to store the value of the flag. -func Float64Var(p *float64, names []string, value float64, usage string) { - CommandLine.Var(newFloat64Value(value, p), names, usage) -} - -// Float64 defines a float64 flag with specified name, default value, and usage string. -// The return value is the address of a float64 variable that stores the value of the flag. -func (fs *FlagSet) Float64(names []string, value float64, usage string) *float64 { - p := new(float64) - fs.Float64Var(p, names, value, usage) - return p -} - -// Float64 defines a float64 flag with specified name, default value, and usage string. -// The return value is the address of a float64 variable that stores the value of the flag. -func Float64(names []string, value float64, usage string) *float64 { - return CommandLine.Float64(names, value, usage) -} - -// DurationVar defines a time.Duration flag with specified name, default value, and usage string. -// The argument p points to a time.Duration variable in which to store the value of the flag. -func (fs *FlagSet) DurationVar(p *time.Duration, names []string, value time.Duration, usage string) { - fs.Var(newDurationValue(value, p), names, usage) -} - -// DurationVar defines a time.Duration flag with specified name, default value, and usage string. -// The argument p points to a time.Duration variable in which to store the value of the flag. -func DurationVar(p *time.Duration, names []string, value time.Duration, usage string) { - CommandLine.Var(newDurationValue(value, p), names, usage) -} - -// Duration defines a time.Duration flag with specified name, default value, and usage string. -// The return value is the address of a time.Duration variable that stores the value of the flag. -func (fs *FlagSet) Duration(names []string, value time.Duration, usage string) *time.Duration { - p := new(time.Duration) - fs.DurationVar(p, names, value, usage) - return p -} - -// Duration defines a time.Duration flag with specified name, default value, and usage string. -// The return value is the address of a time.Duration variable that stores the value of the flag. -func Duration(names []string, value time.Duration, usage string) *time.Duration { - return CommandLine.Duration(names, value, usage) -} - -// Var defines a flag with the specified name and usage string. The type and -// value of the flag are represented by the first argument, of type Value, which -// typically holds a user-defined implementation of Value. For instance, the -// caller could create a flag that turns a comma-separated string into a slice -// of strings by giving the slice the methods of Value; in particular, Set would -// decompose the comma-separated string into the slice. -func (fs *FlagSet) Var(value Value, names []string, usage string) { - // Remember the default value as a string; it won't change. - flag := &Flag{names, usage, value, value.String()} - for _, name := range names { - name = strings.TrimPrefix(name, "#") - _, alreadythere := fs.formal[name] - if alreadythere { - var msg string - if fs.name == "" { - msg = fmt.Sprintf("flag redefined: %s", name) - } else { - msg = fmt.Sprintf("%s flag redefined: %s", fs.name, name) - } - fmt.Fprintln(fs.Out(), msg) - panic(msg) // Happens only if flags are declared with identical names - } - if fs.formal == nil { - fs.formal = make(map[string]*Flag) - } - fs.formal[name] = flag - } -} - -// Var defines a flag with the specified name and usage string. The type and -// value of the flag are represented by the first argument, of type Value, which -// typically holds a user-defined implementation of Value. For instance, the -// caller could create a flag that turns a comma-separated string into a slice -// of strings by giving the slice the methods of Value; in particular, Set would -// decompose the comma-separated string into the slice. -func Var(value Value, names []string, usage string) { - CommandLine.Var(value, names, usage) -} - -// failf prints to standard error a formatted error and usage message and -// returns the error. -func (fs *FlagSet) failf(format string, a ...interface{}) error { - err := fmt.Errorf(format, a...) - fmt.Fprintln(fs.Out(), err) - if os.Args[0] == fs.name { - fmt.Fprintf(fs.Out(), "See '%s --help'.\n", os.Args[0]) - } else { - fmt.Fprintf(fs.Out(), "See '%s %s --help'.\n", os.Args[0], fs.name) - } - return err -} - -// usage calls the Usage method for the flag set, or the usage function if -// the flag set is CommandLine. -func (fs *FlagSet) usage() { - if fs == CommandLine { - Usage() - } else if fs.Usage == nil { - defaultUsage(fs) - } else { - fs.Usage() - } -} - -func trimQuotes(str string) string { - if len(str) == 0 { - return str - } - type quote struct { - start, end byte - } - - // All valid quote types. - quotes := []quote{ - // Double quotes - { - start: '"', - end: '"', - }, - - // Single quotes - { - start: '\'', - end: '\'', - }, - } - - for _, quote := range quotes { - // Only strip if outermost match. - if str[0] == quote.start && str[len(str)-1] == quote.end { - str = str[1 : len(str)-1] - break - } - } - - return str -} - -// parseOne parses one flag. It reports whether a flag was seen. -func (fs *FlagSet) parseOne() (bool, string, error) { - if len(fs.args) == 0 { - return false, "", nil - } - s := fs.args[0] - if len(s) == 0 || s[0] != '-' || len(s) == 1 { - return false, "", nil - } - if s[1] == '-' && len(s) == 2 { // "--" terminates the flags - fs.args = fs.args[1:] - return false, "", nil - } - name := s[1:] - if len(name) == 0 || name[0] == '=' { - return false, "", fs.failf("bad flag syntax: %s", s) - } - - // it's a flag. does it have an argument? - fs.args = fs.args[1:] - hasValue := false - value := "" - if i := strings.Index(name, "="); i != -1 { - value = trimQuotes(name[i+1:]) - hasValue = true - name = name[:i] - } - - m := fs.formal - flag, alreadythere := m[name] // BUG - if !alreadythere { - if name == "-help" || name == "help" || name == "h" { // special case for nice help message. - fs.usage() - return false, "", ErrHelp - } - if len(name) > 0 && name[0] == '-' { - return false, "", fs.failf("flag provided but not defined: -%s", name) - } - return false, name, ErrRetry - } - if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg - if hasValue { - if err := fv.Set(value); err != nil { - return false, "", fs.failf("invalid boolean value %q for -%s: %v", value, name, err) - } - } else { - fv.Set("true") - } - } else { - // It must have a value, which might be the next argument. - if !hasValue && len(fs.args) > 0 { - // value is the next arg - hasValue = true - value, fs.args = fs.args[0], fs.args[1:] - } - if !hasValue { - return false, "", fs.failf("flag needs an argument: -%s", name) - } - if err := flag.Value.Set(value); err != nil { - return false, "", fs.failf("invalid value %q for flag -%s: %v", value, name, err) - } - } - if fs.actual == nil { - fs.actual = make(map[string]*Flag) - } - fs.actual[name] = flag - for i, n := range flag.Names { - if n == fmt.Sprintf("#%s", name) { - replacement := "" - for j := i; j < len(flag.Names); j++ { - if flag.Names[j][0] != '#' { - replacement = flag.Names[j] - break - } - } - if replacement != "" { - fmt.Fprintf(fs.Out(), "Warning: '-%s' is deprecated, it will be replaced by '-%s' soon. See usage.\n", name, replacement) - } else { - fmt.Fprintf(fs.Out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name) - } - } - } - return true, "", nil -} - -// Parse parses flag definitions from the argument list, which should not -// include the command name. Must be called after all flags in the FlagSet -// are defined and before flags are accessed by the program. -// The return value will be ErrHelp if -help was set but not defined. -func (fs *FlagSet) Parse(arguments []string) error { - fs.parsed = true - fs.args = arguments - for { - seen, name, err := fs.parseOne() - if seen { - continue - } - if err == nil { - break - } - if err == ErrRetry { - if len(name) > 1 { - err = nil - for _, letter := range strings.Split(name, "") { - fs.args = append([]string{"-" + letter}, fs.args...) - seen2, _, err2 := fs.parseOne() - if seen2 { - continue - } - if err2 != nil { - err = fs.failf("flag provided but not defined: -%s", name) - break - } - } - if err == nil { - continue - } - } else { - err = fs.failf("flag provided but not defined: -%s", name) - } - } - switch fs.errorHandling { - case ContinueOnError: - return err - case ExitOnError: - os.Exit(125) - case PanicOnError: - panic(err) - } - } - return nil -} - -// ParseFlags is a utility function that adds a help flag if withHelp is true, -// calls fs.Parse(args) and prints a relevant error message if there are -// incorrect number of arguments. It returns error only if error handling is -// set to ContinueOnError and parsing fails. If error handling is set to -// ExitOnError, it's safe to ignore the return value. -func (fs *FlagSet) ParseFlags(args []string, withHelp bool) error { - var help *bool - if withHelp { - help = fs.Bool([]string{"#help", "-help"}, false, "Print usage") - } - if err := fs.Parse(args); err != nil { - return err - } - if help != nil && *help { - fs.SetOutput(os.Stdout) - fs.Usage() - os.Exit(0) - } - if str := fs.CheckArgs(); str != "" { - fs.SetOutput(os.Stderr) - fs.ReportError(str, withHelp) - fs.ShortUsage() - os.Exit(1) - } - return nil -} - -// ReportError is a utility method that prints a user-friendly message -// containing the error that occurred during parsing and a suggestion to get help -func (fs *FlagSet) ReportError(str string, withHelp bool) { - if withHelp { - if os.Args[0] == fs.Name() { - str += ".\nSee '" + os.Args[0] + " --help'" - } else { - str += ".\nSee '" + os.Args[0] + " " + fs.Name() + " --help'" - } - } - fmt.Fprintf(fs.Out(), "%s: %s.\n", os.Args[0], str) -} - -// Parsed reports whether fs.Parse has been called. -func (fs *FlagSet) Parsed() bool { - return fs.parsed -} - -// Parse parses the command-line flags from os.Args[1:]. Must be called -// after all flags are defined and before flags are accessed by the program. -func Parse() { - // Ignore errors; CommandLine is set for ExitOnError. - CommandLine.Parse(os.Args[1:]) -} - -// Parsed returns true if the command-line flags have been parsed. -func Parsed() bool { - return CommandLine.Parsed() -} - -// CommandLine is the default set of command-line flags, parsed from os.Args. -// The top-level functions such as BoolVar, Arg, and on are wrappers for the -// methods of CommandLine. -var CommandLine = NewFlagSet(os.Args[0], ExitOnError) - -// NewFlagSet returns a new, empty flag set with the specified name and -// error handling property. -func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { - f := &FlagSet{ - name: name, - errorHandling: errorHandling, - } - return f -} - -// Init sets the name and error handling property for a flag set. -// By default, the zero FlagSet uses an empty name and the -// ContinueOnError error handling policy. -func (fs *FlagSet) Init(name string, errorHandling ErrorHandling) { - fs.name = name - fs.errorHandling = errorHandling -} - -type mergeVal struct { - Value - key string - fset *FlagSet -} - -func (v mergeVal) Set(s string) error { - return v.fset.Set(v.key, s) -} - -func (v mergeVal) IsBoolFlag() bool { - if b, ok := v.Value.(boolFlag); ok { - return b.IsBoolFlag() - } - return false -} - -// Name returns the name of a mergeVal. -// If the original value had a name, return the original name, -// otherwise, return the key asinged to this mergeVal. -func (v mergeVal) Name() string { - type namedValue interface { - Name() string - } - if nVal, ok := v.Value.(namedValue); ok { - return nVal.Name() - } - return v.key -} - -// Merge is an helper function that merges n FlagSets into a single dest FlagSet -// In case of name collision between the flagsets it will apply -// the destination FlagSet's errorHandling behavior. -func Merge(dest *FlagSet, flagsets ...*FlagSet) error { - for _, fset := range flagsets { - if fset.formal == nil { - continue - } - for k, f := range fset.formal { - if _, ok := dest.formal[k]; ok { - var err error - if fset.name == "" { - err = fmt.Errorf("flag redefined: %s", k) - } else { - err = fmt.Errorf("%s flag redefined: %s", fset.name, k) - } - fmt.Fprintln(fset.Out(), err.Error()) - // Happens only if flags are declared with identical names - switch dest.errorHandling { - case ContinueOnError: - return err - case ExitOnError: - os.Exit(2) - case PanicOnError: - panic(err) - } - } - newF := *f - newF.Value = mergeVal{f.Value, k, fset} - if dest.formal == nil { - dest.formal = make(map[string]*Flag) - } - dest.formal[k] = &newF - } - } - return nil -} - -// IsEmpty reports if the FlagSet is actually empty. -func (fs *FlagSet) IsEmpty() bool { - return len(fs.actual) == 0 -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/README.md deleted file mode 100644 index 45592ce85a..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## 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/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/README.md deleted file mode 100644 index 2b237a5942..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/signal/README.md +++ /dev/null @@ -1 +0,0 @@ -This package provides helper functions for dealing with signals across various operating systems \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/stringid/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/stringid/README.md deleted file mode 100644 index 37a5098fd9..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/stringid/README.md +++ /dev/null @@ -1 +0,0 @@ -This package provides helper functions for dealing with string identifiers diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.APACHE b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.APACHE deleted file mode 100644 index 34c4ea7c50..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.APACHE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://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 2014-2016 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 - - http://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/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.BSD b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.BSD deleted file mode 100644 index 9b4f4a294e..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.BSD +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014-2016 The Docker & Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/README.md deleted file mode 100644 index 8dba54fd08..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/README.md +++ /dev/null @@ -1,6 +0,0 @@ -Package symlink implements EvalSymlinksInScope which is an extension of filepath.EvalSymlinks, -as well as a Windows long-path aware version of filepath.EvalSymlinks -from the [Go standard library](https://golang.org/pkg/path/filepath). - -The code from filepath.EvalSymlinks has been adapted in fs.go. -Please read the LICENSE.BSD file that governs fs.go and LICENSE.APACHE for fs_test.go. diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/filesys.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/filesys.go deleted file mode 100644 index c14feb8496..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/filesys.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build !windows - -package system - -import ( - "os" - "path/filepath" -) - -// MkdirAll creates a directory named path along with any necessary parents, -// with permission specified by attribute perm for all dir created. -func MkdirAll(path string, perm os.FileMode) error { - return os.MkdirAll(path, perm) -} - -// IsAbs is a platform-specific wrapper for filepath.IsAbs. -func IsAbs(path string) bool { - return filepath.IsAbs(path) -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/filesys_windows.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/system/filesys_windows.go deleted file mode 100644 index 16823d5517..0000000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/system/filesys_windows.go +++ /dev/null @@ -1,82 +0,0 @@ -// +build windows - -package system - -import ( - "os" - "path/filepath" - "regexp" - "strings" - "syscall" -) - -// MkdirAll implementation that is volume path aware for Windows. -func MkdirAll(path string, perm os.FileMode) error { - if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) { - return nil - } - - // The rest of this method is copied from os.MkdirAll and should be kept - // as-is to ensure compatibility. - - // Fast path: if we can tell whether path is a directory or file, stop with success or error. - dir, err := os.Stat(path) - if err == nil { - if dir.IsDir() { - return nil - } - return &os.PathError{ - Op: "mkdir", - Path: path, - Err: syscall.ENOTDIR, - } - } - - // Slow path: make sure parent exists and then call Mkdir for path. - i := len(path) - for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. - i-- - } - - j := i - for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. - j-- - } - - if j > 1 { - // Create parent - err = MkdirAll(path[0:j-1], perm) - if err != nil { - return err - } - } - - // Parent now exists; invoke Mkdir and use its result. - err = os.Mkdir(path, perm) - if err != nil { - // Handle arguments like "foo/." by - // double-checking that directory doesn't exist. - dir, err1 := os.Lstat(path) - if err1 == nil && dir.IsDir() { - return nil - } - return err - } - return nil -} - -// IsAbs is a platform-specific wrapper for filepath.IsAbs. On Windows, -// golang filepath.IsAbs does not consider a path \windows\system32 as absolute -// as it doesn't start with a drive-letter/colon combination. However, in -// docker we need to verify things such as WORKDIR /windows/system32 in -// a Dockerfile (which gets translated to \windows\system32 when being processed -// by the daemon. This SHOULD be treated as absolute from a docker processing -// perspective. -func IsAbs(path string) bool { - if !filepath.IsAbs(path) { - if !strings.HasPrefix(path, string(os.PathSeparator)) { - return false - } - } - return true -} diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/LICENSE b/Godeps/_workspace/src/github.com/docker/engine-api/LICENSE deleted file mode 100644 index c157bff96a..0000000000 --- a/Godeps/_workspace/src/github.com/docker/engine-api/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - 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 2015-2016 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/Godeps/_workspace/src/github.com/docker/go-connections/sockets/README.md b/Godeps/_workspace/src/github.com/docker/go-connections/sockets/README.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Godeps/_workspace/src/github.com/docker/go-events/.gitignore b/Godeps/_workspace/src/github.com/docker/go-events/.gitignore deleted file mode 100644 index daf913b1b3..0000000000 --- a/Godeps/_workspace/src/github.com/docker/go-events/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/Godeps/_workspace/src/github.com/docker/go-events/README.md b/Godeps/_workspace/src/github.com/docker/go-events/README.md deleted file mode 100644 index 9e3625da9e..0000000000 --- a/Godeps/_workspace/src/github.com/docker/go-events/README.md +++ /dev/null @@ -1,112 +0,0 @@ -# Docker Events Package - -[![GoDoc](https://godoc.org/github.com/docker/go-events?status.svg)](https://godoc.org/github.com/docker/go-events) -[![Circle CI](https://circleci.com/gh/docker/go-events.svg?style=shield)](https://circleci.com/gh/docker/go-events) - -The Docker `events` package implements a composable event distribution package -for Go. - -Originally created to implement the [notifications in Docker Registry -2](https://github.com/docker/distribution/blob/master/docs/notifications.md), -we've found the pattern to be useful in other applications. This package is -most of the same code with slightly updated interfaces. Much of the internals -have been made available. - -## Usage - -The `events` package centers around a `Sink` type. Events are written with -calls to `Sink.Write(event Event)`. Sinks can be wired up in various -configurations to achieve interesting behavior. - -The canonical example is that employed by the -[docker/distribution/notifications](https://godoc.org/github.com/docker/distribution/notifications) -package. Let's say we have a type `httpSink` where we'd like to queue -notifications. As a rule, it should send a single http request and return an -error if it fails: - -```go -func (h *httpSink) Write(event Event) error { - p, err := json.Marshal(event) - if err != nil { - return err - } - body := bytes.NewReader(p) - resp, err := h.client.Post(h.url, "application/json", body) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.Status != 200 { - return errors.New("unexpected status") - } - - return nil -} - -// implement (*httpSink).Close() -``` - -With just that, we can start using components from this package. One can call -`(*httpSink).Write` to send events as the body of a post request to a -configured URL. - -### Retries - -HTTP can be unreliable. The first feature we'd like is to have some retry: - -```go -hs := newHTTPSink(/*...*/) -retry := NewRetryingSink(hs, NewBreaker(5, time.Second)) -``` - -We now have a sink that will retry events against the `httpSink` until they -succeed. The retry will backoff for one second after 5 consecutive failures -using the breaker strategy. - -### Queues - -This isn't quite enough. We we want a sink that doesn't block while we are -waiting for events to be sent. Let's add a `Queue`: - -```go -queue := NewQueue(retry) -``` - -Now, we have an unbounded queue that will work through all events sent with -`(*Queue).Write`. Events can be added asynchronously to the queue without -blocking the current execution path. This is ideal for use in an http request. - -### Broadcast - -It usually turns out that you want to send to more than one listener. We can -use `Broadcaster` to support this: - -```go -var broadcast = NewBroadcaster() // make it available somewhere in your application. -broadcast.Add(queue) // add your queue! -broadcast.Add(queue2) // and another! -``` - -With the above, we can now call `broadcast.Write` in our http handlers and have -all the events distributed to each queue. Because the events are queued, not -listener blocks another. - -### Extending - -For the most part, the above is sufficient for a lot of applications. However, -extending the above functionality can be done implementing your own `Sink`. The -behavior and semantics of the sink can be completely dependent on the -application requirements. The interface is provided below for reference: - -```go -type Sink { - Write(Event) error - Close() error -} -``` - -Application behavior can be controlled by how `Write` behaves. The examples -above are designed to queue the message and return as quickly as possible. -Other implementations may block until the event is committed to durable -storage. diff --git a/Godeps/_workspace/src/github.com/docker/go-units/CONTRIBUTING.md b/Godeps/_workspace/src/github.com/docker/go-units/CONTRIBUTING.md deleted file mode 100644 index 9ea86d784e..0000000000 --- a/Godeps/_workspace/src/github.com/docker/go-units/CONTRIBUTING.md +++ /dev/null @@ -1,67 +0,0 @@ -# Contributing to go-units - -Want to hack on go-units? Awesome! Here are instructions to get you started. - -go-units is a part of the [Docker](https://www.docker.com) project, and follows -the same rules and principles. If you're already familiar with the way -Docker does things, you'll feel right at home. - -Otherwise, go read Docker's -[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), -[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md), -[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and -[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md). - -### Sign your work - -The sign-off is a simple line at the end of the explanation for the patch. Your -signature certifies that you wrote the patch or otherwise have the right to pass -it on as an open-source patch. The rules are pretty simple: if you can certify -the below (from [developercertificate.org](http://developercertificate.org/)): - -``` -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -660 York Street, Suite 102, -San Francisco, CA 94110 USA - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. -``` - -Then you just add a line to every git commit message: - - Signed-off-by: Joe Smith - -Use your real name (sorry, no pseudonyms or anonymous contributions.) - -If you set your `user.name` and `user.email` git configs, you can sign your -commit automatically with `git commit -s`. diff --git a/Godeps/_workspace/src/github.com/docker/go-units/LICENSE.code b/Godeps/_workspace/src/github.com/docker/go-units/LICENSE.code deleted file mode 100644 index b55b37bc31..0000000000 --- a/Godeps/_workspace/src/github.com/docker/go-units/LICENSE.code +++ /dev/null @@ -1,191 +0,0 @@ - - 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 2015 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/Godeps/_workspace/src/github.com/docker/go-units/LICENSE.docs b/Godeps/_workspace/src/github.com/docker/go-units/LICENSE.docs deleted file mode 100644 index e26cd4fc8e..0000000000 --- a/Godeps/_workspace/src/github.com/docker/go-units/LICENSE.docs +++ /dev/null @@ -1,425 +0,0 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More_considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - - including for purposes of Section 3(b); and - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public licenses. -Notwithstanding, Creative Commons may elect to apply one of its public -licenses to material it publishes and in those instances will be -considered the "Licensor." Except for the limited purpose of indicating -that material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the public -licenses. - -Creative Commons may be contacted at creativecommons.org. diff --git a/Godeps/_workspace/src/github.com/docker/go-units/MAINTAINERS b/Godeps/_workspace/src/github.com/docker/go-units/MAINTAINERS deleted file mode 100644 index 477be8b214..0000000000 --- a/Godeps/_workspace/src/github.com/docker/go-units/MAINTAINERS +++ /dev/null @@ -1,27 +0,0 @@ -# go-connections maintainers file -# -# This file describes who runs the docker/go-connections project and how. -# This is a living document - if you see something out of date or missing, speak up! -# -# It is structured to be consumable by both humans and programs. -# To extract its contents programmatically, use any TOML-compliant parser. -# -# This file is compiled into the MAINTAINERS file in docker/opensource. -# -[Org] - [Org."Core maintainers"] - people = [ - "calavera", - ] - -[people] - -# A reference list of all people associated with the project. -# All other sections should refer to people by their canonical key -# in the people section. - - # ADD YOURSELF HERE IN ALPHABETICAL ORDER - [people.calavera] - Name = "David Calavera" - Email = "david.calavera@gmail.com" - GitHub = "calavera" diff --git a/Godeps/_workspace/src/github.com/docker/go-units/README.md b/Godeps/_workspace/src/github.com/docker/go-units/README.md deleted file mode 100644 index 3ce4d79dac..0000000000 --- a/Godeps/_workspace/src/github.com/docker/go-units/README.md +++ /dev/null @@ -1,18 +0,0 @@ -[![GoDoc](https://godoc.org/github.com/docker/go-units?status.svg)](https://godoc.org/github.com/docker/go-units) - -# Introduction - -go-units is a library to transform human friendly measurements into machine friendly values. - -## Usage - -See the [docs in godoc](https://godoc.org/github.com/docker/go-units) for examples and documentation. - -## Copyright and license - -Copyright © 2015 Docker, Inc. All rights reserved, except as follows. Code -is released under the Apache 2.0 license. The README.md file, and files in the -"docs" folder are licensed under the Creative Commons Attribution 4.0 -International License under the terms and conditions set forth in the file -"LICENSE.docs". You may obtain a duplicate copy of the same license, titled -CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/. diff --git a/Godeps/_workspace/src/github.com/docker/go-units/circle.yml b/Godeps/_workspace/src/github.com/docker/go-units/circle.yml deleted file mode 100644 index 9043b35478..0000000000 --- a/Godeps/_workspace/src/github.com/docker/go-units/circle.yml +++ /dev/null @@ -1,11 +0,0 @@ -dependencies: - post: - # install golint - - go get github.com/golang/lint/golint - -test: - pre: - # run analysis before tests - - go vet ./... - - test -z "$(golint ./... | tee /dev/stderr)" - - test -z "$(gofmt -s -l . | tee /dev/stderr)" diff --git a/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml b/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml deleted file mode 100644 index a7a3bcffc7..0000000000 --- a/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -language: go - -go: - - 1.7.1 - -# let us have speedy Docker-based Travis workers -sudo: false - -before_install: - # Symlink below is needed for Travis CI to work correctly on personal forks of libkv - - ln -s $HOME/gopath/src/github.com/${TRAVIS_REPO_SLUG///libkv/} $HOME/gopath/src/github.com/docker - - go get golang.org/x/tools/cmd/cover - - go get github.com/mattn/goveralls - - go get github.com/golang/lint/golint - - go get github.com/GeertJohan/fgt - -before_script: - - script/travis_consul.sh 0.6.3 - - script/travis_etcd.sh 3.0.0 - - script/travis_zk.sh 3.5.1-alpha - -script: - - ./consul agent -server -bootstrap -advertise=127.0.0.1 -data-dir /tmp/consul -config-file=./config.json 1>/dev/null & - - ./etcd/etcd --listen-client-urls 'http://0.0.0.0:4001' --advertise-client-urls 'http://127.0.0.1:4001' >/dev/null 2>&1 & - - ./zk/bin/zkServer.sh start ./zk/conf/zoo.cfg 1> /dev/null - - script/validate-gofmt - - go vet ./... - - fgt golint ./... - - go test -v -race ./... - - script/coverage - - goveralls -service=travis-ci -coverprofile=goverage.report diff --git a/Godeps/_workspace/src/github.com/docker/libkv/LICENSE.code b/Godeps/_workspace/src/github.com/docker/libkv/LICENSE.code deleted file mode 100644 index 34c4ea7c50..0000000000 --- a/Godeps/_workspace/src/github.com/docker/libkv/LICENSE.code +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://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 2014-2016 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 - - http://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/Godeps/_workspace/src/github.com/docker/libkv/LICENSE.docs b/Godeps/_workspace/src/github.com/docker/libkv/LICENSE.docs deleted file mode 100644 index e26cd4fc8e..0000000000 --- a/Godeps/_workspace/src/github.com/docker/libkv/LICENSE.docs +++ /dev/null @@ -1,425 +0,0 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More_considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - - including for purposes of Section 3(b); and - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public licenses. -Notwithstanding, Creative Commons may elect to apply one of its public -licenses to material it publishes and in those instances will be -considered the "Licensor." Except for the limited purpose of indicating -that material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the public -licenses. - -Creative Commons may be contacted at creativecommons.org. diff --git a/Godeps/_workspace/src/github.com/docker/libkv/MAINTAINERS b/Godeps/_workspace/src/github.com/docker/libkv/MAINTAINERS deleted file mode 100644 index 4a8bbc6135..0000000000 --- a/Godeps/_workspace/src/github.com/docker/libkv/MAINTAINERS +++ /dev/null @@ -1,40 +0,0 @@ -# Libkv maintainers file -# -# This file describes who runs the docker/libkv project and how. -# This is a living document - if you see something out of date or missing, speak up! -# -# It is structured to be consumable by both humans and programs. -# To extract its contents programmatically, use any TOML-compliant parser. -# -# This file is compiled into the MAINTAINERS file in docker/opensource. -# -[Org] - [Org."Core maintainers"] - people = [ - "aluzzardi", - "sanimej", - "vieux", - ] - -[people] - -# A reference list of all people associated with the project. -# All other sections should refer to people by their canonical key -# in the people section. - - # ADD YOURSELF HERE IN ALPHABETICAL ORDER - - [people.aluzzardi] - Name = "Andrea Luzzardi" - Email = "al@docker.com" - GitHub = "aluzzardi" - - [people.sanimej] - Name = "Santhosh Manohar" - Email = "santhosh@docker.com" - GitHub = "sanimej" - - [people.vieux] - Name = "Victor Vieux" - Email = "vieux@docker.com" - GitHub = "vieux" diff --git a/Godeps/_workspace/src/github.com/docker/libkv/README.md b/Godeps/_workspace/src/github.com/docker/libkv/README.md deleted file mode 100644 index baad81b4f8..0000000000 --- a/Godeps/_workspace/src/github.com/docker/libkv/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# libkv - -[![GoDoc](https://godoc.org/github.com/docker/libkv?status.png)](https://godoc.org/github.com/docker/libkv) -[![Build Status](https://travis-ci.org/docker/libkv.svg?branch=master)](https://travis-ci.org/docker/libkv) -[![Coverage Status](https://coveralls.io/repos/docker/libkv/badge.svg)](https://coveralls.io/r/docker/libkv) -[![Go Report Card](https://goreportcard.com/badge/github.com/docker/libkv)](https://goreportcard.com/report/github.com/docker/libkv) - -`libkv` provides a `Go` native library to store metadata. - -The goal of `libkv` is to abstract common store operations for multiple distributed and/or local Key/Value store backends. - -For example, you can use it to store your metadata or for service discovery to register machines and endpoints inside your cluster. - -You can also easily implement a generic *Leader Election* on top of it (see the [docker/leadership](https://github.com/docker/leadership) repository). - -As of now, `libkv` offers support for `Consul`, `Etcd`, `Zookeeper` (**Distributed** store) and `BoltDB` (**Local** store). - -## Usage - -`libkv` is meant to be used as an abstraction layer over existing distributed Key/Value stores. It is especially useful if you plan to support `consul`, `etcd` and `zookeeper` using the same codebase. - -It is ideal if you plan for something written in Go that should support: - -- A simple metadata storage, distributed or local -- A lightweight discovery service for your nodes -- A distributed lock mechanism - -You can find examples of usage for `libkv` under in `docs/examples.go`. Optionally you can also take a look at the `docker/swarm` or `docker/libnetwork` repositories which are using `docker/libkv` for all the use cases listed above. - -## Supported versions - -`libkv` supports: -- Consul versions >= `0.5.1` because it uses Sessions with `Delete` behavior for the use of `TTLs` (mimics zookeeper's Ephemeral node support), If you don't plan to use `TTLs`: you can use Consul version `0.4.0+`. -- Etcd versions >= `2.0` because it uses the new `coreos/etcd/client`, this might change in the future as the support for `APIv3` comes along and adds more capabilities. -- Zookeeper versions >= `3.4.5`. Although this might work with previous version but this remains untested as of now. -- Boltdb, which shouldn't be subject to any version dependencies. - -## Interface - -A **storage backend** in `libkv` should implement (fully or partially) this interface: - -```go -type Store interface { - Put(key string, value []byte, options *WriteOptions) error - Get(key string) (*KVPair, error) - Delete(key string) error - Exists(key string) (bool, error) - Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) - WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*KVPair, error) - NewLock(key string, options *LockOptions) (Locker, error) - List(directory string) ([]*KVPair, error) - DeleteTree(directory string) error - AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error) - AtomicDelete(key string, previous *KVPair) (bool, error) - Close() -} -``` - -## Compatibility matrix - -Backend drivers in `libkv` are generally divided between **local drivers** and **distributed drivers**. Distributed backends offer enhanced capabilities like `Watches` and/or distributed `Locks`. - -Local drivers are usually used in complement to the distributed drivers to store informations that only needs to be available locally. - -| Calls | Consul | Etcd | Zookeeper | BoltDB | -|-----------------------|:----------:|:------:|:-----------:|:--------:| -| Put | X | X | X | X | -| Get | X | X | X | X | -| Delete | X | X | X | X | -| Exists | X | X | X | X | -| Watch | X | X | X | | -| WatchTree | X | X | X | | -| NewLock (Lock/Unlock) | X | X | X | | -| List | X | X | X | X | -| DeleteTree | X | X | X | X | -| AtomicPut | X | X | X | X | -| Close | X | X | X | X | - -## Limitations - -Distributed Key/Value stores often have different concepts for managing and formatting keys and their associated values. Even though `libkv` tries to abstract those stores aiming for some consistency, in some cases it can't be applied easily. - -Please refer to the `docs/compatibility.md` to see what are the special cases for cross-backend compatibility. - -Other than those special cases, you should expect the same experience for basic operations like `Get`/`Put`, etc. - -Calls like `WatchTree` may return different events (or number of events) depending on the backend (for now, `Etcd` and `Consul` will likely return more events than `Zookeeper` that you should triage properly). Although you should be able to use it successfully to watch on events in an interchangeable way (see the **docker/leadership** repository or the **pkg/discovery/kv** package in **docker/docker**). - -## TLS - -Only `Consul` and `etcd` have support for TLS and you should build and provide your own `config.TLS` object to feed the client. Support is planned for `zookeeper`. - -##Roadmap - -- Make the API nicer to use (using `options`) -- Provide more options (`consistency` for example) -- Improve performance (remove extras `Get`/`List` operations) -- Better key formatting -- New backends? - -##Contributing - -Want to hack on libkv? [Docker's contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) apply. - -##Copyright and license - -Copyright © 2014-2016 Docker, Inc. All rights reserved, except as follows. Code is released under the Apache 2.0 license. The README.md file, and files in the "docs" folder are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file "LICENSE.docs". You may obtain a duplicate copy of the same license, titled CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/. diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/CONTRIBUTING.md b/Godeps/_workspace/src/github.com/godbus/dbus/CONTRIBUTING.md deleted file mode 100644 index c88f9b2bdd..0000000000 --- a/Godeps/_workspace/src/github.com/godbus/dbus/CONTRIBUTING.md +++ /dev/null @@ -1,50 +0,0 @@ -# How to Contribute - -## Getting Started - -- Fork the repository on GitHub -- Read the [README](README.markdown) for build and test instructions -- Play with the project, submit bugs, submit patches! - -## Contribution Flow - -This is a rough outline of what a contributor's workflow looks like: - -- Create a topic branch from where you want to base your work (usually master). -- Make commits of logical units. -- Make sure your commit messages are in the proper format (see below). -- Push your changes to a topic branch in your fork of the repository. -- Make sure the tests pass, and add any new tests as appropriate. -- Submit a pull request to the original repository. - -Thanks for your contributions! - -### Format of the Commit Message - -We follow a rough convention for commit messages that is designed to answer two -questions: what changed and why. The subject line should feature the what and -the body of the commit should describe the why. - -``` -scripts: add the test-cluster command - -this uses tmux to setup a test cluster that you can easily kill and -start for debugging. - -Fixes #38 -``` - -The format can be described more formally as follows: - -``` -: - - - -