diff --git a/libnetwork/api/api.go b/libnetwork/api/api.go index bfb94af06b..95accac2c3 100644 --- a/libnetwork/api/api.go +++ b/libnetwork/api/api.go @@ -9,6 +9,7 @@ import ( "github.com/docker/libnetwork" "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/types" "github.com/gorilla/mux" ) @@ -459,6 +460,7 @@ func procDeleteNetwork(c libnetwork.NetworkController, vars map[string]string, b *******************/ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { var ej endpointJoin + var setFctList []libnetwork.EndpointOption err := json.Unmarshal(body, &ej) if err != nil { return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} @@ -477,7 +479,15 @@ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, bo return nil, errRsp } - err = ep.Join(sb) + for _, str := range ej.Aliases { + name, alias, err := netutils.ParseAlias(str) + if err != nil { + return "", convertNetworkError(err) + } + setFctList = append(setFctList, libnetwork.CreateOptionAlias(name, alias)) + } + + err = ep.Join(sb, setFctList...) if err != nil { return nil, convertNetworkError(err) } @@ -637,6 +647,7 @@ func procUnpublishService(c libnetwork.NetworkController, vars map[string]string func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { var bk endpointJoin + var setFctList []libnetwork.EndpointOption err := json.Unmarshal(body, &bk) if err != nil { return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} @@ -653,7 +664,15 @@ func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, b return nil, errRsp } - err = sv.Join(sb) + for _, str := range bk.Aliases { + name, alias, err := netutils.ParseAlias(str) + if err != nil { + return "", convertNetworkError(err) + } + setFctList = append(setFctList, libnetwork.CreateOptionAlias(name, alias)) + } + + err = sv.Join(sb, setFctList...) if err != nil { return nil, convertNetworkError(err) } diff --git a/libnetwork/api/types.go b/libnetwork/api/types.go index df565c4056..bd37b0c5a2 100644 --- a/libnetwork/api/types.go +++ b/libnetwork/api/types.go @@ -62,7 +62,8 @@ type sandboxCreate struct { // endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages type endpointJoin struct { - SandboxID string `json:"sandbox_id"` + SandboxID string `json:"sandbox_id"` + Aliases []string `json:"aliases"` } // servicePublish represents the body of the "publish service" http request message diff --git a/libnetwork/client/service.go b/libnetwork/client/service.go index f2ecedddeb..16acab6d5f 100644 --- a/libnetwork/client/service.go +++ b/libnetwork/client/service.go @@ -8,8 +8,10 @@ import ( "strings" "text/tabwriter" + "github.com/docker/docker/opts" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/stringid" + "github.com/docker/libnetwork/netutils" ) var ( @@ -319,6 +321,8 @@ func (cli *NetworkCli) CmdServiceInfo(chain string, args ...string) error { // CmdServiceAttach handles service attach UI func (cli *NetworkCli) CmdServiceAttach(chain string, args ...string) error { cmd := cli.Subcmd(chain, "attach", "CONTAINER SERVICE[.NETWORK]", "Sets a container as a service backend", false) + flAlias := opts.NewListOpts(netutils.ValidateAlias) + cmd.Var(&flAlias, []string{"-alias"}, "Add alias for another container") cmd.Require(flag.Min, 2) err := cmd.ParseFlags(args, true) if err != nil { @@ -341,7 +345,7 @@ func (cli *NetworkCli) CmdServiceAttach(chain string, args ...string) error { return err } - nc := serviceAttach{SandboxID: sandboxID} + nc := serviceAttach{SandboxID: sandboxID, Aliases: flAlias.GetAll()} _, _, err = readBody(cli.call("POST", "/services/"+serviceID+"/backend", nc, nil)) diff --git a/libnetwork/client/types.go b/libnetwork/client/types.go index c87b6792fc..a18d16ee3b 100644 --- a/libnetwork/client/types.go +++ b/libnetwork/client/types.go @@ -50,7 +50,8 @@ type serviceCreate struct { // serviceAttach represents the expected body of the "attach/detach sandbox to/from service" http request messages type serviceAttach struct { - SandboxID string `json:"sandbox_id"` + SandboxID string `json:"sandbox_id"` + Aliases []string `json:"aliases"` } // SandboxCreate is the body of the "post /sandboxes" http request message diff --git a/libnetwork/netutils/utils.go b/libnetwork/netutils/utils.go index 70f514b7cb..62287efcc9 100644 --- a/libnetwork/netutils/utils.go +++ b/libnetwork/netutils/utils.go @@ -169,3 +169,26 @@ func ReverseIP(IP string) string { return strings.Join(reverseIP, ".") } + +// ParseAlias parses and validates the specified string as a alias format (name:alias) +func ParseAlias(val string) (string, string, error) { + if val == "" { + return "", "", fmt.Errorf("empty string specified for alias") + } + arr := strings.Split(val, ":") + if len(arr) > 2 { + return "", "", fmt.Errorf("bad format for alias: %s", val) + } + if len(arr) == 1 { + return val, val, nil + } + return arr[0], arr[1], nil +} + +// ValidateAlias validates that the specified string has a valid alias format (containerName:alias). +func ValidateAlias(val string) (string, error) { + if _, _, err := ParseAlias(val); err != nil { + return val, err + } + return val, nil +} diff --git a/libnetwork/test/integration/dnet/bridge.bats b/libnetwork/test/integration/dnet/bridge.bats index 385c9ae43e..e3be64dccb 100644 --- a/libnetwork/test/integration/dnet/bridge.bats +++ b/libnetwork/test/integration/dnet/bridge.bats @@ -233,3 +233,19 @@ function test_single_network_connectivity() { done } + +@test "Test bridge network alias support" { + skip_for_circleci + dnet_cmd $(inst_id2port 1) network create -d bridge br1 + dnet_cmd $(inst_id2port 1) container create container_1 + net_connect 1 container_1 br1 container_2:c2 + dnet_cmd $(inst_id2port 1) container create container_2 + net_connect 1 container_2 br1 + runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 container_2" + runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 c2" + net_disconnect 1 container_1 br1 + net_disconnect 1 container_2 br1 + dnet_cmd $(inst_id2port 1) container rm container_1 + dnet_cmd $(inst_id2port 1) container rm container_2 + dnet_cmd $(inst_id2port 1) network rm br1 +} diff --git a/libnetwork/test/integration/dnet/helpers.bash b/libnetwork/test/integration/dnet/helpers.bash index 456b7e8a54..b12eb91d3f 100644 --- a/libnetwork/test/integration/dnet/helpers.bash +++ b/libnetwork/test/integration/dnet/helpers.bash @@ -18,8 +18,12 @@ function get_sbox_id() { } function net_connect() { + local al + if [ -n "$4" ]; then + al="--alias=${4}" + fi dnet_cmd $(inst_id2port ${1}) service publish ${2}.${3} - dnet_cmd $(inst_id2port ${1}) service attach ${2} ${2}.${3} + dnet_cmd $(inst_id2port ${1}) service attach $al ${2} ${2}.${3} } function net_disconnect() {