diff --git a/daemon/mgr/network.go b/daemon/mgr/network.go index c2d310edf..20d0256b6 100644 --- a/daemon/mgr/network.go +++ b/daemon/mgr/network.go @@ -15,6 +15,7 @@ import ( "github.com/alibaba/pouch/pkg/errtypes" "github.com/alibaba/pouch/pkg/meta" "github.com/alibaba/pouch/pkg/randomid" + "github.com/alibaba/pouch/pkg/utils" "github.com/docker/go-connections/nat" "github.com/docker/libnetwork" @@ -579,12 +580,22 @@ func endpointOptions(n libnetwork.Network, endpoint *types.Endpoint) ([]libnetwo } } + // generate genric endpoint options genericOption := options.Generic{} - createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) - if len(endpoint.GenericParams) > 0 { - createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(endpoint.GenericParams)) + genericOption, _ = utils.MergeMap(genericOption, endpoint.GenericParams) } + + if n.Name() == endpoint.NetworkMode && endpoint.MacAddress != "" { + mac, err := net.ParseMAC(endpoint.MacAddress) + if err != nil { + return nil, err + } + genericOption, _ = utils.MergeMap(genericOption, options.Generic{netlabel.MacAddress: mac}) + logrus.Debugf("generate endpoint macaddress: (%s)", endpoint.MacAddress) + } + createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) + if endpoint.DisableResolver { createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index fea388d4d..705dd7d6f 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -330,3 +330,24 @@ func StringSliceEqual(s1, s2 []string) bool { return true } + +// MergeMap merges the m2 into m1, if it has the same keys, m2 will overwrite m1. +func MergeMap(m1 map[string]interface{}, m2 map[string]interface{}) (map[string]interface{}, error) { + if m1 == nil && m2 == nil { + return nil, fmt.Errorf("all of maps are nil") + } + + if m1 == nil { + return m2, nil + } + + if m2 == nil { + return m1, nil + } + + for k, v := range m2 { + m1[k] = v + } + + return m1, nil +} diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 942d0792b..b9f1a7ce8 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -544,3 +544,35 @@ func TestStringSliceEqual(t *testing.T) { } } } + +func TestMergeMap(t *testing.T) { + type Expect struct { + err error + key string + value interface{} + } + tests := []struct { + m1 map[string]interface{} + m2 map[string]interface{} + expect Expect + }{ + {nil, nil, Expect{fmt.Errorf("all of maps are nil"), "", nil}}, + {nil, map[string]interface{}{"a": "a"}, Expect{nil, "a", "a"}}, + {map[string]interface{}{"a": "a"}, nil, Expect{nil, "a", "a"}}, + {map[string]interface{}{"a": "a"}, map[string]interface{}{"a": "b"}, Expect{nil, "a", "b"}}, + {map[string]interface{}{"a": "a"}, map[string]interface{}{"b": "b"}, Expect{nil, "b", "b"}}, + } + + for _, test := range tests { + m3, err := MergeMap(test.m1, test.m2) + if err != nil { + if test.expect.err.Error() != err.Error() { + t.Fatalf("MergeMap(%v, %v) expected: %v, but got %v", test.m1, test.m2, test.expect.err, err) + } + } else { + if m3[test.expect.key] != test.expect.value { + t.Fatalf("MergeMap(%v, %v) expected: %v, but got %v", test.m1, test.m2, test.expect.value, m3[test.expect.key]) + } + } + } +} diff --git a/test/api_container_create_test.go b/test/api_container_create_test.go index 1ae903796..85a3371bf 100644 --- a/test/api_container_create_test.go +++ b/test/api_container_create_test.go @@ -3,12 +3,15 @@ package main import ( "net/url" "sort" + "strings" "github.com/alibaba/pouch/apis/types" + "github.com/alibaba/pouch/test/command" "github.com/alibaba/pouch/test/environment" "github.com/alibaba/pouch/test/request" "github.com/go-check/check" + "github.com/gotestyourself/gotestyourself/icmd" ) // APIContainerCreateSuite is the test suite for container create API. @@ -231,3 +234,48 @@ func (suite *APIContainerCreateSuite) TestCreateNvidiaConfig(c *check.C) { DelContainerForceMultyTime(c, cname) } + +func (suite *APIContainerCreateSuite) TestCreateWithMacAddress(c *check.C) { + cname := "TestCreateWithMacAddress" + mac := "00:16:3e:02:00:b7" + q := url.Values{} + q.Add("name", cname) + query := request.WithQuery(q) + + obj := map[string]interface{}{ + "Entrypoint": []string{"top"}, + "Image": busyboxImage, + "MacAddress": mac, + "NetworkMode": "bridge", + } + body := request.WithJSONBody(obj) + + resp, err := request.Post("/containers/create", query, body) + c.Assert(err, check.IsNil) + CheckRespStatus(c, resp, 201) + + q = url.Values{} + q.Add("detachKeys", "EOF") + query = request.WithQuery(q) + + resp, err = request.Post("/containers/"+cname+"/start", query) + c.Assert(err, check.IsNil) + CheckRespStatus(c, resp, 204) + + ret := command.PouchRun("exec", cname, "ip", "addr", "show", "eth0") + ret.Assert(c, icmd.Success) + + found := false + for _, line := range strings.Split(ret.Stdout(), "\n") { + if strings.Contains(line, "link/ether") { + if mac == strings.Fields(line)[1] { + found = true + break + } + } + } + + c.Assert(found, check.Equals, true) + + DelContainerForceMultyTime(c, cname) +}