Allow passing global datastore to libnetwork and v0.7.0-dev1 vendoring
This commit is contained in:
Arnaud Porterie 2016-02-18 17:39:46 -08:00
Родитель c96564a76c c9bec2be2a
Коммит 117a982d2e
36 изменённых файлов: 1285 добавлений и 431 удалений

Просмотреть файл

@ -1598,12 +1598,12 @@ func (daemon *Daemon) initDiscovery(config *Config) error {
// daemon according to those changes.
// This are the settings that Reload changes:
// - Daemon labels.
// - Cluster discovery (reconfigure and restart).
func (daemon *Daemon) Reload(config *Config) error {
daemon.configStore.reloadLock.Lock()
defer daemon.configStore.reloadLock.Unlock()
daemon.configStore.Labels = config.Labels
daemon.configStore.reloadLock.Unlock()
return nil
return daemon.reloadClusterDiscovery(config)
}
func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
@ -1640,6 +1640,19 @@ func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
daemon.configStore.ClusterOpts = config.ClusterOpts
daemon.configStore.ClusterAdvertise = newAdvertise
if daemon.netController == nil {
return nil
}
netOptions, err := daemon.networkOptions(daemon.configStore)
if err != nil {
logrus.Warnf("Failed to reload configuration with network controller: %v", err)
return nil
}
err = daemon.netController.ReloadConfiguration(netOptions...)
if err != nil {
logrus.Warnf("Failed to reload configuration with network controller: %v", err)
}
return nil
}

Просмотреть файл

@ -371,7 +371,7 @@ func TestDaemonDiscoveryReload(t *testing.T) {
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
}
if err := daemon.reloadClusterDiscovery(newConfig); err != nil {
if err := daemon.Reload(newConfig); err != nil {
t.Fatal(err)
}
ch, errCh = daemon.discoveryWatcher.Watch(stopCh)
@ -403,7 +403,7 @@ func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
}
if err := daemon.reloadClusterDiscovery(newConfig); err != nil {
if err := daemon.Reload(newConfig); err != nil {
t.Fatal(err)
}
stopCh := make(chan struct{})

Просмотреть файл

@ -22,6 +22,7 @@ import (
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/system"
"github.com/docker/libnetwork"
nwconfig "github.com/docker/libnetwork/config"
blkiodev "github.com/opencontainers/runc/libcontainer/configs"
)
@ -251,3 +252,7 @@ func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) erro
}
return nil
}
func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
return nil, fmt.Errorf("Network controller config reload not aavailable on Windows yet")
}

Просмотреть файл

@ -890,4 +890,13 @@ if there are conflicts, but it won't stop execution.
The list of currently supported options that can be reconfigured is this:
- `debug`: it changes the daemon to debug mode when set to true.
- `cluster-store`: it reloads the discovery store with the new address.
- `cluster-store-opts`: it uses the new options to reload the discovery store.
- `cluster-advertise`: it modifies the address advertised after reloading.
- `labels`: it replaces the daemon labels with a new set of labels.
Updating and reloading the cluster configurations such as `--cluster-store`,
`--cluster-advertise` and `--cluster-store-opts` will take effect only if
these configurations were not previously configured. Configuration reload will
log a warning message if it detects a change in previously configured cluster
configurations.

Просмотреть файл

@ -29,7 +29,7 @@ clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de
clone git github.com/imdario/mergo 0.2.1
#get libnetwork packages
clone git github.com/docker/libnetwork v0.7.0-dev.2
clone git github.com/docker/libnetwork v0.7.0-dev.3
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4

Просмотреть файл

@ -17,6 +17,7 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"time"
"github.com/docker/docker/pkg/integration/checker"
@ -2156,3 +2157,43 @@ func (s *DockerDaemonSuite) TestDaemonDebugLog(c *check.C) {
newD.Stop()
c.Assert(b.String(), checker.Contains, debugLog)
}
func (s *DockerSuite) TestDaemonDiscoveryBackendConfigReload(c *check.C) {
testRequires(c, SameHostDaemon, DaemonIsLinux)
// daemon config file
daemonConfig := `{ "debug" : false }`
configFilePath := "test.json"
configFile, err := os.Create(configFilePath)
c.Assert(err, checker.IsNil)
fmt.Fprintf(configFile, "%s", daemonConfig)
d := NewDaemon(c)
err = d.Start(fmt.Sprintf("--config-file=%s", configFilePath))
c.Assert(err, checker.IsNil)
defer d.Stop()
// daemon config file
daemonConfig = `{
"cluster-store": "consul://consuladdr:consulport/some/path",
"cluster-advertise": "192.168.56.100:0",
"debug" : false
}`
configFile.Close()
os.Remove(configFilePath)
configFile, err = os.Create(configFilePath)
c.Assert(err, checker.IsNil)
fmt.Fprintf(configFile, "%s", daemonConfig)
syscall.Kill(d.cmd.Process.Pid, syscall.SIGHUP)
time.Sleep(3 * time.Second)
out, err := d.Cmd("info")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, fmt.Sprintf("Cluster store: consul://consuladdr:consulport/some/path"))
c.Assert(out, checker.Contains, fmt.Sprintf("Cluster advertise: 192.168.56.100:0"))
}

Просмотреть файл

