1
0
mirror of https://github.com/rancher/os.git synced 2025-09-01 14:48:55 +00:00

move dependencies to vendor

This commit is contained in:
Ivan Mikushin
2015-11-26 17:37:01 +05:00
parent 63d7de67cd
commit 1d691cd8d6
2232 changed files with 154499 additions and 9037 deletions

33
vendor/github.com/docker/libnetwork/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,33 @@
# 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
# Coverage
*.tmp
*.coverprofile
# IDE files
.project
libnetwork-build.created

202
vendor/github.com/docker/libnetwork/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
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
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

5
vendor/github.com/docker/libnetwork/MAINTAINERS generated vendored Normal file
View File

@@ -0,0 +1,5 @@
Alessandro Boch <aboch@docker.com> (@aboch)
Alexandr Morozov <lk4d4@docker.com> (@LK4D4)
Arnaud Porterie <arnaud@docker.com> (@icecrime)
Jana Radhakrishnan <mrjana@docker.com> (@mrjana)
Madhu Venugopal <madhu@docker.com> (@mavenugo)

79
vendor/github.com/docker/libnetwork/Makefile generated vendored Normal file
View File

@@ -0,0 +1,79 @@
.PHONY: all all-local build build-local check check-code check-format run-tests check-local install-deps coveralls circle-ci
SHELL=/bin/bash
build_image=libnetwork-build
dockerargs = --privileged -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork
container_env = -e "INSIDECONTAINER=-incontainer=true"
docker = docker run --rm ${dockerargs} ${container_env} ${build_image}
ciargs = -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=-incontainer=true"
cidocker = docker run ${ciargs} ${dockerargs} golang:1.4
all: ${build_image}.created
${docker} make all-local
all-local: check-local build-local
${build_image}.created:
docker run --name=libnetworkbuild -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork golang:1.4 make install-deps
docker commit libnetworkbuild ${build_image}
docker rm libnetworkbuild
touch ${build_image}.created
build: ${build_image}.created
${docker} make build-local
build-local:
$(shell which godep) go build -tags libnetwork_discovery ./...
check: ${build_image}.created
${docker} make check-local
check-code:
@echo "Checking code... "
test -z "$$(golint ./... | tee /dev/stderr)"
go vet ./...
@echo "Done checking code"
check-format:
@echo "Checking format... "
test -z "$$(goimports -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
@echo "Done checking 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 \
if ls $$dir/*.go &> /dev/null; then \
pushd . &> /dev/null ; \
cd $$dir ; \
$(shell which godep) go test ${INSIDECONTAINER} -test.parallel 3 -test.v -covermode=count -coverprofile=./profile.tmp ; \
ret=$$? ;\
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 ; \
rm $$dir/profile.tmp ; \
fi ; \
fi ; \
done
@echo "Done running tests"
check-local: check-format check-code run-tests
install-deps:
apt-get update && apt-get -y install iptables
git clone https://github.com/golang/tools /go/src/golang.org/x/tools
go install golang.org/x/tools/cmd/vet
go install golang.org/x/tools/cmd/goimports
go install golang.org/x/tools/cmd/cover
go get github.com/tools/godep
go get github.com/golang/lint/golint
go get github.com/mattn/goveralls
coveralls:
-@goveralls -service circleci -coverprofile=coverage.coverprofile -repotoken $$COVERALLS_TOKEN
# CircleCI's Docker fails when cleaning up using the --rm flag
# The following target is a workaround for this
circle-ci:
@${cidocker} make install-deps check-local coveralls

88
vendor/github.com/docker/libnetwork/README.md generated vendored Normal file
View File

