Browse Source

Add/Delete etc hosts record support

Currently the etchosts package only provides helpers
to completely build an /etc/hosts file from scratch
or update a single hostname's IP address to a different
one. This commit adds the ability to add/delete an arbitrary
number of host record entries to/from the etc hosts file

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
Jana Radhakrishnan 10 năm trước cách đây
mục cha
commit
362568467d

+ 40 - 0
libnetwork/etchosts/etchosts.go

@@ -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

+ 79 - 0
libnetwork/etchosts/etchosts_test.go

@@ -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)
+	}
+}