@ -1389,6 +1389,14 @@ func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) {
c.Assert(err, check.NotNil)
}
func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace)
dockerCmd(c, "network", "create", "-d", "bridge", "nw1")
// Sending garbge to embedded DNS shouldn't crash the daemon
dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
}
func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) {
dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
c.Assert(waitRun("bb"), check.IsNil)

Просмотреть файл

@ -1,5 +1,13 @@
# Changelog
## 0.7.0-dev.3 (2016-02-17)
- Fixes https://github.com/docker/docker/issues/20350
- Fixes https://github.com/docker/docker/issues/20145
- Initial Windows HNS integration
- Allow passing global datastore config to libnetwork after boot
- Set Recursion Available bit in DNS query responses
- Make sure iptables chains are recreated on firewalld reload
## 0.7.0-dev.2 (2016-02-11)
- Fixes https://github.com/docker/docker/issues/20140

Просмотреть файл

@ -8,6 +8,5 @@ RUN cd /go/src && mkdir -p golang.org/x && \
RUN go get github.com/tools/godep \
github.com/golang/lint/golint \
golang.org/x/tools/cmd/vet \
golang.org/x/tools/cmd/goimports \
golang.org/x/tools/cmd/cover\
github.com/mattn/goveralls

Просмотреть файл

@ -53,7 +53,7 @@ check-code:
check-format:
@echo "Checking format... "
test -z "$$(goimports -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
test -z "$$(gofmt -s -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
@echo "Done checking format"
run-tests:

Просмотреть файл

@ -61,6 +61,22 @@ func ParseConfig(tomlCfgFile string) (*Config, error) {
return cfg, nil
}
// ParseConfigOptions parses the configuration options and returns
// a reference to the corresponding Config structure
func ParseConfigOptions(cfgOptions ...Option) *Config {
cfg := &Config{
Daemon: DaemonCfg{
DriverCfg: make(map[string]interface{}),
},
Scopes: make(map[string]*datastore.ScopeCfg),
}
cfg.ProcessOptions(cfgOptions...)
cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
return cfg
}
// Option is an option setter function type used to pass various configurations
// to the controller
type Option func(c *Config)

Просмотреть файл

@ -106,6 +106,9 @@ type NetworkController interface {
// Stop network controller
Stop()
// ReloadCondfiguration updates the controller configuration
ReloadConfiguration(cfgOptions ...config.Option) error
}
// NetworkWalker is a client provided function which will be used to walk the Networks.
@ -129,7 +132,6 @@ type ipamData struct {
}
type driverTable map[string]*driverData
type ipamTable map[string]*ipamData
type sandboxTable map[string]*sandbox
@ -153,22 +155,9 @@ type controller struct {
// New creates a new instance of network controller.
func New(cfgOptions ...config.Option) (NetworkController, error) {
var cfg *config.Config
cfg = &config.Config{
Daemon: config.DaemonCfg{
DriverCfg: make(map[string]interface{}),
},
Scopes: make(map[string]*datastore.ScopeCfg),
}
if len(cfgOptions) > 0 {
cfg.ProcessOptions(cfgOptions...)
}
cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
c := &controller{
id: stringid.GenerateRandomID(),
cfg: cfg,
cfg: config.ParseConfigOptions(cfgOptions...),
sandboxes: sandboxTable{},
drivers: driverTable{},
ipamDrivers: ipamTable{},
@ -179,8 +168,8 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
return nil, err
}
if cfg != nil && cfg.Cluster.Watcher != nil {
if err := c.initDiscovery(cfg.Cluster.Watcher); err != nil {
if c.cfg != nil && c.cfg.Cluster.Watcher != nil {
if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
// Failing to initalize discovery is a bad situation to be in.
// But it cannot fail creating the Controller
log.Errorf("Failed to Initialize Discovery : %v", err)
@ -206,6 +195,83 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
return c, nil
}
var procReloadConfig = make(chan (bool), 1)
func (c *controller) ReloadConfiguration(cfgOptions ...config.Option) error {
procReloadConfig <- true
defer func() { <-procReloadConfig }()
// For now we accept the configuration reload only as a mean to provide a global store config after boot.
// Refuse the configuration if it alters an existing datastore client configuration.
update := false
cfg := config.ParseConfigOptions(cfgOptions...)
for s := range c.cfg.Scopes {
if _, ok := cfg.Scopes[s]; !ok {
return types.ForbiddenErrorf("cannot accept new configuration because it removes an existing datastore client")
}
}
for s, nSCfg := range cfg.Scopes {
if eSCfg, ok := c.cfg.Scopes[s]; ok {
if eSCfg.Client.Provider != nSCfg.Client.Provider ||
eSCfg.Client.Address != nSCfg.Client.Address {
return types.ForbiddenErrorf("cannot accept new configuration because it modifies an existing datastore client")
}
} else {
update = true
}
}
if !update {
return nil
}
c.Lock()
c.cfg = cfg
c.Unlock()
if err := c.initStores(); err != nil {
return err
}
if c.discovery == nil && c.cfg.Cluster.Watcher != nil {
if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
log.Errorf("Failed to Initialize Discovery after configuration update: %v", err)
}
}
var dsConfig *discoverapi.DatastoreConfigData
for scope, sCfg := range cfg.Scopes {
if scope == datastore.LocalScope || !sCfg.IsValid() {
continue
}
dsConfig = &discoverapi.DatastoreConfigData{
Scope: scope,
Provider: sCfg.Client.Provider,
Address: sCfg.Client.Address,
Config: sCfg.Client.Config,
}
break
}
if dsConfig == nil {
return nil
}
for nm, id := range c.getIpamDrivers() {
err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
if err != nil {
log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
}
}
for nm, id := range c.getNetDrivers() {
err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
if err != nil {
log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
}
}
return nil
}
func (c *controller) ID() string {
return c.id
}
@ -726,6 +792,26 @@ func (c *controller) getIpamDriver(name string) (ipamapi.Ipam, error) {
return id.driver, nil
}
func (c *controller) getIpamDrivers() ipamTable {
c.Lock()
defer c.Unlock()
table := ipamTable{}
for i, d := range c.ipamDrivers {
table[i] = d
}
return table
}
func (c *controller) getNetDrivers() driverTable {
c.Lock()
defer c.Unlock()
table := driverTable{}
for i, d := range c.drivers {
table[i] = d
}
return table
}
func (c *controller) Stop() {
c.closeStores()
c.stopExternalKeyListener()

Просмотреть файл

@ -13,6 +13,7 @@ import (
"github.com/docker/libkv/store/consul"
"github.com/docker/libkv/store/etcd"
"github.com/docker/libkv/store/zookeeper"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/types"
)
@ -253,6 +254,34 @@ func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
return newClient(scope, cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config, cached)
}
// NewDataStoreFromConfig creates a new instance of LibKV data store starting from the datastore config data
func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, error) {
var (
ok bool
sCfgP *store.Config
)
sCfgP, ok = dsc.Config.(*store.Config)
if !ok && dsc.Config != nil {
return nil, fmt.Errorf("cannot parse store configuration: %v", dsc.Config)
}
scopeCfg := &ScopeCfg{
Client: ScopeClientCfg{
Address: dsc.Address,
Provider: dsc.Provider,
Config: sCfgP,
},
}
ds, err := NewDataStore(dsc.Scope, scopeCfg)
if err != nil {
return nil, fmt.Errorf("failed to construct datastore client from datastore configuration %v: %v", dsc, err)
}
return ds, err
}
func (ds *datastore) Close() {
ds.store.Close()
}

Просмотреть файл

@ -16,8 +16,8 @@ type DiscoveryType int
const (
// NodeDiscovery represents Node join/leave events provided by discovery
NodeDiscovery = iota + 1
// DatastoreUpdate represents a add/remove datastore event
DatastoreUpdate
// DatastoreConfig represents a add/remove datastore event
DatastoreConfig
)
// NodeDiscoveryData represents the structure backing the node discovery data json string
@ -26,8 +26,9 @@ type NodeDiscoveryData struct {
Self bool
}
// DatastoreUpdateData is the data for the datastore update event message
type DatastoreUpdateData struct {
// DatastoreConfigData is the data for the datastore update event message
type DatastoreConfigData struct {
Scope string
Provider string
Address string
Config interface{}

Просмотреть файл

@ -3,11 +3,13 @@ package libnetwork
import (
"strings"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/ipamapi"
"github.com/docker/libnetwork/netlabel"
builtinIpam "github.com/docker/libnetwork/ipams/builtin"
remoteIpam "github.com/docker/libnetwork/ipams/remote"
"github.com/docker/libnetwork/netlabel"
)
type initializer struct {
@ -56,10 +58,12 @@ func makeDriverConfig(c *controller, ntype string) map[string]interface{} {
if !v.IsValid() {
continue
}
config[netlabel.MakeKVProvider(k)] = v.Client.Provider
config[netlabel.MakeKVProviderURL(k)] = v.Client.Address
config[netlabel.MakeKVProviderConfig(k)] = v.Client.Config
config[netlabel.MakeKVClient(k)] = discoverapi.DatastoreConfigData{
Scope: k,
Provider: v.Client.Provider,
Address: v.Client.Address,
Config: v.Client.Config,
}
}
return config

Просмотреть файл

@ -133,6 +133,9 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
if out, err := exec.Command("modprobe", "-va", "nf_nat").CombinedOutput(); err != nil {
logrus.Warnf("Running modprobe nf_nat failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
}
if out, err := exec.Command("modprobe", "-va", "xt_conntrack").CombinedOutput(); err != nil {
logrus.Warnf("Running modprobe xt_conntrack failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
}
if err := iptables.FirewalldInit(); err != nil {
logrus.Debugf("Fail to initialize firewalld: %v, using raw iptables instead", err)
}
@ -384,6 +387,8 @@ func (d *driver) configure(option map[string]interface{}) error {
if err != nil {
return err
}
// Make sure on firewall reload, first thing being re-played is chains creation
iptables.OnReloaded(func() { logrus.Debugf("Recreating iptables chains on firewall reload"); setupIPChains(config) })
}
d.Lock()

Просмотреть файл

@ -6,9 +6,9 @@ import (
"net"
"github.com/Sirupsen/logrus"
"github.com/docker/libkv/store"
"github.com/docker/libkv/store/boltdb"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/types"
)
@ -16,27 +16,15 @@ import (
const bridgePrefix = "bridge"
func (d *driver) initStore(option map[string]interface{}) error {
var err error
provider, provOk := option[netlabel.LocalKVProvider]
provURL, urlOk := option[netlabel.LocalKVProviderURL]
if provOk && urlOk {
cfg := &datastore.ScopeCfg{
Client: datastore.ScopeClientCfg{
Provider: provider.(string),
Address: provURL.(string),
},
if data, ok := option[netlabel.LocalKVClient]; ok {
var err error
dsc, ok := data.(discoverapi.DatastoreConfigData)
if !ok {
return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
}
provConfig, confOk := option[netlabel.LocalKVProviderConfig]
if confOk {
cfg.Client.Config = provConfig.(*store.Config)
}
d.store, err = datastore.NewDataStore(datastore.LocalScope, cfg)
d.store, err = datastore.NewDataStoreFromConfig(dsc)
if err != nil {
return fmt.Errorf("bridge driver failed to initialize data store: %v", err)
return types.InternalErrorf("bridge driver failed to initialize data store: %v", err)
}
return d.populateNetworks()

Просмотреть файл

@ -6,12 +6,12 @@ import (
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/libkv/store"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/idm"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/types"
"github.com/hashicorp/serf/serf"
)
@ -25,6 +25,8 @@ const (
vxlanVethMTU = 1450
)
var initVxlanIdm = make(chan (bool), 1)
type driver struct {
eventCh chan serf.Event
notifyCh chan ovNotify
@ -56,6 +58,18 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
config: config,
}
if data, ok := config[netlabel.GlobalKVClient]; ok {
var err error
dsc, ok := data.(discoverapi.DatastoreConfigData)
if !ok {
return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
}
d.store, err = datastore.NewDataStoreFromConfig(dsc)
if err != nil {
return types.InternalErrorf("failed to initialize data store: %v", err)
}
}
return dc.RegisterDriver(networkType, d, c)
}
@ -73,42 +87,33 @@ func Fini(drv driverapi.Driver) {
}
func (d *driver) configure() error {
if d.store == nil {
return types.NoServiceErrorf("datastore is not available")
}
if d.vxlanIdm == nil {
return d.initializeVxlanIdm()
}
return nil
}
func (d *driver) initializeVxlanIdm() error {
var err error
if len(d.config) == 0 {
initVxlanIdm <- true
defer func() { <-initVxlanIdm }()
if d.vxlanIdm != nil {
return nil
}
d.once.Do(func() {
provider, provOk := d.config[netlabel.GlobalKVProvider]
provURL, urlOk := d.config[netlabel.GlobalKVProviderURL]
d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
if err != nil {
return fmt.Errorf("failed to initialize vxlan id manager: %v", err)
}
if provOk && urlOk {
cfg := &datastore.ScopeCfg{
Client: datastore.ScopeClientCfg{
Provider: provider.(string),
Address: provURL.(string),
},
}
provConfig, confOk := d.config[netlabel.GlobalKVProviderConfig]
if confOk {
cfg.Client.Config = provConfig.(*store.Config)
}
d.store, err = datastore.NewDataStore(datastore.GlobalScope, cfg)
if err != nil {
err = fmt.Errorf("failed to initialize data store: %v", err)
return
}
}
d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
if err != nil {
err = fmt.Errorf("failed to initialize vxlan id manager: %v", err)
return
}
})
return err
return nil
}
func (d *driver) Type() string {
@ -187,12 +192,27 @@ func (d *driver) pushLocalEndpointEvent(action, nid, eid string) {
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
if dType == discoverapi.NodeDiscovery {
switch dType {
case discoverapi.NodeDiscovery:
nodeData, ok := data.(discoverapi.NodeDiscoveryData)
if !ok || nodeData.Address == "" {
return fmt.Errorf("invalid discovery data")
}
d.nodeJoin(nodeData.Address, nodeData.Self)
case discoverapi.DatastoreConfig:
var err error
if d.store != nil {
return types.ForbiddenErrorf("cannot accept datastore configuration: Overlay driver has a datastore configured already")
}
dsc, ok := data.(discoverapi.DatastoreConfigData)
if !ok {
return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
}
d.store, err = datastore.NewDataStoreFromConfig(dsc)
if err != nil {
return types.InternalErrorf("failed to initialize data store: %v", err)
}
default:
}
return nil
}

Просмотреть файл

@ -0,0 +1,12 @@
package windows
const (
// NetworkName label for bridge driver
NetworkName = "com.docker.network.windowsshim.networkname"
// HNSID of the discovered network
HNSID = "com.docker.network.windowsshim.hnsid"
// RoutingDomain of the network
RoutingDomain = "com.docker.network.windowsshim.routingdomain"
)

Просмотреть файл

@ -1,57 +1,419 @@
// +build windows
// Shim for the Host Network Service (HNS) to manage networking for
// Windows Server containers and Hyper-V containers. This module
// is a basic libnetwork driver that passes all the calls to HNS
// It implements the 4 networking modes supported by HNS L2Bridge,
// L2Tunnel, NAT and Transparent(DHCP)
//
// The network are stored in memory and docker daemon ensures discovering
// and loading these networks on startup
package windows
import (
"encoding/json"
"fmt"
"net"
"strings"
"sync"
"github.com/Microsoft/hcsshim"
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/types"
)
const networkType = "windows"
// TODO Windows. This is a placeholder for now
type driver struct{}
// Init registers a new instance of null driver
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
c := driverapi.Capability{
DataScope: datastore.LocalScope,
}
return dc.RegisterDriver(networkType, &driver{}, c)
// networkConfiguration for network specific configuration
type networkConfiguration struct {
ID string
Type string
Name string
HnsID string
RDID string
}
type hnsEndpoint struct {
id string
profileID string
macAddress net.HardwareAddr
addr *net.IPNet
}
type hnsNetwork struct {
id string
config *networkConfiguration
endpoints map[string]*hnsEndpoint // key: endpoint id
driver *driver // The network's driver
sync.Mutex
}
type driver struct {
name string
networks map[string]*hnsNetwork
sync.Mutex
}
func isValidNetworkType(networkType string) bool {
if "L2Bridge" == networkType || "L2Tunnel" == networkType || "NAT" == networkType || "Transparent" == networkType {
return true
}
return false
}
// New constructs a new bridge driver
func newDriver(networkType string) *driver {
return &driver{name: networkType, networks: map[string]*hnsNetwork{}}
}
// GetInit returns an initializer for the given network type
func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error {
return func(dc driverapi.DriverCallback, config map[string]interface{}) error {
if !isValidNetworkType(networkType) {
return types.BadRequestErrorf("Network type not supported: %s", networkType)
}
return dc.RegisterDriver(networkType, newDriver(networkType), driverapi.Capability{
DataScope: datastore.LocalScope,
})
}
}
func (d *driver) getNetwork(id string) (*hnsNetwork, error) {
d.Lock()
defer d.Unlock()
if nw, ok := d.networks[id]; ok {
return nw, nil
}
return nil, types.NotFoundErrorf("network not found: %s", id)
}
func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) {
n.Lock()
defer n.Unlock()
if ep, ok := n.endpoints[eid]; ok {
return ep, nil
}
return nil, types.NotFoundErrorf("Endpoint not found: %s", eid)
}
func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) {
config := &networkConfiguration{}
for label, value := range genericOptions {
switch label {
case NetworkName:
config.Name = value
case HNSID:
config.HnsID = value
case RoutingDomain:
config.RDID = value
}
}
config.ID = id
config.Type = d.name
return config, nil
}
func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
if len(ipamV6Data) > 0 {
return types.ForbiddenErrorf("windowsshim driver doesnt support v6 subnets")
}
if len(ipamV4Data) == 0 {
return types.BadRequestErrorf("network %s requires ipv4 configuration", id)
}
return nil
}
// Create a new network
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
if _, err := d.getNetwork(id); err == nil {
return types.ForbiddenErrorf("network %s exists", id)
}
genData, ok := option[netlabel.GenericData].(map[string]string)
if !ok {
return fmt.Errorf("Unknown generic data option")
}
// Parse and validate the config. It should not conflict with existing networks' config
config, err := d.parseNetworkOptions(id, genData)
if err != nil {
return err
}
err = config.processIPAM(id, ipV4Data, ipV6Data)
if err != nil {
return err
}
network := &hnsNetwork{
id: config.ID,
endpoints: make(map[string]*hnsEndpoint),
config: config,
driver: d,
}
d.Lock()
d.networks[config.ID] = network
d.Unlock()
// A non blank hnsid indicates that the network was discovered
// from HNS. No need to call HNS if this network was discovered
// from HNS
if config.HnsID == "" {
subnets := []hcsshim.Subnet{}
for _, ipData := range ipV4Data {
subnet := hcsshim.Subnet{
AddressPrefix: ipData.Pool.String(),
GatewayAddress: ipData.Gateway.IP.String(),
}
subnets = append(subnets, subnet)
}
network := &hcsshim.HNSNetwork{
Name: config.Name,
Type: d.name,
Subnets: subnets,
}
if network.Name == "" {
network.Name = id
}
configurationb, err := json.Marshal(network)
if err != nil {
return err
}
configuration := string(configurationb)
log.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets)
hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
if err != nil {
return err
}
config.HnsID = hnsresponse.Id
genData[HNSID] = config.HnsID
}
return nil
}
func (d *driver) DeleteNetwork(nid string) error {
n, err := d.getNetwork(nid)
if err != nil {
return types.InternalMaskableErrorf("%s", err)
}
n.Lock()
config := n.config
n.Unlock()
// Cannot remove network if endpoints are still present
if len(n.endpoints) != 0 {
return fmt.Errorf("network %s has active endpoint", n.id)
}
_, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "")
if err != nil {
return err
}
d.Lock()
delete(d.networks, nid)
d.Unlock()
return nil
}
func convertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) {
var pbs []json.RawMessage
// Enumerate through the port bindings specified by the user and convert
// them into the internal structure matching the JSON blob that can be
// understood by the HCS.
for _, elem := range portBindings {
proto := strings.ToUpper(elem.Proto.String())
if proto != "TCP" && proto != "UDP" {
return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String())
}
if elem.HostPort != elem.HostPortEnd {
return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings")
}
if len(elem.HostIP) != 0 {
return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings")
}
encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{
Type: "NAT",
ExternalPort: elem.HostPort,
InternalPort: elem.Port,
Protocol: elem.Proto.String(),
})
if err != nil {
return nil, err
}
pbs = append(pbs, encodedPolicy)
}
return pbs, nil
}
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
n, err := d.getNetwork(nid)
if err != nil {
return err
}
// Check if endpoint id is good and retrieve corresponding endpoint
ep, err := n.getEndpoint(eid)
if err == nil && ep != nil {
return driverapi.ErrEndpointExists(eid)
}
endpointStruct := &hcsshim.HNSEndpoint{
VirtualNetwork: n.config.HnsID,
}
// Convert the port mapping for the network
if opt, ok := epOptions[netlabel.PortMap]; ok {
if bs, ok := opt.([]types.PortBinding); ok {
endpointStruct.Policies, err = convertPortBindings(bs)
if err != nil {
return err
}
} else {
return fmt.Errorf("Invalid endpoint configuration for endpoint id%s", eid)
}
}
configurationb, err := json.Marshal(endpointStruct)
if err != nil {
return err
}
hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb))
if err != nil {
return err
}
mac, err := net.ParseMAC(hnsresponse.MacAddress)
if err != nil {
return err
}
// TODO For now the ip mask is not in the info generated by HNS
endpoint := &hnsEndpoint{
id: eid,
addr: &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
macAddress: mac,
}
endpoint.profileID = hnsresponse.Id
n.Lock()
n.endpoints[eid] = endpoint
n.Unlock()
ifInfo.SetIPAddress(endpoint.addr)
ifInfo.SetMacAddress(endpoint.macAddress)
return nil
}
func (d *driver) DeleteEndpoint(nid, eid string) error {
n, err := d.getNetwork(nid)
if err != nil {
return types.InternalMaskableErrorf("%s", err)
}
ep, err := n.getEndpoint(eid)
if err != nil {
return err
}
n.Lock()
delete(n.endpoints, eid)
n.Unlock()
_, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "")
if err != nil {
return err
}
return nil
}
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
return make(map[string]interface{}, 0), nil
network, err := d.getNetwork(nid)
if err != nil {
return nil, err
}
endpoint, err := network.getEndpoint(eid)
if err != nil {
return nil, err
}
data := make(map[string]interface{}, 1)
data["hnsid"] = endpoint.profileID
return data, nil
}
// Join method is invoked when a Sandbox is attached to an endpoint.
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
network, err := d.getNetwork(nid)
if err != nil {
return err
}
// Ensure that the endpoint exists
_, err = network.getEndpoint(eid)
if err != nil {
return err
}
// This is just a stub for now
jinfo.DisableGatewayService()
return nil
}
// Leave method is invoked when a Sandbox detaches from an endpoint.
func (d *driver) Leave(nid, eid string) error {
network, err := d.getNetwork(nid)
if err != nil {
return types.InternalMaskableErrorf("%s", err)
}
// Ensure that the endpoint exists
_, err = network.getEndpoint(eid)
if err != nil {
return err
}
// This is just a stub for now
return nil
}
func (d *driver) Type() string {
return networkType
return d.name
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster

Просмотреть файл

@ -1,9 +1,16 @@
package libnetwork
import "github.com/docker/libnetwork/drivers/windows"
import (
"github.com/docker/libnetwork/drivers/null"
"github.com/docker/libnetwork/drivers/windows"
)
func getInitializers() []initializer {
return []initializer{
{windows.Init, "windows"},
{null.Init, "null"},
{windows.GetInit("Transparent"), "Transparent"},
{windows.GetInit("L2Bridge"), "L2Bridge"},
{windows.GetInit("L2Tunnel"), "L2Tunnel"},
{windows.GetInit("NAT"), "NAT"},
}
}

Просмотреть файл

@ -8,6 +8,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/bitseq"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/ipamapi"
"github.com/docker/libnetwork/ipamutils"
"github.com/docker/libnetwork/types"
@ -60,19 +61,9 @@ func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
if aspc.ds == nil {
continue
}
a.addrSpaces[aspc.as] = &addrSpace{
subnets: map[SubnetKey]*PoolData{},
id: dsConfigKey + "/" + aspc.as,
scope: aspc.ds.Scope(),
ds: aspc.ds,
alloc: a,
}
a.initializeAddressSpace(aspc.as, aspc.ds)
}
a.checkConsistency(localAddressSpace)
a.checkConsistency(globalAddressSpace)
return a, nil
}
@ -118,25 +109,83 @@ func (a *Allocator) updateBitMasks(aSpace *addrSpace) error {
return nil
}
// Checks for and fixes damaged bitmask. Meant to be called in constructor only.
// Checks for and fixes damaged bitmask.
func (a *Allocator) checkConsistency(as string) {
var sKeyList []SubnetKey
// Retrieve this address space's configuration and bitmasks from the datastore
a.refresh(as)
a.Lock()
aSpace, ok := a.addrSpaces[as]
a.Unlock()
if !ok {
return
}
a.updateBitMasks(aSpace)
aSpace.Lock()
for sk, pd := range aSpace.subnets {
if pd.Range != nil {
continue
}
if err := a.addresses[sk].CheckConsistency(); err != nil {
sKeyList = append(sKeyList, sk)
}
aSpace.Unlock()
for _, sk := range sKeyList {
a.Lock()
bm := a.addresses[sk]
a.Unlock()
if err := bm.CheckConsistency(); err != nil {
log.Warnf("Error while running consistency check for %s: %v", sk, err)
}
}
}
func (a *Allocator) initializeAddressSpace(as string, ds datastore.DataStore) error {
a.Lock()
if _, ok := a.addrSpaces[as]; ok {
a.Unlock()
return types.ForbiddenErrorf("tried to add an axisting address space: %s", as)
}
a.addrSpaces[as] = &addrSpace{
subnets: map[SubnetKey]*PoolData{},
id: dsConfigKey + "/" + as,
scope: ds.Scope(),
ds: ds,
alloc: a,
}
a.Unlock()
a.checkConsistency(as)
return nil
}
// DiscoverNew informs the allocator about a new global scope datastore
func (a *Allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
if dType != discoverapi.DatastoreConfig {
return nil
}
dsc, ok := data.(discoverapi.DatastoreConfigData)
if !ok {
return types.InternalErrorf("incorrect data in datastore update notification: %v", data)
}
ds, err := datastore.NewDataStoreFromConfig(dsc)
if err != nil {
return err
}
return a.initializeAddressSpace(globalAddressSpace, ds)
}
// DiscoverDelete is a notification of no interest for the allocator
func (a *Allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}
// GetDefaultAddressSpaces returns the local and global default address spaces
func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
return localAddressSpace, globalAddressSpace, nil

Просмотреть файл

@ -4,6 +4,7 @@ package ipamapi
import (
"net"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/types"
)
@ -56,6 +57,8 @@ var (
// Ipam represents the interface the IPAM service plugins must implement
// in order to allow injection/modification of IPAM database.
type Ipam interface {
discoverapi.Discover
// GetDefaultAddressSpaces returns the default local and global address spaces for this ipam
GetDefaultAddressSpaces() (string, string, error)
// RequestPool returns an address pool along with its unique id. Address space is a mandatory field

Просмотреть файл

@ -1,3 +1,5 @@
// +build linux freebsd
package builtin
import (

Просмотреть файл

@ -0,0 +1,16 @@
// +build windows
package builtin
import (
"github.com/docker/libnetwork/ipamapi"
windowsipam "github.com/docker/libnetwork/ipams/windowsipam"
)
// Init registers the built-in ipam service with libnetwork
func Init(ic ipamapi.Callback, l, g interface{}) error {
initFunc := windowsipam.GetInit(ipamapi.DefaultIPAM)
return initFunc(ic, l, g)
}

Просмотреть файл

@ -6,6 +6,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/ipamapi"
"github.com/docker/libnetwork/ipams/remote/api"
"github.com/docker/libnetwork/types"
@ -124,3 +125,13 @@ func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
res := &api.ReleaseAddressResponse{}
return a.call("ReleaseAddress", req, res)
}
// DiscoverNew is a notification for a new discovery event, such as a new global datastore
func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}

Просмотреть файл

@ -0,0 +1,93 @@
package windowsipam
import (
"net"
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/ipamapi"
"github.com/docker/libnetwork/types"
)
const (
localAddressSpace = "LocalDefault"
globalAddressSpace = "GlobalDefault"
)
var (
defaultPool, _ = types.ParseCIDR("0.0.0.0/0")
)
type allocator struct {
}
// GetInit registers the built-in ipam service with libnetwork
func GetInit(ipamName string) func(ic ipamapi.Callback, l, g interface{}) error {
return func(ic ipamapi.Callback, l, g interface{}) error {
return ic.RegisterIpamDriver(ipamName, &allocator{})
}
}
func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
return localAddressSpace, globalAddressSpace, nil
}
// RequestPool returns an address pool along with its unique id. This is a null ipam driver. It allocates the
// subnet user asked and does not validate anything. Doesnt support subpool allocation
func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
if subPool != "" || v6 {
return "", nil, nil, types.InternalErrorf("This request is not supported by null ipam driver")
}
var ipNet *net.IPNet
var err error
if pool != "" {
_, ipNet, err = net.ParseCIDR(pool)
if err != nil {
return "", nil, nil, err
}
} else {
ipNet = defaultPool
}
return ipNet.String(), ipNet, nil, nil
}
// ReleasePool releases the address pool - always succeeds
func (a *allocator) ReleasePool(poolID string) error {
log.Debugf("ReleasePool(%s)", poolID)
return nil
}
// RequestAddress returns an address from the specified pool ID.
// Always allocate the 0.0.0.0/32 ip if no preferred address was specified
func (a *allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
log.Debugf("RequestAddress(%s, %v, %v) %s", poolID, prefAddress, opts, opts["RequestAddressType"])
_, ipNet, err := net.ParseCIDR(poolID)
if err != nil {
return nil, nil, err
}
if prefAddress == nil {
return ipNet, nil, nil
}
return &net.IPNet{IP: prefAddress, Mask: ipNet.Mask}, nil, nil
}
// ReleaseAddress releases the address - always succeeds
func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
log.Debugf("ReleaseAddress(%s, %v)", poolID, address)
return nil
}
// DiscoverNew informs the allocator about a new global scope datastore
func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}
// DiscoverDelete is a notification of no interest for the allocator
func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}