@@ -0,0 +1,88 @@
# libnetwork - networking for containers
[![Circle CI](https://circleci.com/gh/docker/libnetwork/tree/master.svg?style=svg)](https://circleci.com/gh/docker/libnetwork/tree/master) [![Coverage Status](https://coveralls.io/repos/docker/libnetwork/badge.svg)](https://coveralls.io/r/docker/libnetwork) [![GoDoc](https://godoc.org/github.com/docker/libnetwork?status.svg)](https://godoc.org/github.com/docker/libnetwork)
Libnetwork provides a native Go implementation for connecting containers
The goal of libnetwork is to deliver a robust Container Network Model that provides a consistent programming interface and the required network abstractions for applications.
**NOTE**: libnetwork project is under heavy development and is not ready for general use.
#### Design
Please refer to the [design](docs/design.md) for more information.
#### Using libnetwork
There are many networking solutions available to suit a broad range of use-cases. libnetwork uses a driver / plugin model to support all of these solutions while abstracting the complexity of the driver implementations by exposing a simple and consistent Network Model to users.
```go
// Create a new controller instance
controller, err := libnetwork.New()
if err != nil {
return
}
// Select and configure the network driver
networkType := "bridge"
driverOptions := options.Generic{}
genericOption := make(map[string]interface{})
genericOption[netlabel.GenericData] = driverOptions
err := controller.ConfigureNetworkDriver(networkType, genericOption)
if err != nil {
return
}
// Create a network for containers to join.
// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
network, err := controller.NewNetwork(networkType, "network1")
if err != nil {
return
}
// For each new container: allocate IP and interfaces. The returned network
// settings will be used for container infos (inspect and such), as well as
// iptables rules for port publishing. This info is contained or accessible
// from the returned endpoint.
ep, err := network.CreateEndpoint("Endpoint1")
if err != nil {
return
}
// A container can join the endpoint by providing the container ID to the join
// api.
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
err = ep.Join("container1",
libnetwork.JoinOptionHostname("test"),
libnetwork.JoinOptionDomainname("docker.io"))
if err != nil {
return
}
// libnetwork client can check the endpoint's operational data via the Info() API
epInfo, err := ep.DriverInfo()
mapData, ok := epInfo[netlabel.PortMap]
if ok {
portMapping, ok := mapData.([]netutils.PortBinding)
if ok {
fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping)
}
}
```
#### Current Status
Please watch this space for updates on the progress.
Currently libnetwork is nothing more than an attempt to modularize the Docker platform's networking subsystem by moving it into libnetwork as a library.
## Future
Please refer to [roadmap](ROADMAP.md) for more information.
## Contributing
Want to hack on libnetwork? [Docker's contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) apply.
## Copyright and license
Code and documentation copyright 2015 Docker, inc. Code released under the Apache 2.0 license. Docs released under Creative commons.

20
vendor/github.com/docker/libnetwork/ROADMAP.md generated vendored Normal file
View File

@@ -0,0 +1,20 @@
# Roadmap
This document defines the high-level goals of the libnetwork project. See [Project Planning](#project-planning) for information on Releases.
## Long-term Goal
libnetwork project will follow Docker and Linux philosophy of delivering small, highly modular and composable tools that works well independently.
libnetwork aims to satisfy that composable need for Networking in Containers.
## Short-term Goals
- Modularize the networking logic in Docker Engine and libcontainer in to a single, reusable library
- Replace the networking subsystem of Docker Engine, with libnetwork
- Define a flexible model that allows local and remote drivers to provide networking to containers
- Provide a stand-alone tool "dnet" for managing and testing libnetwork
Project Planning
================
[Project Pages](https://github.com/docker/libnetwork/wiki) define the goals for each Milestone and identify the release-relationship to the Docker Platform.

12
vendor/github.com/docker/libnetwork/circle.yml generated vendored Normal file
View File

@@ -0,0 +1,12 @@
machine:
services:
- docker
dependencies:
override:
- echo "Nothing to install"
test:
override:
- make circle-ci

399
vendor/github.com/docker/libnetwork/controller.go generated vendored Normal file
View File

@@ -0,0 +1,399 @@
/*
Package libnetwork provides the basic functionality and extension points to
create network namespaces and allocate interfaces for containers to use.
// Create a new controller instance
controller, _err := libnetwork.New(nil)
// Select and configure the network driver
networkType := "bridge"
driverOptions := options.Generic{}
genericOption := make(map[string]interface{})
genericOption[netlabel.GenericData] = driverOptions
err := controller.ConfigureNetworkDriver(networkType, genericOption)
if err != nil {
return
}
// Create a network for containers to join.
// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
network, err := controller.NewNetwork(networkType, "network1")
if err != nil {
return
}
// For each new container: allocate IP and interfaces. The returned network
// settings will be used for container infos (inspect and such), as well as
// iptables rules for port publishing. This info is contained or accessible
// from the returned endpoint.
ep, err := network.CreateEndpoint("Endpoint1")
if err != nil {
return
}
// A container can join the endpoint by providing the container ID to the join
// api.
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
err = ep.Join("container1",
libnetwork.JoinOptionHostname("test"),
libnetwork.JoinOptionDomainname("docker.io"))
if err != nil {
return
}
*/
package libnetwork
import (
"fmt"
"net"
"strings"
"sync"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/libnetwork/config"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/hostdiscovery"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/sandbox"
"github.com/docker/libnetwork/types"
)
// NetworkController provides the interface for controller instance which manages
// networks.
type NetworkController interface {
// ConfigureNetworkDriver applies the passed options to the driver instance for the specified network type
ConfigureNetworkDriver(networkType string, options map[string]interface{}) error
// Config method returns the bootup configuration for the controller
Config() config.Config
// Create a new network. The options parameter carries network specific options.
// Labels support will be added in the near future.
NewNetwork(networkType, name string, options ...NetworkOption) (Network, error)
// Networks returns the list of Network(s) managed by this controller.
Networks() []Network
// WalkNetworks uses the provided function to walk the Network(s) managed by this controller.
WalkNetworks(walker NetworkWalker)
// NetworkByName returns the Network which has the passed name. If not found, the error ErrNoSuchNetwork is returned.
NetworkByName(name string) (Network, error)
// NetworkByID returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned.
NetworkByID(id string) (Network, error)
// LeaveAll accepts a container id and attempts to leave all endpoints that the container has joined
LeaveAll(id string) error
// GC triggers immediate garbage collection of resources which are garbage collected.
GC()
}
// NetworkWalker is a client provided function which will be used to walk the Networks.
// When the function returns true, the walk will stop.
type NetworkWalker func(nw Network) bool
type driverData struct {
driver driverapi.Driver
capability driverapi.Capability
}
type driverTable map[string]*driverData
type networkTable map[types.UUID]*network
type endpointTable map[types.UUID]*endpoint
type sandboxTable map[string]*sandboxData
type controller struct {
networks networkTable
drivers driverTable
sandboxes sandboxTable
cfg *config.Config
store datastore.DataStore
sync.Mutex
}
// New creates a new instance of network controller.
func New(cfgOptions ...config.Option) (NetworkController, error) {
var cfg *config.Config
if len(cfgOptions) > 0 {
cfg = &config.Config{}
cfg.ProcessOptions(cfgOptions...)
}
c := &controller{
cfg: cfg,
networks: networkTable{},
sandboxes: sandboxTable{},
drivers: driverTable{}}
if err := initDrivers(c); err != nil {
return nil, err
}
if cfg != nil {
if err := c.initDataStore(); err != nil {
// Failing to initalize datastore is a bad situation to be in.
// But it cannot fail creating the Controller
log.Debugf("Failed to Initialize Datastore due to %v. Operating in non-clustered mode", err)
}
if err := c.initDiscovery(); err != nil {
// Failing to initalize discovery is a bad situation to be in.
// But it cannot fail creating the Controller
log.Debugf("Failed to Initialize Discovery : %v", err)
}
}
return c, nil
}
func (c *controller) validateHostDiscoveryConfig() bool {
if c.cfg == nil || c.cfg.Cluster.Discovery == "" || c.cfg.Cluster.Address == "" {
return false
}
return true
}
func (c *controller) initDiscovery() error {
if c.cfg == nil {
return fmt.Errorf("discovery initialization requires a valid configuration")
}
hostDiscovery := hostdiscovery.NewHostDiscovery()
return hostDiscovery.StartDiscovery(&c.cfg.Cluster, c.hostJoinCallback, c.hostLeaveCallback)
}
func (c *controller) hostJoinCallback(hosts []net.IP) {
}
func (c *controller) hostLeaveCallback(hosts []net.IP) {
}
func (c *controller) Config() config.Config {
c.Lock()
defer c.Unlock()
if c.cfg == nil {
return config.Config{}
}
return *c.cfg
}
func (c *controller) ConfigureNetworkDriver(networkType string, options map[string]interface{}) error {
c.Lock()
dd, ok := c.drivers[networkType]
c.Unlock()
if !ok {
return NetworkTypeError(networkType)
}
return dd.driver.Config(options)
}
func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
c.Lock()
if !config.IsValidName(networkType) {
c.Unlock()
return ErrInvalidName(networkType)
}
if _, ok := c.drivers[networkType]; ok {
c.Unlock()
return driverapi.ErrActiveRegistration(networkType)
}
c.drivers[networkType] = &driverData{driver, capability}
if c.cfg == nil {
c.Unlock()
return nil
}
opt := make(map[string]interface{})
for _, label := range c.cfg.Daemon.Labels {
if strings.HasPrefix(label, netlabel.DriverPrefix+"."+networkType) {
opt[netlabel.Key(label)] = netlabel.Value(label)
}
}
if capability.Scope == driverapi.GlobalScope && c.validateDatastoreConfig() {
opt[netlabel.KVProvider] = c.cfg.Datastore.Client.Provider
opt[netlabel.KVProviderURL] = c.cfg.Datastore.Client.Address
}
c.Unlock()
if len(opt) != 0 {
if err := driver.Config(opt); err != nil {
return err
}
}
return nil
}
// 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, options ...NetworkOption) (Network, error) {
if !config.IsValidName(name) {
return nil, ErrInvalidName(name)
}
// Check if a network already exists with the specified network name
c.Lock()
for _, n := range c.networks {
if n.name == name {
c.Unlock()
return nil, NetworkNameError(name)
}
}
c.Unlock()
// Construct the network object
network := &network{
name: name,
networkType: networkType,
id: types.UUID(stringid.GenerateRandomID()),
ctrlr: c,
endpoints: endpointTable{},
}
network.processOptions(options...)
if err := c.addNetwork(network); err != nil {
return nil, err
}
if err := c.updateNetworkToStore(network); err != nil {
log.Warnf("couldnt create network %s: %v", network.name, err)
if e := network.Delete(); e != nil {
log.Warnf("couldnt cleanup network %s: %v", network.name, err)
}
return nil, err
}
return network, nil
}
func (c *controller) addNetwork(n *network) error {
c.Lock()
// Check if a driver for the specified network type is available
dd, ok := c.drivers[n.networkType]
c.Unlock()
if !ok {
var err error
dd, err = c.loadDriver(n.networkType)
if err != nil {
return err
}
}
n.Lock()
n.svcRecords = svcMap{}
n.driver = dd.driver
d := n.driver
n.Unlock()
// Create the network
if err := d.CreateNetwork(n.id, n.generic); err != nil {
return err
}
if err := n.watchEndpoints(); err != nil {
return err
}
c.Lock()
c.networks[n.id] = n
c.Unlock()
return nil
}
func (c *controller) Networks() []Network {
c.Lock()
defer c.Unlock()
list := make([]Network, 0, len(c.networks))
for _, n := range c.networks {
list = append(list, n)
}
return list
}
func (c *controller) WalkNetworks(walker NetworkWalker) {
for _, n := range c.Networks() {
if walker(n) {
return
}
}
}
func (c *controller) NetworkByName(name string) (Network, error) {
if name == "" {
return nil, ErrInvalidName(name)
}
var n Network
s := func(current Network) bool {
if current.Name() == name {
n = current
return true
}
return false
}
c.WalkNetworks(s)
if n == nil {
return nil, ErrNoSuchNetwork(name)
}
return n, nil
}
func (c *controller) NetworkByID(id string) (Network, error) {
if id == "" {
return nil, ErrInvalidID(id)
}
c.Lock()
defer c.Unlock()
if n, ok := c.networks[types.UUID(id)]; ok {
return n, nil
}
return nil, ErrNoSuchNetwork(id)
}
func (c *controller) loadDriver(networkType string) (*driverData, 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)
if err != nil {
if err == plugins.ErrNotFound {
return nil, types.NotFoundErrorf(err.Error())
}
return nil, err
}
c.Lock()
defer c.Unlock()
dd, ok := c.drivers[networkType]
if !ok {
return nil, ErrInvalidNetworkDriver(networkType)
}
return dd, nil
}
func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) {
c.Lock()
dd, ok := c.drivers[networkType]
c.Unlock()
if !ok {
return false, types.NotFoundErrorf("driver not found for %s", networkType)
}
if dd.capability.Scope == driverapi.GlobalScope {
return true, nil
}
return false, nil
}
func (c *controller) GC() {
sandbox.GC()
}

19
vendor/github.com/docker/libnetwork/drivers_freebsd.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
package libnetwork
import (
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/drivers/null"
"github.com/docker/libnetwork/drivers/remote"
)
func initDrivers(dc driverapi.DriverCallback) error {
for _, fn := range [](func(driverapi.DriverCallback) error){
null.Init,
remote.Init,
} {
if err := fn(dc); err != nil {
return err
}
}
return nil
}

25
vendor/github.com/docker/libnetwork/drivers_linux.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
package libnetwork
import (
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/drivers/bridge"
"github.com/docker/libnetwork/drivers/host"
"github.com/docker/libnetwork/drivers/null"
o "github.com/docker/libnetwork/drivers/overlay"
"github.com/docker/libnetwork/drivers/remote"
)
func initDrivers(dc driverapi.DriverCallback) error {
for _, fn := range [](func(driverapi.DriverCallback) error){
bridge.Init,
host.Init,
null.Init,
remote.Init,
o.Init,
} {
if err := fn(dc); err != nil {
return err
}
}
return nil
}

17
vendor/github.com/docker/libnetwork/drivers_windows.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package libnetwork
import (
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/drivers/windows"
)
func initDrivers(dc driverapi.DriverCallback) error {
for _, fn := range [](func(driverapi.DriverCallback) error){
windows.Init,
} {
if err := fn(dc); err != nil {
return err
}
}
return nil
}

998
vendor/github.com/docker/libnetwork/endpoint.go generated vendored Normal file
View File

@@ -0,0 +1,998 @@
package libnetwork
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"sync"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/etchosts"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/resolvconf"
"github.com/docker/libnetwork/sandbox"
"github.com/docker/libnetwork/types"
)
// Endpoint represents a logical connection between a network and a sandbox.
type Endpoint interface {
// A system generated id for this endpoint.
ID() string
// Name returns the name of this endpoint.
Name() string
// Network returns the name of the network to which this endpoint is attached.
Network() string
// Join creates a new sandbox for the given container ID and populates the
// network resources allocated for the endpoint and joins the sandbox to
// the endpoint.
Join(containerID string, options ...EndpointOption) error
// Leave removes the sandbox associated with container ID and detaches
// the network resources populated in the sandbox
Leave(containerID string, options ...EndpointOption) error
// Return certain operational data belonging to this endpoint
Info() EndpointInfo
// DriverInfo returns a collection of driver operational data related to this endpoint retrieved from the driver
DriverInfo() (map[string]interface{}, error)
// ContainerInfo returns the info available at the endpoint about the attached container
ContainerInfo() ContainerInfo
// Delete and detaches this endpoint from the network.
Delete() error
// Retrieve the interfaces' statistics from the sandbox
Statistics() (map[string]*sandbox.InterfaceStatistics, error)
}
// EndpointOption is a option setter function type used to pass varios options to Network
// and Endpoint interfaces methods. The various setter functions of type EndpointOption are
// provided by libnetwork, they look like <Create|Join|Leave>Option[...](...)
type EndpointOption func(ep *endpoint)
// ContainerData is a set of data returned when a container joins an endpoint.
type ContainerData struct {
SandboxKey string
}
// These are the container configs used to customize container /etc/hosts file.
type hostsPathConfig struct {
hostName string
domainName string
hostsPath string
extraHosts []extraHost
parentUpdates []parentUpdate
}
// These are the container configs used to customize container /etc/resolv.conf file.
type resolvConfPathConfig struct {
resolvConfPath string
dnsList []string
dnsSearchList []string
}
type containerConfig struct {
hostsPathConfig
resolvConfPathConfig
generic map[string]interface{}
useDefaultSandBox bool
prio int // higher the value, more the priority
}
type extraHost struct {
name string
IP string
}
type parentUpdate struct {
eid string
name string
ip string
}
type containerInfo struct {
id string
config containerConfig
data ContainerData
sync.Mutex
}
func (ci *containerInfo) ID() string {
return ci.id
}
func (ci *containerInfo) Labels() map[string]interface{} {
return ci.config.generic
}
type endpoint struct {
name string
id types.UUID
network *network
iFaces []*endpointInterface
joinInfo *endpointJoinInfo
container *containerInfo
exposedPorts []types.TransportPort
generic map[string]interface{}
joinLeaveDone chan struct{}
dbIndex uint64
dbExists bool
sync.Mutex
}
func (ci *containerInfo) MarshalJSON() ([]byte, error) {
ci.Lock()
defer ci.Unlock()
// We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need
return json.Marshal(ci.id)
}
func (ci *containerInfo) UnmarshalJSON(b []byte) (err error) {
ci.Lock()
defer ci.Unlock()
var id string
if err := json.Unmarshal(b, &id); err != nil {
return err
}
ci.id = id
return nil
}
func (ep *endpoint) MarshalJSON() ([]byte, error) {
ep.Lock()
defer ep.Unlock()
epMap := make(map[string]interface{})
epMap["name"] = ep.name
epMap["id"] = string(ep.id)
epMap["ep_iface"] = ep.iFaces
epMap["exposed_ports"] = ep.exposedPorts
epMap["generic"] = ep.generic
if ep.container != nil {
epMap["container"] = ep.container
}
return json.Marshal(epMap)
}
func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
ep.Lock()
defer ep.Unlock()
var epMap map[string]interface{}
if err := json.Unmarshal(b, &epMap); err != nil {
return err
}
ep.name = epMap["name"].(string)
ep.id = types.UUID(epMap["id"].(string))
ib, _ := json.Marshal(epMap["ep_iface"])
var ifaces []endpointInterface
json.Unmarshal(ib, &ifaces)
ep.iFaces = make([]*endpointInterface, 0)
for _, iface := range ifaces {
ep.iFaces = append(ep.iFaces, &iface)
}
tb, _ := json.Marshal(epMap["exposed_ports"])
var tPorts []types.TransportPort
json.Unmarshal(tb, &tPorts)
ep.exposedPorts = tPorts
epc, ok := epMap["container"]
if ok {
cb, _ := json.Marshal(epc)
var cInfo containerInfo
json.Unmarshal(cb, &cInfo)
ep.container = &cInfo
}
if epMap["generic"] != nil {
ep.generic = epMap["generic"].(map[string]interface{})
}
return nil
}
const defaultPrefix = "/var/lib/docker/network/files"
func (ep *endpoint) ID() string {
ep.Lock()
defer ep.Unlock()
return string(ep.id)
}
func (ep *endpoint) Name() string {
ep.Lock()
defer ep.Unlock()
return ep.name
}
func (ep *endpoint) Network() string {
ep.Lock()
defer ep.Unlock()
return ep.network.name
}
// endpoint Key structure : endpoint/network-id/endpoint-id
func (ep *endpoint) Key() []string {
ep.Lock()
n := ep.network
defer ep.Unlock()
return []string{datastore.EndpointKeyPrefix, string(n.id), string(ep.id)}
}
func (ep *endpoint) KeyPrefix() []string {
ep.Lock()
n := ep.network
defer ep.Unlock()
return []string{datastore.EndpointKeyPrefix, string(n.id)}
}
func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) {
// endpoint Key structure : endpoint/network-id/endpoint-id
// it's an invalid key if the key doesn't have all the 3 key elements above
if key == nil || len(key) < 3 || key[0] != datastore.EndpointKeyPrefix {
return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key)
}
// network-id is placed at index=1. pls refer to endpoint.Key() method
return types.UUID(key[1]), nil
}
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) Index() uint64 {
ep.Lock()
defer ep.Unlock()
return ep.dbIndex
}
func (ep *endpoint) SetIndex(index uint64) {
ep.Lock()
defer ep.Unlock()
ep.dbIndex = index
ep.dbExists = true
}
func (ep *endpoint) Exists() bool {
ep.Lock()
defer ep.Unlock()
return ep.dbExists
}
func (ep *endpoint) processOptions(options ...EndpointOption) {
ep.Lock()
defer ep.Unlock()
for _, opt := range options {
if opt != nil {
opt(ep)
}
}
}
func createBasePath(dir string) error {
err := os.MkdirAll(dir, 0644)
if err != nil && !os.IsExist(err) {
return err
}
return nil
}
func createFile(path string) error {
var f *os.File
dir, _ := filepath.Split(path)
err := createBasePath(dir)
if err != nil {
return err
}
f, err = os.Create(path)
if err == nil {
f.Close()
}
return err
}
// joinLeaveStart waits to ensure there are no joins or leaves in progress and
// marks this join/leave in progress without race
func (ep *endpoint) joinLeaveStart() {
ep.Lock()
defer ep.Unlock()
for ep.joinLeaveDone != nil {
joinLeaveDone := ep.joinLeaveDone
ep.Unlock()
select {
case <-joinLeaveDone:
}
ep.Lock()
}
ep.joinLeaveDone = make(chan struct{})
}
// joinLeaveEnd marks the end of this join/leave operation and
// signals the same without race to other join and leave waiters
func (ep *endpoint) joinLeaveEnd() {
ep.Lock()
defer ep.Unlock()
if ep.joinLeaveDone != nil {
close(ep.joinLeaveDone)
ep.joinLeaveDone = nil
}
}
func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
var err error
if containerID == "" {
return InvalidContainerIDError(containerID)
}
ep.joinLeaveStart()
defer func() {
ep.joinLeaveEnd()
}()
ep.Lock()
if ep.container != nil {
ep.Unlock()
return ErrInvalidJoin{}
}
ep.container = &containerInfo{
id: containerID,
config: containerConfig{
hostsPathConfig: hostsPathConfig{
extraHosts: []extraHost{},
parentUpdates: []parentUpdate{},
},
}}
ep.joinInfo = &endpointJoinInfo{}
container := ep.container
network := ep.network
epid := ep.id
ep.Unlock()
defer func() {
if err != nil {
ep.Lock()
ep.container = nil
ep.Unlock()
}
}()
network.Lock()
driver := network.driver
nid := network.id
ctrlr := network.ctrlr
network.Unlock()
ep.processOptions(options...)
sboxKey := sandbox.GenerateKey(containerID)
if container.config.useDefaultSandBox {
sboxKey = sandbox.GenerateKey("default")
}
err = driver.Join(nid, epid, sboxKey, ep, container.config.generic)
if err != nil {
return err
}
defer func() {
if err != nil {
if err = driver.Leave(nid, epid); err != nil {
log.Warnf("driver leave failed while rolling back join: %v", err)
}
}
}()
err = ep.buildHostsFiles()
if err != nil {
return err
}
err = ep.updateParentHosts()
if err != nil {
return err
}
err = ep.setupDNS()
if err != nil {
return err
}
sb, err := ctrlr.sandboxAdd(sboxKey, !container.config.useDefaultSandBox, ep)
if err != nil {
return fmt.Errorf("failed sandbox add: %v", err)
}
defer func() {
if err != nil {
ctrlr.sandboxRm(sboxKey, ep)
}
}()
if err := network.ctrlr.updateEndpointToStore(ep); err != nil {
return err
}
container.data.SandboxKey = sb.Key()
return nil
}
func (ep *endpoint) hasInterface(iName string) bool {
ep.Lock()
defer ep.Unlock()
for _, iface := range ep.iFaces {
if iface.srcName == iName {
return true
}
}
return false
}
func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
var err error
ep.joinLeaveStart()
defer ep.joinLeaveEnd()
ep.processOptions(options...)
ep.Lock()
container := ep.container
n := ep.network
if container == nil || container.id == "" || container.data.SandboxKey == "" ||
containerID == "" || container.id != containerID {
if container == nil {
err = ErrNoContainer{}
} else {
err = InvalidContainerIDError(containerID)
}
ep.Unlock()
return err
}
ep.container = nil
ep.Unlock()
n.Lock()
driver := n.driver
ctrlr := n.ctrlr
n.Unlock()
if err := ctrlr.updateEndpointToStore(ep); err != nil {
ep.Lock()
ep.container = container
ep.Unlock()
return err
}
err = driver.Leave(n.id, ep.id)
ctrlr.sandboxRm(container.data.SandboxKey, ep)
return err
}
func (ep *endpoint) Delete() error {
var err error
ep.Lock()
epid := ep.id
name := ep.name
n := ep.network
if ep.container != nil {
ep.Unlock()
return &ActiveContainerError{name: name, id: string(epid)}
}
n.Lock()
ctrlr := n.ctrlr
n.Unlock()
ep.Unlock()
if err = ctrlr.deleteEndpointFromStore(ep); err != nil {
return err
}
defer func() {
if err != nil {
ep.SetIndex(0)
if e := ctrlr.updateEndpointToStore(ep); e != nil {
log.Warnf("failed to recreate endpoint in store %s : %v", name, err)
}
}
}()
// Update the endpoint count in network and update it in the datastore
n.DecEndpointCnt()
if err = ctrlr.updateNetworkToStore(n); err != nil {
return err
}
defer func() {
if err != nil {
n.IncEndpointCnt()
if e := ctrlr.updateNetworkToStore(n); e != nil {
log.Warnf("failed to update network %s : %v", n.name, e)
}
}
}()
if err = ep.deleteEndpoint(); err != nil {
return err
}
return nil
}
func (ep *endpoint) Statistics() (map[string]*sandbox.InterfaceStatistics, error) {
m := make(map[string]*sandbox.InterfaceStatistics)
ep.Lock()
n := ep.network
skey := ep.container.data.SandboxKey
ep.Unlock()
n.Lock()
c := n.ctrlr
n.Unlock()
sbox := c.sandboxGet(skey)
if sbox == nil {
return m, nil
}
var err error
for _, i := range sbox.Info().Interfaces() {
if m[i.DstName()], err = i.Statistics(); err != nil {
return m, err
}
}
return m, nil
}
func (ep *endpoint) deleteEndpoint() error {
ep.Lock()
n := ep.network
name := ep.name
epid := ep.id
ep.Unlock()
n.Lock()
_, ok := n.endpoints[epid]
if !ok {
n.Unlock()
return nil
}
nid := n.id
driver := n.driver
delete(n.endpoints, epid)
n.Unlock()
if err := driver.DeleteEndpoint(nid, epid); err != nil {
if _, ok := err.(types.ForbiddenError); ok {
n.Lock()
n.endpoints[epid] = ep
n.Unlock()
return err
}
log.Warnf("driver error deleting endpoint %s : %v", name, err)
}
n.updateSvcRecord(ep, false)
return nil
}
func (ep *endpoint) addHostEntries(recs []etchosts.Record) {
ep.Lock()
container := ep.container
ep.Unlock()
if container == nil {
return
}
if err := etchosts.Add(container.config.hostsPath, recs); err != nil {
log.Warnf("Failed adding service host entries to the running container: %v", err)
}
}
func (ep *endpoint) deleteHostEntries(recs []etchosts.Record) {
ep.Lock()
container := ep.container
ep.Unlock()
if container == nil {
return
}
if err := etchosts.Delete(container.config.hostsPath, recs); err != nil {
log.Warnf("Failed deleting service host entries to the running container: %v", err)
}
}
func (ep *endpoint) buildHostsFiles() error {
var extraContent []etchosts.Record
ep.Lock()
container := ep.container
joinInfo := ep.joinInfo
ifaces := ep.iFaces
n := ep.network
ep.Unlock()
if container == nil {
return ErrNoContainer{}
}
if container.config.hostsPath == "" {
container.config.hostsPath = defaultPrefix + "/" + container.id + "/hosts"
}
dir, _ := filepath.Split(container.config.hostsPath)
err := createBasePath(dir)
if err != nil {
return err
}
if joinInfo != nil && joinInfo.hostsPath != "" {
content, err := ioutil.ReadFile(joinInfo.hostsPath)
if err != nil && !os.IsNotExist(err) {
return err
}
if err == nil {
return ioutil.WriteFile(container.config.hostsPath, content, 0644)
}
}
for _, extraHost := range container.config.extraHosts {
extraContent = append(extraContent,
etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
}
extraContent = append(extraContent, n.getSvcRecords()...)
IP := ""
if len(ifaces) != 0 && ifaces[0] != nil {
IP = ifaces[0].addr.IP.String()
}
return etchosts.Build(container.config.hostsPath, IP, container.config.hostName,
container.config.domainName, extraContent)
}
func (ep *endpoint) updateParentHosts() error {
ep.Lock()
container := ep.container
network := ep.network
ep.Unlock()
if container == nil {
return ErrNoContainer{}
}
for _, update := range container.config.parentUpdates {
network.Lock()
pep, ok := network.endpoints[types.UUID(update.eid)]
if !ok {
network.Unlock()
continue
}
network.Unlock()
pep.Lock()
pContainer := pep.container
pep.Unlock()
if pContainer != nil {
if err := etchosts.Update(pContainer.config.hostsPath, update.ip, update.name); err != nil {
return err
}
}
}
return nil
}
func (ep *endpoint) updateDNS(resolvConf []byte) error {
ep.Lock()
container := ep.container
network := ep.network
ep.Unlock()
if container == nil {
return ErrNoContainer{}
}
oldHash := []byte{}
hashFile := container.config.resolvConfPath + ".hash"
resolvBytes, err := ioutil.ReadFile(container.config.resolvConfPath)
if err != nil {
if !os.IsNotExist(err) {
return err
}
} else {
oldHash, err = ioutil.ReadFile(hashFile)
if err != nil {
if !os.IsNotExist(err) {
return err
}
oldHash = []byte{}
}
}
curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes))
if err != nil {
return err
}
if string(oldHash) != "" && curHash != string(oldHash) {
// Seems the user has changed the container resolv.conf since the last time
// we checked so return without doing anything.
return nil
}
// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
resolvConf, _ = resolvconf.FilterResolvDNS(resolvConf, network.enableIPv6)
newHash, err := ioutils.HashData(bytes.NewReader(resolvConf))
if err != nil {
return err
}
// for atomic updates to these files, use temporary files with os.Rename:
dir := path.Dir(container.config.resolvConfPath)
tmpHashFile, err := ioutil.TempFile(dir, "hash")
if err != nil {
return err
}
tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
if err != nil {
return err
}
// Change the perms to 0644 since ioutil.TempFile creates it by default as 0600
if err := os.Chmod(tmpResolvFile.Name(), 0644); err != nil {
return err
}
// write the updates to the temp files
if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newHash), 0644); err != nil {
return err
}
if err = ioutil.WriteFile(tmpResolvFile.Name(), resolvConf, 0644); err != nil {
return err
}
// rename the temp files for atomic replace
if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil {
return err
}
return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath)
}
func copyFile(src, dst string) error {
sBytes, err := ioutil.ReadFile(src)
if err != nil {
return err
}
return ioutil.WriteFile(dst, sBytes, 0644)
}
func (ep *endpoint) setupDNS() error {
ep.Lock()
container := ep.container
joinInfo := ep.joinInfo
ep.Unlock()
if container == nil {
return ErrNoContainer{}
}
if container.config.resolvConfPath == "" {
container.config.resolvConfPath = defaultPrefix + "/" + container.id + "/resolv.conf"
}
dir, _ := filepath.Split(container.config.resolvConfPath)
err := createBasePath(dir)
if err != nil {
return err
}
if joinInfo.resolvConfPath != "" {
if err := copyFile(joinInfo.resolvConfPath, container.config.resolvConfPath); err != nil {
return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", joinInfo.resolvConfPath, container.config.resolvConfPath, err)
}
return nil
}
resolvConf, err := resolvconf.Get()
if err != nil {
return err
}
if len(container.config.dnsList) > 0 ||
len(container.config.dnsSearchList) > 0 {
var (
dnsList = resolvconf.GetNameservers(resolvConf)
dnsSearchList = resolvconf.GetSearchDomains(resolvConf)
)
if len(container.config.dnsList) > 0 {
dnsList = container.config.dnsList
}
if len(container.config.dnsSearchList) > 0 {
dnsSearchList = container.config.dnsSearchList
}
return resolvconf.Build(container.config.resolvConfPath, dnsList, dnsSearchList)
}
return ep.updateDNS(resolvConf)
}
// EndpointOptionGeneric function returns an option setter for a Generic option defined
// in a Dictionary of Key-Value pair
func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
return func(ep *endpoint) {
for k, v := range generic {
ep.generic[k] = v
}
}
}
// JoinOptionPriority function returns an option setter for priority option to
// be passed to endpoint Join method.
func JoinOptionPriority(prio int) EndpointOption {
return func(ep *endpoint) {
ep.container.config.prio = prio
}
}
// JoinOptionHostname function returns an option setter for hostname option to
// be passed to endpoint Join method.
func JoinOptionHostname(name string) EndpointOption {
return func(ep *endpoint) {
ep.container.config.hostName = name
}
}
// JoinOptionDomainname function returns an option setter for domainname option to
// be passed to endpoint Join method.
func JoinOptionDomainname(name string) EndpointOption {
return func(ep *endpoint) {
ep.container.config.domainName = name
}
}
// JoinOptionHostsPath function returns an option setter for hostspath option to
// be passed to endpoint Join method.
func JoinOptionHostsPath(path string) EndpointOption {
return func(ep *endpoint) {
ep.container.config.hostsPath = path
}
}
// JoinOptionExtraHost function returns an option setter for extra /etc/hosts options
// which is a name and IP as strings.
func JoinOptionExtraHost(name string, IP string) EndpointOption {
return func(ep *endpoint) {
ep.container.config.extraHosts = append(ep.container.config.extraHosts, extraHost{name: name, IP: IP})
}
}
// JoinOptionParentUpdate function returns an option setter for parent container
// which needs to update the IP address for the linked container.
func JoinOptionParentUpdate(eid string, name, ip string) EndpointOption {
return func(ep *endpoint) {
ep.container.config.parentUpdates = append(ep.container.config.parentUpdates, parentUpdate{eid: eid, name: name, ip: ip})
}
}
// JoinOptionResolvConfPath function returns an option setter for resolvconfpath option to
// be passed to endpoint Join method.
func JoinOptionResolvConfPath(path string) EndpointOption {
return func(ep *endpoint) {
ep.container.config.resolvConfPath = path
}
}
// JoinOptionDNS function returns an option setter for dns entry option to
// be passed to endpoint Join method.
func JoinOptionDNS(dns string) EndpointOption {
return func(ep *endpoint) {
ep.container.config.dnsList = append(ep.container.config.dnsList, dns)
}
}
// JoinOptionDNSSearch function returns an option setter for dns search entry option to
// be passed to endpoint Join method.
func JoinOptionDNSSearch(search string) EndpointOption {
return func(ep *endpoint) {
ep.container.config.dnsSearchList = append(ep.container.config.dnsSearchList, search)
}
}
// JoinOptionUseDefaultSandbox function returns an option setter for using default sandbox to
// be passed to endpoint Join method.
func JoinOptionUseDefaultSandbox() EndpointOption {
return func(ep *endpoint) {
ep.container.config.useDefaultSandBox = true
}
}
// CreateOptionExposedPorts function returns an option setter for the container exposed
// ports option to be passed to network.CreateEndpoint() method.
func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption {
return func(ep *endpoint) {
// Defensive copy
eps := make([]types.TransportPort, len(exposedPorts))
copy(eps, exposedPorts)
// Store endpoint label and in generic because driver needs it
ep.exposedPorts = eps
ep.generic[netlabel.ExposedPorts] = eps
}
}
// CreateOptionPortMapping function returns an option setter for the mapping
// ports option to be passed to network.CreateEndpoint() method.
func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption {
return func(ep *endpoint) {
// Store a copy of the bindings as generic data to pass to the driver
pbs := make([]types.PortBinding, len(portBindings))
copy(pbs, portBindings)
ep.generic[netlabel.PortMap] = pbs
}
}
// JoinOptionGeneric function returns an option setter for Generic configuration
// that is not managed by libNetwork but can be used by the Drivers during the call to
// endpoint join method. Container Labels are a good example.
func JoinOptionGeneric(generic map[string]interface{}) EndpointOption {
return func(ep *endpoint) {
ep.container.config.generic = generic
}
}

