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>
This commit is contained in:
Jana Radhakrishnan 2015-06-18 23:37:36 -07:00
parent 28091d1d4d
commit 362568467d
2 changed files with 119 additions and 0 deletions

View file

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

View file

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