mirror of https://github.com/docker/docs.git
commit
d02540a44a
|
@ -18,7 +18,7 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith
|
||||||
clone hg code.google.com/p/gosqlite 74691fb6f837
|
clone hg code.google.com/p/gosqlite 74691fb6f837
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
clone git github.com/docker/libnetwork 82a1f5634904b57e619fd715ded6903727e00143
|
clone git github.com/docker/libnetwork 4c14cd316f40f16bc1c17e420b18a1902dc575a7
|
||||||
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||||
|
|
|
@ -49,7 +49,7 @@ There are many networking solutions available to suit a broad range of use-cases
|
||||||
|
|
||||||
// A container can join the endpoint by providing the container ID to the join
|
// A container can join the endpoint by providing the container ID to the join
|
||||||
// api.
|
// api.
|
||||||
// Join acceps Variadic arguments which will be made use of by libnetwork and Drivers
|
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
|
||||||
err = ep.Join("container1",
|
err = ep.Join("container1",
|
||||||
libnetwork.JoinOptionHostname("test"),
|
libnetwork.JoinOptionHostname("test"),
|
||||||
libnetwork.JoinOptionDomainname("docker.io"))
|
libnetwork.JoinOptionDomainname("docker.io"))
|
||||||
|
@ -57,7 +57,7 @@ There are many networking solutions available to suit a broad range of use-cases
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// libentwork client can check the endpoint's operational data via the Info() API
|
// libnetwork client can check the endpoint's operational data via the Info() API
|
||||||
epInfo, err := ep.DriverInfo()
|
epInfo, err := ep.DriverInfo()
|
||||||
mapData, ok := epInfo[netlabel.PortMap]
|
mapData, ok := epInfo[netlabel.PortMap]
|
||||||
if ok {
|
if ok {
|
||||||
|
|
|
@ -28,6 +28,7 @@ type Handle struct {
|
||||||
app string
|
app string
|
||||||
id string
|
id string
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
|
dbExists bool
|
||||||
store datastore.DataStore
|
store datastore.DataStore
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
@ -54,18 +55,10 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
|
||||||
h.watchForChanges()
|
h.watchForChanges()
|
||||||
|
|
||||||
// Get the initial status from the ds if present.
|
// Get the initial status from the ds if present.
|
||||||
// We will be getting an instance without a dbIndex
|
err := h.store.GetObject(datastore.Key(h.Key()...), h)
|
||||||
// (GetObject() does not set it): It is ok for now,
|
|
||||||
// it will only cause the first allocation on this
|
|
||||||
// node to go through a retry.
|
|
||||||
var bah []byte
|
|
||||||
if err := h.store.GetObject(datastore.Key(h.Key()...), &bah); err != nil {
|
|
||||||
if err != datastore.ErrKeyNotFound {
|
if err != datastore.ErrKeyNotFound {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
err := h.FromByteArray(bah)
|
|
||||||
|
|
||||||
return h, err
|
return h, err
|
||||||
}
|
}
|
||||||
|
@ -199,7 +192,14 @@ func (h *Handle) CheckIfAvailable(ordinal int) (int, int, error) {
|
||||||
func (h *Handle) PushReservation(bytePos, bitPos int, release bool) error {
|
func (h *Handle) PushReservation(bytePos, bitPos int, release bool) error {
|
||||||
// Create a copy of the current handler
|
// Create a copy of the current handler
|
||||||
h.Lock()
|
h.Lock()
|
||||||
nh := &Handle{app: h.app, id: h.id, store: h.store, dbIndex: h.dbIndex, head: h.head.GetCopy()}
|
nh := &Handle{
|
||||||
|
app: h.app,
|
||||||
|
id: h.id,
|
||||||
|
store: h.store,
|
||||||
|
dbIndex: h.dbIndex,
|
||||||
|
head: h.head.GetCopy(),
|
||||||
|
dbExists: h.dbExists,
|
||||||
|
}
|
||||||
h.Unlock()
|
h.Unlock()
|
||||||
|
|
||||||
nh.head = PushReservation(bytePos, bitPos, nh.head, release)
|
nh.head = PushReservation(bytePos, bitPos, nh.head, release)
|
||||||
|
@ -214,7 +214,9 @@ func (h *Handle) PushReservation(bytePos, bitPos int, release bool) error {
|
||||||
} else {
|
} else {
|
||||||
h.unselected--
|
h.unselected--
|
||||||
}
|
}
|
||||||
h.dbIndex = nh.dbIndex
|
// Can't use SetIndex() since we're locked.
|
||||||
|
h.dbIndex = nh.Index()
|
||||||
|
h.dbExists = true
|
||||||
h.Unlock()
|
h.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,12 +278,6 @@ func (h *Handle) Unselected() uint32 {
|
||||||
return h.unselected
|
return h.unselected
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) getDBIndex() uint64 {
|
|
||||||
h.Lock()
|
|
||||||
defer h.Unlock()
|
|
||||||
return h.dbIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFirstAvailable looks for the first unset bit in passed mask
|
// GetFirstAvailable looks for the first unset bit in passed mask
|
||||||
func GetFirstAvailable(head *Sequence) (int, int, error) {
|
func GetFirstAvailable(head *Sequence) (int, int, error) {
|
||||||
byteIndex := 0
|
byteIndex := 0
|
||||||
|
|
|
@ -38,6 +38,11 @@ func (h *Handle) Value() []byte {
|
||||||
return jv
|
return jv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetValue unmarshals the data from the KV store
|
||||||
|
func (h *Handle) SetValue(value []byte) error {
|
||||||
|
return h.FromByteArray(value)
|
||||||
|
}
|
||||||
|
|
||||||
// Index returns the latest DB Index as seen by this object
|
// Index returns the latest DB Index as seen by this object
|
||||||
func (h *Handle) Index() uint64 {
|
func (h *Handle) Index() uint64 {
|
||||||
h.Lock()
|
h.Lock()
|
||||||
|
@ -49,9 +54,17 @@ func (h *Handle) Index() uint64 {
|
||||||
func (h *Handle) SetIndex(index uint64) {
|
func (h *Handle) SetIndex(index uint64) {
|
||||||
h.Lock()
|
h.Lock()
|
||||||
h.dbIndex = index
|
h.dbIndex = index
|
||||||
|
h.dbExists = true
|
||||||
h.Unlock()
|
h.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exists method is true if this object has been stored in the DB.
|
||||||
|
func (h *Handle) Exists() bool {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
return h.dbExists
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handle) watchForChanges() error {
|
func (h *Handle) watchForChanges() error {
|
||||||
h.Lock()
|
h.Lock()
|
||||||
store := h.store
|
store := h.store
|
||||||
|
@ -70,14 +83,12 @@ func (h *Handle) watchForChanges() error {
|
||||||
select {
|
select {
|
||||||
case kvPair := <-kvpChan:
|
case kvPair := <-kvpChan:
|
||||||
// Only process remote update
|
// Only process remote update
|
||||||
if kvPair != nil && (kvPair.LastIndex != h.getDBIndex()) {
|
if kvPair != nil && (kvPair.LastIndex != h.Index()) {
|
||||||
err := h.fromDsValue(kvPair.Value)
|
err := h.fromDsValue(kvPair.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Failed to reconstruct bitseq handle from ds watch: %s", err.Error())
|
log.Warnf("Failed to reconstruct bitseq handle from ds watch: %s", err.Error())
|
||||||
} else {
|
} else {
|
||||||
h.Lock()
|
h.SetIndex(kvPair.LastIndex)
|
||||||
h.dbIndex = kvPair.LastIndex
|
|
||||||
h.Unlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libnetwork/netlabel"
|
"github.com/docker/libnetwork/netlabel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,6 +58,7 @@ type Option func(c *Config)
|
||||||
// OptionDefaultNetwork function returns an option setter for a default network
|
// OptionDefaultNetwork function returns an option setter for a default network
|
||||||
func OptionDefaultNetwork(dn string) Option {
|
func OptionDefaultNetwork(dn string) Option {
|
||||||
return func(c *Config) {
|
return func(c *Config) {
|
||||||
|
log.Infof("Option DefaultNetwork: %s", dn)
|
||||||
c.Daemon.DefaultNetwork = strings.TrimSpace(dn)
|
c.Daemon.DefaultNetwork = strings.TrimSpace(dn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +66,7 @@ func OptionDefaultNetwork(dn string) Option {
|
||||||
// OptionDefaultDriver function returns an option setter for default driver
|
// OptionDefaultDriver function returns an option setter for default driver
|
||||||
func OptionDefaultDriver(dd string) Option {
|
func OptionDefaultDriver(dd string) Option {
|
||||||
return func(c *Config) {
|
return func(c *Config) {
|
||||||
|
log.Infof("Option DefaultDriver: %s", dd)
|
||||||
c.Daemon.DefaultDriver = strings.TrimSpace(dd)
|
c.Daemon.DefaultDriver = strings.TrimSpace(dd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +85,7 @@ func OptionLabels(labels []string) Option {
|
||||||
// OptionKVProvider function returns an option setter for kvstore provider
|
// OptionKVProvider function returns an option setter for kvstore provider
|
||||||
func OptionKVProvider(provider string) Option {
|
func OptionKVProvider(provider string) Option {
|
||||||
return func(c *Config) {
|
return func(c *Config) {
|
||||||
|
log.Infof("Option OptionKVProvider: %s", provider)
|
||||||
c.Datastore.Client.Provider = strings.TrimSpace(provider)
|
c.Datastore.Client.Provider = strings.TrimSpace(provider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,6 +93,7 @@ func OptionKVProvider(provider string) Option {
|
||||||
// OptionKVProviderURL function returns an option setter for kvstore url
|
// OptionKVProviderURL function returns an option setter for kvstore url
|
||||||
func OptionKVProviderURL(url string) Option {
|
func OptionKVProviderURL(url string) Option {
|
||||||
return func(c *Config) {
|
return func(c *Config) {
|
||||||
|
log.Infof("Option OptionKVProviderURL: %s", url)
|
||||||
c.Datastore.Client.Address = strings.TrimSpace(url)
|
c.Datastore.Client.Address = strings.TrimSpace(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ create network namespaces and allocate interfaces for containers to use.
|
||||||
|
|
||||||
// A container can join the endpoint by providing the container ID to the join
|
// A container can join the endpoint by providing the container ID to the join
|
||||||
// api.
|
// api.
|
||||||
// Join acceps Variadic arguments which will be made use of by libnetwork and Drivers
|
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
|
||||||
err = ep.Join("container1",
|
err = ep.Join("container1",
|
||||||
libnetwork.JoinOptionHostname("test"),
|
libnetwork.JoinOptionHostname("test"),
|
||||||
libnetwork.JoinOptionDomainname("docker.io"))
|
libnetwork.JoinOptionDomainname("docker.io"))
|
||||||
|
@ -262,6 +262,7 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.updateNetworkToStore(network); err != nil {
|
if err := c.updateNetworkToStore(network); err != nil {
|
||||||
|
log.Warnf("couldnt create network %s: %v", network.name, err)
|
||||||
if e := network.Delete(); e != nil {
|
if e := network.Delete(); e != nil {
|
||||||
log.Warnf("couldnt cleanup network %s: %v", network.name, err)
|
log.Warnf("couldnt cleanup network %s: %v", network.name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package datastore
|
package datastore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -14,9 +13,7 @@ import (
|
||||||
//DataStore exported
|
//DataStore exported
|
||||||
type DataStore interface {
|
type DataStore interface {
|
||||||
// GetObject gets data from datastore and unmarshals to the specified object
|
// GetObject gets data from datastore and unmarshals to the specified object
|
||||||
GetObject(key string, o interface{}) error
|
GetObject(key string, o KV) error
|
||||||
// GetUpdatedObject gets data from datastore along with its index and unmarshals to the specified object
|
|
||||||
GetUpdatedObject(key string, o interface{}) (uint64, error)
|
|
||||||
// PutObject adds a new Record based on an object into the datastore
|
// PutObject adds a new Record based on an object into the datastore
|
||||||
PutObject(kvObject KV) error
|
PutObject(kvObject KV) error
|
||||||
// PutObjectAtomic provides an atomic add and update operation for a Record
|
// PutObjectAtomic provides an atomic add and update operation for a Record
|
||||||
|
@ -49,10 +46,15 @@ type KV interface {
|
||||||
KeyPrefix() []string
|
KeyPrefix() []string
|
||||||
// Value method lets an object to marshal its content to be stored in the KV store
|
// Value method lets an object to marshal its content to be stored in the KV store
|
||||||
Value() []byte
|
Value() []byte
|
||||||
|
// SetValue is used by the datastore to set the object's value when loaded from the data store.
|
||||||
|
SetValue([]byte) error
|
||||||
// Index method returns the latest DB Index as seen by the object
|
// Index method returns the latest DB Index as seen by the object
|
||||||
Index() uint64
|
Index() uint64
|
||||||
// SetIndex method allows the datastore to store the latest DB Index into the object
|
// SetIndex method allows the datastore to store the latest DB Index into the object
|
||||||
SetIndex(uint64)
|
SetIndex(uint64)
|
||||||
|
// True if the object exists in the datastore, false if it hasn't been stored yet.
|
||||||
|
// When SetIndex() is called, the object has been stored.
|
||||||
|
Exists() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -121,7 +123,12 @@ func (ds *datastore) PutObjectAtomic(kvObject KV) error {
|
||||||
return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
|
return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
|
||||||
}
|
}
|
||||||
|
|
||||||
previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
|
var previous *store.KVPair
|
||||||
|
if kvObject.Exists() {
|
||||||
|
previous = &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
|
||||||
|
} else {
|
||||||
|
previous = nil
|
||||||
|
}
|
||||||
_, pair, err := ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
|
_, pair, err := ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -149,24 +156,20 @@ func (ds *datastore) putObjectWithKey(kvObject KV, key ...string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetObject returns a record matching the key
|
// GetObject returns a record matching the key
|
||||||
func (ds *datastore) GetObject(key string, o interface{}) error {
|
func (ds *datastore) GetObject(key string, o KV) error {
|
||||||
kvPair, err := ds.store.Get(key)
|
kvPair, err := ds.store.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return json.Unmarshal(kvPair.Value, o)
|
err = o.SetValue(kvPair.Value)
|
||||||
}
|
|
||||||
|
|
||||||
// GetUpdateObject returns a record matching the key
|
|
||||||
func (ds *datastore) GetUpdatedObject(key string, o interface{}) (uint64, error) {
|
|
||||||
kvPair, err := ds.store.Get(key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(kvPair.Value, o); err != nil {
|
|
||||||
return 0, err
|
// Make sure the object has a correct view of the DB index in case we need to modify it
|
||||||
}
|
// and update the DB.
|
||||||
return kvPair.LastIndex, nil
|
o.SetIndex(kvPair.LastIndex)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteObject unconditionally deletes a record from the store
|
// DeleteObject unconditionally deletes a record from the store
|
||||||
|
|
|
@ -93,8 +93,18 @@ func (s *MockStore) NewLock(key string, options *store.LockOptions) (store.Locke
|
||||||
// modified in the meantime, throws an error if this is the case
|
// modified in the meantime, throws an error if this is the case
|
||||||
func (s *MockStore) AtomicPut(key string, newValue []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
func (s *MockStore) AtomicPut(key string, newValue []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
||||||
mData := s.db[key]
|
mData := s.db[key]
|
||||||
|
|
||||||
|
if previous == nil {
|
||||||
|
if mData != nil {
|
||||||
|
return false, nil, types.BadRequestErrorf("atomic put failed because key exists")
|
||||||
|
} // Else OK.
|
||||||
|
} else {
|
||||||
|
if mData == nil {
|
||||||
|
return false, nil, types.BadRequestErrorf("atomic put failed because key exists")
|
||||||
|
}
|
||||||
if mData != nil && mData.Index != previous.LastIndex {
|
if mData != nil && mData.Index != previous.LastIndex {
|
||||||
return false, nil, types.BadRequestErrorf("atomic put failed due to mismatched Index")
|
return false, nil, types.BadRequestErrorf("atomic put failed due to mismatched Index")
|
||||||
|
} // Else OK.
|
||||||
}
|
}
|
||||||
err := s.Put(key, newValue, nil)
|
err := s.Put(key, newValue, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -108,8 +108,11 @@ func newDriver() driverapi.Driver {
|
||||||
func Init(dc driverapi.DriverCallback) error {
|
func Init(dc driverapi.DriverCallback) error {
|
||||||
// try to modprobe bridge first
|
// try to modprobe bridge first
|
||||||
// see gh#12177
|
// see gh#12177
|
||||||
if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil {
|
if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").CombinedOutput(); err != nil {
|
||||||
logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
|
logrus.Warnf("Running modprobe bridge nf_nat br_netfilter failed with message: %s, error: %v", out, err)
|
||||||
|
}
|
||||||
|
if err := iptables.FirewalldInit(); err != nil {
|
||||||
|
logrus.Debugf("Fail to initialize firewalld: %v, using raw iptables instead", err)
|
||||||
}
|
}
|
||||||
if err := iptables.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
|
if err := iptables.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
|
||||||
logrus.Warnf("Failed to remove existing iptables entries in %s : %v", DockerChain, err)
|
logrus.Warnf("Failed to remove existing iptables entries in %s : %v", DockerChain, err)
|
||||||
|
@ -453,7 +456,7 @@ func (d *driver) getNetwork(id types.UUID) (*bridgeNetwork, error) {
|
||||||
return nw, nil
|
return nw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, types.NotFoundErrorf("network not found: %s", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) {
|
func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ type network struct {
|
||||||
id types.UUID
|
id types.UUID
|
||||||
vni uint32
|
vni uint32
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
|
dbExists bool
|
||||||
sbox sandbox.Sandbox
|
sbox sandbox.Sandbox
|
||||||
endpoints endpointTable
|
endpoints endpointTable
|
||||||
ipAllocator *ipallocator.IPAllocator
|
ipAllocator *ipallocator.IPAllocator
|
||||||
|
@ -260,6 +261,20 @@ func (n *network) Index() uint64 {
|
||||||
|
|
||||||
func (n *network) SetIndex(index uint64) {
|
func (n *network) SetIndex(index uint64) {
|
||||||
n.dbIndex = index
|
n.dbIndex = index
|
||||||
|
n.dbExists = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *network) Exists() bool {
|
||||||
|
return n.dbExists
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *network) SetValue(value []byte) error {
|
||||||
|
var vni uint32
|
||||||
|
err := json.Unmarshal(value, &vni)
|
||||||
|
if err == nil {
|
||||||
|
n.setVxlanID(vni)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) writeToStore() error {
|
func (n *network) writeToStore() error {
|
||||||
|
@ -297,8 +312,7 @@ func (n *network) obtainVxlanID() error {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var vxlanID uint32
|
var vxlanID uint32
|
||||||
if err := n.driver.store.GetObject(datastore.Key(n.Key()...),
|
if err := n.driver.store.GetObject(datastore.Key(n.Key()...), n); err != nil {
|
||||||
&vxlanID); err != nil {
|
|
||||||
if err == datastore.ErrKeyNotFound {
|
if err == datastore.ErrKeyNotFound {
|
||||||
vxlanID, err = n.driver.vxlanIdm.GetID()
|
vxlanID, err = n.driver.vxlanIdm.GetID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -318,8 +332,6 @@ func (n *network) obtainVxlanID() error {
|
||||||
}
|
}
|
||||||
return fmt.Errorf("failed to obtain vxlan id from data store: %v", err)
|
return fmt.Errorf("failed to obtain vxlan id from data store: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
n.setVxlanID(vxlanID)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,9 @@ type Endpoint interface {
|
||||||
|
|
||||||
// Delete and detaches this endpoint from the network.
|
// Delete and detaches this endpoint from the network.
|
||||||
Delete() error
|
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
|
// EndpointOption is a option setter function type used to pass varios options to Network
|
||||||
|
@ -124,6 +127,7 @@ type endpoint struct {
|
||||||
generic map[string]interface{}
|
generic map[string]interface{}
|
||||||
joinLeaveDone chan struct{}
|
joinLeaveDone chan struct{}
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
|
dbExists bool
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +245,7 @@ func (ep *endpoint) KeyPrefix() []string {
|
||||||
|
|
||||||
func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) {
|
func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) {
|
||||||
// endpoint Key structure : endpoint/network-id/endpoint-id
|
// endpoint Key structure : endpoint/network-id/endpoint-id
|
||||||
// its an invalid key if the key doesnt have all the 3 key elements above
|
// 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 {
|
if key == nil || len(key) < 3 || key[0] != datastore.EndpointKeyPrefix {
|
||||||
return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key)
|
return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key)
|
||||||
}
|
}
|
||||||
|
@ -258,6 +262,10 @@ func (ep *endpoint) Value() []byte {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ep *endpoint) SetValue(value []byte) error {
|
||||||
|
return json.Unmarshal(value, ep)
|
||||||
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Index() uint64 {
|
func (ep *endpoint) Index() uint64 {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
defer ep.Unlock()
|
defer ep.Unlock()
|
||||||
|
@ -268,6 +276,13 @@ func (ep *endpoint) SetIndex(index uint64) {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
defer ep.Unlock()
|
defer ep.Unlock()
|
||||||
ep.dbIndex = index
|
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) {
|
func (ep *endpoint) processOptions(options ...EndpointOption) {
|
||||||
|
@ -545,6 +560,33 @@ func (ep *endpoint) Delete() error {
|
||||||
return nil
|
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 {
|
func (ep *endpoint) deleteEndpoint() error {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
n := ep.network
|
n := ep.network
|
||||||
|
|
|
@ -67,6 +67,7 @@ type network struct {
|
||||||
generic options.Generic
|
generic options.Generic
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
svcRecords svcMap
|
svcRecords svcMap
|
||||||
|
dbExists bool
|
||||||
stopWatchCh chan struct{}
|
stopWatchCh chan struct{}
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
@ -116,6 +117,10 @@ func (n *network) Value() []byte {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *network) SetValue(value []byte) error {
|
||||||
|
return json.Unmarshal(value, n)
|
||||||
|
}
|
||||||
|
|
||||||
func (n *network) Index() uint64 {
|
func (n *network) Index() uint64 {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
@ -125,9 +130,16 @@ func (n *network) Index() uint64 {
|
||||||
func (n *network) SetIndex(index uint64) {
|
func (n *network) SetIndex(index uint64) {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
n.dbIndex = index
|
n.dbIndex = index
|
||||||
|
n.dbExists = true
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *network) Exists() bool {
|
||||||
|
n.Lock()
|
||||||
|
defer n.Unlock()
|
||||||
|
return n.dbExists
|
||||||
|
}
|
||||||
|
|
||||||
func (n *network) EndpointCnt() uint64 {
|
func (n *network) EndpointCnt() uint64 {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
@ -292,7 +304,9 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
||||||
return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
|
return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})}
|
ep := &endpoint{name: name,
|
||||||
|
iFaces: []*endpointInterface{},
|
||||||
|
generic: make(map[string]interface{})}
|
||||||
ep.id = types.UUID(stringid.GenerateRandomID())
|
ep.id = types.UUID(stringid.GenerateRandomID())
|
||||||
ep.network = n
|
ep.network = n
|
||||||
ep.processOptions(options...)
|
ep.processOptions(options...)
|
||||||
|
|
|
@ -3,6 +3,8 @@ package sandbox
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
|
@ -153,6 +155,36 @@ func (i *nwIface) Remove() error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the sandbox's side veth interface statistics
|
||||||
|
func (i *nwIface) Statistics() (*InterfaceStatistics, error) {
|
||||||
|
i.Lock()
|
||||||
|
n := i.ns
|
||||||
|
i.Unlock()
|
||||||
|
|
||||||
|
n.Lock()
|
||||||
|
path := n.path
|
||||||
|
n.Unlock()
|
||||||
|
|
||||||
|
s := &InterfaceStatistics{}
|
||||||
|
|
||||||
|
err := nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
|
||||||
|
// For some reason ioutil.ReadFile(netStatsFile) reads the file in
|
||||||
|
// the default netns when this code is invoked from docker.
|
||||||
|
// Executing "cat <netStatsFile>" works as expected.
|
||||||
|
data, err := exec.Command("cat", netStatsFile).Output()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failure opening %s: %v", netStatsFile, err)
|
||||||
|
}
|
||||||
|
return scanInterfaceStats(string(data), i.DstName(), s)
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
|
func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
@ -311,3 +343,28 @@ func setInterfaceRoutes(iface netlink.Link, i *nwIface) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In older kernels (like the one in Centos 6.6 distro) sysctl does not have netns support. Therefore
|
||||||
|
// we cannot gather the statistics from /sys/class/net/<dev>/statistics/<counter> files. Per-netns stats
|
||||||
|
// are naturally found in /proc/net/dev in kernels which support netns (ifconfig relyes on that).
|
||||||
|
const (
|
||||||
|
netStatsFile = "/proc/net/dev"
|
||||||
|
base = "[ ]*%s:([ ]+[0-9]+){16}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func scanInterfaceStats(data, ifName string, i *InterfaceStatistics) error {
|
||||||
|
var (
|
||||||
|
bktStr string
|
||||||
|
bkt uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
regex := fmt.Sprintf(base, ifName)
|
||||||
|
re := regexp.MustCompile(regex)
|
||||||
|
line := re.FindString(data)
|
||||||
|
|
||||||
|
_, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
|
||||||
|
&bktStr, &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &bkt, &bkt, &bkt,
|
||||||
|
&bkt, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, &bkt, &bkt, &bkt, &bkt)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
|
@ -146,4 +147,24 @@ type Interface interface {
|
||||||
// Remove an interface from the sandbox by renaming to original name
|
// Remove an interface from the sandbox by renaming to original name
|
||||||
// and moving it out of the sandbox.
|
// and moving it out of the sandbox.
|
||||||
Remove() error
|
Remove() error
|
||||||
|
|
||||||
|
// Statistics returns the statistics for this interface
|
||||||
|
Statistics() (*InterfaceStatistics, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceStatistics represents the interface's statistics
|
||||||
|
type InterfaceStatistics struct {
|
||||||
|
RxBytes uint64
|
||||||
|
RxPackets uint64
|
||||||
|
RxErrors uint64
|
||||||
|
RxDropped uint64
|
||||||
|
TxBytes uint64
|
||||||
|
TxPackets uint64
|
||||||
|
TxErrors uint64
|
||||||
|
TxDropped uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *InterfaceStatistics) String() string {
|
||||||
|
return fmt.Sprintf("\nRxBytes: %d, RxPackets: %d, RxErrors: %d, RxDropped: %d, TxBytes: %d, TxPackets: %d, TxErrors: %d, TxDropped: %d",
|
||||||
|
is.RxBytes, is.RxPackets, is.RxErrors, is.RxDropped, is.TxBytes, is.TxPackets, is.TxErrors, is.TxDropped)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *controller) validateDatastoreConfig() bool {
|
func (c *controller) validateDatastoreConfig() bool {
|
||||||
if c.cfg == nil || c.cfg.Datastore.Client.Provider == "" || c.cfg.Datastore.Client.Address == "" {
|
return c.cfg != nil && c.cfg.Datastore.Client.Provider != "" && c.cfg.Datastore.Client.Address != ""
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) initDataStore() error {
|
func (c *controller) initDataStore() error {
|
||||||
|
@ -197,6 +194,7 @@ func (c *controller) watchNetworks() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.processNetworkUpdate(nws, &tmpview)
|
c.processNetworkUpdate(nws, &tmpview)
|
||||||
|
|
||||||
// Delete processing
|
// Delete processing
|
||||||
for k := range tmpview {
|
for k := range tmpview {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
|
@ -259,7 +257,7 @@ func (n *network) watchEndpoints() error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
delete(tmpview, ep.id)
|
delete(tmpview, ep.id)
|
||||||
ep.dbIndex = epe.LastIndex
|
ep.SetIndex(epe.LastIndex)
|
||||||
ep.network = n
|
ep.network = n
|
||||||
if n.ctrlr.processEndpointUpdate(&ep) {
|
if n.ctrlr.processEndpointUpdate(&ep) {
|
||||||
err = n.ctrlr.newEndpointFromStore(epe.Key, &ep)
|
err = n.ctrlr.newEndpointFromStore(epe.Key, &ep)
|
||||||
|
@ -310,15 +308,17 @@ func (c *controller) processNetworkUpdate(nws []*store.KVPair, prune *networkTab
|
||||||
if prune != nil {
|
if prune != nil {
|
||||||
delete(*prune, n.id)
|
delete(*prune, n.id)
|
||||||
}
|
}
|
||||||
n.dbIndex = kve.LastIndex
|
n.SetIndex(kve.LastIndex)
|
||||||
c.Lock()
|
c.Lock()
|
||||||
existing, ok := c.networks[n.id]
|
existing, ok := c.networks[n.id]
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
if ok {
|
if ok {
|
||||||
existing.Lock()
|
existing.Lock()
|
||||||
// Skip existing network update
|
// Skip existing network update
|
||||||
if existing.dbIndex != n.dbIndex {
|
if existing.dbIndex != n.Index() {
|
||||||
existing.dbIndex = n.dbIndex
|
// Can't use SetIndex() since existing is locked.
|
||||||
|
existing.dbIndex = n.Index()
|
||||||
|
existing.dbExists = true
|
||||||
existing.endpointCnt = n.endpointCnt
|
existing.endpointCnt = n.endpointCnt
|
||||||
}
|
}
|
||||||
existing.Unlock()
|
existing.Unlock()
|
||||||
|
@ -353,8 +353,10 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool {
|
||||||
|
|
||||||
ee := existing.(*endpoint)
|
ee := existing.(*endpoint)
|
||||||
ee.Lock()
|
ee.Lock()
|
||||||
if ee.dbIndex != ep.dbIndex {
|
if ee.dbIndex != ep.Index() {
|
||||||
ee.dbIndex = ep.dbIndex
|
// Can't use SetIndex() because ee is locked.
|
||||||
|
ee.dbIndex = ep.Index()
|
||||||
|
ee.dbExists = true
|
||||||
if ee.container != nil && ep.container != nil {
|
if ee.container != nil && ep.container != nil {
|
||||||
// we care only about the container id
|
// we care only about the container id
|
||||||
ee.container.id = ep.container.id
|
ee.container.id = ep.container.id
|
||||||
|
|
Loading…
Reference in New Issue