323
vendor/github.com/docker/libnetwork/endpoint_info.go generated vendored Normal file
View File

@@ -0,0 +1,323 @@
package libnetwork
import (
"encoding/json"
"net"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/types"
)
// EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
type EndpointInfo interface {
// InterfaceList returns an interface list which were assigned to the endpoint
// by the driver. This can be used after the endpoint has been created.
InterfaceList() []InterfaceInfo
// Gateway returns the IPv4 gateway assigned by the driver.
// This will only return a valid value if a container has joined the endpoint.
Gateway() net.IP
// GatewayIPv6 returns the IPv6 gateway assigned by the driver.
// This will only return a valid value if a container has joined the endpoint.
GatewayIPv6() net.IP
// SandboxKey returns the sanbox key for the container which has joined
// the endpoint. If there is no container joined then this will return an
// empty string.
SandboxKey() string
}
// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
type InterfaceInfo interface {
// MacAddress returns the MAC address assigned to the endpoint.
MacAddress() net.HardwareAddr
// Address returns the IPv4 address assigned to the endpoint.
Address() net.IPNet
// AddressIPv6 returns the IPv6 address assigned to the endpoint.
AddressIPv6() net.IPNet
}
// ContainerInfo provides an interface to retrieve the info about the container attached to the endpoint
type ContainerInfo interface {
// ID returns the ID of the container
ID() string
// Labels returns the container's labels
Labels() map[string]interface{}
}
type endpointInterface struct {
id int
mac net.HardwareAddr
addr net.IPNet
addrv6 net.IPNet
srcName string
dstPrefix string
routes []*net.IPNet
}
func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
epMap := make(map[string]interface{})
epMap["id"] = epi.id
epMap["mac"] = epi.mac.String()
epMap["addr"] = epi.addr.String()
epMap["addrv6"] = epi.addrv6.String()
epMap["srcName"] = epi.srcName
epMap["dstPrefix"] = epi.dstPrefix
var routes []string
for _, route := range epi.routes {
routes = append(routes, route.String())
}
epMap["routes"] = routes
return json.Marshal(epMap)
}
func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
var epMap map[string]interface{}
if err := json.Unmarshal(b, &epMap); err != nil {
return err
}
epi.id = int(epMap["id"].(float64))
mac, _ := net.ParseMAC(epMap["mac"].(string))
epi.mac = mac
ip, ipnet, _ := net.ParseCIDR(epMap["addr"].(string))
if ipnet != nil {
ipnet.IP = ip
epi.addr = *ipnet
}
ip, ipnet, _ = net.ParseCIDR(epMap["addrv6"].(string))
if ipnet != nil {
ipnet.IP = ip
epi.addrv6 = *ipnet
}
epi.srcName = epMap["srcName"].(string)
epi.dstPrefix = epMap["dstPrefix"].(string)
rb, _ := json.Marshal(epMap["routes"])
var routes []string
json.Unmarshal(rb, &routes)
epi.routes = make([]*net.IPNet, 0)
for _, route := range routes {
ip, ipr, err := net.ParseCIDR(route)
if err == nil {
ipr.IP = ip
epi.routes = append(epi.routes, ipr)
}
}
return nil
}
type endpointJoinInfo struct {
gw net.IP
gw6 net.IP
hostsPath string
resolvConfPath string
StaticRoutes []*types.StaticRoute
}
func (ep *endpoint) ContainerInfo() ContainerInfo {
ep.Lock()
ci := ep.container
defer ep.Unlock()
// Need this since we return the interface
if ci == nil {
return nil
}
return ci
}
func (ep *endpoint) Info() EndpointInfo {
return ep
}
func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
ep.Lock()
network := ep.network
epid := ep.id
ep.Unlock()
network.Lock()
driver := network.driver
nid := network.id
network.Unlock()
return driver.EndpointOperInfo(nid, epid)
}
func (ep *endpoint) InterfaceList() []InterfaceInfo {
ep.Lock()
defer ep.Unlock()
iList := make([]InterfaceInfo, len(ep.iFaces))
for i, iface := range ep.iFaces {
iList[i] = iface
}
return iList
}
func (ep *endpoint) Interfaces() []driverapi.InterfaceInfo {
ep.Lock()
defer ep.Unlock()
iList := make([]driverapi.InterfaceInfo, len(ep.iFaces))
for i, iface := range ep.iFaces {
iList[i] = iface
}
return iList
}
func (ep *endpoint) AddInterface(id int, mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error {
ep.Lock()
defer ep.Unlock()
iface := &endpointInterface{
id: id,
addr: *types.GetIPNetCopy(&ipv4),
addrv6: *types.GetIPNetCopy(&ipv6),
}
iface.mac = types.GetMacCopy(mac)
ep.iFaces = append(ep.iFaces, iface)
return nil
}
func (epi *endpointInterface) ID() int {
return epi.id
}
func (epi *endpointInterface) MacAddress() net.HardwareAddr {
return types.GetMacCopy(epi.mac)
}
func (epi *endpointInterface) Address() net.IPNet {
return (*types.GetIPNetCopy(&epi.addr))
}
func (epi *endpointInterface) AddressIPv6() net.IPNet {
return (*types.GetIPNetCopy(&epi.addrv6))
}
func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
epi.srcName = srcName
epi.dstPrefix = dstPrefix
return nil
}
func (ep *endpoint) InterfaceNames() []driverapi.InterfaceNameInfo {
ep.Lock()
defer ep.Unlock()
iList := make([]driverapi.InterfaceNameInfo, len(ep.iFaces))
for i, iface := range ep.iFaces {
iList[i] = iface
}
return iList
}
func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP, interfaceID int) error {
ep.Lock()
defer ep.Unlock()
r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop, InterfaceID: interfaceID}
if routeType == types.NEXTHOP {
// If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r)
} else {
// If the route doesn't specify a next-hop, it must be a connected route, bound to an interface.
if err := ep.addInterfaceRoute(&r); err != nil {
return err
}
}
return nil
}
func (ep *endpoint) addInterfaceRoute(route *types.StaticRoute) error {
for _, iface := range ep.iFaces {
if iface.id == route.InterfaceID {
iface.routes = append(iface.routes, route.Destination)
return nil
}
}
return types.BadRequestErrorf("Interface with ID %d doesn't exist.",
route.InterfaceID)
}
func (ep *endpoint) SandboxKey() string {
ep.Lock()
defer ep.Unlock()
if ep.container == nil {
return ""
}
return ep.container.data.SandboxKey
}
func (ep *endpoint) Gateway() net.IP {
ep.Lock()
defer ep.Unlock()
if ep.joinInfo == nil {
return net.IP{}
}
return types.GetIPCopy(ep.joinInfo.gw)
}
func (ep *endpoint) GatewayIPv6() net.IP {
ep.Lock()
defer ep.Unlock()
if ep.joinInfo == nil {
return net.IP{}
}
return types.GetIPCopy(ep.joinInfo.gw6)
}
func (ep *endpoint) SetGateway(gw net.IP) error {
ep.Lock()
defer ep.Unlock()
ep.joinInfo.gw = types.GetIPCopy(gw)
return nil
}
func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
ep.Lock()
defer ep.Unlock()
ep.joinInfo.gw6 = types.GetIPCopy(gw6)
return nil
}
func (ep *endpoint) SetHostsPath(path string) error {
ep.Lock()
defer ep.Unlock()
ep.joinInfo.hostsPath = path
return nil
}
func (ep *endpoint) SetResolvConfPath(path string) error {
ep.Lock()
defer ep.Unlock()
ep.joinInfo.resolvConfPath = path
return nil
}

