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:
33
vendor/github.com/docker/libnetwork/.gitignore
generated
vendored
Normal file
33
vendor/github.com/docker/libnetwork/.gitignore
generated
vendored
Normal 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
202
vendor/github.com/docker/libnetwork/LICENSE
generated
vendored
Normal 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
5
vendor/github.com/docker/libnetwork/MAINTAINERS
generated
vendored
Normal 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
79
vendor/github.com/docker/libnetwork/Makefile
generated
vendored
Normal 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
88
vendor/github.com/docker/libnetwork/README.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# libnetwork - networking for containers
|
||||
|
||||
[](https://circleci.com/gh/docker/libnetwork/tree/master) [](https://coveralls.io/r/docker/libnetwork) [](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
20
vendor/github.com/docker/libnetwork/ROADMAP.md
generated
vendored
Normal 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
12
vendor/github.com/docker/libnetwork/circle.yml
generated
vendored
Normal 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
399
vendor/github.com/docker/libnetwork/controller.go
generated
vendored
Normal 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
19
vendor/github.com/docker/libnetwork/drivers_freebsd.go
generated
vendored
Normal 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
25
vendor/github.com/docker/libnetwork/drivers_linux.go
generated
vendored
Normal 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
17
vendor/github.com/docker/libnetwork/drivers_windows.go
generated
vendored
Normal 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
998
vendor/github.com/docker/libnetwork/endpoint.go
generated
vendored
Normal 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
323
vendor/github.com/docker/libnetwork/endpoint_info.go
generated
vendored
Normal 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
175
vendor/github.com/docker/libnetwork/error.go
generated
vendored
Normal 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
51
vendor/github.com/docker/libnetwork/errors_test.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
32
vendor/github.com/docker/libnetwork/libnetwork_internal_test.go
generated
vendored
Normal file
32
vendor/github.com/docker/libnetwork/libnetwork_internal_test.go
generated
vendored
Normal 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
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
471
vendor/github.com/docker/libnetwork/network.go
generated
vendored
Normal 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
|
||||
}
|
1
vendor/github.com/docker/libnetwork/resolvconf/README.md
generated
vendored
Normal file
1
vendor/github.com/docker/libnetwork/resolvconf/README.md
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Package resolvconf provides utility code to query and update DNS configuration in /etc/resolv.conf
|
17
vendor/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go
generated
vendored
Normal file
17
vendor/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go
generated
vendored
Normal 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)
|
||||
}
|
187
vendor/github.com/docker/libnetwork/resolvconf/resolvconf.go
generated
vendored
Normal file
187
vendor/github.com/docker/libnetwork/resolvconf/resolvconf.go
generated
vendored
Normal 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)
|
||||
}
|
240
vendor/github.com/docker/libnetwork/resolvconf/resolvconf_test.go
generated
vendored
Normal file
240
vendor/github.com/docker/libnetwork/resolvconf/resolvconf_test.go
generated
vendored
Normal 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
251
vendor/github.com/docker/libnetwork/sandboxdata.go
generated
vendored
Normal 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
141
vendor/github.com/docker/libnetwork/sandboxdata_test.go
generated
vendored
Normal 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
371
vendor/github.com/docker/libnetwork/store.go
generated
vendored
Normal 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
|
||||
}
|
Reference in New Issue
Block a user