Merge pull request #1225 from puneetpruthi/solaris_integ
libnetwork support for docker on Solaris
This commit is contained in:
commit
9dce786794
27 changed files with 4023 additions and 1089 deletions
|
@ -8,6 +8,14 @@ ciargs = -e CIRCLECI -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=
|
|||
cidocker = docker run ${dockerargs} ${ciargs} $$EXTRA_ARGS ${container_env} ${build_image}
|
||||
CROSS_PLATFORMS = linux/amd64 linux/386 linux/arm windows/amd64
|
||||
export PATH := $(CURDIR)/bin:$(PATH)
|
||||
hostOS = ${shell go env GOHOSTOS}
|
||||
ifeq (${hostOS}, solaris)
|
||||
gnufind=gfind
|
||||
gnutail=gtail
|
||||
else
|
||||
gnufind=find
|
||||
gnutail=tail
|
||||
endif
|
||||
|
||||
all: ${build_image}.created build check integration-tests clean
|
||||
|
||||
|
@ -62,7 +70,40 @@ check-format:
|
|||
run-tests:
|
||||
@echo "Running tests... "
|
||||
@echo "mode: count" > coverage.coverprofile
|
||||
@for dir in $$(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); do \
|
||||
@for dir in $$( ${gnufind} . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); do \
|
||||
if [ ${hostOS} == solaris ]; then \
|
||||
case "$$dir" in \
|
||||
"./cmd/dnet" ) \
|
||||
;& \
|
||||
"./cmd/ovrouter" ) \
|
||||
;& \
|
||||
"./ns" ) \
|
||||
;& \
|
||||
"./iptables" ) \
|
||||
;& \
|
||||
"./ipvs" ) \
|
||||
;& \
|
||||
"./drivers/bridge" ) \
|
||||
;& \
|
||||
"./drivers/host" ) \
|
||||
;& \
|
||||
"./drivers/ipvlan" ) \
|
||||
;& \
|
||||
"./drivers/macvlan" ) \
|
||||
;& \
|
||||
"./drivers/overlay" ) \
|
||||
;& \
|
||||
"./drivers/remote" ) \
|
||||
;& \
|
||||
"./drivers/windows" ) \
|
||||
echo "Skipping $$dir on solaris host... "; \
|
||||
continue; \
|
||||
;; \
|
||||
* )\
|
||||
echo "Entering $$dir ... "; \
|
||||
;; \
|
||||
esac; \
|
||||
fi; \
|
||||
if ls $$dir/*.go &> /dev/null; then \
|
||||
pushd . &> /dev/null ; \
|
||||
cd $$dir ; \
|
||||
|
@ -71,7 +112,7 @@ run-tests:
|
|||
if [ $$ret -ne 0 ]; then exit $$ret; fi ;\
|
||||
popd &> /dev/null; \
|
||||
if [ -f $$dir/profile.tmp ]; then \
|
||||
cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \
|
||||
cat $$dir/profile.tmp | ${gnutail} -n +2 >> coverage.coverprofile ; \
|
||||
rm $$dir/profile.tmp ; \
|
||||
fi ; \
|
||||
fi ; \
|
||||
|
|
18
libnetwork/api/api_linux_test.go
Normal file
18
libnetwork/api/api_linux_test.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/docker/libnetwork/drivers/bridge"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
)
|
||||
|
||||
func GetOpsMap(bridgeName, defaultMTU string) map[string]string {
|
||||
if defaultMTU == "" {
|
||||
return map[string]string{
|
||||
bridge.BridgeName: bridgeName,
|
||||
}
|
||||
}
|
||||
return map[string]string{
|
||||
bridge.BridgeName: bridgeName,
|
||||
netlabel.DriverMTU: defaultMTU,
|
||||
}
|
||||
}
|
18
libnetwork/api/api_solaris_test.go
Normal file
18
libnetwork/api/api_solaris_test.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/docker/libnetwork/drivers/solaris/bridge"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
)
|
||||
|
||||
func GetOpsMap(bridgeName, defaultMTU string) map[string]string {
|
||||
if defaultMTU == "" {
|
||||
return map[string]string{
|
||||
bridge.BridgeName: bridgeName,
|
||||
}
|
||||
}
|
||||
return map[string]string{
|
||||
bridge.BridgeName: bridgeName,
|
||||
netlabel.DriverMTU: defaultMTU,
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@ import (
|
|||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/drivers/bridge"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/options"
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
|
@ -225,9 +224,7 @@ func TestCreateDeleteNetwork(t *testing.T) {
|
|||
t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp)
|
||||
}
|
||||
|
||||
dops := map[string]string{
|
||||
bridge.BridgeName: "abc",
|
||||
}
|
||||
dops := GetOpsMap("abc", "")
|
||||
nops := map[string]string{
|
||||
netlabel.EnableIPv6: "true",
|
||||
}
|
||||
|
@ -273,9 +270,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
|||
}
|
||||
defer c.Stop()
|
||||
|
||||
ops := map[string]string{
|
||||
bridge.BridgeName: "api_test_nw",
|
||||
}
|
||||
ops := GetOpsMap("api_test_nw", "")
|
||||
nc := networkCreate{Name: "sh", NetworkType: bridgeNetType, DriverOpts: ops}
|
||||
body, err := json.Marshal(nc)
|
||||
if err != nil {
|
||||
|
@ -544,7 +539,7 @@ func TestProcGetServices(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
netName2 := "work-dev"
|
||||
netName2 := "workdev"
|
||||
netOption = options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": netName2,
|
||||
|
@ -1811,10 +1806,7 @@ func TestEndToEnd(t *testing.T) {
|
|||
|
||||
handleRequest := NewHTTPHandler(c)
|
||||
|
||||
dops := map[string]string{
|
||||
bridge.BridgeName: "cdef",
|
||||
netlabel.DriverMTU: "1460",
|
||||
}
|
||||
dops := GetOpsMap("cdef", "1460")
|
||||
nops := map[string]string{
|
||||
netlabel.EnableIPv6: "true",
|
||||
}
|
||||
|
|
1254
libnetwork/drivers/solaris/bridge/bridge.go
Normal file
1254
libnetwork/drivers/solaris/bridge/bridge.go
Normal file
File diff suppressed because it is too large
Load diff
384
libnetwork/drivers/solaris/bridge/bridge_store.go
Normal file
384
libnetwork/drivers/solaris/bridge/bridge_store.go
Normal file
|
@ -0,0 +1,384 @@
|
|||
// +build solaris
|
||||
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// network config prefix was not specific enough.
|
||||
// To be backward compatible, need custom endpoint
|
||||
// prefix with different root
|
||||
bridgePrefix = "bridge"
|
||||
bridgeEndpointPrefix = "bridge-endpoint"
|
||||
)
|
||||
|
||||
func (d *driver) initStore(option map[string]interface{}) error {
|
||||
if data, ok := option[netlabel.LocalKVClient]; ok {
|
||||
var err error
|
||||
dsc, ok := data.(discoverapi.DatastoreConfigData)
|
||||
if !ok {
|
||||
return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
|
||||
}
|
||||
d.store, err = datastore.NewDataStoreFromConfig(dsc)
|
||||
if err != nil {
|
||||
return types.InternalErrorf("bridge driver failed to initialize data store: %v", err)
|
||||
}
|
||||
|
||||
err = d.populateNetworks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = d.populateEndpoints()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) populateNetworks() error {
|
||||
kvol, err := d.store.List(datastore.Key(bridgePrefix), &networkConfiguration{})
|
||||
if err != nil && err != datastore.ErrKeyNotFound {
|
||||
return fmt.Errorf("failed to get bridge network configurations from store: %v", err)
|
||||
}
|
||||
|
||||
// It's normal for network configuration state to be empty. Just return.
|
||||
if err == datastore.ErrKeyNotFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, kvo := range kvol {
|
||||
ncfg := kvo.(*networkConfiguration)
|
||||
if err = d.createNetwork(ncfg); err != nil {
|
||||
logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state: %v", ncfg.ID, ncfg.BridgeName, err)
|
||||
}
|
||||
logrus.Debugf("Network (%s) restored", ncfg.ID[0:7])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) populateEndpoints() error {
|
||||
kvol, err := d.store.List(datastore.Key(bridgeEndpointPrefix), &bridgeEndpoint{})
|
||||
if err != nil && err != datastore.ErrKeyNotFound {
|
||||
return fmt.Errorf("failed to get bridge endpoints from store: %v", err)
|
||||
}
|
||||
|
||||
if err == datastore.ErrKeyNotFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, kvo := range kvol {
|
||||
ep := kvo.(*bridgeEndpoint)
|
||||
n, ok := d.networks[ep.nid]
|
||||
if !ok {
|
||||
logrus.Debugf("Network (%s) not found for restored bridge endpoint (%s)", ep.nid[0:7], ep.id[0:7])
|
||||
logrus.Debugf("Deleting stale bridge endpoint (%s) from store", ep.nid[0:7])
|
||||
if err := d.storeDelete(ep); err != nil {
|
||||
logrus.Debugf("Failed to delete stale bridge endpoint (%s) from store", ep.nid[0:7])
|
||||
}
|
||||
continue
|
||||
}
|
||||
n.endpoints[ep.id] = ep
|
||||
n.restorePortAllocations(ep)
|
||||
logrus.Debugf("Endpoint (%s) restored to network (%s)", ep.id[0:7], ep.nid[0:7])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) storeUpdate(kvObject datastore.KVObject) error {
|
||||
if d.store == nil {
|
||||
logrus.Warnf("bridge store not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...))
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := d.store.PutObjectAtomic(kvObject); err != nil {
|
||||
return fmt.Errorf("failed to update bridge store for object type %T: %v", kvObject, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) storeDelete(kvObject datastore.KVObject) error {
|
||||
if d.store == nil {
|
||||
logrus.Debugf("bridge store not initialized. kv object %s is not deleted from store", datastore.Key(kvObject.Key()...))
|
||||
return nil
|
||||
}
|
||||
|
||||
retry:
|
||||
if err := d.store.DeleteObjectAtomic(kvObject); err != nil {
|
||||
if err == datastore.ErrKeyModified {
|
||||
if err := d.store.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
|
||||
return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
|
||||
}
|
||||
goto retry
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) {
|
||||
nMap := make(map[string]interface{})
|
||||
nMap["ID"] = ncfg.ID
|
||||
nMap["BridgeName"] = ncfg.BridgeName
|
||||
nMap["BridgeNameInternal"] = ncfg.BridgeNameInternal
|
||||
nMap["EnableIPv6"] = ncfg.EnableIPv6
|
||||
nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade
|
||||
nMap["EnableICC"] = ncfg.EnableICC
|
||||
nMap["Mtu"] = ncfg.Mtu
|
||||
nMap["Internal"] = ncfg.Internal
|
||||
nMap["DefaultBridge"] = ncfg.DefaultBridge
|
||||
nMap["DefaultBindingIP"] = ncfg.DefaultBindingIP.String()
|
||||
nMap["DefaultBindingIntf"] = ncfg.DefaultBindingIntf
|
||||
nMap["DefaultGatewayIPv4"] = ncfg.DefaultGatewayIPv4.String()
|
||||
nMap["DefaultGatewayIPv6"] = ncfg.DefaultGatewayIPv6.String()
|
||||
|
||||
if ncfg.AddressIPv4 != nil {
|
||||
nMap["AddressIPv4"] = ncfg.AddressIPv4.String()
|
||||
}
|
||||
|
||||
if ncfg.AddressIPv6 != nil {
|
||||
nMap["AddressIPv6"] = ncfg.AddressIPv6.String()
|
||||
}
|
||||
|
||||
return json.Marshal(nMap)
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error {
|
||||
var (
|
||||
err error
|
||||
nMap map[string]interface{}
|
||||
)
|
||||
|
||||
if err = json.Unmarshal(b, &nMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v, ok := nMap["AddressIPv4"]; ok {
|
||||
if ncfg.AddressIPv4, err = types.ParseCIDR(v.(string)); err != nil {
|
||||
return types.InternalErrorf("failed to decode bridge network address IPv4 after json unmarshal: %s", v.(string))
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := nMap["AddressIPv6"]; ok {
|
||||
if ncfg.AddressIPv6, err = types.ParseCIDR(v.(string)); err != nil {
|
||||
return types.InternalErrorf("failed to decode bridge network address IPv6 after json unmarshal: %s", v.(string))
|
||||
}
|
||||
}
|
||||
|
||||
ncfg.DefaultBridge = nMap["DefaultBridge"].(bool)
|
||||
ncfg.DefaultBindingIP = net.ParseIP(nMap["DefaultBindingIP"].(string))
|
||||
ncfg.DefaultBindingIntf = nMap["DefaultBindingIntf"].(string)
|
||||
ncfg.DefaultGatewayIPv4 = net.ParseIP(nMap["DefaultGatewayIPv4"].(string))
|
||||
ncfg.DefaultGatewayIPv6 = net.ParseIP(nMap["DefaultGatewayIPv6"].(string))
|
||||
ncfg.ID = nMap["ID"].(string)
|
||||
ncfg.BridgeName = nMap["BridgeName"].(string)
|
||||
ncfg.BridgeNameInternal = nMap["BridgeNameInternal"].(string)
|
||||
ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool)
|
||||
ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool)
|
||||
ncfg.EnableICC = nMap["EnableICC"].(bool)
|
||||
ncfg.Mtu = int(nMap["Mtu"].(float64))
|
||||
if v, ok := nMap["Internal"]; ok {
|
||||
ncfg.Internal = v.(bool)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Key() []string {
|
||||
return []string{bridgePrefix, ncfg.ID}
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) KeyPrefix() []string {
|
||||
return []string{bridgePrefix}
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Value() []byte {
|
||||
b, err := json.Marshal(ncfg)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) SetValue(value []byte) error {
|
||||
return json.Unmarshal(value, ncfg)
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Index() uint64 {
|
||||
return ncfg.dbIndex
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) SetIndex(index uint64) {
|
||||
ncfg.dbIndex = index
|
||||
ncfg.dbExists = true
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Exists() bool {
|
||||
return ncfg.dbExists
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Skip() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) New() datastore.KVObject {
|
||||
return &networkConfiguration{}
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) CopyTo(o datastore.KVObject) error {
|
||||
dstNcfg := o.(*networkConfiguration)
|
||||
*dstNcfg = *ncfg
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) DataScope() string {
|
||||
return datastore.LocalScope
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) MarshalJSON() ([]byte, error) {
|
||||
epMap := make(map[string]interface{})
|
||||
epMap["id"] = ep.id
|
||||
epMap["nid"] = ep.nid
|
||||
epMap["SrcName"] = ep.srcName
|
||||
epMap["MacAddress"] = ep.macAddress.String()
|
||||
epMap["Addr"] = ep.addr.String()
|
||||
if ep.addrv6 != nil {
|
||||
epMap["Addrv6"] = ep.addrv6.String()
|
||||
}
|
||||
epMap["Config"] = ep.config
|
||||
epMap["ContainerConfig"] = ep.containerConfig
|
||||
epMap["ExternalConnConfig"] = ep.extConnConfig
|
||||
epMap["PortMapping"] = ep.portMapping
|
||||
|
||||
return json.Marshal(epMap)
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) UnmarshalJSON(b []byte) error {
|
||||
var (
|
||||
err error
|
||||
epMap map[string]interface{}
|
||||
)
|
||||
|
||||
if err = json.Unmarshal(b, &epMap); err != nil {
|
||||
return fmt.Errorf("Failed to unmarshal to bridge endpoint: %v", err)
|
||||
}
|
||||
|
||||
if v, ok := epMap["MacAddress"]; ok {
|
||||
if ep.macAddress, err = net.ParseMAC(v.(string)); err != nil {
|
||||
return types.InternalErrorf("failed to decode bridge endpoint MAC address (%s) after json unmarshal: %v", v.(string), err)
|
||||
}
|
||||
}
|
||||
if v, ok := epMap["Addr"]; ok {
|
||||
if ep.addr, err = types.ParseCIDR(v.(string)); err != nil {
|
||||
return types.InternalErrorf("failed to decode bridge endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
|
||||
}
|
||||
}
|
||||
if v, ok := epMap["Addrv6"]; ok {
|
||||
if ep.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
|
||||
return types.InternalErrorf("failed to decode bridge endpoint IPv6 address (%s) after json unmarshal: %v", v.(string), err)
|
||||
}
|
||||
}
|
||||
ep.id = epMap["id"].(string)
|
||||
ep.nid = epMap["nid"].(string)
|
||||
ep.srcName = epMap["SrcName"].(string)
|
||||
d, _ := json.Marshal(epMap["Config"])
|
||||
if err := json.Unmarshal(d, &ep.config); err != nil {
|
||||
logrus.Warnf("Failed to decode endpoint config %v", err)
|
||||
}
|
||||
d, _ = json.Marshal(epMap["ContainerConfig"])
|
||||
if err := json.Unmarshal(d, &ep.containerConfig); err != nil {
|
||||
logrus.Warnf("Failed to decode endpoint container config %v", err)
|
||||
}
|
||||
d, _ = json.Marshal(epMap["ExternalConnConfig"])
|
||||
if err := json.Unmarshal(d, &ep.extConnConfig); err != nil {
|
||||
logrus.Warnf("Failed to decode endpoint external connectivity configuration %v", err)
|
||||
}
|
||||
d, _ = json.Marshal(epMap["PortMapping"])
|
||||
if err := json.Unmarshal(d, &ep.portMapping); err != nil {
|
||||
logrus.Warnf("Failed to decode endpoint port mapping %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) Key() []string {
|
||||
return []string{bridgeEndpointPrefix, ep.id}
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) KeyPrefix() []string {
|
||||
return []string{bridgeEndpointPrefix}
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) Value() []byte {
|
||||
b, err := json.Marshal(ep)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) SetValue(value []byte) error {
|
||||
return json.Unmarshal(value, ep)
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) Index() uint64 {
|
||||
return ep.dbIndex
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) SetIndex(index uint64) {
|
||||
ep.dbIndex = index
|
||||
ep.dbExists = true
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) Exists() bool {
|
||||
return ep.dbExists
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) Skip() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) New() datastore.KVObject {
|
||||
return &bridgeEndpoint{}
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) CopyTo(o datastore.KVObject) error {
|
||||
dstEp := o.(*bridgeEndpoint)
|
||||
*dstEp = *ep
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *bridgeEndpoint) DataScope() string {
|
||||
return datastore.LocalScope
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) restorePortAllocations(ep *bridgeEndpoint) {
|
||||
if ep.extConnConfig == nil ||
|
||||
ep.extConnConfig.ExposedPorts == nil ||
|
||||
ep.extConnConfig.PortBindings == nil {
|
||||
return
|
||||
}
|
||||
tmp := ep.extConnConfig.PortBindings
|
||||
ep.extConnConfig.PortBindings = ep.portMapping
|
||||
_, err := n.allocatePorts(ep, n.config.DefaultBindingIntf, n.config.DefaultBindingIP, n.driver.config.EnableUserlandProxy)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to reserve existing port mapping for endpoint %s:%v", ep.id[0:7], err)
|
||||
}
|
||||
ep.extConnConfig.PortBindings = tmp
|
||||
}
|
675
libnetwork/drivers/solaris/bridge/bridge_test.go
Normal file
675
libnetwork/drivers/solaris/bridge/bridge_test.go
Normal file
|
@ -0,0 +1,675 @@
|
|||
// +build solaris
|
||||
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/ipamutils"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ipamutils.InitNetworks()
|
||||
}
|
||||
|
||||
func TestEndpointMarshalling(t *testing.T) {
|
||||
ip1, _ := types.ParseCIDR("172.22.0.9/16")
|
||||
ip2, _ := types.ParseCIDR("2001:db8::9")
|
||||
mac, _ := net.ParseMAC("ac:bd:24:57:66:77")
|
||||
e := &bridgeEndpoint{
|
||||
id: "d2c015a1fe5930650cbcd50493efba0500bcebd8ee1f4401a16319f8a567de33",
|
||||
nid: "ee33fbb43c323f1920b6b35a0101552ac22ede960d0e5245e9738bccc68b2415",
|
||||
addr: ip1,
|
||||
addrv6: ip2,
|
||||
macAddress: mac,
|
||||
srcName: "veth123456",
|
||||
config: &endpointConfiguration{MacAddress: mac},
|
||||
containerConfig: &containerConfiguration{
|
||||
ParentEndpoints: []string{"one", "due", "three"},
|
||||
ChildEndpoints: []string{"four", "five", "six"},
|
||||
},
|
||||
extConnConfig: &connectivityConfiguration{
|
||||
ExposedPorts: []types.TransportPort{
|
||||
{
|
||||
Proto: 6,
|
||||
Port: uint16(18),
|
||||
},
|
||||
},
|
||||
PortBindings: []types.PortBinding{
|
||||
{
|
||||
Proto: 6,
|
||||
IP: net.ParseIP("17210.33.9.56"),
|
||||
Port: uint16(18),
|
||||
HostPort: uint16(3000),
|
||||
HostPortEnd: uint16(14000),
|
||||
},
|
||||
},
|
||||
},
|
||||
portMapping: []types.PortBinding{
|
||||
{
|
||||
Proto: 17,
|
||||
IP: net.ParseIP("172.33.9.56"),
|
||||
Port: uint16(99),
|
||||
HostIP: net.ParseIP("10.10.100.2"),
|
||||
HostPort: uint16(9900),
|
||||
HostPortEnd: uint16(10000),
|
||||
},
|
||||
{
|
||||
Proto: 6,
|
||||
IP: net.ParseIP("171.33.9.56"),
|
||||
Port: uint16(55),
|
||||
HostIP: net.ParseIP("10.11.100.2"),
|
||||
HostPort: uint16(5500),
|
||||
HostPortEnd: uint16(55000),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
b, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ee := &bridgeEndpoint{}
|
||||
err = json.Unmarshal(b, ee)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if e.id != ee.id || e.nid != ee.nid || e.srcName != ee.srcName || !bytes.Equal(e.macAddress, ee.macAddress) ||
|
||||
!types.CompareIPNet(e.addr, ee.addr) || !types.CompareIPNet(e.addrv6, ee.addrv6) ||
|
||||
!compareEpConfig(e.config, ee.config) ||
|
||||
!compareContainerConfig(e.containerConfig, ee.containerConfig) ||
|
||||
!compareConnConfig(e.extConnConfig, ee.extConnConfig) ||
|
||||
!compareBindings(e.portMapping, ee.portMapping) {
|
||||
t.Fatalf("JSON marsh/unmarsh failed.\nOriginal:\n%#v\nDecoded:\n%#v", e, ee)
|
||||
}
|
||||
}
|
||||
|
||||
func compareEpConfig(a, b *endpointConfiguration) bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(a.MacAddress, b.MacAddress)
|
||||
}
|
||||
|
||||
func compareContainerConfig(a, b *containerConfiguration) bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
if len(a.ParentEndpoints) != len(b.ParentEndpoints) ||
|
||||
len(a.ChildEndpoints) != len(b.ChildEndpoints) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(a.ParentEndpoints); i++ {
|
||||
if a.ParentEndpoints[i] != b.ParentEndpoints[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.ChildEndpoints); i++ {
|
||||
if a.ChildEndpoints[i] != b.ChildEndpoints[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func compareConnConfig(a, b *connectivityConfiguration) bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
if len(a.ExposedPorts) != len(b.ExposedPorts) ||
|
||||
len(a.PortBindings) != len(b.PortBindings) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(a.ExposedPorts); i++ {
|
||||
if !a.ExposedPorts[i].Equal(&b.ExposedPorts[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.PortBindings); i++ {
|
||||
if !a.PortBindings[i].Equal(&b.PortBindings[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func compareBindings(a, b []types.PortBinding) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(a); i++ {
|
||||
if !a[i].Equal(&b[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func getIPv4Data(t *testing.T) []driverapi.IPAMData {
|
||||
ipd := driverapi.IPAMData{AddressSpace: "full"}
|
||||
nw, _, err := netutils.ElectInterfaceAddresses("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ipd.Pool = nw
|
||||
// Set network gateway to X.X.X.1
|
||||
ipd.Gateway = types.GetIPNetCopy(nw)
|
||||
ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1
|
||||
return []driverapi.IPAMData{ipd}
|
||||
}
|
||||
|
||||
func TestCreateFullOptions(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPForwarding: true,
|
||||
EnableIPTables: true,
|
||||
}
|
||||
|
||||
// Test this scenario: Default gw address does not belong to
|
||||
// container network and it's greater than bridge address
|
||||
cnw, _ := types.ParseCIDR("172.16.122.0/24")
|
||||
bnw, _ := types.ParseCIDR("172.16.0.0/24")
|
||||
br, _ := types.ParseCIDR("172.16.0.1/16")
|
||||
defgw, _ := types.ParseCIDR("172.16.0.100/16")
|
||||
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netOption := make(map[string]interface{})
|
||||
netOption[netlabel.EnableIPv6] = true
|
||||
netOption[netlabel.GenericData] = &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
}
|
||||
|
||||
ipdList := []driverapi.IPAMData{
|
||||
{
|
||||
Pool: bnw,
|
||||
Gateway: br,
|
||||
AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
|
||||
},
|
||||
}
|
||||
err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
// Verify the IP address allocated for the endpoint belongs to the container network
|
||||
epOptions := make(map[string]interface{})
|
||||
te := newTestEndpoint(cnw, 10)
|
||||
err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
||||
}
|
||||
|
||||
if !cnw.Contains(te.Interface().Address().IP) {
|
||||
t.Fatalf("endpoint got assigned address outside of container network(%s): %s", cnw.String(), te.Interface().Address())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateNoConfig(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
d := newDriver()
|
||||
|
||||
netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFullOptionsLabels(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPForwarding: true,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
bndIPs := "127.0.0.1"
|
||||
nwV6s := "2001:db8:2600:2700:2800::/80"
|
||||
gwV6s := "2001:db8:2600:2700:2800::25/80"
|
||||
nwV6, _ := types.ParseCIDR(nwV6s)
|
||||
gwV6, _ := types.ParseCIDR(gwV6s)
|
||||
|
||||
labels := map[string]string{
|
||||
BridgeName: DefaultBridgeName,
|
||||
DefaultBridge: "true",
|
||||
EnableICC: "true",
|
||||
EnableIPMasquerade: "true",
|
||||
DefaultBindingIP: bndIPs,
|
||||
}
|
||||
|
||||
netOption := make(map[string]interface{})
|
||||
netOption[netlabel.EnableIPv6] = true
|
||||
netOption[netlabel.GenericData] = labels
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
ipd6List := []driverapi.IPAMData{
|
||||
{
|
||||
Pool: nwV6,
|
||||
AuxAddresses: map[string]*net.IPNet{
|
||||
DefaultGatewayV6AuxKey: gwV6,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := d.CreateNetwork("dummy", netOption, nil, ipdList, ipd6List)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
nw, ok := d.networks["dummy"]
|
||||
if !ok {
|
||||
t.Fatalf("Cannot find dummy network in bridge driver")
|
||||
}
|
||||
|
||||
if nw.config.BridgeName != DefaultBridgeName {
|
||||
t.Fatalf("incongruent name in bridge network")
|
||||
}
|
||||
|
||||
if !nw.config.EnableIPv6 {
|
||||
t.Fatalf("incongruent EnableIPv6 in bridge network")
|
||||
}
|
||||
|
||||
if !nw.config.EnableICC {
|
||||
t.Fatalf("incongruent EnableICC in bridge network")
|
||||
}
|
||||
|
||||
if !nw.config.EnableIPMasquerade {
|
||||
t.Fatalf("incongruent EnableIPMasquerade in bridge network")
|
||||
}
|
||||
|
||||
bndIP := net.ParseIP(bndIPs)
|
||||
if !bndIP.Equal(nw.config.DefaultBindingIP) {
|
||||
t.Fatalf("Unexpected: %v", nw.config.DefaultBindingIP)
|
||||
}
|
||||
|
||||
if !types.CompareIPNet(nw.config.AddressIPv6, nwV6) {
|
||||
t.Fatalf("Unexpected: %v", nw.config.AddressIPv6)
|
||||
}
|
||||
|
||||
if !gwV6.IP.Equal(nw.config.DefaultGatewayIPv6) {
|
||||
t.Fatalf("Unexpected: %v", nw.config.DefaultGatewayIPv6)
|
||||
}
|
||||
|
||||
// In short here we are testing --fixed-cidr-v6 daemon option
|
||||
// plus --mac-address run option
|
||||
mac, _ := net.ParseMAC("aa:bb:cc:dd:ee:ff")
|
||||
epOptions := map[string]interface{}{netlabel.MacAddress: mac}
|
||||
te := newTestEndpoint(ipdList[0].Pool, 20)
|
||||
err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected bridge driver to refuse creation of second network with default name")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Creation of second network with default name failed with unexpected error type")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFail(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netconfig := &networkConfiguration{BridgeName: "dummy0", DefaultBridge: true}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err == nil {
|
||||
t.Fatal("Bridge creation was expected to fail")
|
||||
}
|
||||
}
|
||||
|
||||
type testInterface struct {
|
||||
mac net.HardwareAddr
|
||||
addr *net.IPNet
|
||||
addrv6 *net.IPNet
|
||||
srcName string
|
||||
dstName string
|
||||
}
|
||||
|
||||
type testEndpoint struct {
|
||||
iface *testInterface
|
||||
gw net.IP
|
||||
gw6 net.IP
|
||||
hostsPath string
|
||||
resolvConfPath string
|
||||
routes []types.StaticRoute
|
||||
}
|
||||
|
||||
func newTestEndpoint(nw *net.IPNet, ordinal byte) *testEndpoint {
|
||||
addr := types.GetIPNetCopy(nw)
|
||||
addr.IP[len(addr.IP)-1] = ordinal
|
||||
return &testEndpoint{iface: &testInterface{addr: addr}}
|
||||
}
|
||||
|
||||
func (te *testEndpoint) Interface() driverapi.InterfaceInfo {
|
||||
if te.iface != nil {
|
||||
return te.iface
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *testInterface) MacAddress() net.HardwareAddr {
|
||||
return i.mac
|
||||
}
|
||||
|
||||
func (i *testInterface) Address() *net.IPNet {
|
||||
return i.addr
|
||||
}
|
||||
|
||||
func (i *testInterface) AddressIPv6() *net.IPNet {
|
||||
return i.addrv6
|
||||
}
|
||||
|
||||
func (i *testInterface) SetMacAddress(mac net.HardwareAddr) error {
|
||||
if i.mac != nil {
|
||||
return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", i.mac, mac)
|
||||
}
|
||||
if mac == nil {
|
||||
return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
|
||||
}
|
||||
i.mac = types.GetMacCopy(mac)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *testInterface) SetIPAddress(address *net.IPNet) error {
|
||||
if address.IP == nil {
|
||||
return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
|
||||
}
|
||||
if address.IP.To4() == nil {
|
||||
return setAddress(&i.addrv6, address)
|
||||
}
|
||||
return setAddress(&i.addr, address)
|
||||
}
|
||||
|
||||
func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
|
||||
if *ifaceAddr != nil {
|
||||
return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
|
||||
}
|
||||
*ifaceAddr = types.GetIPNetCopy(address)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *testInterface) SetNames(srcName string, dstName string) error {
|
||||
i.srcName = srcName
|
||||
i.dstName = dstName
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo {
|
||||
if te.iface != nil {
|
||||
return te.iface
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) SetGateway(gw net.IP) error {
|
||||
te.gw = gw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) SetGatewayIPv6(gw6 net.IP) error {
|
||||
te.gw6 = gw6
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
|
||||
te.routes = append(te.routes, types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) DisableGatewayService() {}
|
||||
|
||||
func TestQueryEndpointInfo(t *testing.T) {
|
||||
testQueryEndpointInfo(t, true)
|
||||
}
|
||||
|
||||
func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPTables: true,
|
||||
EnableUserlandProxy: ulPxyEnabled,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netconfig := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableICC: false,
|
||||
}
|
||||
genericOption = make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
sbOptions := make(map[string]interface{})
|
||||
sbOptions[netlabel.PortMap] = getPortMapping()
|
||||
|
||||
te := newTestEndpoint(ipdList[0].Pool, 11)
|
||||
err = d.CreateEndpoint("net1", "ep1", te.Interface(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
||||
}
|
||||
|
||||
err = d.Join("net1", "ep1", "sbox", te, sbOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to join the endpoint: %v", err)
|
||||
}
|
||||
|
||||
err = d.ProgramExternalConnectivity("net1", "ep1", sbOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to program external connectivity: %v", err)
|
||||
}
|
||||
|
||||
network, ok := d.networks["net1"]
|
||||
if !ok {
|
||||
t.Fatalf("Cannot find network %s inside driver", "net1")
|
||||
}
|
||||
ep, _ := network.endpoints["ep1"]
|
||||
data, err := d.EndpointOperInfo(network.id, ep.id)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to ask for endpoint operational data: %v", err)
|
||||
}
|
||||
pmd, ok := data[netlabel.PortMap]
|
||||
if !ok {
|
||||
t.Fatalf("Endpoint operational data does not contain port mapping data")
|
||||
}
|
||||
pm, ok := pmd.([]types.PortBinding)
|
||||
if !ok {
|
||||
t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
||||
}
|
||||
if len(ep.portMapping) != len(pm) {
|
||||
t.Fatalf("Incomplete data for port mapping in endpoint operational data")
|
||||
}
|
||||
for i, pb := range ep.portMapping {
|
||||
if !pb.Equal(&pm[i]) {
|
||||
t.Fatalf("Unexpected data for port mapping in endpoint operational data")
|
||||
}
|
||||
}
|
||||
|
||||
err = d.RevokeExternalConnectivity("net1", "ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// release host mapped ports
|
||||
err = d.Leave("net1", "ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getExposedPorts() []types.TransportPort {
|
||||
return []types.TransportPort{
|
||||
{Proto: types.TCP, Port: uint16(5000)},
|
||||
{Proto: types.UDP, Port: uint16(400)},
|
||||
{Proto: types.TCP, Port: uint16(600)},
|
||||
}
|
||||
}
|
||||
|
||||
func getPortMapping() []types.PortBinding {
|
||||
return []types.PortBinding{
|
||||
{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
||||
{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
||||
{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateConfig(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
// Test mtu
|
||||
c := networkConfiguration{Mtu: -2}
|
||||
err := c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid MTU number")
|
||||
}
|
||||
|
||||
c.Mtu = 9000
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected validation error on MTU number")
|
||||
}
|
||||
|
||||
// Bridge network
|
||||
_, network, _ := net.ParseCIDR("172.28.0.0/16")
|
||||
c = networkConfiguration{
|
||||
AddressIPv4: network,
|
||||
}
|
||||
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test v4 gw
|
||||
c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234")
|
||||
err = c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid default gateway")
|
||||
}
|
||||
|
||||
c.DefaultGatewayIPv4 = net.ParseIP("172.28.30.234")
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected validation error on default gateway")
|
||||
}
|
||||
|
||||
// Test v6 gw
|
||||
_, v6nw, _ := net.ParseCIDR("2001:db8:ae:b004::/64")
|
||||
c = networkConfiguration{
|
||||
EnableIPv6: true,
|
||||
AddressIPv6: v6nw,
|
||||
DefaultGatewayIPv6: net.ParseIP("2001:db8:ac:b004::bad:a55"),
|
||||
}
|
||||
err = c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid v6 default gateway")
|
||||
}
|
||||
|
||||
c.DefaultGatewayIPv6 = net.ParseIP("2001:db8:ae:b004::bad:a55")
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected validation error on v6 default gateway")
|
||||
}
|
||||
|
||||
c.AddressIPv6 = nil
|
||||
err = c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid v6 default gateway")
|
||||
}
|
||||
|
||||
c.AddressIPv6 = nil
|
||||
err = c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid v6 default gateway")
|
||||
}
|
||||
}
|
119
libnetwork/drivers/solaris/bridge/errors.go
Normal file
119
libnetwork/drivers/solaris/bridge/errors.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
package bridge
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ErrInvalidEndpointConfig error is returned when an endpoint create is attempted with an invalid endpoint configuration.
|
||||
type ErrInvalidEndpointConfig struct{}
|
||||
|
||||
func (eiec *ErrInvalidEndpointConfig) Error() string {
|
||||
return "trying to create an endpoint with an invalid endpoint configuration"
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eiec *ErrInvalidEndpointConfig) BadRequest() {}
|
||||
|
||||
// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
|
||||
type ErrNoIPAddr struct{}
|
||||
|
||||
func (enip *ErrNoIPAddr) Error() string {
|
||||
return "bridge has no IPv4 address configured"
|
||||
}
|
||||
|
||||
// InternalError denotes the type of this error
|
||||
func (enip *ErrNoIPAddr) InternalError() {}
|
||||
|
||||
// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
|
||||
type ErrInvalidGateway struct{}
|
||||
|
||||
func (eig *ErrInvalidGateway) Error() string {
|
||||
return "default gateway ip must be part of the network"
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eig *ErrInvalidGateway) BadRequest() {}
|
||||
|
||||
// ErrInvalidMtu is returned when the user provided MTU is not valid.
|
||||
type ErrInvalidMtu int
|
||||
|
||||
func (eim ErrInvalidMtu) Error() string {
|
||||
return fmt.Sprintf("invalid MTU number: %d", int(eim))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eim ErrInvalidMtu) BadRequest() {}
|
||||
|
||||
// ErrUnsupportedAddressType is returned when the specified address type is not supported.
|
||||
type ErrUnsupportedAddressType string
|
||||
|
||||
func (uat ErrUnsupportedAddressType) Error() string {
|
||||
return fmt.Sprintf("unsupported address type: %s", string(uat))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (uat ErrUnsupportedAddressType) BadRequest() {}
|
||||
|
||||
// ActiveEndpointsError is returned when there are
|
||||
// still active endpoints in the network being deleted.
|
||||
type ActiveEndpointsError string
|
||||
|
||||
func (aee ActiveEndpointsError) Error() string {
|
||||
return fmt.Sprintf("network %s has active endpoint", string(aee))
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (aee ActiveEndpointsError) Forbidden() {}
|
||||
|
||||
// InvalidNetworkIDError is returned when the passed
|
||||
// network id for an existing network is not a known id.
|
||||
type InvalidNetworkIDError string
|
||||
|
||||
func (inie InvalidNetworkIDError) Error() string {
|
||||
return fmt.Sprintf("invalid network id %s", string(inie))
|
||||
}
|
||||
|
||||
// NotFound denotes the type of this error
|
||||
func (inie InvalidNetworkIDError) NotFound() {}
|
||||
|
||||
// InvalidEndpointIDError is returned when the passed
|
||||
// endpoint id is not valid.
|
||||
type InvalidEndpointIDError string
|
||||
|
||||
func (ieie InvalidEndpointIDError) Error() string {
|
||||
return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (ieie InvalidEndpointIDError) BadRequest() {}
|
||||
|
||||
// EndpointNotFoundError is returned when the no endpoint
|
||||
// with the passed endpoint id is found.
|
||||
type EndpointNotFoundError string
|
||||
|
||||
func (enfe EndpointNotFoundError) Error() string {
|
||||
return fmt.Sprintf("endpoint not found: %s", string(enfe))
|
||||
}
|
||||
|
||||
// NotFound denotes the type of this error
|
||||
func (enfe EndpointNotFoundError) NotFound() {}
|
||||
|
||||
// NonDefaultBridgeExistError is returned when a non-default
|
||||
// bridge config is passed but it does not already exist.
|
||||
type NonDefaultBridgeExistError string
|
||||
|
||||
func (ndbee NonDefaultBridgeExistError) Error() string {
|
||||
return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (ndbee NonDefaultBridgeExistError) Forbidden() {}
|
||||
|
||||
// NonDefaultBridgeNeedsIPError is returned when a non-default
|
||||
// bridge config is passed but it has no ip configured
|
||||
type NonDefaultBridgeNeedsIPError string
|
||||
|
||||
func (ndbee NonDefaultBridgeNeedsIPError) Error() string {
|
||||
return fmt.Sprintf("bridge device with non default name %s must have a valid IP address", string(ndbee))
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (ndbee NonDefaultBridgeNeedsIPError) Forbidden() {}
|
225
libnetwork/drivers/solaris/bridge/port_mapping.go
Normal file
225
libnetwork/drivers/solaris/bridge/port_mapping.go
Normal file
|
@ -0,0 +1,225 @@
|
|||
// +build solaris
|
||||
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultBindingIP = net.IPv4(0, 0, 0, 0)
|
||||
)
|
||||
|
||||
const (
|
||||
maxAllocatePortAttempts = 10
|
||||
)
|
||||
|
||||
func addPFRules(epid, bindIntf string, bs []types.PortBinding) {
|
||||
var id string
|
||||
|
||||
if len(epid) > 12 {
|
||||
id = epid[:12]
|
||||
} else {
|
||||
id = epid
|
||||
}
|
||||
|
||||
fname := "/var/lib/docker/network/files/pf." + id
|
||||
|
||||
f, err := os.OpenFile(fname,
|
||||
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
||||
if err != nil {
|
||||
logrus.Warnf("cannot open temp pf file")
|
||||
return
|
||||
}
|
||||
for _, b := range bs {
|
||||
r := fmt.Sprintf(
|
||||
"pass in on %s proto %s from any to (%s) "+
|
||||
"port %d rdr-to %s port %d\n", bindIntf,
|
||||
b.Proto.String(), bindIntf, b.HostPort,
|
||||
b.IP.String(), b.Port)
|
||||
_, err = f.WriteString(r)
|
||||
if err != nil {
|
||||
logrus.Warnf("cannot write firewall rules to %s: %v", fname, err)
|
||||
}
|
||||
}
|
||||
f.Close()
|
||||
|
||||
anchor := fmt.Sprintf("_auto/docker/ep%s", id)
|
||||
err = exec.Command("/usr/sbin/pfctl", "-a", anchor, "-f", fname).Run()
|
||||
if err != nil {
|
||||
logrus.Warnf("failed to add firewall rules: %v", err)
|
||||
}
|
||||
os.Remove(fname)
|
||||
}
|
||||
|
||||
func removePFRules(epid string) {
|
||||
var id string
|
||||
|
||||
if len(epid) > 12 {
|
||||
id = epid[:12]
|
||||
} else {
|
||||
id = epid
|
||||
}
|
||||
|
||||
anchor := fmt.Sprintf("_auto/docker/ep%s", id)
|
||||
err := exec.Command("/usr/sbin/pfctl", "-a", anchor, "-F", "all").Run()
|
||||
if err != nil {
|
||||
logrus.Warnf("failed to remove firewall rules: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, bindIntf string, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
||||
if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
defHostIP := defaultBindingIP
|
||||
if reqDefBindIP != nil {
|
||||
defHostIP = reqDefBindIP
|
||||
}
|
||||
|
||||
bs, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, bindIntf, ep.addr.IP, defHostIP, ulPxyEnabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add PF rules for port bindings, if any
|
||||
if len(bs) > 0 {
|
||||
addPFRules(ep.id, bindIntf, bs)
|
||||
}
|
||||
|
||||
return bs, err
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, bindIntf string, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
||||
bs := make([]types.PortBinding, 0, len(bindings))
|
||||
for _, c := range bindings {
|
||||
b := c.GetCopy()
|
||||
if err := n.allocatePort(&b, containerIP, defHostIP); err != nil {
|
||||
// On allocation failure,release previously
|
||||
// allocated ports. On cleanup error, just log
|
||||
// a warning message
|
||||
if cuErr := n.releasePortsInternal(bs); cuErr != nil {
|
||||
logrus.Warnf("Upon allocation failure "+
|
||||
"for %v, failed to clear previously "+
|
||||
"allocated port bindings: %v", b, cuErr)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
bs = append(bs, b)
|
||||
}
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP) error {
|
||||
var (
|
||||
host net.Addr
|
||||
err error
|
||||
)
|
||||
|
||||
// Store the container interface address in the operational binding
|
||||
bnd.IP = containerIP
|
||||
|
||||
// Adjust the host address in the operational binding
|
||||
if len(bnd.HostIP) == 0 {
|
||||
bnd.HostIP = defHostIP
|
||||
}
|
||||
|
||||
// Adjust HostPortEnd if this is not a range.
|
||||
if bnd.HostPortEnd == 0 {
|
||||
bnd.HostPortEnd = bnd.HostPort
|
||||
}
|
||||
|
||||
// Construct the container side transport address
|
||||
container, err := bnd.ContainerAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Try up to maxAllocatePortAttempts times to get a port that's
|
||||
// not already allocated.
|
||||
for i := 0; i < maxAllocatePortAttempts; i++ {
|
||||
if host, err = n.portMapper.MapRange(container, bnd.HostIP,
|
||||
int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil {
|
||||
break
|
||||
}
|
||||
// There is no point in immediately retrying to map an
|
||||
// explicitly chosen port.
|
||||
if bnd.HostPort != 0 {
|
||||
logrus.Warnf(
|
||||
"Failed to allocate and map port %d-%d: %s",
|
||||
bnd.HostPort, bnd.HostPortEnd, err)
|
||||
break
|
||||
}
|
||||
logrus.Warnf("Failed to allocate and map port: %s, retry: %d",
|
||||
err, i+1)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the host port (regardless it was or not specified in the
|
||||
// binding)
|
||||
switch netAddr := host.(type) {
|
||||
case *net.TCPAddr:
|
||||
bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
|
||||
return nil
|
||||
case *net.UDPAddr:
|
||||
bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
|
||||
return nil
|
||||
default:
|
||||
// For completeness
|
||||
return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
|
||||
}
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
|
||||
err := n.releasePortsInternal(ep.portMapping)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// remove rules if there are any port mappings
|
||||
if len(ep.portMapping) > 0 {
|
||||
removePFRules(ep.id)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
|
||||
var errorBuf bytes.Buffer
|
||||
|
||||
// Attempt to release all port bindings, do not stop on failure
|
||||
for _, m := range bindings {
|
||||
if err := n.releasePort(m); err != nil {
|
||||
errorBuf.WriteString(
|
||||
fmt.Sprintf(
|
||||
"\ncould not release %v because of %v",
|
||||
m, err))
|
||||
}
|
||||
}
|
||||
|
||||
if errorBuf.Len() != 0 {
|
||||
return errors.New(errorBuf.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
|
||||
// Construct the host side transport address
|
||||
host, err := bnd.HostAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.portMapper.Unmap(host)
|
||||
}
|
|
@ -1,5 +1,13 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"github.com/docker/libnetwork/drivers/null"
|
||||
"github.com/docker/libnetwork/drivers/solaris/bridge"
|
||||
)
|
||||
|
||||
func getInitializers() []initializer {
|
||||
return []initializer{}
|
||||
return []initializer{
|
||||
{bridge.Init, "bridge"},
|
||||
{null.Init, "null"},
|
||||
}
|
||||
}
|
||||
|
|
995
libnetwork/libnetwork_linux_test.go
Normal file
995
libnetwork/libnetwork_linux_test.go
Normal file
|
@ -0,0 +1,995 @@
|
|||
package libnetwork_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/options"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
func TestHost(t *testing.T) {
|
||||
sbx1, err := controller.NewSandbox("host_c1",
|
||||
libnetwork.OptionHostname("test1"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.OptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sbx1.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
sbx2, err := controller.NewSandbox("host_c2",
|
||||
libnetwork.OptionHostname("test2"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.OptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sbx2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ep1, err := network.CreateEndpoint("testep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep1.Join(sbx1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ep2, err := network.CreateEndpoint("testep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep2.Join(sbx2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep1.Leave(sbx1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep2.Leave(sbx2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep1.Delete(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep2.Delete(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Try to create another host endpoint and join/leave that.
|
||||
cnt3, err := controller.NewSandbox("host_c3",
|
||||
libnetwork.OptionHostname("test3"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.OptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := cnt3.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep3, err := network.CreateEndpoint("testep3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep3.Join(sbx2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep3.Leave(sbx2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep3.Delete(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Testing IPV6 from MAC address
|
||||
func TestBridgeIpv6FromMac(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
netOption := options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testipv6mac",
|
||||
"EnableICC": true,
|
||||
"EnableIPMasquerade": true,
|
||||
},
|
||||
}
|
||||
ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}}
|
||||
ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
|
||||
|
||||
network, err := controller.NewNetwork(bridgeNetType, "testipv6mac", "",
|
||||
libnetwork.NetworkOptionGeneric(netOption),
|
||||
libnetwork.NetworkOptionEnableIPv6(true),
|
||||
libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4ConfList, ipamV6ConfList, nil),
|
||||
libnetwork.NetworkOptionDeferIPv6Alloc(true))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mac := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
|
||||
epOption := options.Generic{netlabel.MacAddress: mac}
|
||||
|
||||
ep, err := network.CreateEndpoint("testep", libnetwork.EndpointOptionGeneric(epOption))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
iface := ep.Info().Iface()
|
||||
if !bytes.Equal(iface.MacAddress(), mac) {
|
||||
t.Fatalf("Unexpected mac address: %v", iface.MacAddress())
|
||||
}
|
||||
|
||||
ip, expIP, _ := net.ParseCIDR("fe90::aabb:ccdd:eeff/64")
|
||||
expIP.IP = ip
|
||||
if !types.CompareIPNet(expIP, iface.AddressIPv6()) {
|
||||
t.Fatalf("Expected %v. Got: %v", expIP, iface.AddressIPv6())
|
||||
}
|
||||
|
||||
if err := ep.Delete(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := network.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
|
||||
key := info.Sandbox().Key()
|
||||
sbNs, err := netns.GetFromPath(key)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get network namespace path %q: %v", key, err)
|
||||
}
|
||||
defer sbNs.Close()
|
||||
|
||||
nh, err := netlink.NewHandleAt(sbNs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = nh.LinkByName("eth0")
|
||||
if err != nil {
|
||||
t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
|
||||
}
|
||||
|
||||
_, err = nh.LinkByName("eth1")
|
||||
if err != nil {
|
||||
t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEndpointJoin(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
// Create network 1 and add 2 endpoint: ep11, ep12
|
||||
netOption := options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork1",
|
||||
"EnableICC": true,
|
||||
"EnableIPMasquerade": true,
|
||||
},
|
||||
}
|
||||
ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
|
||||
n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "",
|
||||
libnetwork.NetworkOptionGeneric(netOption),
|
||||
libnetwork.NetworkOptionEnableIPv6(true),
|
||||
libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil),
|
||||
libnetwork.NetworkOptionDeferIPv6Alloc(true))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n1.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep1, err := n1.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := ep1.Delete(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint()
|
||||
info := ep1.Info()
|
||||
iface := info.Iface()
|
||||
if iface.Address() != nil && iface.Address().IP.To4() == nil {
|
||||
t.Fatalf("Invalid IP address returned: %v", iface.Address())
|
||||
}
|
||||
if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil {
|
||||
t.Fatalf("Invalid IPv6 address returned: %v", iface.Address())
|
||||
}
|
||||
|
||||
if len(info.Gateway()) != 0 {
|
||||
t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway())
|
||||
}
|
||||
if len(info.GatewayIPv6()) != 0 {
|
||||
t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6())
|
||||
}
|
||||
|
||||
if info.Sandbox() != nil {
|
||||
t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key())
|
||||
}
|
||||
|
||||
// test invalid joins
|
||||
err = ep1.Join(nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected to fail join with nil Sandbox")
|
||||
}
|
||||
if _, ok := err.(types.BadRequestError); !ok {
|
||||
t.Fatalf("Unexpected error type returned: %T", err)
|
||||
}
|
||||
|
||||
fsbx := &fakeSandbox{}
|
||||
if err = ep1.Join(fsbx); err == nil {
|
||||
t.Fatalf("Expected to fail join with invalid Sandbox")
|
||||
}
|
||||
if _, ok := err.(types.BadRequestError); !ok {
|
||||
t.Fatalf("Unexpected error type returned: %T", err)
|
||||
}
|
||||
|
||||
sb, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := sb.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep1.Join(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined.
|
||||
info = ep1.Info()
|
||||
if len(info.Gateway()) == 0 {
|
||||
t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway())
|
||||
}
|
||||
if len(info.GatewayIPv6()) == 0 {
|
||||
t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6())
|
||||
}
|
||||
|
||||
if info.Sandbox() == nil {
|
||||
t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key")
|
||||
}
|
||||
|
||||
// Check endpoint provided container information
|
||||
if ep1.Info().Sandbox().Key() != sb.Key() {
|
||||
t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key())
|
||||
}
|
||||
|
||||
// Attempt retrieval of endpoint interfaces statistics
|
||||
stats, err := sb.Statistics()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := stats["eth0"]; !ok {
|
||||
t.Fatalf("Did not find eth0 statistics")
|
||||
}
|
||||
|
||||
// Now test the container joining another network
|
||||
n2, err := createTestNetwork(bridgeNetType, "testnetwork2",
|
||||
options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork2",
|
||||
},
|
||||
}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep2, err := n2.CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := ep2.Delete(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep2.Join(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep2.Leave(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
|
||||
t.Fatalf("ep1 and ep2 returned different container sandbox key")
|
||||
}
|
||||
|
||||
checkSandbox(t, info)
|
||||
}
|
||||
|
||||
func TestExternalKey(t *testing.T) {
|
||||
externalKeyTest(t, false)
|
||||
}
|
||||
|
||||
func externalKeyTest(t *testing.T, reexec bool) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork",
|
||||
},
|
||||
}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep, err := n.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep.Delete(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep2, err := n.CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep2.Delete(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
cnt, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionUseExternalKey(),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
||||
defer func() {
|
||||
if err := cnt.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
osl.GC()
|
||||
}()
|
||||
|
||||
// Join endpoint to sandbox before SetKey
|
||||
err = ep.Join(cnt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep.Leave(cnt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
sbox := ep.Info().Sandbox()
|
||||
if sbox == nil {
|
||||
t.Fatalf("Expected to have a valid Sandbox")
|
||||
}
|
||||
|
||||
if reexec {
|
||||
err := reexecSetKey("this-must-fail", containerID, controller.ID())
|
||||
if err == nil {
|
||||
t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created")
|
||||
}
|
||||
} else {
|
||||
// Setting an non-existing key (namespace) must fail
|
||||
if err := sbox.SetKey("this-must-fail"); err == nil {
|
||||
t.Fatalf("Setkey must fail if the corresponding namespace is not created")
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new OS sandbox using the osl API before using it in SetKey
|
||||
if extOsBox, err := osl.NewSandbox("ValidKey", true, false); err != nil {
|
||||
t.Fatalf("Failed to create new osl sandbox")
|
||||
} else {
|
||||
defer func() {
|
||||
if err := extOsBox.Destroy(); err != nil {
|
||||
log.Warnf("Failed to remove os sandbox: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if reexec {
|
||||
err := reexecSetKey("ValidKey", containerID, controller.ID())
|
||||
if err != nil {
|
||||
t.Fatalf("SetExternalKey failed with %v", err)
|
||||
}
|
||||
} else {
|
||||
if err := sbox.SetKey("ValidKey"); err != nil {
|
||||
t.Fatalf("Setkey failed with %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Join endpoint to sandbox after SetKey
|
||||
err = ep2.Join(sbox)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep2.Leave(sbox)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
|
||||
t.Fatalf("ep1 and ep2 returned different container sandbox key")
|
||||
}
|
||||
|
||||
checkSandbox(t, ep.Info())
|
||||
}
|
||||
|
||||
func reexecSetKey(key string, containerID string, controllerID string) error {
|
||||
var (
|
||||
state libcontainer.State
|
||||
b []byte
|
||||
err error
|
||||
)
|
||||
|
||||
state.NamespacePaths = make(map[configs.NamespaceType]string)
|
||||
state.NamespacePaths[configs.NamespaceType("NEWNET")] = key
|
||||
if b, err = json.Marshal(state); err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: append([]string{"libnetwork-setkey"}, containerID, controllerID),
|
||||
Stdin: strings.NewReader(string(b)),
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func TestEnableIPv6(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
||||
expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\noptions ndots:0\n")
|
||||
//take a copy of resolv.conf for restoring after test completes
|
||||
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
//cleanup
|
||||
defer func() {
|
||||
if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
netOption := options.Generic{
|
||||
netlabel.EnableIPv6: true,
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork",
|
||||
},
|
||||
}
|
||||
ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe99::/64", Gateway: "fe99::9"}}
|
||||
|
||||
n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, ipamV6ConfList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep1, err := n.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
|
||||
defer os.Remove(resolvConfPath)
|
||||
|
||||
sb, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sb.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep1.Join(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(resolvConfPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(content, expectedResolvConf) {
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf), string(content))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvConfHost(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888\n")
|
||||
|
||||
//take a copy of resolv.conf for restoring after test completes
|
||||
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
//cleanup
|
||||
defer func() {
|
||||
if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
n, err := controller.NetworkByName("testhost")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ep1, err := n.CreateEndpoint("ep1", libnetwork.CreateOptionDisableResolution())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
|
||||
defer os.Remove(resolvConfPath)
|
||||
|
||||
sb, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionResolvConfPath(resolvConfPath),
|
||||
libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sb.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep1.Join(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
finfo, err := os.Stat(resolvConfPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fmode := (os.FileMode)(0644)
|
||||
if finfo.Mode() != fmode {
|
||||
t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(resolvConfPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(content, tmpResolvConf) {
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvConf(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
||||
tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
||||
expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\noptions ndots:0\n")
|
||||
tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n")
|
||||
|
||||
//take a copy of resolv.conf for restoring after test completes
|
||||
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
//cleanup
|
||||
defer func() {
|
||||
if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
netOption := options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork",
|
||||
},
|
||||
}
|
||||
n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep, err := n.CreateEndpoint("ep")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf1, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
|
||||
defer os.Remove(resolvConfPath)
|
||||
|
||||
sb1, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sb1.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep.Join(sb1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finfo, err := os.Stat(resolvConfPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fmode := (os.FileMode)(0644)
|
||||
if finfo.Mode() != fmode {
|
||||
t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(resolvConfPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(content, expectedResolvConf1) {
|
||||
fmt.Printf("\n%v\n%v\n", expectedResolvConf1, content)
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
|
||||
}
|
||||
|
||||
err = ep.Leave(sb1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf2, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sb2, err := controller.NewSandbox(containerID+"_2", libnetwork.OptionResolvConfPath(resolvConfPath))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sb2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep.Join(sb2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
content, err = ioutil.ReadFile(resolvConfPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(content, expectedResolvConf1) {
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep.Leave(sb2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep.Join(sb2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
content, err = ioutil.ReadFile(resolvConfPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(content, tmpResolvConf3) {
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf3), string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func parallelJoin(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
|
||||
debugf("J%d.", thrNumber)
|
||||
var err error
|
||||
|
||||
sb := sboxes[thrNumber-1]
|
||||
err = ep.Join(sb)
|
||||
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("thread %d: %v", thrNumber, err)
|
||||
}
|
||||
debugf("JE%d(%v).", thrNumber, err)
|
||||
}
|
||||
debugf("JD%d.", thrNumber)
|
||||
}
|
||||
|
||||
func parallelLeave(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
|
||||
debugf("L%d.", thrNumber)
|
||||
var err error
|
||||
|
||||
sb := sboxes[thrNumber-1]
|
||||
|
||||
err = ep.Leave(sb)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("thread %d: %v", thrNumber, err)
|
||||
}
|
||||
debugf("LE%d(%v).", thrNumber, err)
|
||||
}
|
||||
debugf("LD%d.", thrNumber)
|
||||
}
|
||||
|
||||
func runParallelTests(t *testing.T, thrNumber int) {
|
||||
var (
|
||||
ep libnetwork.Endpoint
|
||||
sb libnetwork.Sandbox
|
||||
err error
|
||||
)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
pTest := flag.Lookup("test.parallel")
|
||||
if pTest == nil {
|
||||
t.Skip("Skipped because test.parallel flag not set;")
|
||||
}
|
||||
numParallel, err := strconv.Atoi(pTest.Value.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if numParallel < numThreads {
|
||||
t.Skip("Skipped because t.parallel was less than ", numThreads)
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if thrNumber == first {
|
||||
createGlobalInstance(t)
|
||||
}
|
||||
|
||||
if thrNumber != first {
|
||||
select {
|
||||
case <-start:
|
||||
}
|
||||
|
||||
thrdone := make(chan struct{})
|
||||
done <- thrdone
|
||||
defer close(thrdone)
|
||||
|
||||
if thrNumber == last {
|
||||
defer close(done)
|
||||
}
|
||||
|
||||
err = netns.Set(testns)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
defer netns.Set(origns)
|
||||
|
||||
net1, err := controller.NetworkByName("testhost")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if net1 == nil {
|
||||
t.Fatal("Could not find testhost")
|
||||
}
|
||||
|
||||
net2, err := controller.NetworkByName("network2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if net2 == nil {
|
||||
t.Fatal("Could not find network2")
|
||||
}
|
||||
|
||||
epName := fmt.Sprintf("pep%d", thrNumber)
|
||||
|
||||
if thrNumber == first {
|
||||
ep, err = net1.EndpointByName(epName)
|
||||
} else {
|
||||
ep, err = net2.EndpointByName(epName)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ep == nil {
|
||||
t.Fatal("Got nil ep with no error")
|
||||
}
|
||||
|
||||
cid := fmt.Sprintf("%drace", thrNumber)
|
||||
controller.WalkSandboxes(libnetwork.SandboxContainerWalker(&sb, cid))
|
||||
if sb == nil {
|
||||
t.Fatalf("Got nil sandbox for container: %s", cid)
|
||||
}
|
||||
|
||||
for i := 0; i < iterCnt; i++ {
|
||||
parallelJoin(t, sb, ep, thrNumber)
|
||||
parallelLeave(t, sb, ep, thrNumber)
|
||||
}
|
||||
|
||||
debugf("\n")
|
||||
|
||||
err = sb.Delete()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if thrNumber == first {
|
||||
for thrdone := range done {
|
||||
select {
|
||||
case <-thrdone:
|
||||
}
|
||||
}
|
||||
|
||||
testns.Close()
|
||||
if err := net2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
err = ep.Delete(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParallel1(t *testing.T) {
|
||||
runParallelTests(t, 1)
|
||||
}
|
||||
|
||||
func TestParallel2(t *testing.T) {
|
||||
runParallelTests(t, 2)
|
||||
}
|
||||
|
||||
func TestParallel3(t *testing.T) {
|
||||
runParallelTests(t, 3)
|
||||
}
|
||||
|
||||
func TestNullIpam(t *testing.T) {
|
||||
_, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", "", libnetwork.NetworkOptionIpam(ipamapi.NullIPAM, "", nil, nil, nil))
|
||||
if err == nil || err.Error() != "ipv4 pool is empty" {
|
||||
t.Fatal("bridge network should complain empty pool")
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,13 +1,26 @@
|
|||
// +build solaris
|
||||
|
||||
package netutils
|
||||
|
||||
// Solaris: TODO
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/libnetwork/ipamutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
var (
|
||||
networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error)
|
||||
)
|
||||
|
||||
// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
|
||||
func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ElectInterfaceAddresses looks for an interface on the OS with the specified name
|
||||
// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
|
||||
// it chooses from a predifined list the first IPv4 address which does not conflict
|
||||
|
@ -15,18 +28,75 @@ import (
|
|||
func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
|
||||
var (
|
||||
v4Net *net.IPNet
|
||||
err error
|
||||
)
|
||||
|
||||
v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
|
||||
out, err := exec.Command("/usr/sbin/ipadm", "show-addr",
|
||||
"-p", "-o", "addrobj,addr").Output()
|
||||
if err != nil {
|
||||
fmt.Println("failed to list interfaces on system")
|
||||
return nil, nil, err
|
||||
}
|
||||
alist := strings.Fields(string(out))
|
||||
for _, a := range alist {
|
||||
linkandaddr := strings.SplitN(a, ":", 2)
|
||||
if len(linkandaddr) != 2 {
|
||||
fmt.Println("failed to check interfaces on system: ", a)
|
||||
continue
|
||||
}
|
||||
gw := fmt.Sprintf("%s_gw0", name)
|
||||
link := strings.Split(linkandaddr[0], "/")[0]
|
||||
addr := linkandaddr[1]
|
||||
if gw != link {
|
||||
continue
|
||||
}
|
||||
_, ipnet, err := net.ParseCIDR(addr)
|
||||
if err != nil {
|
||||
fmt.Println("failed to parse address: ", addr)
|
||||
continue
|
||||
}
|
||||
v4Net = ipnet
|
||||
break
|
||||
}
|
||||
if v4Net == nil {
|
||||
v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
return v4Net, nil, nil
|
||||
}
|
||||
|
||||
// FindAvailableNetwork returns a network from the passed list which does not
|
||||
// overlap with existing interfaces in the system
|
||||
func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
|
||||
return list[0], nil
|
||||
out, err := exec.Command("/usr/sbin/ipadm", "show-addr",
|
||||
"-p", "-o", "addr").Output()
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("failed to list interfaces on system")
|
||||
return nil, err
|
||||
}
|
||||
ipaddrs := strings.Fields(string(out))
|
||||
inuse := []*net.IPNet{}
|
||||
for _, ip := range ipaddrs {
|
||||
_, ipnet, err := net.ParseCIDR(ip)
|
||||
if err != nil {
|
||||
fmt.Println("failed to check interfaces on system: ", ip)
|
||||
continue
|
||||
}
|
||||
inuse = append(inuse, ipnet)
|
||||
}
|
||||
for _, avail := range list {
|
||||
is_avail := true
|
||||
for _, ipnet := range inuse {
|
||||
if NetworkOverlaps(avail, ipnet) {
|
||||
is_avail = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if is_avail {
|
||||
return avail, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no available network")
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !solaris
|
||||
|
||||
package netutils
|
||||
|
||||
import (
|
||||
|
|
24
libnetwork/osl/sandbox_solaris.go
Normal file
24
libnetwork/osl/sandbox_solaris.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package osl
|
||||
|
||||
// NewSandbox provides a new sandbox instance created in an os specific way
|
||||
// provided a key which uniquely identifies the sandbox
|
||||
func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GenerateKey generates a sandbox key based on the passed
|
||||
// container id.
|
||||
func GenerateKey(containerID string) string {
|
||||
maxLen := 12
|
||||
|
||||
if len(containerID) < maxLen {
|
||||
maxLen = len(containerID)
|
||||
}
|
||||
|
||||
return containerID[:maxLen]
|
||||
}
|
||||
|
||||
// InitOSContext initializes OS context while configuring network resources
|
||||
func InitOSContext() func() {
|
||||
return func() {}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// +build !solaris
|
||||
|
||||
package osl
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !linux,!windows,!freebsd
|
||||
// +build !linux,!windows,!freebsd,!solaris
|
||||
|
||||
package osl
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !linux
|
||||
// +build !linux,!solaris
|
||||
|
||||
package osl
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package portallocator
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
@ -106,26 +104,6 @@ func newInstance() *PortAllocator {
|
|||
}
|
||||
}
|
||||
|
||||
func getDynamicPortRange() (start int, end int, err error) {
|
||||
const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range"
|
||||
portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
|
||||
file, err := os.Open(portRangeKernelParam)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end)
|
||||
if n != 2 || err != nil {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("unexpected count of parsed numbers (%d)", n)
|
||||
}
|
||||
return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err)
|
||||
}
|
||||
return start, end, nil
|
||||
}
|
||||
|
||||
// RequestPort requests new port from global ports pool for specified ip and proto.
|
||||
// If port is 0 it returns first free port. Otherwise it checks port availability
|
||||
// in proto's pool and returns that port or error if port is already busy.
|
||||
|
|
27
libnetwork/portallocator/portallocator_linux.go
Normal file
27
libnetwork/portallocator/portallocator_linux.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package portallocator
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func getDynamicPortRange() (start int, end int, err error) {
|
||||
const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range"
|
||||
portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
|
||||
file, err := os.Open(portRangeKernelParam)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end)
|
||||
if n != 2 || err != nil {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("unexpected count of parsed numbers (%d)", n)
|
||||
}
|
||||
return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err)
|
||||
}
|
||||
return start, end, nil
|
||||
}
|
5
libnetwork/portallocator/portallocator_solaris.go
Normal file
5
libnetwork/portallocator/portallocator_solaris.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package portallocator
|
||||
|
||||
func getDynamicPortRange() (start int, end int, err error) {
|
||||
return 32768, 65535, nil
|
||||
}
|
|
@ -7,8 +7,6 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -25,36 +23,6 @@ type proxyCommand struct {
|
|||
cmd *exec.Cmd
|
||||
}
|
||||
|
||||
func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
|
||||
path := proxyPath
|
||||
if proxyPath == "" {
|
||||
cmd, err := exec.LookPath(userlandProxyCommandName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path = cmd
|
||||
}
|
||||
|
||||
args := []string{
|
||||
path,
|
||||
"-proto", proto,
|
||||
"-host-ip", hostIP.String(),
|
||||
"-host-port", strconv.Itoa(hostPort),
|
||||
"-container-ip", containerIP.String(),
|
||||
"-container-port", strconv.Itoa(containerPort),
|
||||
}
|
||||
|
||||
return &proxyCommand{
|
||||
cmd: &exec.Cmd{
|
||||
Path: path,
|
||||
Args: args,
|
||||
SysProcAttr: &syscall.SysProcAttr{
|
||||
Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *proxyCommand) Start() error {
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
|
|
38
libnetwork/portmapper/proxy_linux.go
Normal file
38
libnetwork/portmapper/proxy_linux.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package portmapper
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
|
||||
path := proxyPath
|
||||
if proxyPath == "" {
|
||||
cmd, err := exec.LookPath(userlandProxyCommandName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path = cmd
|
||||
}
|
||||
|
||||
args := []string{
|
||||
path,
|
||||
"-proto", proto,
|
||||
"-host-ip", hostIP.String(),
|
||||
"-host-port", strconv.Itoa(hostPort),
|
||||
"-container-ip", containerIP.String(),
|
||||
"-container-port", strconv.Itoa(containerPort),
|
||||
}
|
||||
|
||||
return &proxyCommand{
|
||||
cmd: &exec.Cmd{
|
||||
Path: path,
|
||||
Args: args,
|
||||
SysProcAttr: &syscall.SysProcAttr{
|
||||
Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
34
libnetwork/portmapper/proxy_solaris.go
Normal file
34
libnetwork/portmapper/proxy_solaris.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package portmapper
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
|
||||
path := proxyPath
|
||||
if proxyPath == "" {
|
||||
cmd, err := exec.LookPath(userlandProxyCommandName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path = cmd
|
||||
}
|
||||
|
||||
args := []string{
|
||||
path,
|
||||
"-proto", proto,
|
||||
"-host-ip", hostIP.String(),
|
||||
"-host-port", strconv.Itoa(hostPort),
|
||||
"-container-ip", containerIP.String(),
|
||||
"-container-port", strconv.Itoa(containerPort),
|
||||
}
|
||||
|
||||
return &proxyCommand{
|
||||
cmd: &exec.Cmd{
|
||||
Path: path,
|
||||
Args: args,
|
||||
},
|
||||
}, nil
|
||||
}
|
45
libnetwork/store_linux_test.go
Normal file
45
libnetwork/store_linux_test.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libkv/store"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
)
|
||||
|
||||
func TestBoltdbBackend(t *testing.T) {
|
||||
defer os.Remove(datastore.DefaultScopes("")[datastore.LocalScope].Client.Address)
|
||||
testLocalBackend(t, "", "", nil)
|
||||
defer os.Remove("/tmp/boltdb.db")
|
||||
config := &store.Config{Bucket: "testBackend"}
|
||||
testLocalBackend(t, "boltdb", "/tmp/boltdb.db", config)
|
||||
|
||||
}
|
||||
|
||||
func TestNoPersist(t *testing.T) {
|
||||
cfgOptions, err := OptionBoltdbWithRandomDBFile()
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating random boltdb file : %v", err)
|
||||
}
|
||||
ctrl, err := New(cfgOptions...)
|
||||
if err != nil {
|
||||
t.Fatalf("Error new controller: %v", err)
|
||||
}
|
||||
nw, err := ctrl.NewNetwork("host", "host", "", NetworkOptionPersist(false))
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating default \"host\" network: %v", err)
|
||||
}
|
||||
ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating endpoint: %v", err)
|
||||
}
|
||||
store := ctrl.(*controller).getStore(datastore.LocalScope).KVStore()
|
||||
if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists {
|
||||
t.Fatalf("Network with persist=false should not be stored in KV Store")
|
||||
}
|
||||
if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists {
|
||||
t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store")
|
||||
}
|
||||
store.Close()
|
||||
}
|
|
@ -3,7 +3,6 @@ package libnetwork
|
|||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libkv/store"
|
||||
|
@ -31,15 +30,6 @@ func testNewController(t *testing.T, provider, url string) (NetworkController, e
|
|||
return New(cfgOptions...)
|
||||
}
|
||||
|
||||
func TestBoltdbBackend(t *testing.T) {
|
||||
defer os.Remove(datastore.DefaultScopes("")[datastore.LocalScope].Client.Address)
|
||||
testLocalBackend(t, "", "", nil)
|
||||
defer os.Remove("/tmp/boltdb.db")
|
||||
config := &store.Config{Bucket: "testBackend"}
|
||||
testLocalBackend(t, "boltdb", "/tmp/boltdb.db", config)
|
||||
|
||||
}
|
||||
|
||||
func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Config) {
|
||||
cfgOptions := []config.Option{}
|
||||
cfgOptions = append(cfgOptions, config.OptionLocalKVProvider(provider))
|
||||
|
@ -82,33 +72,6 @@ func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Con
|
|||
}
|
||||
}
|
||||
|
||||
func TestNoPersist(t *testing.T) {
|
||||
cfgOptions, err := OptionBoltdbWithRandomDBFile()
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating random boltdb file : %v", err)
|
||||
}
|
||||
ctrl, err := New(cfgOptions...)
|
||||
if err != nil {
|
||||
t.Fatalf("Error new controller: %v", err)
|
||||
}
|
||||
nw, err := ctrl.NewNetwork("host", "host", "", NetworkOptionPersist(false))
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating default \"host\" network: %v", err)
|
||||
}
|
||||
ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating endpoint: %v", err)
|
||||
}
|
||||
store := ctrl.(*controller).getStore(datastore.LocalScope).KVStore()
|
||||
if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists {
|
||||
t.Fatalf("Network with persist=false should not be stored in KV Store")
|
||||
}
|
||||
if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists {
|
||||
t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store")
|
||||
}
|
||||
store.Close()
|
||||
}
|
||||
|
||||
// OptionBoltdbWithRandomDBFile function returns a random dir for local store backend
|
||||
func OptionBoltdbWithRandomDBFile() ([]config.Option, error) {
|
||||
tmp, err := ioutil.TempFile("", "libnetwork-")
|
||||
|
|
25
libnetwork/testutils/context_solaris.go
Normal file
25
libnetwork/testutils/context_solaris.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
// +build solaris
|
||||
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// SetupTestOSContext joins a new network namespace, and returns its associated
|
||||
// teardown function.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// defer SetupTestOSContext(t)()
|
||||
//
|
||||
func SetupTestOSContext(t *testing.T) func() {
|
||||
return func() {
|
||||
}
|
||||
}
|
||||
|
||||
// RunningOnCircleCI returns true if being executed on libnetwork Circle CI setup
|
||||
func RunningOnCircleCI() bool {
|
||||
return os.Getenv("CIRCLECI") != ""
|
||||
}
|
Loading…
Reference in a new issue