175
vendor/github.com/docker/libnetwork/error.go generated vendored Normal file
View File

@@ -0,0 +1,175 @@
package libnetwork
import (
"fmt"
)
// ErrNoSuchNetwork is returned when a network query finds no result
type ErrNoSuchNetwork string
func (nsn ErrNoSuchNetwork) Error() string {
return fmt.Sprintf("network %s not found", string(nsn))
}
// NotFound denotes the type of this error
func (nsn ErrNoSuchNetwork) NotFound() {}
// ErrNoSuchEndpoint is returned when a endpoint query finds no result
type ErrNoSuchEndpoint string
func (nse ErrNoSuchEndpoint) Error() string {
return fmt.Sprintf("endpoint %s not found", string(nse))
}
// NotFound denotes the type of this error
func (nse ErrNoSuchEndpoint) NotFound() {}
// ErrInvalidNetworkDriver is returned if an invalid driver
// name is passed.
type ErrInvalidNetworkDriver string
func (ind ErrInvalidNetworkDriver) Error() string {
return fmt.Sprintf("invalid driver bound to network: %s", string(ind))
}
// BadRequest denotes the type of this error
func (ind ErrInvalidNetworkDriver) BadRequest() {}
// ErrInvalidJoin is returned if a join is attempted on an endpoint
// which already has a container joined.
type ErrInvalidJoin struct{}
func (ij ErrInvalidJoin) Error() string {
return "a container has already joined the endpoint"
}
// BadRequest denotes the type of this error
func (ij ErrInvalidJoin) BadRequest() {}
// ErrNoContainer is returned when the endpoint has no container
// attached to it.
type ErrNoContainer struct{}
func (nc ErrNoContainer) Error() string {
return "no container is attached to the endpoint"
}
// Maskable denotes the type of this error
func (nc ErrNoContainer) Maskable() {}
// ErrInvalidID is returned when a query-by-id method is being invoked
// with an empty id parameter
type ErrInvalidID string
func (ii ErrInvalidID) Error() string {
return fmt.Sprintf("invalid id: %s", string(ii))
}
// BadRequest denotes the type of this error
func (ii ErrInvalidID) BadRequest() {}
// ErrInvalidName is returned when a query-by-name or resource create method is
// invoked with an empty name parameter
type ErrInvalidName string
func (in ErrInvalidName) Error() string {
return fmt.Sprintf("invalid name: %s", string(in))
}
// BadRequest denotes the type of this error
func (in ErrInvalidName) BadRequest() {}
// ErrInvalidConfigFile type is returned when an invalid LibNetwork config file is detected
type ErrInvalidConfigFile string
func (cf ErrInvalidConfigFile) Error() string {
return fmt.Sprintf("Invalid Config file %q", string(cf))
}
// NetworkTypeError type is returned when the network type string is not
// known to libnetwork.
type NetworkTypeError string
func (nt NetworkTypeError) Error() string {
return fmt.Sprintf("unknown driver %q", string(nt))
}
// NotFound denotes the type of this error
func (nt NetworkTypeError) NotFound() {}
// NetworkNameError is returned when a network with the same name already exists.
type NetworkNameError string
func (nnr NetworkNameError) Error() string {
return fmt.Sprintf("network with name %s already exists", string(nnr))
}
// Forbidden denotes the type of this error
func (nnr NetworkNameError) Forbidden() {}
// UnknownNetworkError is returned when libnetwork could not find in it's database
// a network with the same name and id.
type UnknownNetworkError struct {
name string
id string
}
func (une *UnknownNetworkError) Error() string {
return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
}
// NotFound denotes the type of this error
func (une *UnknownNetworkError) NotFound() {}
// ActiveEndpointsError is returned when a network is deleted which has active
// endpoints in it.
type ActiveEndpointsError struct {
name string
id string
}
func (aee *ActiveEndpointsError) Error() string {
return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id)
}
// Forbidden denotes the type of this error
func (aee *ActiveEndpointsError) Forbidden() {}
// UnknownEndpointError is returned when libnetwork could not find in it's database
// an endpoint with the same name and id.
type UnknownEndpointError struct {
name string
id string
}
func (uee *UnknownEndpointError) Error() string {
return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
}
// NotFound denotes the type of this error
func (uee *UnknownEndpointError) NotFound() {}
// ActiveContainerError is returned when an endpoint is deleted which has active
// containers attached to it.
type ActiveContainerError struct {
name string
id string
}
func (ace *ActiveContainerError) Error() string {
return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id)
}
// Forbidden denotes the type of this error
func (ace *ActiveContainerError) Forbidden() {}
// InvalidContainerIDError is returned when an invalid container id is passed
// in Join/Leave
type InvalidContainerIDError string
func (id InvalidContainerIDError) Error() string {
return fmt.Sprintf("invalid container id %s", string(id))
}
// BadRequest denotes the type of this error
func (id InvalidContainerIDError) BadRequest() {}

51
vendor/github.com/docker/libnetwork/errors_test.go generated vendored Normal file
View File

@@ -0,0 +1,51 @@
package libnetwork
import (
"testing"
"github.com/docker/libnetwork/types"
)
func TestErrorInterfaces(t *testing.T) {
badRequestErrorList := []error{ErrInvalidID(""), ErrInvalidName(""), ErrInvalidJoin{}, ErrInvalidNetworkDriver(""), InvalidContainerIDError(""), ErrNoSuchNetwork(""), ErrNoSuchEndpoint("")}
for _, err := range badRequestErrorList {
switch u := err.(type) {
case types.BadRequestError:
return
default:
t.Fatalf("Failed to detect err %v is of type BadRequestError. Got type: %T", err, u)
}
}
maskableErrorList := []error{ErrNoContainer{}}
for _, err := range maskableErrorList {
switch u := err.(type) {
case types.MaskableError:
return
default:
t.Fatalf("Failed to detect err %v is of type MaskableError. Got type: %T", err, u)
}
}
notFoundErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
for _, err := range notFoundErrorList {
switch u := err.(type) {
case types.NotFoundError:
return
default:
t.Fatalf("Failed to detect err %v is of type NotFoundError. Got type: %T", err, u)
}
}
forbiddenErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
for _, err := range forbiddenErrorList {
switch u := err.(type) {
case types.ForbiddenError:
return
default:
t.Fatalf("Failed to detect err %v is of type ForbiddenError. Got type: %T", err, u)
}
}
}

View File

@@ -0,0 +1,32 @@
package libnetwork
import (
"testing"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/driverapi"
)
func TestDriverRegistration(t *testing.T) {
bridgeNetType := "bridge"
c, err := New()
if err != nil {
t.Fatal(err)
}
err = c.(*controller).RegisterDriver(bridgeNetType, nil, driverapi.Capability{})
if err == nil {
t.Fatalf("Expecting the RegisterDriver to fail for %s", bridgeNetType)
}
if _, ok := err.(driverapi.ErrActiveRegistration); !ok {
t.Fatalf("Failed for unexpected reason: %v", err)
}
err = c.(*controller).RegisterDriver("test-dummy", nil, driverapi.Capability{})
if err != nil {
t.Fatalf("Test failed with an error %v", err)
}
}
func SetTestDataStore(c NetworkController, custom datastore.DataStore) {
con := c.(*controller)
con.store = custom
}

2067
vendor/github.com/docker/libnetwork/libnetwork_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

471
vendor/github.com/docker/libnetwork/network.go generated vendored Normal file
View File

@@ -0,0 +1,471 @@
package libnetwork
import (
"encoding/json"
"net"
"sync"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/libnetwork/config"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/etchosts"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/options"
"github.com/docker/libnetwork/types"
)
// A Network represents a logical connectivity zone that containers may
// join using the Link method. A Network is managed by a specific driver.
type Network interface {
// A user chosen name for this network.
Name() string
// A system generated id for this network.
ID() string
// The type of network, which corresponds to its managing driver.
Type() string
// Create a new endpoint to this network symbolically identified by the
// specified unique name. The options parameter carry driver specific options.
// Labels support will be added in the near future.
CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error)
// Delete the network.
Delete() error
// Endpoints returns the list of Endpoint(s) in this network.
Endpoints() []Endpoint
// WalkEndpoints uses the provided function to walk the Endpoints
WalkEndpoints(walker EndpointWalker)
// EndpointByName returns the Endpoint which has the passed name. If not found, the error ErrNoSuchEndpoint is returned.
EndpointByName(name string) (Endpoint, error)
// EndpointByID returns the Endpoint which has the passed id. If not found, the error ErrNoSuchEndpoint is returned.
EndpointByID(id string) (Endpoint, error)
}
// EndpointWalker is a client provided function which will be used to walk the Endpoints.
// When the function returns true, the walk will stop.
type EndpointWalker func(ep Endpoint) bool
type svcMap map[string]net.IP
type network struct {
ctrlr *controller
name string
networkType string
id types.UUID
driver driverapi.Driver
enableIPv6 bool
endpointCnt uint64
endpoints endpointTable
generic options.Generic
dbIndex uint64
svcRecords svcMap
dbExists bool
stopWatchCh chan struct{}
sync.Mutex
}
func (n *network) Name() string {
n.Lock()
defer n.Unlock()
return n.name
}
func (n *network) ID() string {
n.Lock()
defer n.Unlock()
return string(n.id)
}
func (n *network) Type() string {
n.Lock()
defer n.Unlock()
if n.driver == nil {
return ""
}
return n.driver.Type()
}
func (n *network) Key() []string {
n.Lock()
defer n.Unlock()
return []string{datastore.NetworkKeyPrefix, string(n.id)}
}
func (n *network) KeyPrefix() []string {
return []string{datastore.NetworkKeyPrefix}
}
func (n *network) Value() []byte {
n.Lock()
defer n.Unlock()
b, err := json.Marshal(n)
if err != nil {
return nil
}
return b
}
func (n *network) SetValue(value []byte) error {
return json.Unmarshal(value, n)
}
func (n *network) Index() uint64 {
n.Lock()
defer n.Unlock()
return n.dbIndex
}
func (n *network) SetIndex(index uint64) {
n.Lock()
n.dbIndex = index
n.dbExists = true
n.Unlock()
}
func (n *network) Exists() bool {
n.Lock()
defer n.Unlock()
return n.dbExists
}
func (n *network) EndpointCnt() uint64 {
n.Lock()
defer n.Unlock()
return n.endpointCnt
}
func (n *network) IncEndpointCnt() {
n.Lock()
n.endpointCnt++
n.Unlock()
}
func (n *network) DecEndpointCnt() {
n.Lock()
n.endpointCnt--
n.Unlock()
}
// TODO : Can be made much more generic with the help of reflection (but has some golang limitations)
func (n *network) MarshalJSON() ([]byte, error) {
netMap := make(map[string]interface{})
netMap["name"] = n.name
netMap["id"] = string(n.id)
netMap["networkType"] = n.networkType
netMap["endpointCnt"] = n.endpointCnt
netMap["enableIPv6"] = n.enableIPv6
netMap["generic"] = n.generic
return json.Marshal(netMap)
}
// TODO : Can be made much more generic with the help of reflection (but has some golang limitations)
func (n *network) UnmarshalJSON(b []byte) (err error) {
var netMap map[string]interface{}
if err := json.Unmarshal(b, &netMap); err != nil {
return err
}
n.name = netMap["name"].(string)
n.id = types.UUID(netMap["id"].(string))
n.networkType = netMap["networkType"].(string)
n.endpointCnt = uint64(netMap["endpointCnt"].(float64))
n.enableIPv6 = netMap["enableIPv6"].(bool)
if netMap["generic"] != nil {
n.generic = netMap["generic"].(map[string]interface{})
}
return nil
}
// NetworkOption is a option setter function type used to pass varios options to
// NewNetwork method. The various setter functions of type NetworkOption are
// provided by libnetwork, they look like NetworkOptionXXXX(...)
type NetworkOption func(n *network)
// NetworkOptionGeneric function returns an option setter for a Generic option defined
// in a Dictionary of Key-Value pair
func NetworkOptionGeneric(generic map[string]interface{}) NetworkOption {
return func(n *network) {
n.generic = generic
if _, ok := generic[netlabel.EnableIPv6]; ok {
n.enableIPv6 = generic[netlabel.EnableIPv6].(bool)
}
}
}
func (n *network) processOptions(options ...NetworkOption) {
for _, opt := range options {
if opt != nil {
opt(n)
}
}
}
func (n *network) Delete() error {
var err error
n.Lock()
ctrlr := n.ctrlr
n.Unlock()
ctrlr.Lock()
_, ok := ctrlr.networks[n.id]
ctrlr.Unlock()
if !ok {
return &UnknownNetworkError{name: n.name, id: string(n.id)}
}
numEps := n.EndpointCnt()
if numEps != 0 {
return &ActiveEndpointsError{name: n.name, id: string(n.id)}
}
// deleteNetworkFromStore performs an atomic delete operation and the network.endpointCnt field will help
// prevent any possible race between endpoint join and network delete
if err = ctrlr.deleteNetworkFromStore(n); err != nil {
if err == datastore.ErrKeyModified {
return types.InternalErrorf("operation in progress. delete failed for network %s. Please try again.")
}
return err
}
if err = n.deleteNetwork(); err != nil {
return err
}
return nil
}
func (n *network) deleteNetwork() error {
n.Lock()
id := n.id
d := n.driver
n.ctrlr.Lock()
delete(n.ctrlr.networks, id)
n.ctrlr.Unlock()
n.Unlock()
if err := d.DeleteNetwork(n.id); err != nil {
// Forbidden Errors should be honored
if _, ok := err.(types.ForbiddenError); ok {
n.ctrlr.Lock()
n.ctrlr.networks[n.id] = n
n.ctrlr.Unlock()
return err
}
log.Warnf("driver error deleting network %s : %v", n.name, err)
}
n.stopWatch()
return nil
}
func (n *network) addEndpoint(ep *endpoint) error {
var err error
n.Lock()
n.endpoints[ep.id] = ep
d := n.driver
n.Unlock()
defer func() {
if err != nil {
n.Lock()
delete(n.endpoints, ep.id)
n.Unlock()
}
}()
err = d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
if err != nil {
return err
}
n.updateSvcRecord(ep, true)
return nil
}
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
var err error
if !config.IsValidName(name) {
return nil, ErrInvalidName(name)
}
if _, err = n.EndpointByName(name); err == nil {
return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
}
ep := &endpoint{name: name,
iFaces: []*endpointInterface{},
generic: make(map[string]interface{})}
ep.id = types.UUID(stringid.GenerateRandomID())
ep.network = n
ep.processOptions(options...)
n.Lock()
ctrlr := n.ctrlr
n.Unlock()
n.IncEndpointCnt()
if err = ctrlr.updateNetworkToStore(n); err != nil {
return nil, err
}
defer func() {
if err != nil {
n.DecEndpointCnt()
if err = ctrlr.updateNetworkToStore(n); err != nil {
log.Warnf("endpoint count cleanup failed when updating network for %s : %v", name, err)
}
}
}()
if err = n.addEndpoint(ep); err != nil {
return nil, err
}
defer func() {
if err != nil {
if e := ep.Delete(); ep != nil {
log.Warnf("cleaning up endpoint failed %s : %v", name, e)
}
}
}()
if err = ctrlr.updateEndpointToStore(ep); err != nil {
return nil, err
}
return ep, nil
}
func (n *network) Endpoints() []Endpoint {
n.Lock()
defer n.Unlock()
list := make([]Endpoint, 0, len(n.endpoints))
for _, e := range n.endpoints {
list = append(list, e)
}
return list
}
func (n *network) WalkEndpoints(walker EndpointWalker) {
for _, e := range n.Endpoints() {
if walker(e) {
return
}
}
}
func (n *network) EndpointByName(name string) (Endpoint, error) {
if name == "" {
return nil, ErrInvalidName(name)
}
var e Endpoint
s := func(current Endpoint) bool {
if current.Name() == name {
e = current
return true
}
return false
}
n.WalkEndpoints(s)
if e == nil {
return nil, ErrNoSuchEndpoint(name)
}
return e, nil
}
func (n *network) EndpointByID(id string) (Endpoint, error) {
if id == "" {
return nil, ErrInvalidID(id)
}
n.Lock()
defer n.Unlock()
if e, ok := n.endpoints[types.UUID(id)]; ok {
return e, nil
}
return nil, ErrNoSuchEndpoint(id)
}
func (n *network) isGlobalScoped() (bool, error) {
n.Lock()
c := n.ctrlr
n.Unlock()
return c.isDriverGlobalScoped(n.networkType)
}
func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
n.Lock()
var recs []etchosts.Record
for _, iface := range ep.InterfaceList() {
if isAdd {
n.svcRecords[ep.Name()] = iface.Address().IP
n.svcRecords[ep.Name()+"."+n.name] = iface.Address().IP
} else {
delete(n.svcRecords, ep.Name())
delete(n.svcRecords, ep.Name()+"."+n.name)
}
recs = append(recs, etchosts.Record{
Hosts: ep.Name(),
IP: iface.Address().IP.String(),
})
recs = append(recs, etchosts.Record{
Hosts: ep.Name() + "." + n.name,
IP: iface.Address().IP.String(),
})
}
n.Unlock()
// If there are no records to add or delete then simply return here
if len(recs) == 0 {
return
}
var epList []*endpoint
n.WalkEndpoints(func(e Endpoint) bool {
cEp := e.(*endpoint)
cEp.Lock()
if cEp.container != nil {
epList = append(epList, cEp)
}
cEp.Unlock()
return false
})
for _, cEp := range epList {
if isAdd {
cEp.addHostEntries(recs)
} else {
cEp.deleteHostEntries(recs)
}
}
}
func (n *network) getSvcRecords() []etchosts.Record {
n.Lock()
defer n.Unlock()
var recs []etchosts.Record
for h, ip := range n.svcRecords {
recs = append(recs, etchosts.Record{
Hosts: h,
IP: ip.String(),
})
}
return recs
}

View File

@@ -0,0 +1 @@
Package resolvconf provides utility code to query and update DNS configuration in /etc/resolv.conf

View File

@@ -0,0 +1,17 @@
package dns
import (
"regexp"
)
// IPLocalhost is a regex patter for localhost IP address range.
const IPLocalhost = `((127\.([0-9]{1,3}.){2}[0-9]{1,3})|(::1))`
var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
// IsLocalhost returns true if ip matches the localhost IP regular expression.
// Used for determining if nameserver settings are being passed which are
// localhost addresses
func IsLocalhost(ip string) bool {
return localhostIPRegexp.MatchString(ip)
}

View File

@@ -0,0 +1,187 @@
// Package resolvconf provides utility code to query and update DNS configuration in /etc/resolv.conf
package resolvconf
import (
"bytes"
"io/ioutil"
"regexp"
"strings"
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/libnetwork/resolvconf/dns"
)
var (
// Note: the default IPv4 & IPv6 resolvers are set to Google's Public DNS
defaultIPv4Dns = []string{"nameserver 8.8.8.8", "nameserver 8.8.4.4"}
defaultIPv6Dns = []string{"nameserver 2001:4860:4860::8888", "nameserver 2001:4860:4860::8844"}
ipv4NumBlock = `(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)`
ipv4Address = `(` + ipv4NumBlock + `\.){3}` + ipv4NumBlock
// This is not an IPv6 address verifier as it will accept a super-set of IPv6, and also
// will *not match* IPv4-Embedded IPv6 Addresses (RFC6052), but that and other variants
// -- 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})`
localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + dns.IPLocalhost + `\s*\n*`)
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
)
var lastModified struct {
sync.Mutex
sha256 string
contents []byte
}
// Get returns the contents of /etc/resolv.conf
func Get() ([]byte, error) {
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
return nil, err
}
return resolv, nil
}
// GetIfChanged retrieves the host /etc/resolv.conf file, checks against the last hash
// and, if modified since last check, returns the bytes and new hash.
// This feature is used by the resolv.conf updater for containers
func GetIfChanged() ([]byte, string, error) {
lastModified.Lock()
defer lastModified.Unlock()
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
return nil, "", err
}
newHash, err := ioutils.HashData(bytes.NewReader(resolv))
if err != nil {
return nil, "", err
}
if lastModified.sha256 != newHash {
lastModified.sha256 = newHash
lastModified.contents = resolv
return resolv, newHash, nil
}
// nothing changed, so return no data
return nil, "", nil
}
// GetLastModified retrieves the last used contents and hash of the host resolv.conf.
// Used by containers updating on restart
func GetLastModified() ([]byte, string) {
lastModified.Lock()
defer lastModified.Unlock()
return lastModified.contents, lastModified.sha256
}
// FilterResolvDNS cleans up the config in resolvConf. It has two main jobs:
// 1. It looks for localhost (127.*|::1) entries in the provided
// resolv.conf, removing local nameserver entries, and, if the resulting
// cleaned config has no defined nameservers left, adds default DNS entries
// 2. Given the caller provides the enable/disable state of IPv6, the filter
// code will remove all IPv6 nameservers if it is not enabled for containers
//
// It returns a boolean to notify the caller if changes were made at all
func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) ([]byte, bool) {
changed := false
cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{})
// if IPv6 is not enabled, also clean out any IPv6 address nameserver
if !ipv6Enabled {
cleanedResolvConf = nsIPv6Regexp.ReplaceAll(cleanedResolvConf, []byte{})
}
// if the resulting resolvConf has no more nameservers defined, add appropriate
// default DNS servers for IPv4 and (optionally) IPv6
if len(GetNameservers(cleanedResolvConf)) == 0 {
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)
dns = append(dns, defaultIPv6Dns...)
}
cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
}
if !bytes.Equal(resolvConf, cleanedResolvConf) {
changed = true
}
return cleanedResolvConf, changed
}
// getLines parses input into lines and strips away comments.
func getLines(input []byte, commentMarker []byte) [][]byte {
lines := bytes.Split(input, []byte("\n"))
var output [][]byte
for _, currentLine := range lines {
var commentIndex = bytes.Index(currentLine, commentMarker)
if commentIndex == -1 {
output = append(output, currentLine)
} else {
output = append(output, currentLine[:commentIndex])
}
}
return output
}
// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf
func GetNameservers(resolvConf []byte) []string {
nameservers := []string{}
for _, line := range getLines(resolvConf, []byte("#")) {
var ns = nsRegexp.FindSubmatch(line)
if len(ns) > 0 {
nameservers = append(nameservers, string(ns[1]))
}
}
return nameservers
}
// GetNameserversAsCIDR returns nameservers (if any) listed in
// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32")
// This function's output is intended for net.ParseCIDR
func GetNameserversAsCIDR(resolvConf []byte) []string {
nameservers := []string{}
for _, nameserver := range GetNameservers(resolvConf) {
nameservers = append(nameservers, nameserver+"/32")
}
return nameservers
}
// GetSearchDomains returns search domains (if any) listed in /etc/resolv.conf
// If more than one search line is encountered, only the contents of the last
// one is returned.
func GetSearchDomains(resolvConf []byte) []string {
domains := []string{}
for _, line := range getLines(resolvConf, []byte("#")) {
match := searchRegexp.FindSubmatch(line)
if match == nil {
continue
}
domains = strings.Fields(string(match[1]))
}
return domains
}
// Build writes a configuration file to path containing a "nameserver" entry
// for every element in dns, and a "search" entry for every element in
// dnsSearch.
func Build(path string, dns, dnsSearch []string) error {
content := bytes.NewBuffer(nil)
for _, dns := range dns {
if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
return err
}
}
if len(dnsSearch) > 0 {
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
return err
}
}
}
return ioutil.WriteFile(path, content.Bytes(), 0644)
}

View File

@@ -0,0 +1,240 @@
package resolvconf
import (
"bytes"
"io/ioutil"
"os"
"testing"
_ "github.com/docker/libnetwork/netutils"
)
func TestGet(t *testing.T) {
resolvConfUtils, err := Get()
if err != nil {
t.Fatal(err)
}
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
t.Fatal(err)
}
if string(resolvConfUtils) != string(resolvConfSystem) {
t.Fatalf("/etc/resolv.conf and GetResolvConf have different content.")
}
}
func TestGetNameservers(t *testing.T) {
for resolv, result := range map[string][]string{`
nameserver 1.2.3.4
nameserver 40.3.200.10
search example.com`: {"1.2.3.4", "40.3.200.10"},
`search example.com`: {},
`nameserver 1.2.3.4
search example.com
nameserver 4.30.20.100`: {"1.2.3.4", "4.30.20.100"},
``: {},
` nameserver 1.2.3.4 `: {"1.2.3.4"},
`search example.com
nameserver 1.2.3.4
#nameserver 4.3.2.1`: {"1.2.3.4"},
`search example.com
nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4"},
} {
test := GetNameservers([]byte(resolv))
if !strSlicesEqual(test, result) {
t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv)
}
}
}
func TestGetNameserversAsCIDR(t *testing.T) {
for resolv, result := range map[string][]string{`
nameserver 1.2.3.4
nameserver 40.3.200.10
search example.com`: {"1.2.3.4/32", "40.3.200.10/32"},
`search example.com`: {},
`nameserver 1.2.3.4
search example.com
nameserver 4.30.20.100`: {"1.2.3.4/32", "4.30.20.100/32"},
``: {},
` nameserver 1.2.3.4 `: {"1.2.3.4/32"},
`search example.com
nameserver 1.2.3.4
#nameserver 4.3.2.1`: {"1.2.3.4/32"},
`search example.com
nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4/32"},
} {
test := GetNameserversAsCIDR([]byte(resolv))
if !strSlicesEqual(test, result) {
t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv)
}
}
}
func TestGetSearchDomains(t *testing.T) {
for resolv, result := range map[string][]string{
`search example.com`: {"example.com"},
`search example.com # ignored`: {"example.com"},
` search example.com `: {"example.com"},
` search example.com # ignored`: {"example.com"},
`search foo.example.com example.com`: {"foo.example.com", "example.com"},
` search foo.example.com example.com `: {"foo.example.com", "example.com"},
` search foo.example.com example.com # ignored`: {"foo.example.com", "example.com"},
``: {},
`# ignored`: {},
`nameserver 1.2.3.4
search foo.example.com example.com`: {"foo.example.com", "example.com"},
`nameserver 1.2.3.4
search dup1.example.com dup2.example.com
search foo.example.com example.com`: {"foo.example.com", "example.com"},
`nameserver 1.2.3.4
search foo.example.com example.com
nameserver 4.30.20.100`: {"foo.example.com", "example.com"},
} {
test := GetSearchDomains([]byte(resolv))
if !strSlicesEqual(test, result) {
t.Fatalf("Wrong search domain string {%s} should be %v. Input: %s", test, result, resolv)
}
}
}
func strSlicesEqual(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
func TestBuild(t *testing.T) {
file, err := ioutil.TempFile("", "")
if err != nil {
t.Fatal(err)
}
defer os.Remove(file.Name())
err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"})
if err != nil {
t.Fatal(err)
}
content, err := ioutil.ReadFile(file.Name())
if err != nil {
t.Fatal(err)
}
if expected := "nameserver ns1\nnameserver ns2\nnameserver ns3\nsearch search1\n"; !bytes.Contains(content, []byte(expected)) {
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
}
}
func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
file, err := ioutil.TempFile("", "")
if err != nil {
t.Fatal(err)
}
defer os.Remove(file.Name())
err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."})
if err != nil {
t.Fatal(err)
}
content, err := ioutil.ReadFile(file.Name())
if err != nil {
t.Fatal(err)
}
if expected := "nameserver ns1\nnameserver ns2\nnameserver ns3\n"; !bytes.Contains(content, []byte(expected)) {
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
}
if notExpected := "search ."; bytes.Contains(content, []byte(notExpected)) {
t.Fatalf("Expected to not find '%s' got '%s'", notExpected, content)
}
}
func TestFilterResolvDns(t *testing.T) {
ns0 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\n"
if result, _ := FilterResolvDNS([]byte(ns0), false); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed No Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
ns1 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\n"
if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
ns1 = "nameserver 10.16.60.14\nnameserver 127.0.0.1\nnameserver 10.16.60.21\n"
if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
ns1 = "nameserver 127.0.1.1\nnameserver 10.16.60.14\nnameserver 10.16.60.21\n"
if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
ns1 = "nameserver ::1\nnameserver 10.16.60.14\nnameserver 127.0.2.1\nnameserver 10.16.60.21\n"
if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
ns1 = "nameserver 10.16.60.14\nnameserver ::1\nnameserver 10.16.60.21\nnameserver ::1"
if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
// with IPv6 disabled (false param), the IPv6 nameserver should be removed
ns1 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1"
if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost+IPv6 off: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
// 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"
if result, _ := FilterResolvDNS([]byte(ns1), true); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost+IPv6 on: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
// with IPv6 enabled, and no non-localhost servers, Google defaults (both IPv4+IPv6) should be added
ns0 = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844"
ns1 = "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1"
if result, _ := FilterResolvDNS([]byte(ns1), true); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed no Localhost+IPv6 enabled: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
// with IPv6 disabled, and no non-localhost servers, Google defaults (only IPv4) should be added
ns0 = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
ns1 = "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1"
if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed no Localhost+IPv6 enabled: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
}

251
vendor/github.com/docker/libnetwork/sandboxdata.go generated vendored Normal file
View File

@@ -0,0 +1,251 @@
package libnetwork
import (
"container/heap"
"fmt"
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/sandbox"
)
type epHeap []*endpoint
type sandboxData struct {
sbox sandbox.Sandbox
refCnt int
endpoints epHeap
sync.Mutex
}
func (eh epHeap) Len() int { return len(eh) }
func (eh epHeap) Less(i, j int) bool {
eh[i].Lock()
eh[j].Lock()
defer eh[j].Unlock()
defer eh[i].Unlock()
if eh[i].container.config.prio == eh[j].container.config.prio {
return eh[i].network.Name() < eh[j].network.Name()
}
return eh[i].container.config.prio > eh[j].container.config.prio
}
func (eh epHeap) Swap(i, j int) { eh[i], eh[j] = eh[j], eh[i] }
func (eh *epHeap) Push(x interface{}) {
*eh = append(*eh, x.(*endpoint))
}
func (eh *epHeap) Pop() interface{} {
old := *eh
n := len(old)
x := old[n-1]
*eh = old[0 : n-1]
return x
}
func (s *sandboxData) updateGateway(ep *endpoint) error {
sb := s.sandbox()
sb.UnsetGateway()
sb.UnsetGatewayIPv6()
if ep == nil {
return nil
}
ep.Lock()
joinInfo := ep.joinInfo
ep.Unlock()
if err := sb.SetGateway(joinInfo.gw); err != nil {
return fmt.Errorf("failed to set gateway while updating gateway: %v", err)
}
if err := sb.SetGatewayIPv6(joinInfo.gw6); err != nil {
return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
}
return nil
}
func (s *sandboxData) addEndpoint(ep *endpoint) error {
ep.Lock()
joinInfo := ep.joinInfo
ifaces := ep.iFaces
ep.Unlock()
sb := s.sandbox()
for _, i := range ifaces {
var ifaceOptions []sandbox.IfaceOption
ifaceOptions = append(ifaceOptions, sb.InterfaceOptions().Address(&i.addr),
sb.InterfaceOptions().Routes(i.routes))
if i.addrv6.IP.To16() != nil {
ifaceOptions = append(ifaceOptions,
sb.InterfaceOptions().AddressIPv6(&i.addrv6))
}
if err := sb.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
}
}
if joinInfo != nil {
// Set up non-interface routes.
for _, r := range ep.joinInfo.StaticRoutes {
if err := sb.AddStaticRoute(r); err != nil {
return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err)
}
}
}
s.Lock()
heap.Push(&s.endpoints, ep)
highEp := s.endpoints[0]
s.Unlock()
if ep == highEp {
if err := s.updateGateway(ep); err != nil {
return err
}
}
return nil
}
func (s *sandboxData) rmEndpoint(ep *endpoint) {
ep.Lock()
joinInfo := ep.joinInfo
ep.Unlock()
sb := s.sandbox()
for _, i := range sb.Info().Interfaces() {
// Only remove the interfaces owned by this endpoint from the sandbox.
if ep.hasInterface(i.SrcName()) {
if err := i.Remove(); err != nil {
logrus.Debugf("Remove interface failed: %v", err)
}
}
}
// Remove non-interface routes.
for _, r := range joinInfo.StaticRoutes {
if err := sb.RemoveStaticRoute(r); err != nil {
logrus.Debugf("Remove route failed: %v", err)
}
}
// We don't check if s.endpoints is empty here because
// it should never be empty during a rmEndpoint call and
// if it is we will rightfully panic here
s.Lock()
highEpBefore := s.endpoints[0]
var (
i int
e *endpoint
)
for i, e = range s.endpoints {
if e == ep {
break
}
}
heap.Remove(&s.endpoints, i)
var highEpAfter *endpoint
if len(s.endpoints) > 0 {
highEpAfter = s.endpoints[0]
}
s.Unlock()
if highEpBefore != highEpAfter {
s.updateGateway(highEpAfter)
}
}
func (s *sandboxData) sandbox() sandbox.Sandbox {
s.Lock()
defer s.Unlock()
return s.sbox
}
func (c *controller) sandboxAdd(key string, create bool, ep *endpoint) (sandbox.Sandbox, error) {
c.Lock()
sData, ok := c.sandboxes[key]
c.Unlock()
if !ok {
sb, err := sandbox.NewSandbox(key, create)
if err != nil {
return nil, fmt.Errorf("failed to create new sandbox: %v", err)
}
sData = &sandboxData{
sbox: sb,
endpoints: epHeap{},
}
heap.Init(&sData.endpoints)
c.Lock()
c.sandboxes[key] = sData
c.Unlock()
}
if err := sData.addEndpoint(ep); err != nil {
return nil, err
}
return sData.sandbox(), nil
}
func (c *controller) sandboxRm(key string, ep *endpoint) {
c.Lock()
sData := c.sandboxes[key]
c.Unlock()
sData.rmEndpoint(ep)
}
func (c *controller) sandboxGet(key string) sandbox.Sandbox {
c.Lock()
sData, ok := c.sandboxes[key]
c.Unlock()
if !ok {
return nil
}
return sData.sandbox()
}
func (c *controller) LeaveAll(id string) error {
c.Lock()
sData, ok := c.sandboxes[sandbox.GenerateKey(id)]
c.Unlock()
if !ok {
return fmt.Errorf("could not find sandbox for container id %s", id)
}
sData.Lock()
eps := make([]*endpoint, len(sData.endpoints))
for i, ep := range sData.endpoints {
eps[i] = ep
}
sData.Unlock()
for _, ep := range eps {
if err := ep.Leave(id); err != nil {
logrus.Warnf("Failed leaving endpoint id %s: %v\n", ep.ID(), err)
}
}
sData.sandbox().Destroy()
delete(c.sandboxes, sandbox.GenerateKey(id))
return nil
}

141
vendor/github.com/docker/libnetwork/sandboxdata_test.go generated vendored Normal file
View File

