mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #222 from aboch/nlb
Labels support for Network Create
This commit is contained in:
commit
b5145e597b
14 changed files with 494 additions and 176 deletions
|
@ -8,7 +8,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
@ -52,9 +51,6 @@ const (
|
|||
urlSbPID = "sandbox-partial-id"
|
||||
urlCnID = "container-id"
|
||||
urlCnPID = "container-partial-id"
|
||||
|
||||
// BridgeNetworkDriver is the built-in default for Network Driver
|
||||
BridgeNetworkDriver = "bridge"
|
||||
)
|
||||
|
||||
// NewHTTPHandler creates and initialize the HTTP handler to serve the requests for libnetwork
|
||||
|
@ -222,16 +218,6 @@ func buildSandboxResource(sb libnetwork.Sandbox) *sandboxResource {
|
|||
Options Parsers
|
||||
*****************/
|
||||
|
||||
func (nc *networkCreate) parseOptions() []libnetwork.NetworkOption {
|
||||
var setFctList []libnetwork.NetworkOption
|
||||
|
||||
if nc.Options != nil {
|
||||
setFctList = append(setFctList, libnetwork.NetworkOptionGeneric(nc.Options))
|
||||
}
|
||||
|
||||
return setFctList
|
||||
}
|
||||
|
||||
func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
|
||||
var setFctList []libnetwork.SandboxOption
|
||||
if sc.HostName != "" {
|
||||
|
@ -278,21 +264,6 @@ func processCreateDefaults(c libnetwork.NetworkController, nc *networkCreate) {
|
|||
if nc.NetworkType == "" {
|
||||
nc.NetworkType = c.Config().Daemon.DefaultDriver
|
||||
}
|
||||
if nc.NetworkType == BridgeNetworkDriver {
|
||||
if nc.Options == nil {
|
||||
nc.Options = make(map[string]interface{})
|
||||
}
|
||||
genericData, ok := nc.Options[netlabel.GenericData]
|
||||
if !ok {
|
||||
genericData = make(map[string]interface{})
|
||||
}
|
||||
gData := genericData.(map[string]interface{})
|
||||
|
||||
if _, ok := gData["BridgeName"]; !ok {
|
||||
gData["BridgeName"] = nc.Name
|
||||
}
|
||||
nc.Options[netlabel.GenericData] = genericData
|
||||
}
|
||||
}
|
||||
|
||||
/***************************
|
||||
|
@ -307,7 +278,7 @@ func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, b
|
|||
}
|
||||
processCreateDefaults(c, &create)
|
||||
|
||||
nw, err := c.NewNetwork(create.NetworkType, create.Name, create.parseOptions()...)
|
||||
nw, err := c.NewNetwork(create.NetworkType, create.Name, libnetwork.NetworkOptionLabels(create.Labels))
|
||||
if err != nil {
|
||||
return "", convertNetworkError(err)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ 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"
|
||||
|
@ -26,12 +27,6 @@ const (
|
|||
bridgeName = "docker0"
|
||||
)
|
||||
|
||||
func getEmptyGenericOption() map[string]interface{} {
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = options.Generic{}
|
||||
return genericOption
|
||||
}
|
||||
|
||||
func i2s(i interface{}) string {
|
||||
s, ok := i.(string)
|
||||
if !ok {
|
||||
|
@ -111,6 +106,22 @@ func createTestNetwork(t *testing.T, network string) (libnetwork.NetworkControll
|
|||
return c, nw
|
||||
}
|
||||
|
||||
func getExposedPorts() []types.TransportPort {
|
||||
return []types.TransportPort{
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
|
||||
types.TransportPort{Proto: types.UDP, Port: uint16(400)},
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(600)},
|
||||
}
|
||||
}
|
||||
|
||||
func getPortMapping() []types.PortBinding {
|
||||
return []types.PortBinding{
|
||||
types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
||||
types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
||||
types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
||||
}
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
if reexec.Init() {
|
||||
return
|
||||
|
@ -214,15 +225,11 @@ func TestCreateDeleteNetwork(t *testing.T) {
|
|||
t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp)
|
||||
}
|
||||
|
||||
ops := options.Generic{
|
||||
netlabel.EnableIPv6: true,
|
||||
netlabel.GenericData: map[string]string{
|
||||
"BridgeName": "abc",
|
||||
"FixedCIDRv6": "fe80::1/64",
|
||||
"AddressIP": "172.28.30.254/24",
|
||||
},
|
||||
ops := []string{
|
||||
bridge.BridgeName + "=abc",
|
||||
netlabel.EnableIPv6 + "=true",
|
||||
}
|
||||
nc := networkCreate{Name: "network_1", NetworkType: bridgeNetType, Options: ops}
|
||||
nc := networkCreate{Name: "network_1", NetworkType: bridgeNetType, Labels: ops}
|
||||
goodBody, err := json.Marshal(nc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -250,6 +257,29 @@ func TestCreateDeleteNetwork(t *testing.T) {
|
|||
if errRsp != &successResponse {
|
||||
t.Fatalf("Unexepected failure: %v", errRsp)
|
||||
}
|
||||
|
||||
// Create with labels
|
||||
labels := []string{
|
||||
netlabel.EnableIPv6 + "=true",
|
||||
bridge.BridgeName + "=abc",
|
||||
}
|
||||
nc = networkCreate{Name: "network_2", NetworkType: bridgeNetType, Labels: labels}
|
||||
goodBody, err = json.Marshal(nc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, errRsp = procCreateNetwork(c, vars, goodBody)
|
||||
if errRsp != &createdResponse {
|
||||
t.Fatalf("Unexepected failure: %v", errRsp)
|
||||
}
|
||||
|
||||
vars[urlNwName] = "network_2"
|
||||
_, errRsp = procDeleteNetwork(c, vars, nil)
|
||||
if errRsp != &successResponse {
|
||||
t.Fatalf("Unexepected failure: %v", errRsp)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetNetworksAndEndpoints(t *testing.T) {
|
||||
|
@ -264,13 +294,10 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
|||
}
|
||||
defer c.Stop()
|
||||
|
||||
ops := options.Generic{
|
||||
netlabel.GenericData: map[string]string{
|
||||
"BridgeName": "api_test_nw",
|
||||
},
|
||||
ops := []string{
|
||||
bridge.BridgeName + "=api_test_nw",
|
||||
}
|
||||
|
||||
nc := networkCreate{Name: "sh", NetworkType: bridgeNetType, Options: ops}
|
||||
nc := networkCreate{Name: "sh", NetworkType: bridgeNetType, Labels: ops}
|
||||
body, err := json.Marshal(nc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -287,17 +314,9 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
|||
}
|
||||
|
||||
ec1 := endpointCreate{
|
||||
Name: "ep1",
|
||||
ExposedPorts: []types.TransportPort{
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
|
||||
types.TransportPort{Proto: types.UDP, Port: uint16(400)},
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(600)},
|
||||
},
|
||||
PortMapping: []types.PortBinding{
|
||||
types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
||||
types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
||||
types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
||||
},
|
||||
Name: "ep1",
|
||||
ExposedPorts: getExposedPorts(),
|
||||
PortMapping: getPortMapping(),
|
||||
}
|
||||
b1, err := json.Marshal(ec1)
|
||||
if err != nil {
|
||||
|
@ -439,10 +458,10 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
|||
nr1 := i2n(inr1)
|
||||
|
||||
delete(vars, urlNwName)
|
||||
vars[urlNwID] = "cacca"
|
||||
vars[urlNwID] = "acacac"
|
||||
_, errRsp = procGetNetwork(c, vars, nil)
|
||||
if errRsp == &successResponse {
|
||||
t.Fatalf("Unexepected failure: %v", errRsp)
|
||||
t.Fatalf("Expected failure. Got: %v", errRsp)
|
||||
}
|
||||
vars[urlNwID] = nid
|
||||
inr2, errRsp := procGetNetwork(c, vars, nil)
|
||||
|
@ -825,18 +844,10 @@ func TestProcPublishUnpublishService(t *testing.T) {
|
|||
}
|
||||
|
||||
sp := servicePublish{
|
||||
Name: "web",
|
||||
Network: "network",
|
||||
ExposedPorts: []types.TransportPort{
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(6000)},
|
||||
types.TransportPort{Proto: types.UDP, Port: uint16(500)},
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(700)},
|
||||
},
|
||||
PortMapping: []types.PortBinding{
|
||||
types.PortBinding{Proto: types.TCP, Port: uint16(1230), HostPort: uint16(37000)},
|
||||
types.PortBinding{Proto: types.UDP, Port: uint16(1200), HostPort: uint16(36000)},
|
||||
types.PortBinding{Proto: types.TCP, Port: uint16(1120), HostPort: uint16(35000)},
|
||||
},
|
||||
Name: "web",
|
||||
Network: "network",
|
||||
ExposedPorts: getExposedPorts(),
|
||||
PortMapping: getPortMapping(),
|
||||
}
|
||||
b, err = json.Marshal(sp)
|
||||
if err != nil {
|
||||
|
@ -1330,6 +1341,7 @@ func TestJoinLeave(t *testing.T) {
|
|||
t.Fatalf("Expected failure, got: %v", errRsp)
|
||||
}
|
||||
|
||||
// bad labels
|
||||
vars[urlEpName] = "endpoint"
|
||||
key, errRsp := procJoinEndpoint(c, vars, jlb)
|
||||
if errRsp != &successResponse {
|
||||
|
@ -1818,21 +1830,14 @@ func TestEndToEnd(t *testing.T) {
|
|||
|
||||
handleRequest := NewHTTPHandler(c)
|
||||
|
||||
ops := options.Generic{
|
||||
netlabel.EnableIPv6: true,
|
||||
netlabel.GenericData: map[string]string{
|
||||
"BridgeName": "cdef",
|
||||
"FixedCIDRv6": "fe80:2000::1/64",
|
||||
"EnableIPv6": "true",
|
||||
"Mtu": "1460",
|
||||
"EnableIPTables": "true",
|
||||
"AddressIP": "172.28.30.254/16",
|
||||
"EnableUserlandProxy": "true",
|
||||
},
|
||||
ops := []string{
|
||||
bridge.BridgeName + "=cdef",
|
||||
netlabel.EnableIPv6 + "=true",
|
||||
netlabel.DriverMTU + "=1460",
|
||||
}
|
||||
|
||||
// Create network
|
||||
nc := networkCreate{Name: "network-fiftyfive", NetworkType: bridgeNetType, Options: ops}
|
||||
nc := networkCreate{Name: "network-fiftyfive", NetworkType: bridgeNetType, Labels: ops}
|
||||
body, err := json.Marshal(nc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -26,7 +26,6 @@ type sandboxResource struct {
|
|||
ID string `json:"id"`
|
||||
Key string `json:"key"`
|
||||
ContainerID string `json:"container_id"`
|
||||
// will add more fields once labels change is in
|
||||
}
|
||||
|
||||
/***********
|
||||
|
@ -35,9 +34,9 @@ type sandboxResource struct {
|
|||
|
||||
// networkCreate is the expected body of the "create network" http request message
|
||||
type networkCreate struct {
|
||||
Name string `json:"name"`
|
||||
NetworkType string `json:"network_type"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
Name string `json:"name"`
|
||||
NetworkType string `json:"network_type"`
|
||||
Labels []string `json:"labels"`
|
||||
}
|
||||
|
||||
// endpointCreate represents the body of the "create endpoint" http request message
|
||||
|
|
|
@ -48,8 +48,8 @@ func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error {
|
|||
}
|
||||
|
||||
// Construct network create request body
|
||||
ops := make(map[string]interface{})
|
||||
nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver, Options: ops}
|
||||
var labels []string
|
||||
nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver, Labels: labels}
|
||||
obj, _, err := readBody(cli.call("POST", "/networks", nc, nil))
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -34,9 +34,9 @@ type SandboxResource struct {
|
|||
|
||||
// networkCreate is the expected body of the "create network" http request message
|
||||
type networkCreate struct {
|
||||
Name string `json:"name"`
|
||||
NetworkType string `json:"network_type"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
Name string `json:"name"`
|
||||
NetworkType string `json:"network_type"`
|
||||
Labels []string `json:"labels"`
|
||||
}
|
||||
|
||||
// serviceCreate represents the body of the "publish service" http request message
|
||||
|
|
|
@ -184,7 +184,7 @@ func createDefaultNetwork(c libnetwork.NetworkController) {
|
|||
if nw != "" && d != "" {
|
||||
// Bridge driver is special due to legacy reasons
|
||||
if d == "bridge" {
|
||||
genericOption[netlabel.GenericData] = map[string]interface{}{
|
||||
genericOption[netlabel.GenericData] = map[string]string{
|
||||
"BridgeName": "docker0",
|
||||
"DefaultBridge": "true",
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
|
|||
|
||||
// Also empty, becasue only one network with empty name is allowed
|
||||
if c.BridgeName == o.BridgeName {
|
||||
return fmt.Errorf("networks have same name")
|
||||
return fmt.Errorf("networks have same bridge name")
|
||||
}
|
||||
|
||||
// They must be in different subnets
|
||||
|
@ -196,79 +196,46 @@ func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// fromMap retrieve the configuration data from the map form.
|
||||
func (c *networkConfiguration) fromMap(data map[string]interface{}) error {
|
||||
func (c *networkConfiguration) fromLabels(labels map[string]string) error {
|
||||
var err error
|
||||
|
||||
if i, ok := data["BridgeName"]; ok && i != nil {
|
||||
if c.BridgeName, ok = i.(string); !ok {
|
||||
return types.BadRequestErrorf("invalid type for BridgeName value")
|
||||
}
|
||||
}
|
||||
|
||||
if i, ok := data["Mtu"]; ok && i != nil {
|
||||
if s, ok := i.(string); ok {
|
||||
if c.Mtu, err = strconv.Atoi(s); err != nil {
|
||||
return types.BadRequestErrorf("failed to parse Mtu value: %s", err.Error())
|
||||
for label, value := range labels {
|
||||
switch label {
|
||||
case BridgeName:
|
||||
c.BridgeName = value
|
||||
case netlabel.DriverMTU:
|
||||
if c.Mtu, err = strconv.Atoi(value); err != nil {
|
||||
return parseErr(label, value, err.Error())
|
||||
}
|
||||
} else {
|
||||
return types.BadRequestErrorf("invalid type for Mtu value")
|
||||
}
|
||||
}
|
||||
|
||||
if i, ok := data["EnableIPv6"]; ok && i != nil {
|
||||
if s, ok := i.(string); ok {
|
||||
if c.EnableIPv6, err = strconv.ParseBool(s); err != nil {
|
||||
return types.BadRequestErrorf("failed to parse EnableIPv6 value: %s", err.Error())
|
||||
case netlabel.EnableIPv6:
|
||||
if c.EnableIPv6, err = strconv.ParseBool(value); err != nil {
|
||||
return parseErr(label, value, err.Error())
|
||||
}
|
||||
} else {
|
||||
return types.BadRequestErrorf("invalid type for EnableIPv6 value")
|
||||
}
|
||||
}
|
||||
|
||||
if i, ok := data["EnableIPMasquerade"]; ok && i != nil {
|
||||
if s, ok := i.(string); ok {
|
||||
if c.EnableIPMasquerade, err = strconv.ParseBool(s); err != nil {
|
||||
return types.BadRequestErrorf("failed to parse EnableIPMasquerade value: %s", err.Error())
|
||||
case EnableIPMasquerade:
|
||||
if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil {
|
||||
return parseErr(label, value, err.Error())
|
||||
}
|
||||
} else {
|
||||
return types.BadRequestErrorf("invalid type for EnableIPMasquerade value")
|
||||
}
|
||||
}
|
||||
|
||||
if i, ok := data["EnableICC"]; ok && i != nil {
|
||||
if s, ok := i.(string); ok {
|
||||
if c.EnableICC, err = strconv.ParseBool(s); err != nil {
|
||||
return types.BadRequestErrorf("failed to parse EnableICC value: %s", err.Error())
|
||||
case EnableICC:
|
||||
if c.EnableICC, err = strconv.ParseBool(value); err != nil {
|
||||
return parseErr(label, value, err.Error())
|
||||
}
|
||||
} else {
|
||||
return types.BadRequestErrorf("invalid type for EnableICC value")
|
||||
}
|
||||
}
|
||||
|
||||
if i, ok := data["DefaultBridge"]; ok && i != nil {
|
||||
if s, ok := i.(string); ok {
|
||||
if c.DefaultBridge, err = strconv.ParseBool(s); err != nil {
|
||||
return types.BadRequestErrorf("failed to parse DefaultBridge value: %s", err.Error())
|
||||
case DefaultBridge:
|
||||
if c.DefaultBridge, err = strconv.ParseBool(value); err != nil {
|
||||
return parseErr(label, value, err.Error())
|
||||
}
|
||||
} else {
|
||||
return types.BadRequestErrorf("invalid type for DefaultBridge value")
|
||||
}
|
||||
}
|
||||
|
||||
if i, ok := data["DefaultBindingIP"]; ok && i != nil {
|
||||
if s, ok := i.(string); ok {
|
||||
if c.DefaultBindingIP = net.ParseIP(s); c.DefaultBindingIP == nil {
|
||||
return types.BadRequestErrorf("failed to parse DefaultBindingIP value")
|
||||
case DefaultBindingIP:
|
||||
if c.DefaultBindingIP = net.ParseIP(value); c.DefaultBindingIP == nil {
|
||||
return parseErr(label, value, "nil ip")
|
||||
}
|
||||
} else {
|
||||
return types.BadRequestErrorf("invalid type for DefaultBindingIP value")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseErr(label, value, errString string) error {
|
||||
return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString)
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainInfo, error) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
@ -442,12 +409,12 @@ func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error)
|
|||
switch opt := data.(type) {
|
||||
case *networkConfiguration:
|
||||
config = opt
|
||||
case map[string]interface{}:
|
||||
case map[string]string:
|
||||
config = &networkConfiguration{
|
||||
EnableICC: true,
|
||||
EnableIPMasquerade: true,
|
||||
}
|
||||
err = config.fromMap(opt)
|
||||
err = config.fromLabels(opt)
|
||||
case options.Generic:
|
||||
var opaqueConfig interface{}
|
||||
if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil {
|
||||
|
@ -491,8 +458,10 @@ func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []d
|
|||
}
|
||||
|
||||
func parseNetworkOptions(id string, option options.Generic) (*networkConfiguration, error) {
|
||||
var err error
|
||||
config := &networkConfiguration{}
|
||||
var (
|
||||
err error
|
||||
config = &networkConfiguration{}
|
||||
)
|
||||
|
||||
// Parse generic label first, config will be re-assigned
|
||||
if genData, ok := option[netlabel.GenericData]; ok && genData != nil {
|
||||
|
@ -502,8 +471,8 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
|
|||
}
|
||||
|
||||
// Process well-known labels next
|
||||
if _, ok := option[netlabel.EnableIPv6]; ok {
|
||||
config.EnableIPv6 = option[netlabel.EnableIPv6].(bool)
|
||||
if val, ok := option[netlabel.EnableIPv6]; ok {
|
||||
config.EnableIPv6 = val.(bool)
|
||||
}
|
||||
|
||||
// Finally validate the configuration
|
||||
|
|
|
@ -97,6 +97,58 @@ func TestCreateNoConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCreateFullOptionsLabels(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
|
||||
labels := map[string]string{
|
||||
BridgeName: "cu",
|
||||
netlabel.EnableIPv6: "true",
|
||||
EnableICC: "true",
|
||||
EnableIPMasquerade: "true",
|
||||
DefaultBindingIP: "127.0.0.1",
|
||||
}
|
||||
|
||||
netOption := make(map[string]interface{})
|
||||
netOption[netlabel.GenericData] = labels
|
||||
|
||||
err := d.CreateNetwork("dummy", netOption, getIPv4Data(t), nil)
|
||||
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 != "cu" {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
|
18
libnetwork/drivers/bridge/labels.go
Normal file
18
libnetwork/drivers/bridge/labels.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package bridge
|
||||
|
||||
const (
|
||||
// BridgeName label for bridge driver
|
||||
BridgeName = "com.docker.network.bridge.name"
|
||||
|
||||
// EnableIPMasquerade label for bridge driver
|
||||
EnableIPMasquerade = "com.docker.network.bridge.enable_ip_masquerade"
|
||||
|
||||
// EnableICC label
|
||||
EnableICC = "com.docker.network.bridge.enable_icc"
|
||||
|
||||
// DefaultBindingIP label
|
||||
DefaultBindingIP = "com.docker.network.bridge.host_binding_ipv4"
|
||||
|
||||
// DefaultBridge label
|
||||
DefaultBridge = "com.docker.network.bridge.default_bridge"
|
||||
)
|
|
@ -1,6 +1,8 @@
|
|||
package netlabel
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Prefix constant marks the reserved label space for libnetwork
|
||||
|
@ -22,12 +24,15 @@ const (
|
|||
// MacAddress constant represents Mac Address config of a Container
|
||||
MacAddress = Prefix + ".endpoint.macaddress"
|
||||
|
||||
// ExposedPorts constant represents exposedports of a Container
|
||||
// ExposedPorts constant represents the container's Exposed Ports
|
||||
ExposedPorts = Prefix + ".endpoint.exposedports"
|
||||
|
||||
//EnableIPv6 constant represents enabling IPV6 at network level
|
||||
EnableIPv6 = Prefix + ".enable_ipv6"
|
||||
|
||||
// DriverMTU constant represents the MTU size for the network driver
|
||||
DriverMTU = DriverPrefix + ".mtu"
|
||||
|
||||
// OverlayBindInterface constant represents overlay driver bind interface
|
||||
OverlayBindInterface = DriverPrefix + ".overlay.bind_interface"
|
||||
|
||||
|
@ -74,15 +79,51 @@ func MakeKVProviderConfig(scope string) string {
|
|||
}
|
||||
|
||||
// Key extracts the key portion of the label
|
||||
func Key(label string) string {
|
||||
kv := strings.SplitN(label, "=", 2)
|
||||
|
||||
return kv[0]
|
||||
func Key(label string) (key string) {
|
||||
if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {
|
||||
key = kv[0]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Value extracts the value portion of the label
|
||||
func Value(label string) string {
|
||||
kv := strings.SplitN(label, "=", 2)
|
||||
|
||||
return kv[1]
|
||||
func Value(label string) (value string) {
|
||||
if kv := strings.SplitN(label, "=", 2); len(kv) > 1 {
|
||||
value = kv[1]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// KeyValue decomposes the label in the (key,value) pair
|
||||
func KeyValue(label string) (key string, value string) {
|
||||
if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {
|
||||
key = kv[0]
|
||||
if len(kv) > 1 {
|
||||
value = kv[1]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ToMap converts a list of labels in a map of (key,value) pairs
|
||||
func ToMap(labels []string) map[string]string {
|
||||
m := make(map[string]string, len(labels))
|
||||
for _, l := range labels {
|
||||
k, v := KeyValue(l)
|
||||
m[k] = v
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// FromMap converts a map of (key,value) pairs in a lsit of labels
|
||||
func FromMap(m map[string]string) []string {
|
||||
l := make([]string, 0, len(m))
|
||||
for k, v := range m {
|
||||
s := k
|
||||
if v != "" {
|
||||
s = s + "=" + v
|
||||
}
|
||||
l = append(l, s)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
|
77
libnetwork/netlabel/labels_test.go
Normal file
77
libnetwork/netlabel/labels_test.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
package netlabel
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "github.com/docker/libnetwork/testutils"
|
||||
)
|
||||
|
||||
var input = []struct {
|
||||
label string
|
||||
key string
|
||||
value string
|
||||
}{
|
||||
{"com.directory.person.name=joe", "com.directory.person.name", "joe"},
|
||||
{"com.directory.person.age=24", "com.directory.person.age", "24"},
|
||||
{"com.directory.person.address=1234 First st.", "com.directory.person.address", "1234 First st."},
|
||||
{"com.directory.person.friends=", "com.directory.person.friends", ""},
|
||||
{"com.directory.person.nickname=o=u=8", "com.directory.person.nickname", "o=u=8"},
|
||||
{"", "", ""},
|
||||
{"com.directory.person.student", "com.directory.person.student", ""},
|
||||
}
|
||||
|
||||
func TestKeyValue(t *testing.T) {
|
||||
for _, i := range input {
|
||||
k, v := KeyValue(i.label)
|
||||
if k != i.key || v != i.value {
|
||||
t.Fatalf("unexpected: %s, %s", k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToMap(t *testing.T) {
|
||||
lista := make([]string, len(input))
|
||||
for ind, i := range input {
|
||||
lista[ind] = i.label
|
||||
}
|
||||
|
||||
mappa := ToMap(lista)
|
||||
|
||||
if len(mappa) != len(lista) {
|
||||
t.Fatalf("Incorrect map length. Expected %d. Got %d", len(lista), len(mappa))
|
||||
}
|
||||
|
||||
for _, i := range input {
|
||||
if v, ok := mappa[i.key]; !ok || v != i.value {
|
||||
t.Fatalf("Cannot find key or value for key: %s", i.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromMap(t *testing.T) {
|
||||
var m map[string]string
|
||||
lbls := FromMap(m)
|
||||
if len(lbls) != 0 {
|
||||
t.Fatalf("unexpected lbls length")
|
||||
}
|
||||
|
||||
m = make(map[string]string, 3)
|
||||
m["peso"] = "85"
|
||||
m["statura"] = "170"
|
||||
m["maschio"] = ""
|
||||
|
||||
lbls = FromMap(m)
|
||||
if len(lbls) != 3 {
|
||||
t.Fatalf("unexpected lbls length")
|
||||
}
|
||||
|
||||
for _, l := range lbls {
|
||||
switch l {
|
||||
case "peso=85":
|
||||
case "statura=170":
|
||||
case "maschio":
|
||||
default:
|
||||
t.Fatalf("unexpected label: %s", l)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
@ -49,6 +50,15 @@ type Network interface {
|
|||
|
||||
// EndpointByID returns the Endpoint which has the passed id. If not found, the error ErrNoSuchEndpoint is returned.
|
||||
EndpointByID(id string) (Endpoint, error)
|
||||
|
||||
// Return certain operational data belonging to this network
|
||||
Info() NetworkInfo
|
||||
}
|
||||
|
||||
// NetworkInfo returns operational information about the network
|
||||
type NetworkInfo interface {
|
||||
Labels() []string
|
||||
Scope() string
|
||||
}
|
||||
|
||||
// EndpointWalker is a client provided function which will be used to walk the Endpoints.
|
||||
|
@ -150,7 +160,6 @@ type network struct {
|
|||
dbExists bool
|
||||
persist bool
|
||||
stopWatchCh chan struct{}
|
||||
scope string
|
||||
drvOnce *sync.Once
|
||||
sync.Mutex
|
||||
}
|
||||
|
@ -382,6 +391,18 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
|||
|
||||
if v, ok := netMap["generic"]; ok {
|
||||
n.generic = v.(map[string]interface{})
|
||||
// Restore labels in their map[string]string form
|
||||
if v, ok := n.generic[netlabel.GenericData]; ok {
|
||||
var lmap map[string]string
|
||||
ba, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(ba, &lmap); err != nil {
|
||||
return err
|
||||
}
|
||||
n.generic[netlabel.GenericData] = lmap
|
||||
}
|
||||
}
|
||||
if v, ok := netMap["persist"]; ok {
|
||||
n.persist = v.(bool)
|
||||
|
@ -391,7 +412,6 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
|||
} else {
|
||||
n.ipamType = ipamapi.DefaultIPAM
|
||||
}
|
||||
|
||||
if v, ok := netMap["addrSpace"]; ok {
|
||||
n.addrSpace = v.(string)
|
||||
}
|
||||
|
@ -451,6 +471,25 @@ func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ip
|
|||
}
|
||||
}
|
||||
|
||||
// NetworkOptionLabels function returns an option setter for any parameter described by a map
|
||||
func NetworkOptionLabels(labels []string) NetworkOption {
|
||||
return func(n *network) {
|
||||
if n.generic == nil {
|
||||
n.generic = make(map[string]interface{})
|
||||
}
|
||||
opts := netlabel.ToMap(labels)
|
||||
// Store the options
|
||||
n.generic[netlabel.GenericData] = opts
|
||||
// Decode and store the endpoint options of libnetwork interest
|
||||
if val, ok := opts[netlabel.EnableIPv6]; ok {
|
||||
var err error
|
||||
if n.enableIPv6, err = strconv.ParseBool(val); err != nil {
|
||||
log.Warnf("Failed to parse %s' value: %s (%s)", netlabel.EnableIPv6, val, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *network) processOptions(options ...NetworkOption) {
|
||||
for _, opt := range options {
|
||||
if opt != nil {
|
||||
|
@ -1003,3 +1042,22 @@ func (n *network) deriveAddressSpace() (string, error) {
|
|||
}
|
||||
return ipd.defaultLocalAddressSpace, nil
|
||||
}
|
||||
|
||||
func (n *network) Info() NetworkInfo {
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *network) Labels() []string {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
if n.generic != nil {
|
||||
if m, ok := n.generic[netlabel.GenericData]; ok {
|
||||
return netlabel.FromMap(m.(map[string]string))
|
||||
}
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (n *network) Scope() string {
|
||||
return n.driverScope()
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -17,11 +18,46 @@ type TransportPort struct {
|
|||
Port uint16
|
||||
}
|
||||
|
||||
// Equal checks if this instance of Transportport is equal to the passed one
|
||||
func (t *TransportPort) Equal(o *TransportPort) bool {
|
||||
if t == o {
|
||||
return true
|
||||
}
|
||||
|
||||
if o == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if t.Proto != o.Proto || t.Port != o.Port {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GetCopy returns a copy of this TransportPort structure instance
|
||||
func (t *TransportPort) GetCopy() TransportPort {
|
||||
return TransportPort{Proto: t.Proto, Port: t.Port}
|
||||
}
|
||||
|
||||
// String returns the TransportPort structure in string form
|
||||
func (t *TransportPort) String() string {
|
||||
return fmt.Sprintf("%s/%d", t.Proto.String(), t.Port)
|
||||
}
|
||||
|
||||
// FromString reads the TransportPort structure from string
|
||||
func (t *TransportPort) FromString(s string) error {
|
||||
ps := strings.Split(s, "/")
|
||||
if len(ps) == 2 {
|
||||
t.Proto = ParseProtocol(ps[0])
|
||||
if p, err := strconv.ParseUint(ps[1], 10, 16); err == nil {
|
||||
t.Port = uint16(p)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return BadRequestErrorf("invalid format for transport port: %s", s)
|
||||
}
|
||||
|
||||
// PortBinding represent a port binding between the container and the host
|
||||
type PortBinding struct {
|
||||
Proto Protocol
|
||||
|
@ -68,6 +104,62 @@ func (p *PortBinding) GetCopy() PortBinding {
|
|||
}
|
||||
}
|
||||
|
||||
// String return the PortBinding structure in string form
|
||||
func (p *PortBinding) String() string {
|
||||
ret := fmt.Sprintf("%s/", p.Proto)
|
||||
if p.IP != nil {
|
||||
ret = fmt.Sprintf("%s%s", ret, p.IP.String())
|
||||
}
|
||||
ret = fmt.Sprintf("%s:%d/", ret, p.Port)
|
||||
if p.HostIP != nil {
|
||||
ret = fmt.Sprintf("%s%s", ret, p.HostIP.String())
|
||||
}
|
||||
ret = fmt.Sprintf("%s:%d", ret, p.HostPort)
|
||||
return ret
|
||||
}
|
||||
|
||||
// FromString reads the TransportPort structure from string
|
||||
func (p *PortBinding) FromString(s string) error {
|
||||
ps := strings.Split(s, "/")
|
||||
if len(ps) != 3 {
|
||||
return BadRequestErrorf("invalid format for port binding: %s", s)
|
||||
}
|
||||
|
||||
p.Proto = ParseProtocol(ps[0])
|
||||
|
||||
var err error
|
||||
if p.IP, p.Port, err = parseIPPort(ps[1]); err != nil {
|
||||
return BadRequestErrorf("failed to parse Container IP/Port in port binding: %s", err.Error())
|
||||
}
|
||||
|
||||
if p.HostIP, p.HostPort, err = parseIPPort(ps[2]); err != nil {
|
||||
return BadRequestErrorf("failed to parse Host IP/Port in port binding: %s", err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseIPPort(s string) (net.IP, uint16, error) {
|
||||
pp := strings.Split(s, ":")
|
||||
if len(pp) != 2 {
|
||||
return nil, 0, BadRequestErrorf("invalid format: %s", s)
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
if pp[0] != "" {
|
||||
if ip = net.ParseIP(pp[0]); ip == nil {
|
||||
return nil, 0, BadRequestErrorf("invalid ip: %s", pp[0])
|
||||
}
|
||||
}
|
||||
|
||||
port, err := strconv.ParseUint(pp[1], 10, 16)
|
||||
if err != nil {
|
||||
return nil, 0, BadRequestErrorf("invalid port: %s", pp[1])
|
||||
}
|
||||
|
||||
return ip, uint16(port), nil
|
||||
}
|
||||
|
||||
// Equal checks if this instance of PortBinding is equal to the passed one
|
||||
func (p *PortBinding) Equal(o *PortBinding) bool {
|
||||
if p == o {
|
||||
|
|
|
@ -8,6 +8,42 @@ import (
|
|||
|
||||
var runningInContainer = flag.Bool("incontainer", false, "Indicates if the test is running in a container")
|
||||
|
||||
func TestTransportPortConv(t *testing.T) {
|
||||
sform := "tcp/23"
|
||||
tp := &TransportPort{Proto: TCP, Port: uint16(23)}
|
||||
|
||||
if sform != tp.String() {
|
||||
t.Fatalf("String() method failed")
|
||||
}
|
||||
|
||||
rc := new(TransportPort)
|
||||
if err := rc.FromString(sform); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !tp.Equal(rc) {
|
||||
t.Fatalf("FromString() method failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransportPortBindingConv(t *testing.T) {
|
||||
sform := "tcp/172.28.30.23:80/112.0.43.56:8001"
|
||||
pb := &PortBinding{
|
||||
Proto: TCP,
|
||||
IP: net.IPv4(172, 28, 30, 23),
|
||||
Port: uint16(80),
|
||||
HostIP: net.IPv4(112, 0, 43, 56),
|
||||
HostPort: uint16(8001),
|
||||
}
|
||||
|
||||
rc := new(PortBinding)
|
||||
if err := rc.FromString(sform); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !pb.Equal(rc) {
|
||||
t.Fatalf("FromString() method failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorConstructors(t *testing.T) {
|
||||
var err error
|
||||
|
||||
|
|
Loading…
Reference in a new issue