mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
Populate DNS records for IPv6-only endpoints
Also, return IPv6 records from Network.getSvcRecords() so that /etc/hosts entries are deleted when an IPv6-only endpoint is removed. Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
@@ -143,6 +143,10 @@ func mergeRecords(path string, recs []Record) ([]byte, error) {
|
||||
}
|
||||
|
||||
// Delete deletes an arbitrary number of Records already existing in /etc/hosts file
|
||||
//
|
||||
// FIXME(robmry) - this only matches on hostname, not address. So, if a container
|
||||
// is connected to two networks then disconnected from one of them, the hosts
|
||||
// entries for both networks are deleted.
|
||||
func Delete(path string, recs []Record) error {
|
||||
defer pathLock(path)()
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/docker/docker/internal/testutils/netnsutils"
|
||||
"github.com/docker/docker/libnetwork/config"
|
||||
"github.com/docker/docker/libnetwork/driverapi"
|
||||
"github.com/docker/docker/libnetwork/etchosts"
|
||||
"github.com/docker/docker/libnetwork/ipams/defaultipam"
|
||||
"github.com/docker/docker/libnetwork/ipamutils"
|
||||
"github.com/docker/docker/libnetwork/netlabel"
|
||||
@@ -358,6 +359,91 @@ func TestAuxAddresses(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateSvcRecord(t *testing.T) {
|
||||
skip.If(t, runtime.GOOS == "windows", "bridge driver and IPv6, only works on linux")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
epName string
|
||||
addr4 string
|
||||
addr6 string
|
||||
expSvcRecs []etchosts.Record
|
||||
}{
|
||||
{
|
||||
name: "v4only",
|
||||
epName: "ep4",
|
||||
addr4: "172.16.0.2/24",
|
||||
expSvcRecs: []etchosts.Record{
|
||||
{Hosts: "id-ep4", IP: "172.16.0.2"},
|
||||
},
|
||||
},
|
||||
/* TODO(robmry) - add this test when the bridge driver understands v6-only
|
||||
{
|
||||
name: "v6only",
|
||||
epName: "ep6",
|
||||
addr6: "fde6:045d:b2aa::2/64",
|
||||
expSvcRecs: []etchosts.Record{
|
||||
{Hosts: "id-ep6", IP: "fde6:45d:b2aa::2"},
|
||||
},
|
||||
},
|
||||
*/
|
||||
{
|
||||
name: "dual-stack",
|
||||
epName: "ep46",
|
||||
addr4: "172.16.1.2/24",
|
||||
addr6: "fd60:8677:5a4c::2/64",
|
||||
expSvcRecs: []etchosts.Record{
|
||||
{Hosts: "id-ep46", IP: "172.16.1.2"},
|
||||
{Hosts: "id-ep46", IP: "fd60:8677:5a4c::2"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
defer netnsutils.SetupTestOSContext(t)()
|
||||
ctrlr, err := New(OptionBoltdbWithRandomDBFile(t))
|
||||
assert.NilError(t, err)
|
||||
defer ctrlr.Stop()
|
||||
|
||||
var ipam4, ipam6 []*IpamConf
|
||||
var ip4, ip6 net.IP
|
||||
if tc.addr4 != "" {
|
||||
var net4 *net.IPNet
|
||||
ip4, net4, err = net.ParseCIDR(tc.addr4)
|
||||
assert.NilError(t, err)
|
||||
ipam4 = []*IpamConf{{PreferredPool: net4.String()}}
|
||||
}
|
||||
if tc.addr6 != "" {
|
||||
var net6 *net.IPNet
|
||||
ip6, net6, err = net.ParseCIDR(tc.addr6)
|
||||
assert.NilError(t, err)
|
||||
ipam6 = []*IpamConf{{PreferredPool: net6.String()}}
|
||||
}
|
||||
n, err := ctrlr.NewNetwork("bridge", "net1", "", nil,
|
||||
NetworkOptionEnableIPv4(tc.addr4 != ""),
|
||||
NetworkOptionEnableIPv6(tc.addr6 != ""),
|
||||
NetworkOptionIpam(defaultipam.DriverName, "", ipam4, ipam6, nil),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
ep, err := n.CreateEndpoint(context.Background(), tc.epName,
|
||||
CreateOptionDNSNames([]string{tc.epName, "id-" + tc.epName}),
|
||||
CreateOptionIpam(ip4, ip6, nil, nil),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
n.updateSvcRecord(context.Background(), ep, true)
|
||||
recs := n.getSvcRecords(ep)
|
||||
assert.Check(t, is.DeepEqual(recs, tc.expSvcRecs))
|
||||
|
||||
n.updateSvcRecord(context.Background(), ep, false)
|
||||
recs = n.getSvcRecords(ep)
|
||||
assert.Check(t, is.Nil(recs))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSRVServiceQuery(t *testing.T) {
|
||||
skip.If(t, runtime.GOOS == "windows", "test only works on linux")
|
||||
|
||||
|
||||
@@ -1329,11 +1329,14 @@ func (n *Network) updateSvcRecord(ctx context.Context, ep *Endpoint, isAdd bool)
|
||||
defer span.End()
|
||||
|
||||
iface := ep.Iface()
|
||||
if iface == nil || iface.Address() == nil {
|
||||
if iface == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var ipv6 net.IP
|
||||
var ipv4, ipv6 net.IP
|
||||
if iface.Address() != nil {
|
||||
ipv4 = iface.Address().IP
|
||||
}
|
||||
if iface.AddressIPv6() != nil {
|
||||
ipv6 = iface.AddressIPv6().IP
|
||||
}
|
||||
@@ -1347,12 +1350,12 @@ func (n *Network) updateSvcRecord(ctx context.Context, ep *Endpoint, isAdd bool)
|
||||
if isAdd {
|
||||
for i, dnsName := range dnsNames {
|
||||
ipMapUpdate := i == 0 // ipMapUpdate indicates whether PTR records should be updated.
|
||||
n.addSvcRecords(ep.ID(), dnsName, serviceID, iface.Address().IP, ipv6, ipMapUpdate, "updateSvcRecord")
|
||||
n.addSvcRecords(ep.ID(), dnsName, serviceID, ipv4, ipv6, ipMapUpdate, "updateSvcRecord")
|
||||
}
|
||||
} else {
|
||||
for i, dnsName := range dnsNames {
|
||||
ipMapUpdate := i == 0 // ipMapUpdate indicates whether PTR records should be updated.
|
||||
n.deleteSvcRecords(ep.ID(), dnsName, serviceID, iface.Address().IP, ipv6, ipMapUpdate, "updateSvcRecord")
|
||||
n.deleteSvcRecords(ep.ID(), dnsName, serviceID, ipv4, ipv6, ipMapUpdate, "updateSvcRecord")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1392,14 +1395,14 @@ func delNameToIP(svcMap *setmatrix.SetMatrix[svcMapEntry], name, serviceID strin
|
||||
}
|
||||
|
||||
// TODO(aker): remove ipMapUpdate param and add a proper method dedicated to update PTR records.
|
||||
func (n *Network) addSvcRecords(eID, name, serviceID string, epIP, epIPv6 net.IP, ipMapUpdate bool, method string) {
|
||||
func (n *Network) addSvcRecords(eID, name, serviceID string, epIPv4, epIPv6 net.IP, ipMapUpdate bool, method string) {
|
||||
// Do not add service names for ingress network as this is a
|
||||
// routing only network
|
||||
if n.ingress {
|
||||
return
|
||||
}
|
||||
networkID := n.ID()
|
||||
log.G(context.TODO()).Debugf("%s (%.7s).addSvcRecords(%s, %s, %s, %t) %s sid:%s", eID, networkID, name, epIP, epIPv6, ipMapUpdate, method, serviceID)
|
||||
log.G(context.TODO()).Debugf("%s (%.7s).addSvcRecords(%s, %s, %s, %t) %s sid:%s", eID, networkID, name, epIPv4, epIPv6, ipMapUpdate, method, serviceID)
|
||||
|
||||
c := n.getController()
|
||||
c.mu.Lock()
|
||||
@@ -1412,26 +1415,30 @@ func (n *Network) addSvcRecords(eID, name, serviceID string, epIP, epIPv6 net.IP
|
||||
}
|
||||
|
||||
if ipMapUpdate {
|
||||
addIPToName(&sr.ipMap, name, serviceID, epIP)
|
||||
if epIPv4 != nil {
|
||||
addIPToName(&sr.ipMap, name, serviceID, epIPv4)
|
||||
}
|
||||
if epIPv6 != nil {
|
||||
addIPToName(&sr.ipMap, name, serviceID, epIPv6)
|
||||
}
|
||||
}
|
||||
|
||||
addNameToIP(&sr.svcMap, name, serviceID, epIP)
|
||||
if epIPv4 != nil {
|
||||
addNameToIP(&sr.svcMap, name, serviceID, epIPv4)
|
||||
}
|
||||
if epIPv6 != nil {
|
||||
addNameToIP(&sr.svcIPv6Map, name, serviceID, epIPv6)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Network) deleteSvcRecords(eID, name, serviceID string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool, method string) {
|
||||
func (n *Network) deleteSvcRecords(eID, name, serviceID string, epIPv4, epIPv6 net.IP, ipMapUpdate bool, method string) {
|
||||
// Do not delete service names from ingress network as this is a
|
||||
// routing only network
|
||||
if n.ingress {
|
||||
return
|
||||
}
|
||||
networkID := n.ID()
|
||||
log.G(context.TODO()).Debugf("%s (%.7s).deleteSvcRecords(%s, %s, %s, %t) %s sid:%s ", eID, networkID, name, epIP, epIPv6, ipMapUpdate, method, serviceID)
|
||||
log.G(context.TODO()).Debugf("%s (%.7s).deleteSvcRecords(%s, %s, %s, %t) %s sid:%s ", eID, networkID, name, epIPv4, epIPv6, ipMapUpdate, method, serviceID)
|
||||
|
||||
c := n.getController()
|
||||
c.mu.Lock()
|
||||
@@ -1443,15 +1450,17 @@ func (n *Network) deleteSvcRecords(eID, name, serviceID string, epIP net.IP, epI
|
||||
}
|
||||
|
||||
if ipMapUpdate {
|
||||
delIPToName(&sr.ipMap, name, serviceID, epIP)
|
||||
|
||||
if epIPv4 != nil {
|
||||
delIPToName(&sr.ipMap, name, serviceID, epIPv4)
|
||||
}
|
||||
if epIPv6 != nil {
|
||||
delIPToName(&sr.ipMap, name, serviceID, epIPv6)
|
||||
}
|
||||
}
|
||||
|
||||
delNameToIP(&sr.svcMap, name, serviceID, epIP)
|
||||
|
||||
if epIPv4 != nil {
|
||||
delNameToIP(&sr.svcMap, name, serviceID, epIPv4)
|
||||
}
|
||||
if epIPv6 != nil {
|
||||
delNameToIP(&sr.svcIPv6Map, name, serviceID, epIPv6)
|
||||
}
|
||||
@@ -1476,27 +1485,29 @@ func (n *Network) getSvcRecords(ep *Endpoint) []etchosts.Record {
|
||||
return nil
|
||||
}
|
||||
|
||||
svcMapKeys := sr.svcMap.Keys()
|
||||
// Loop on service names on this network
|
||||
for _, k := range svcMapKeys {
|
||||
if strings.Split(k, ".")[0] == epName {
|
||||
continue
|
||||
}
|
||||
// Get all the IPs associated to this service
|
||||
mapEntryList, ok := sr.svcMap.Get(k)
|
||||
if !ok {
|
||||
// The key got deleted
|
||||
continue
|
||||
}
|
||||
if len(mapEntryList) == 0 {
|
||||
log.G(context.TODO()).Warnf("Found empty list of IP addresses for service %s on network %s (%s)", k, n.name, n.id)
|
||||
continue
|
||||
}
|
||||
for _, svcMap := range []*setmatrix.SetMatrix[svcMapEntry]{&sr.svcMap, &sr.svcIPv6Map} {
|
||||
svcMapKeys := svcMap.Keys()
|
||||
// Loop on service names on this network
|
||||
for _, k := range svcMapKeys {
|
||||
if strings.Split(k, ".")[0] == epName {
|
||||
continue
|
||||
}
|
||||
// Get all the IPs associated to this service
|
||||
mapEntryList, ok := svcMap.Get(k)
|
||||
if !ok {
|
||||
// The key got deleted
|
||||
continue
|
||||
}
|
||||
if len(mapEntryList) == 0 {
|
||||
log.G(context.TODO()).Warnf("Found empty list of IP addresses for service %s on network %s (%s)", k, n.name, n.id)
|
||||
continue
|
||||
}
|
||||
|
||||
recs = append(recs, etchosts.Record{
|
||||
Hosts: k,
|
||||
IP: mapEntryList[0].ip,
|
||||
})
|
||||
recs = append(recs, etchosts.Record{
|
||||
Hosts: k,
|
||||
IP: mapEntryList[0].ip,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return recs
|
||||
|
||||
Reference in New Issue
Block a user