-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
199 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package core | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"runtime" | ||
"strings" | ||
) | ||
|
||
var defaultEtcHostsReader = func() ([]byte, error) { | ||
ehp := `/etc/hosts` | ||
if runtime.GOOS == "windows" { | ||
ehp = `c:\Windows\System32\Drivers\etc\hosts` | ||
} | ||
return os.ReadFile(ehp) | ||
} | ||
|
||
// EtcHostsPrecondition verify /etc/hosts contains given host. | ||
type EtcHostsPrecondition struct { | ||
Contains map[string][]string | ||
|
||
etcHostsReader func() ([]byte, error) | ||
} | ||
|
||
// Verify ... | ||
func (p *EtcHostsPrecondition) Verify() PreconditionVerifyResult { | ||
if p.etcHostsReader == nil { | ||
p.etcHostsReader = defaultEtcHostsReader | ||
} | ||
etcHosts, err := p.etcHostsReader() | ||
if err != nil { | ||
return PreconditionVerifyResult{ | ||
Vote: Stop, | ||
Reasons: []string{err.Error()}, | ||
} | ||
} | ||
hosts, err := parseEtcHosts(etcHosts) | ||
for k, values := range p.Contains { | ||
mapped, exist := hosts[k] | ||
if !exist { | ||
return PreconditionVerifyResult{ | ||
Vote: Stop, | ||
Reasons: []string{fmt.Sprintf(`No mapping found for "%s"`, k)}, | ||
} | ||
} | ||
for _, v := range values { | ||
if sliceContains(mapped, v) { | ||
continue | ||
} | ||
return PreconditionVerifyResult{ | ||
Vote: Stop, | ||
Reasons: []string{fmt.Sprintf(`Hosts mapping "%s" %v does not contain "%s"`, k, mapped, v)}, | ||
} | ||
} | ||
} | ||
return PreconditionVerifyResult{ | ||
Vote: Proceed, | ||
Reasons: []string{}, | ||
} | ||
} | ||
|
||
// IsSet ... | ||
func (p *EtcHostsPrecondition) IsSet() bool { | ||
return len(p.Contains) > 0 | ||
} | ||
|
||
func parseEtcHosts(hostsFileContent []byte) (map[string][]string, error) { | ||
hostsMap := map[string][]string{} | ||
for _, line := range strings.Split(strings.Trim(string(hostsFileContent), " \t\r\n"), "\n") { | ||
line = strings.Replace(strings.Trim(line, " \t"), "\t", " ", -1) | ||
if len(line) == 0 || line[0] == ';' || line[0] == '#' { | ||
continue | ||
} | ||
pieces := strings.SplitN(line, " ", 2) | ||
if len(pieces) > 1 && len(pieces[0]) > 0 { | ||
if names := strings.Fields(pieces[1]); len(names) > 0 { | ||
if _, ok := hostsMap[pieces[0]]; ok { | ||
hostsMap[pieces[0]] = append(hostsMap[pieces[0]], names...) | ||
} else { | ||
hostsMap[pieces[0]] = names | ||
} | ||
} | ||
} | ||
} | ||
return hostsMap, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package core | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
const etcHosts01 = ` | ||
# Copyright (c) 1993-2009 Microsoft Corp. | ||
# | ||
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. | ||
# | ||
# This file contains the mappings of IP addresses to host names. Each | ||
# entry should be kept on an individual line. The IP address should | ||
# be placed in the first column followed by the corresponding host name. | ||
# The IP address and the host name should be separated by at least one | ||
# space. | ||
# | ||
# Additionally, comments (such as these) may be inserted on individual | ||
# lines or following the machine name denoted by a '#' symbol. | ||
# | ||
# For example: | ||
# | ||
# 102.54.94.97 rhino.acme.com # source server | ||
# 38.25.63.10 x.acme.com # x client host | ||
# localhost name resolution is handled within DNS itself. | ||
# 127.0.0.1 localhost | ||
# ::1 localhost | ||
# Added by Docker Desktop | ||
# 192.168.22.134 host.docker.internal | ||
# 192.168.22.134 gateway.docker.internal | ||
127.0.0.1 private-host-01 | ||
127.0.0.1 private-host-02 | ||
# To allow the same kube context to work on the host and the container: | ||
# 127.0.0.1 kubernetes.docker.internal | ||
# End of section | ||
127.0.0.1 domain-01 | ||
192.168.2.2 domain-03 | ||
102.54.99.99 rhino.acme.com | ||
` | ||
|
||
func TestEtcHostsOk(t *testing.T) { | ||
|
||
wanted := map[string][]string{} | ||
wanted[`127.0.0.1`] = []string{ | ||
`private-host-01`, | ||
`private-host-02`, | ||
`domain-01`, | ||
} | ||
wanted[`192.168.2.2`] = []string{ | ||
`domain-03`, | ||
} | ||
wanted[`102.54.99.99`] = []string{ | ||
`rhino.acme.com`, | ||
} | ||
|
||
ui = CreateMainLogger(" ", 6, "%s> ", true, false) | ||
|
||
sut := &EtcHostsPrecondition{ | ||
Contains: wanted, | ||
etcHostsReader: func() ([]byte, error) { | ||
return []byte(etcHosts01), nil | ||
}, | ||
} | ||
res := sut.Verify() | ||
if res.Vote != Proceed { | ||
t.Errorf("Expected Proceed but got %v: %v", res.Vote, res.Reasons) | ||
} | ||
} | ||
|
||
func TestEtcHostsKo(t *testing.T) { | ||
|
||
wanted := map[string][]string{} | ||
wanted[`127.0.0.1`] = []string{ | ||
`no.such.host`, | ||
// correct but not enough to satisfy precondition | ||
`domain-01`, | ||
} | ||
wanted[`192.168.22.134`] = []string{ | ||
`host.docker.internal`, | ||
} | ||
|
||
ui = CreateMainLogger(" ", 6, "%s> ", true, false) | ||
|
||
sut := &EtcHostsPrecondition{ | ||
Contains: wanted, | ||
etcHostsReader: func() ([]byte, error) { | ||
return []byte(etcHosts01), nil | ||
}, | ||
} | ||
res := sut.Verify() | ||
if res.Vote != Stop { | ||
t.Errorf("Expected Stop but got %v", res.Vote) | ||
} | ||
} |