@@ -0,0 +1,141 @@
package libnetwork
import (
"testing"
"github.com/docker/libnetwork/sandbox"
)
func createEmptyCtrlr() *controller {
return &controller{sandboxes: sandboxTable{}}
}
func createEmptyEndpoint() *endpoint {
return &endpoint{
container: &containerInfo{},
joinInfo: &endpointJoinInfo{},
iFaces: []*endpointInterface{},
}
}
func TestSandboxAddEmpty(t *testing.T) {
ctrlr := createEmptyCtrlr()
ep := createEmptyEndpoint()
if _, err := ctrlr.sandboxAdd(sandbox.GenerateKey("sandbox1"), true, ep); err != nil {
t.Fatal(err)
}
ctrlr.sandboxRm(sandbox.GenerateKey("sandbox1"), ep)
ctrlr.LeaveAll("sandbox1")
if len(ctrlr.sandboxes) != 0 {
t.Fatalf("controller sandboxes is not empty. len = %d", len(ctrlr.sandboxes))
}
sandbox.GC()
}
func TestSandboxAddMultiPrio(t *testing.T) {
ctrlr := createEmptyCtrlr()
ep1 := createEmptyEndpoint()
ep2 := createEmptyEndpoint()
ep3 := createEmptyEndpoint()
ep1.container.config.prio = 1
ep2.container.config.prio = 2
ep3.container.config.prio = 3
sKey := sandbox.GenerateKey("sandbox1")
if _, err := ctrlr.sandboxAdd(sKey, true, ep1); err != nil {
t.Fatal(err)
}
if _, err := ctrlr.sandboxAdd(sKey, true, ep2); err != nil {
t.Fatal(err)
}
if _, err := ctrlr.sandboxAdd(sKey, true, ep3); err != nil {
t.Fatal(err)
}
if ctrlr.sandboxes[sKey].endpoints[0] != ep3 {
t.Fatal("Expected ep3 to be at the top of the heap. But did not find ep3 at the top of the heap")
}
ctrlr.sandboxRm(sKey, ep3)
if ctrlr.sandboxes[sKey].endpoints[0] != ep2 {
t.Fatal("Expected ep2 to be at the top of the heap after removing ep3. But did not find ep2 at the top of the heap")
}
ctrlr.sandboxRm(sKey, ep2)
if ctrlr.sandboxes[sKey].endpoints[0] != ep1 {
t.Fatal("Expected ep1 to be at the top of the heap after removing ep2. But did not find ep1 at the top of the heap")
}
// Re-add ep3 back
if _, err := ctrlr.sandboxAdd(sKey, true, ep3); err != nil {
t.Fatal(err)
}
if ctrlr.sandboxes[sKey].endpoints[0] != ep3 {
t.Fatal("Expected ep3 to be at the top of the heap after adding ep3 back. But did not find ep3 at the top of the heap")
}
ctrlr.sandboxRm(sKey, ep3)
ctrlr.sandboxRm(sKey, ep1)
if err := ctrlr.LeaveAll("sandbox1"); err != nil {
t.Fatal(err)
}
if len(ctrlr.sandboxes) != 0 {
t.Fatalf("controller sandboxes is not empty. len = %d", len(ctrlr.sandboxes))
}
sandbox.GC()
}
func TestSandboxAddSamePrio(t *testing.T) {
ctrlr := createEmptyCtrlr()
ep1 := createEmptyEndpoint()
ep2 := createEmptyEndpoint()
ep1.network = &network{name: "aaa"}
ep2.network = &network{name: "bbb"}
sKey := sandbox.GenerateKey("sandbox1")
if _, err := ctrlr.sandboxAdd(sKey, true, ep1); err != nil {
t.Fatal(err)
}
if _, err := ctrlr.sandboxAdd(sKey, true, ep2); err != nil {
t.Fatal(err)
}
if ctrlr.sandboxes[sKey].endpoints[0] != ep1 {
t.Fatal("Expected ep1 to be at the top of the heap. But did not find ep1 at the top of the heap")
}
ctrlr.sandboxRm(sKey, ep1)
if ctrlr.sandboxes[sKey].endpoints[0] != ep2 {
t.Fatal("Expected ep2 to be at the top of the heap after removing ep3. But did not find ep2 at the top of the heap")
}
ctrlr.sandboxRm(sKey, ep2)
if err := ctrlr.LeaveAll("sandbox1"); err != nil {
t.Fatal(err)
}
if len(ctrlr.sandboxes) != 0 {
t.Fatalf("controller sandboxes is not empty. len = %d", len(ctrlr.sandboxes))
}
sandbox.GC()
}

371
vendor/github.com/docker/libnetwork/store.go generated vendored Normal file
View File

@@ -0,0 +1,371 @@
package libnetwork
import (
"encoding/json"
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/docker/libkv/store"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/types"
)
func (c *controller) validateDatastoreConfig() bool {
return c.cfg != nil && c.cfg.Datastore.Client.Provider != "" && c.cfg.Datastore.Client.Address != ""
}
func (c *controller) initDataStore() error {
c.Lock()
cfg := c.cfg
c.Unlock()
if !c.validateDatastoreConfig() {
return fmt.Errorf("datastore initialization requires a valid configuration")
}
store, err := datastore.NewDataStore(&cfg.Datastore)
if err != nil {
return err
}
c.Lock()
c.store = store
c.Unlock()
nws, err := c.getNetworksFromStore()
if err == nil {
c.processNetworkUpdate(nws, nil)
} else if err != datastore.ErrKeyNotFound {
log.Warnf("failed to read networks from datastore during init : %v", err)
}
return c.watchNetworks()
}
func (c *controller) getNetworksFromStore() ([]*store.KVPair, error) {
c.Lock()
cs := c.store
c.Unlock()
return cs.KVStore().List(datastore.Key(datastore.NetworkKeyPrefix))
}
func (c *controller) newNetworkFromStore(n *network) error {
n.Lock()
n.ctrlr = c
n.endpoints = endpointTable{}
n.Unlock()
return c.addNetwork(n)
}
func (c *controller) updateNetworkToStore(n *network) error {
global, err := n.isGlobalScoped()
if err != nil || !global {
return err
}
c.Lock()
cs := c.store
c.Unlock()
if cs == nil {
log.Debugf("datastore not initialized. Network %s is not added to the store", n.Name())
return nil
}
return cs.PutObjectAtomic(n)
}
func (c *controller) deleteNetworkFromStore(n *network) error {
global, err := n.isGlobalScoped()
if err != nil || !global {
return err
}
c.Lock()
cs := c.store
c.Unlock()
if cs == nil {
log.Debugf("datastore not initialized. Network %s is not deleted from datastore", n.Name())
return nil
}
if err := cs.DeleteObjectAtomic(n); err != nil {
return err
}
return nil
}
func (c *controller) getNetworkFromStore(nid types.UUID) (*network, error) {
n := network{id: nid}
if err := c.store.GetObject(datastore.Key(n.Key()...), &n); err != nil {
return nil, err
}
return &n, nil
}
func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
ep.Lock()
n := ep.network
id := ep.id
ep.Unlock()
_, err := n.EndpointByID(string(id))
if err != nil {
if _, ok := err.(ErrNoSuchEndpoint); ok {
return n.addEndpoint(ep)
}
}
return err
}
func (c *controller) updateEndpointToStore(ep *endpoint) error {
ep.Lock()
n := ep.network
name := ep.name
ep.Unlock()
global, err := n.isGlobalScoped()
if err != nil || !global {
return err
}
c.Lock()
cs := c.store
c.Unlock()
if cs == nil {
log.Debugf("datastore not initialized. endpoint %s is not added to the store", name)
return nil
}
return cs.PutObjectAtomic(ep)
}
func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) {
ep := endpoint{id: eid}
if err := c.store.GetObject(datastore.Key(ep.Key()...), &ep); err != nil {
return nil, err
}
return &ep, nil
}
func (c *controller) deleteEndpointFromStore(ep *endpoint) error {
ep.Lock()
n := ep.network
ep.Unlock()
global, err := n.isGlobalScoped()
if err != nil || !global {
return err
}
c.Lock()
cs := c.store
c.Unlock()
if cs == nil {
log.Debugf("datastore not initialized. endpoint %s is not deleted from datastore", ep.Name())
return nil
}
if err := cs.DeleteObjectAtomic(ep); err != nil {
return err
}
return nil
}
func (c *controller) watchNetworks() error {
if !c.validateDatastoreConfig() {
return nil
}
c.Lock()
cs := c.store
c.Unlock()
nwPairs, err := cs.KVStore().WatchTree(datastore.Key(datastore.NetworkKeyPrefix), nil)
if err != nil {
return err
}
go func() {
for {
select {
case nws := <-nwPairs:
c.Lock()
tmpview := networkTable{}
lview := c.networks
c.Unlock()
for k, v := range lview {
global, _ := v.isGlobalScoped()
if global {
tmpview[k] = v
}
}
c.processNetworkUpdate(nws, &tmpview)
// Delete processing
for k := range tmpview {
c.Lock()
existing, ok := c.networks[k]
c.Unlock()
if !ok {
continue
}
tmp := network{}
if err := c.store.GetObject(datastore.Key(existing.Key()...), &tmp); err != datastore.ErrKeyNotFound {
continue
}
if err := existing.deleteNetwork(); err != nil {
log.Debugf("Delete failed %s: %s", existing.name, err)
}
}
}
}
}()
return nil
}
func (n *network) watchEndpoints() error {
if !n.ctrlr.validateDatastoreConfig() {
return nil
}
n.Lock()
cs := n.ctrlr.store
tmp := endpoint{network: n}
n.stopWatchCh = make(chan struct{})
stopCh := n.stopWatchCh
n.Unlock()
epPairs, err := cs.KVStore().WatchTree(datastore.Key(tmp.KeyPrefix()...), stopCh)
if err != nil {
return err
}
go func() {
for {
select {
case <-stopCh:
return
case eps := <-epPairs:
n.Lock()
tmpview := endpointTable{}
lview := n.endpoints
n.Unlock()
for k, v := range lview {
global, _ := v.network.isGlobalScoped()
if global {
tmpview[k] = v
}
}
for _, epe := range eps {
var ep endpoint
err := json.Unmarshal(epe.Value, &ep)
if err != nil {
log.Error(err)
continue
}
delete(tmpview, ep.id)
ep.SetIndex(epe.LastIndex)
ep.network = n
if n.ctrlr.processEndpointUpdate(&ep) {
err = n.ctrlr.newEndpointFromStore(epe.Key, &ep)
if err != nil {
log.Error(err)
}
}
}
// Delete processing
for k := range tmpview {
n.Lock()
existing, ok := n.endpoints[k]
n.Unlock()
if !ok {
continue
}
tmp := endpoint{}
if err := cs.GetObject(datastore.Key(existing.Key()...), &tmp); err != datastore.ErrKeyNotFound {
continue
}
if err := existing.deleteEndpoint(); err != nil {
log.Debugf("Delete failed %s: %s", existing.name, err)
}
}
}
}
}()
return nil
}
func (n *network) stopWatch() {
n.Lock()
if n.stopWatchCh != nil {
close(n.stopWatchCh)
n.stopWatchCh = nil
}
n.Unlock()
}
func (c *controller) processNetworkUpdate(nws []*store.KVPair, prune *networkTable) {
for _, kve := range nws {
var n network
err := json.Unmarshal(kve.Value, &n)
if err != nil {
log.Error(err)
continue
}
if prune != nil {
delete(*prune, n.id)
}
n.SetIndex(kve.LastIndex)
c.Lock()
existing, ok := c.networks[n.id]
c.Unlock()
if ok {
existing.Lock()
// Skip existing network update
if existing.dbIndex != n.Index() {
// Can't use SetIndex() since existing is locked.
existing.dbIndex = n.Index()
existing.dbExists = true
existing.endpointCnt = n.endpointCnt
}
existing.Unlock()
continue
}
if err = c.newNetworkFromStore(&n); err != nil {
log.Error(err)
}
}
}
func (c *controller) processEndpointUpdate(ep *endpoint) bool {
nw := ep.network
if nw == nil {
return true
}
nw.Lock()
id := nw.id
nw.Unlock()
c.Lock()
n, ok := c.networks[id]
c.Unlock()
if !ok {
return true
}
existing, _ := n.EndpointByID(string(ep.id))
if existing == nil {
return true
}
ee := existing.(*endpoint)
ee.Lock()
if ee.dbIndex != ep.Index() {
// Can't use SetIndex() because ee is locked.
ee.dbIndex = ep.Index()
ee.dbExists = true
if ee.container != nil && ep.container != nil {
// we care only about the container id
ee.container.id = ep.container.id
} else {
// we still care only about the container id, but this is a short-cut to communicate join or leave operation
ee.container = ep.container
}
}
ee.Unlock()
return false
}