diff --git a/libnetwork/libnetwork_internal_test.go b/libnetwork/libnetwork_internal_test.go index 96084c6ef0..10937618a4 100644 --- a/libnetwork/libnetwork_internal_test.go +++ b/libnetwork/libnetwork_internal_test.go @@ -564,6 +564,80 @@ func TestServiceVIPReuse(t *testing.T) { } } +func TestWildcardLookup(t *testing.T) { + skip.If(t, runtime.GOOS == "windows", "test only works on linux") + + c, err := New() + if err != nil { + t.Fatal(err) + } + defer c.Stop() + + n, err := c.NewNetwork("bridge", "net1", "", nil) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := n.Delete(); err != nil { + t.Fatal(err) + } + }() + + ep, err := n.CreateEndpoint("testep") + if err != nil { + t.Fatal(err) + } + + sb, err := c.NewSandbox("c1") + if err != nil { + t.Fatal(err) + } + defer func() { + if err := sb.Delete(); err != nil { + t.Fatal(err) + } + }() + + err = ep.Join(sb) + if err != nil { + t.Fatal(err) + } + + // Add aliases including a wildcard for one service + n.(*network).addSvcRecords("ep1", "foo.local", "serviceID1", net.ParseIP("192.168.0.1"), net.IP{}, true, "test") + n.(*network).addSvcRecords("ep1", "*.bar.local", "serviceID1", net.ParseIP("192.168.0.1"), net.IP{}, false, "test") + + // exact match + ipList, _ := n.(*network).ResolveName("foo.local", types.IPv4) + if len(ipList) == 0 { + t.Fatal("There must be the VIP") + } + if len(ipList) != 1 { + t.Fatal("It must return only 1 VIP") + } + if ipList[0].String() != "192.168.0.1" { + t.Fatal("The service VIP is 192.168.0.1") + } + + // wildcard match + ipList, _ = n.(*network).ResolveName("my.bar.local", types.IPv4) + if len(ipList) == 0 { + t.Fatal("There must be the VIP") + } + if len(ipList) != 1 { + t.Fatal("It must return only 1 VIP") + } + if ipList[0].String() != "192.168.0.1" { + t.Fatal("The service VIP is 192.168.0.1") + } + + // no match + ipList, _ = n.(*network).ResolveName("baz.local", types.IPv4) + if len(ipList) != 0 { + t.Fatal("Invalid hostname must not resolve") + } +} + func TestIpamReleaseOnNetDriverFailures(t *testing.T) { skip.If(t, runtime.GOOS == "windows", "test only works on linux") diff --git a/libnetwork/network.go b/libnetwork/network.go index 311f0e81cc..bb18b23a95 100644 --- a/libnetwork/network.go +++ b/libnetwork/network.go @@ -1963,7 +1963,27 @@ func (n *Network) ResolveName(ctx context.Context, req string, ipType int) ([]ne req = strings.TrimSuffix(req, ".") req = strings.ToLower(req) - ipSet, ok := sr.svcMap.Get(req) + + // Support wildcard matching, naïve implementation uses a loop + selectedKey := req + ok = false + var ipSet []interface{} + for _, key := range sr.svcMap.Keys() { + if key == selectedKey || + (strings.HasPrefix(key, "*.") && + strings.HasSuffix(req, strings.TrimPrefix(key, "*"))) { + selectedKey = key + ok = true + var found bool + ipSet, found = sr.svcMap.Get(selectedKey) + if !found { + logrus.Errorf("svcMap changed unexpectedly looking for key %s", key) + continue + } + + break + } + } if ipType == types.IPv6 { // If the name resolved to v4 address then its a valid name in @@ -1973,7 +1993,7 @@ func (n *Network) ResolveName(ctx context.Context, req string, ipType int) ([]ne if ok && !n.enableIPv6 { ipv6Miss = true } - ipSet, ok = sr.svcIPv6Map.Get(req) + ipSet, ok = sr.svcIPv6Map.Get(selectedKey) } if ok && len(ipSet) > 0 {