Просмотреть файл

@ -56,6 +56,9 @@ var (
// GlobalKVProviderConfig constant represents the KV provider Config
GlobalKVProviderConfig = MakeKVProviderConfig("global")
// GlobalKVClient constants represents the global kv store client
GlobalKVClient = MakeKVClient("global")
// LocalKVProvider constant represents the KV provider backend
LocalKVProvider = MakeKVProvider("local")
@ -64,6 +67,9 @@ var (
// LocalKVProviderConfig constant represents the KV provider Config
LocalKVProviderConfig = MakeKVProviderConfig("local")
// LocalKVClient constants represents the local kv store client
LocalKVClient = MakeKVClient("local")
)
// MakeKVProvider returns the kvprovider label for the scope
@ -81,6 +87,11 @@ func MakeKVProviderConfig(scope string) string {
return DriverPrivatePrefix + scope + "kv_provider_config"
}
// MakeKVClient returns the kv client label for the scope
func MakeKVClient(scope string) string {
return DriverPrivatePrefix + scope + "kv_client"
}
// Key extracts the key portion of the label
func Key(label string) (key string) {
if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {

Просмотреть файл

@ -1004,7 +1004,7 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error {
if ipVer == 6 {
return nil
}
*cfgList = []*IpamConf{&IpamConf{}}
*cfgList = []*IpamConf{{}}
}
*infoList = make([]*IpamInfo, len(*cfgList))

Просмотреть файл

@ -85,7 +85,7 @@ func handleStopSignals(p proxy.Proxy) {
s := make(chan os.Signal, 10)
signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)
for _ = range s {
for range s {
p.Close()
os.Exit(0)

Просмотреть файл

@ -35,7 +35,7 @@ const (
dnsPort = "53"
ptrIPv4domain = ".in-addr.arpa."
ptrIPv6domain = ".ip6.arpa."
respTTL = 1800
respTTL = 600
maxExtDNS = 3 //max number of external servers to try
)
@ -147,6 +147,10 @@ func (r *resolver) ResolverOptions() []string {
return []string{"ndots:0"}
}
func setCommonFlags(msg *dns.Msg) {
msg.RecursionAvailable = true
}
func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
addr := r.sb.ResolveName(name)
if addr == nil {
@ -157,6 +161,7 @@ func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error
resp := new(dns.Msg)
resp.SetReply(query)
setCommonFlags(resp)
rr := new(dns.A)
rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
@ -186,6 +191,7 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error)
resp := new(dns.Msg)
resp.SetReply(query)
setCommonFlags(resp)
rr := new(dns.PTR)
rr.Hdr = dns.RR_Header{Name: ptr, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL}
@ -200,6 +206,9 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
err error
)
if query == nil || len(query.Question) == 0 {
return
}
name := query.Question[0].Name
if query.Question[0].Qtype == dns.TypeA {
resp, err = r.handleIPv4Query(name, query)

Просмотреть файл

@ -4,19 +4,13 @@ import (
"container/heap"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
"path"
"path/filepath"
"strings"
"sync"
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/etchosts"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/resolvconf"
"github.com/docker/libnetwork/types"
)
@ -309,46 +303,6 @@ func (sb *sandbox) UnmarshalJSON(b []byte) (err error) {
return nil
}
func (sb *sandbox) startResolver() {
sb.resolverOnce.Do(func() {
var err error
sb.resolver = NewResolver(sb)
defer func() {
if err != nil {
sb.resolver = nil
}
}()
err = sb.rebuildDNS()
if err != nil {
log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
return
}
sb.resolver.SetExtServers(sb.extDNS)
sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
if err = sb.resolver.Start(); err != nil {
log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
}
})
}
func (sb *sandbox) setupResolutionFiles() error {
if err := sb.buildHostsFile(); err != nil {
return err
}
if err := sb.updateParentHosts(); err != nil {
return err
}
if err := sb.setupDNS(); err != nil {
return err
}
return nil
}
func (sb *sandbox) Endpoints() []Endpoint {
sb.Lock()
defer sb.Unlock()
@ -753,243 +707,6 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
return nil
}
const (
defaultPrefix = "/var/lib/docker/network/files"
dirPerm = 0755
filePerm = 0644
)
func (sb *sandbox) buildHostsFile() error {
if sb.config.hostsPath == "" {
sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
}
dir, _ := filepath.Split(sb.config.hostsPath)
if err := createBasePath(dir); err != nil {
return err
}
// This is for the host mode networking
if sb.config.originHostsPath != "" {
if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
}
return nil
}
extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
for _, extraHost := range sb.config.extraHosts {
extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
}
return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
}
func (sb *sandbox) updateHostsFile(ifaceIP string) error {
var mhost string
if sb.config.originHostsPath != "" {
return nil
}
if sb.config.domainName != "" {
mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
sb.config.hostName)
} else {
mhost = sb.config.hostName
}
extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
sb.addHostsEntries(extraContent)
return nil
}
func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
log.Warnf("Failed adding service host entries to the running container: %v", err)
}
}
func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
log.Warnf("Failed deleting service host entries to the running container: %v", err)
}
}
func (sb *sandbox) updateParentHosts() error {
var pSb Sandbox
for _, update := range sb.config.parentUpdates {
sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
if pSb == nil {
continue
}
if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
return err
}
}
return nil
}
func (sb *sandbox) setupDNS() error {
var newRC *resolvconf.File
if sb.config.resolvConfPath == "" {
sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
}
sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
dir, _ := filepath.Split(sb.config.resolvConfPath)
if err := createBasePath(dir); err != nil {
return err
}
// This is for the host mode networking
if sb.config.originResolvConfPath != "" {
if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
}
return nil
}
currRC, err := resolvconf.Get()
if err != nil {
return err
}
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
var (
err error
dnsList = resolvconf.GetNameservers(currRC.Content, netutils.IP)
dnsSearchList = resolvconf.GetSearchDomains(currRC.Content)
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
)
if len(sb.config.dnsList) > 0 {
dnsList = sb.config.dnsList
}
if len(sb.config.dnsSearchList) > 0 {
dnsSearchList = sb.config.dnsSearchList
}
if len(sb.config.dnsOptionsList) > 0 {
dnsOptionsList = sb.config.dnsOptionsList
}
newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
if err != nil {
return err
}
} else {
// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
return err
}
// No contention on container resolv.conf file at sandbox creation
if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
}
}
// Write hash
if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
}
return nil
}
func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
var (
currHash string
hashFile = sb.config.resolvConfHashFile
)
// This is for the host mode networking
if sb.config.originResolvConfPath != "" {
return nil
}
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
return nil
}
currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
if err != nil {
if !os.IsNotExist(err) {
return err
}
} else {
h, err := ioutil.ReadFile(hashFile)
if err != nil {
if !os.IsNotExist(err) {
return err
}
} else {
currHash = string(h)
}
}
if currHash != "" && currHash != currRC.Hash {
// Seems the user has changed the container resolv.conf since the last time
// we checked so return without doing anything.
log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
return nil
}
// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
if err != nil {
return err
}
err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
if err != nil {
return err
}
// write the new hash in a temp file and rename it to make the update atomic
dir := path.Dir(sb.config.resolvConfPath)
tmpHashFile, err := ioutil.TempFile(dir, "hash")
if err != nil {
return err
}
if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
return err
}
return os.Rename(tmpHashFile.Name(), hashFile)
}
// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
// resolv.conf by doing the follwing
// - Save the external name servers in resolv.conf in the sandbox
// - Add only the embedded server's IP to container's resolv.conf
// - If the embedded server needs any resolv.conf options add it to the current list
func (sb *sandbox) rebuildDNS() error {
currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
if err != nil {
return err
}
// localhost entries have already been filtered out from the list
// retain only the v4 servers in sb for forwarding the DNS queries
sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
var (
dnsList = []string{sb.resolver.NameServer()}
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
dnsSearchList = resolvconf.GetSearchDomains(currRC.Content)
)
// external v6 DNS servers has to be listed in resolv.conf
dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
// Resolver returns the options in the format resolv.conf expects
dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
_, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
return err
}
// joinLeaveStart waits to ensure there are no joins or leaves in progress and
// marks this join/leave in progress without race
func (sb *sandbox) joinLeaveStart() {
@ -1191,32 +908,3 @@ func (eh *epHeap) Pop() interface{} {
*eh = old[0 : n-1]
return x
}
func createBasePath(dir string) error {
return os.MkdirAll(dir, dirPerm)
}
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
}
func copyFile(src, dst string) error {
sBytes, err := ioutil.ReadFile(src)
if err != nil {
return err
}
return ioutil.WriteFile(dst, sBytes, filePerm)
}

323
vendor/src/github.com/docker/libnetwork/sandbox_dns_unix.go поставляемый Normal file
Просмотреть файл

@ -0,0 +1,323 @@
// +build !windows
package libnetwork
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/etchosts"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/resolvconf"
"github.com/docker/libnetwork/types"
)
const (
defaultPrefix = "/var/lib/docker/network/files"
dirPerm = 0755
filePerm = 0644
)
func (sb *sandbox) startResolver() {
sb.resolverOnce.Do(func() {
var err error
sb.resolver = NewResolver(sb)
defer func() {
if err != nil {
sb.resolver = nil
}
}()
err = sb.rebuildDNS()
if err != nil {
log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
return
}
sb.resolver.SetExtServers(sb.extDNS)
sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
if err = sb.resolver.Start(); err != nil {
log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
}
})
}
func (sb *sandbox) setupResolutionFiles() error {
if err := sb.buildHostsFile(); err != nil {
return err
}
if err := sb.updateParentHosts(); err != nil {
return err
}
if err := sb.setupDNS(); err != nil {
return err
}
return nil
}
func (sb *sandbox) buildHostsFile() error {
if sb.config.hostsPath == "" {
sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
}
dir, _ := filepath.Split(sb.config.hostsPath)
if err := createBasePath(dir); err != nil {
return err
}
// This is for the host mode networking
if sb.config.originHostsPath != "" {
if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
}
return nil
}
extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
for _, extraHost := range sb.config.extraHosts {
extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
}
return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
}
func (sb *sandbox) updateHostsFile(ifaceIP string) error {
var mhost string
if sb.config.originHostsPath != "" {
return nil
}
if sb.config.domainName != "" {
mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
sb.config.hostName)
} else {
mhost = sb.config.hostName
}
extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
sb.addHostsEntries(extraContent)
return nil
}
func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
log.Warnf("Failed adding service host entries to the running container: %v", err)
}
}
func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
log.Warnf("Failed deleting service host entries to the running container: %v", err)
}
}
func (sb *sandbox) updateParentHosts() error {
var pSb Sandbox
for _, update := range sb.config.parentUpdates {
sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
if pSb == nil {
continue
}
if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
return err
}
}
return nil
}
func (sb *sandbox) setupDNS() error {
var newRC *resolvconf.File
if sb.config.resolvConfPath == "" {
sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
}
sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
dir, _ := filepath.Split(sb.config.resolvConfPath)
if err := createBasePath(dir); err != nil {
return err
}
// This is for the host mode networking
if sb.config.originResolvConfPath != "" {
if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
}
return nil
}
currRC, err := resolvconf.Get()
if err != nil {
return err
}
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
var (
err error
dnsList = resolvconf.GetNameservers(currRC.Content, netutils.IP)
dnsSearchList = resolvconf.GetSearchDomains(currRC.Content)
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
)
if len(sb.config.dnsList) > 0 {
dnsList = sb.config.dnsList
}
if len(sb.config.dnsSearchList) > 0 {
dnsSearchList = sb.config.dnsSearchList
}
if len(sb.config.dnsOptionsList) > 0 {
dnsOptionsList = sb.config.dnsOptionsList
}
newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
if err != nil {
return err
}
} else {
// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
return err
}
// No contention on container resolv.conf file at sandbox creation
if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
}
}
// Write hash
if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
}
return nil
}
func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
var (
currHash string
hashFile = sb.config.resolvConfHashFile
)
// This is for the host mode networking
if sb.config.originResolvConfPath != "" {
return nil
}
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
return nil
}
currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
if err != nil {
if !os.IsNotExist(err) {
return err
}
} else {
h, err := ioutil.ReadFile(hashFile)
if err != nil {
if !os.IsNotExist(err) {
return err
}
} else {
currHash = string(h)
}
}
if currHash != "" && currHash != currRC.Hash {
// Seems the user has changed the container resolv.conf since the last time
// we checked so return without doing anything.
log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
return nil
}
// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
if err != nil {
return err
}
err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
if err != nil {
return err
}
// write the new hash in a temp file and rename it to make the update atomic
dir := path.Dir(sb.config.resolvConfPath)
tmpHashFile, err := ioutil.TempFile(dir, "hash")
if err != nil {
return err
}
if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
return err
}
return os.Rename(tmpHashFile.Name(), hashFile)
}
// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
// resolv.conf by doing the follwing
// - Save the external name servers in resolv.conf in the sandbox
// - Add only the embedded server's IP to container's resolv.conf
// - If the embedded server needs any resolv.conf options add it to the current list
func (sb *sandbox) rebuildDNS() error {
currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
if err != nil {
return err
}
// localhost entries have already been filtered out from the list
// retain only the v4 servers in sb for forwarding the DNS queries
sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
var (
dnsList = []string{sb.resolver.NameServer()}
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
dnsSearchList = resolvconf.GetSearchDomains(currRC.Content)
)
// external v6 DNS servers has to be listed in resolv.conf
dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
// Resolver returns the options in the format resolv.conf expects
dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
_, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
return err
}
func createBasePath(dir string) error {
return os.MkdirAll(dir, dirPerm)
}
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
}
func copyFile(src, dst string) error {
sBytes, err := ioutil.ReadFile(src)
if err != nil {
return err
}
return ioutil.WriteFile(dst, sBytes, filePerm)
}

32
vendor/src/github.com/docker/libnetwork/sandbox_dns_windows.go поставляемый Normal file
Просмотреть файл

@ -0,0 +1,32 @@
// +build windows
package libnetwork
import (
"github.com/docker/libnetwork/etchosts"
)
// Stub implementations for DNS related functions
func (sb *sandbox) startResolver() {
}
func (sb *sandbox) setupResolutionFiles() error {
return nil
}
func (sb *sandbox) updateHostsFile(ifaceIP string) error {
return nil
}
func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
}
func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
}
func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
return nil
}

Просмотреть файл

@ -1,4 +1,4 @@
// +build !windows
// +build linux freebsd
package libnetwork

Просмотреть файл

@ -14,6 +14,7 @@ func (c *controller) initStores() error {
return nil
}
scopeConfigs := c.cfg.Scopes
c.stores = nil
c.Unlock()
for scope, scfg := range scopeConfigs {
@ -418,6 +419,9 @@ func (c *controller) watchLoop() {
}
func (c *controller) startWatch() {
if c.watchCh != nil {
return
}
c.watchCh = make(chan *endpoint)
c.unWatchCh = make(chan *endpoint)
c.nmap = make(map[string]*netWatch)