mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
commit
2888720904
5 changed files with 219 additions and 0 deletions
|
@ -284,6 +284,7 @@ func (c *controller) addNetwork(n *network) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Lock()
|
n.Lock()
|
||||||
|
n.svcRecords = svcMap{}
|
||||||
n.driver = dd.driver
|
n.driver = dd.driver
|
||||||
d := n.driver
|
d := n.driver
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
|
|
|
@ -571,9 +571,39 @@ func (ep *endpoint) deleteEndpoint() error {
|
||||||
}
|
}
|
||||||
log.Warnf("driver error deleting endpoint %s : %v", name, err)
|
log.Warnf("driver error deleting endpoint %s : %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.updateSvcRecord(ep, false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ep *endpoint) addHostEntries(recs []etchosts.Record) {
|
||||||
|
ep.Lock()
|
||||||
|
container := ep.container
|
||||||
|
ep.Unlock()
|
||||||
|
|
||||||
|
if container == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := etchosts.Add(container.config.hostsPath, recs); err != nil {
|
||||||
|
log.Warnf("Failed adding service host entries to the running container: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ep *endpoint) deleteHostEntries(recs []etchosts.Record) {
|
||||||
|
ep.Lock()
|
||||||
|
container := ep.container
|
||||||
|
ep.Unlock()
|
||||||
|
|
||||||
|
if container == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := etchosts.Delete(container.config.hostsPath, recs); err != nil {
|
||||||
|
log.Warnf("Failed deleting service host entries to the running container: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ep *endpoint) buildHostsFiles() error {
|
func (ep *endpoint) buildHostsFiles() error {
|
||||||
var extraContent []etchosts.Record
|
var extraContent []etchosts.Record
|
||||||
|
|
||||||
|
@ -581,6 +611,7 @@ func (ep *endpoint) buildHostsFiles() error {
|
||||||
container := ep.container
|
container := ep.container
|
||||||
joinInfo := ep.joinInfo
|
joinInfo := ep.joinInfo
|
||||||
ifaces := ep.iFaces
|
ifaces := ep.iFaces
|
||||||
|
n := ep.network
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
|
|
||||||
if container == nil {
|
if container == nil {
|
||||||
|
@ -613,6 +644,8 @@ func (ep *endpoint) buildHostsFiles() error {
|
||||||
etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
|
etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extraContent = append(extraContent, n.getSvcRecords()...)
|
||||||
|
|
||||||
IP := ""
|
IP := ""
|
||||||
if len(ifaces) != 0 && ifaces[0] != nil {
|
if len(ifaces) != 0 && ifaces[0] != nil {
|
||||||
IP = ifaces[0].addr.IP.String()
|
IP = ifaces[0].addr.IP.String()
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -65,6 +66,45 @@ func Build(path, IP, hostname, domainname string, extraContent []Record) error {
|
||||||
return ioutil.WriteFile(path, content.Bytes(), 0644)
|
return ioutil.WriteFile(path, content.Bytes(), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add adds an arbitrary number of Records to an already existing /etc/hosts file
|
||||||
|
func Add(path string, recs []Record) error {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
content := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
_, err = content.ReadFrom(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range recs {
|
||||||
|
if _, err := r.WriteTo(content); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(path, content.Bytes(), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes an arbitrary number of Records already existing in /etc/hosts file
|
||||||
|
func Delete(path string, recs []Record) error {
|
||||||
|
old, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
regexpStr := fmt.Sprintf("\\S*\\t%s\\n", regexp.QuoteMeta(recs[0].Hosts))
|
||||||
|
for _, r := range recs[1:] {
|
||||||
|
regexpStr = regexpStr + "|" + fmt.Sprintf("\\S*\\t%s\\n", regexp.QuoteMeta(r.Hosts))
|
||||||
|
}
|
||||||
|
|
||||||
|
var re = regexp.MustCompile(regexpStr)
|
||||||
|
return ioutil.WriteFile(path, re.ReplaceAll(old, []byte("")), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
// Update all IP addresses where hostname matches.
|
// Update all IP addresses where hostname matches.
|
||||||
// path is path to host file
|
// path is path to host file
|
||||||
// IP is new IP address
|
// IP is new IP address
|
||||||
|
|
|
@ -134,3 +134,82 @@ func TestUpdate(t *testing.T) {
|
||||||
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAdd(t *testing.T) {
|
||||||
|
file, err := ioutil.TempFile("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(file.Name())
|
||||||
|
|
||||||
|
err = Build(file.Name(), "", "", "", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Add(file.Name(), []Record{
|
||||||
|
Record{
|
||||||
|
Hosts: "testhostname",
|
||||||
|
IP: "2.2.2.2",
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile(file.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := "2.2.2.2\ttesthostname\n"; !bytes.Contains(content, []byte(expected)) {
|
||||||
|
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
file, err := ioutil.TempFile("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(file.Name())
|
||||||
|
|
||||||
|
err = Build(file.Name(), "", "", "", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Add(file.Name(), []Record{
|
||||||
|
Record{
|
||||||
|
Hosts: "testhostname1",
|
||||||
|
IP: "1.1.1.1",
|
||||||
|
},
|
||||||
|
Record{
|
||||||
|
Hosts: "testhostname2",
|
||||||
|
IP: "2.2.2.2",
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Delete(file.Name(), []Record{
|
||||||
|
Record{
|
||||||
|
Hosts: "testhostname1",
|
||||||
|
IP: "1.1.1.1",
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile(file.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := "2.2.2.2\ttesthostname2\n"; !bytes.Contains(content, []byte(expected)) {
|
||||||
|
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := "1.1.1.1\ttesthostname1\n"; bytes.Contains(content, []byte(expected)) {
|
||||||
|
t.Fatalf("Did not expect to find '%s' got '%s'", expected, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package libnetwork
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
@ -9,6 +10,7 @@ import (
|
||||||
"github.com/docker/libnetwork/config"
|
"github.com/docker/libnetwork/config"
|
||||||
"github.com/docker/libnetwork/datastore"
|
"github.com/docker/libnetwork/datastore"
|
||||||
"github.com/docker/libnetwork/driverapi"
|
"github.com/docker/libnetwork/driverapi"
|
||||||
|
"github.com/docker/libnetwork/etchosts"
|
||||||
"github.com/docker/libnetwork/netlabel"
|
"github.com/docker/libnetwork/netlabel"
|
||||||
"github.com/docker/libnetwork/options"
|
"github.com/docker/libnetwork/options"
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
|
@ -51,6 +53,8 @@ type Network interface {
|
||||||
// When the function returns true, the walk will stop.
|
// When the function returns true, the walk will stop.
|
||||||
type EndpointWalker func(ep Endpoint) bool
|
type EndpointWalker func(ep Endpoint) bool
|
||||||
|
|
||||||
|
type svcMap map[string]net.IP
|
||||||
|
|
||||||
type network struct {
|
type network struct {
|
||||||
ctrlr *controller
|
ctrlr *controller
|
||||||
name string
|
name string
|
||||||
|
@ -62,6 +66,7 @@ type network struct {
|
||||||
endpoints endpointTable
|
endpoints endpointTable
|
||||||
generic options.Generic
|
generic options.Generic
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
|
svcRecords svcMap
|
||||||
stopWatchCh chan struct{}
|
stopWatchCh chan struct{}
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
@ -272,6 +277,8 @@ func (n *network) addEndpoint(ep *endpoint) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.updateSvcRecord(ep, true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,3 +391,62 @@ func (n *network) isGlobalScoped() (bool, error) {
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
return c.isDriverGlobalScoped(n.networkType)
|
return c.isDriverGlobalScoped(n.networkType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
|
||||||
|
n.Lock()
|
||||||
|
var recs []etchosts.Record
|
||||||
|
for _, iface := range ep.InterfaceList() {
|
||||||
|
if isAdd {
|
||||||
|
n.svcRecords[ep.Name()] = iface.Address().IP
|
||||||
|
n.svcRecords[ep.Name()+"."+n.name] = iface.Address().IP
|
||||||
|
} else {
|
||||||
|
delete(n.svcRecords, ep.Name())
|
||||||
|
delete(n.svcRecords, ep.Name()+"."+n.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
recs = append(recs, etchosts.Record{
|
||||||
|
Hosts: ep.Name(),
|
||||||
|
IP: iface.Address().IP.String(),
|
||||||
|
})
|
||||||
|
|
||||||
|
recs = append(recs, etchosts.Record{
|
||||||
|
Hosts: ep.Name() + "." + n.name,
|
||||||
|
IP: iface.Address().IP.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
n.Unlock()
|
||||||
|
|
||||||
|
var epList []*endpoint
|
||||||
|
n.WalkEndpoints(func(e Endpoint) bool {
|
||||||
|
cEp := e.(*endpoint)
|
||||||
|
cEp.Lock()
|
||||||
|
if cEp.container != nil {
|
||||||
|
epList = append(epList, cEp)
|
||||||
|
}
|
||||||
|
cEp.Unlock()
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, cEp := range epList {
|
||||||
|
if isAdd {
|
||||||
|
cEp.addHostEntries(recs)
|
||||||
|
} else {
|
||||||
|
cEp.deleteHostEntries(recs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *network) getSvcRecords() []etchosts.Record {
|
||||||
|
n.Lock()
|
||||||
|
defer n.Unlock()
|
||||||
|
|
||||||
|
var recs []etchosts.Record
|
||||||
|
for h, ip := range n.svcRecords {
|
||||||
|
recs = append(recs, etchosts.Record{
|
||||||
|
Hosts: h,
|
||||||
|
IP: ip.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return recs
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue