Skip to content

Commit afde45a

Browse files
authored
Merge pull request kubernetes#76507 from bclau/tests/agnhost-updates
tests: agnhost image updates
2 parents c419640 + 60e9fe7 commit afde45a

File tree

5 files changed

+201
-25
lines changed

5 files changed

+201
-25
lines changed

test/images/agnhost/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Agnhost
2+
3+
## Overview
4+
5+
There are significant differences between Linux and Windows, especially in the way
6+
something can be obtained or tested. For example, the DNS suffix list can be found in
7+
`/etc/resolv.conf` on Linux, but on Windows, such file does not exist, the same
8+
information could retrieved through other means. To combat those differences,
9+
`agnhost` was created.
10+
11+
`agnhost` is an extendable CLI that behaves and outputs the same expected content,
12+
no matter the underlying OS. The name itself reflects this idea, being a portmanteau
13+
word of the words agnost and host.
14+
15+
The image was created for testing purposes, reducing the need for having different test
16+
cases for the same tested behaviour.
17+
18+
## Usage
19+
20+
The `agnhost` binary is a CLI with the following subcommands:
21+
22+
- `dns-suffix`: It will output the host's configured DNS suffix list, separated by commas.
23+
- `dns-server-list`: It will output the host's configured DNS servers, separated by commas.
24+
- `etc-hosts`: It will output the contents of host's `hosts` file. This file's location
25+
is `/etc/hosts` on Linux, while on Windows it is `C:/Windows/System32/drivers/etc/hosts`.
26+
- `pause`: It will pause the execution of the binary. This can be used for containers
27+
which have to be kept in a `Running` state for various purposes, including executing
28+
other `agnhost` commands.
29+
- `help`: Prints the binary's help menu. Additionally, it can be followed by another
30+
subcommand in order to get more information about that subcommand, including its
31+
possible arguments.
32+
33+
For example, let's consider the following `pod.yaml` file:
34+
35+
```yaml
36+
apiVersion: v1
37+
kind: Pod
38+
metadata:
39+
name: test-agnhost
40+
spec:
41+
containers:
42+
- args:
43+
- dns-suffix
44+
image: gcr.io/kubernetes-e2e-test-images/agnhost:1.0
45+
name: agnhost
46+
dnsConfig:
47+
nameservers:
48+
- 1.1.1.1
49+
searches:
50+
- resolv.conf.local
51+
dnsPolicy: None
52+
```
53+
54+
After we've used it to create a pod:
55+
56+
```console
57+
kubectl create -f pod.yaml
58+
```
59+
60+
We can then check the container's output to see what is DNS suffix list the Pod was
61+
configured with:
62+
63+
```console
64+
kubectl logs pod/test-agnhost
65+
```
66+
67+
The output will be `resolv.conf.local`, as expected. Alternatively, the Pod could be
68+
created with the `pause` argument instead, allowing us execute multiple commands:
69+
70+
```console
71+
kubectl exec test-agnhost -- /agnhost dns-suffix
72+
kubectl exec test-agnhost -- /agnhost dns-server-list
73+
```
74+
75+
## Image
76+
77+
The image can be found at `gcr.io/kubernetes-e2e-test-images/agnhost:1.0` for Linux
78+
containers, and `e2eteam/agnhost:1.0` for Windows containers. In the future, the same
79+
repository can be used for both OSes.

test/images/agnhost/agnhost.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,40 @@ import (
2323
func main() {
2424
cmdDNSSuffix := &cobra.Command{
2525
Use: "dns-suffix",
26-
Short: "Prints the host's DNS suffix list.",
27-
Long: `prints the DNS suffixes of this host.`,
26+
Short: "Prints the host's DNS suffix list",
27+
Long: `Prints the DNS suffixes of this host.`,
2828
Args: cobra.MaximumNArgs(0),
2929
Run: printDNSSuffixList,
3030
}
3131

32+
cmdDNSServerList := &cobra.Command{
33+
Use: "dns-server-list",
34+
Short: "Prints the host's DNS Server list",
35+
Long: `Prints the DNS Server list of this host.`,
36+
Args: cobra.MaximumNArgs(0),
37+
Run: printDNSServerList,
38+
}
39+
40+
cmdEtcHosts := &cobra.Command{
41+
Use: "etc-hosts",
42+
Short: "Prints the host's /etc/hosts file",
43+
Long: `Prints the "hosts" file of this host."`,
44+
Args: cobra.MaximumNArgs(0),
45+
Run: printHostsFile,
46+
}
47+
48+
cmdPause := &cobra.Command{
49+
Use: "pause",
50+
Short: "Pauses",
51+
Long: `Pauses the execution. Useful for keeping the containers running, so other commands can be executed.`,
52+
Args: cobra.MaximumNArgs(0),
53+
Run: pause,
54+
}
55+
3256
rootCmd := &cobra.Command{Use: "app"}
3357
rootCmd.AddCommand(cmdDNSSuffix)
58+
rootCmd.AddCommand(cmdDNSServerList)
59+
rootCmd.AddCommand(cmdEtcHosts)
60+
rootCmd.AddCommand(cmdPause)
3461
rootCmd.Execute()
3562
}

test/images/agnhost/common.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,14 @@ limitations under the License.
1717
package main
1818

1919
import (
20+
"bytes"
2021
"fmt"
22+
"io/ioutil"
23+
"os"
24+
"os/exec"
25+
"os/signal"
2126
"strings"
27+
"syscall"
2228

2329
"github.com/spf13/cobra"
2430
)
@@ -27,3 +33,58 @@ func printDNSSuffixList(cmd *cobra.Command, args []string) {
2733
dnsSuffixList := getDNSSuffixList()
2834
fmt.Println(strings.Join(dnsSuffixList, ","))
2935
}
36+
37+
func printDNSServerList(cmd *cobra.Command, args []string) {
38+
dnsServerList := getDNSServerList()
39+
fmt.Println(strings.Join(dnsServerList, ","))
40+
}
41+
42+
func printHostsFile(cmd *cobra.Command, args []string) {
43+
fmt.Println(readFile(etcHostsFile))
44+
}
45+
46+
func pause(cmd *cobra.Command, args []string) {
47+
sigCh := make(chan os.Signal)
48+
done := make(chan int, 1)
49+
signal.Notify(sigCh, syscall.SIGINT)
50+
signal.Notify(sigCh, syscall.SIGTERM)
51+
signal.Notify(sigCh, syscall.SIGKILL)
52+
go func() {
53+
sig := <-sigCh
54+
switch sig {
55+
case syscall.SIGINT:
56+
done <- 1
57+
os.Exit(1)
58+
case syscall.SIGTERM:
59+
done <- 2
60+
os.Exit(2)
61+
case syscall.SIGKILL:
62+
done <- 0
63+
os.Exit(0)
64+
}
65+
}()
66+
result := <-done
67+
fmt.Printf("exiting %d\n", result)
68+
}
69+
70+
func readFile(fileName string) string {
71+
fileData, err := ioutil.ReadFile(fileName)
72+
if err != nil {
73+
panic(err)
74+
}
75+
76+
return string(fileData)
77+
}
78+
79+
func runCommand(name string, arg ...string) string {
80+
var out bytes.Buffer
81+
cmd := exec.Command(name, arg...)
82+
cmd.Stdout = &out
83+
84+
err := cmd.Run()
85+
if err != nil {
86+
panic(err)
87+
}
88+
89+
return strings.TrimSpace(out.String())
90+
}

test/images/agnhost/utils.go

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,18 @@ limitations under the License.
1919
package main
2020

2121
import (
22-
"io/ioutil"
2322
"strings"
2423
)
2524

26-
func getDNSSuffixList() []string {
27-
// A /etc/resolv.conf file managed by kubelet looks like this:
28-
// nameserver DNS_CLUSTER_IP
29-
// search test-dns.svc.cluster.local svc.cluster.local cluster.local q53aahaikqaehcai3ylfqdtc5b.bx.internal.cloudapp.net
30-
// options ndots:5
31-
32-
fileData, err := ioutil.ReadFile("/etc/resolv.conf")
33-
if err != nil {
34-
panic(err)
35-
}
25+
const etcHostsFile = "/etc/hosts"
3626

37-
lines := strings.Split(string(fileData), "\n")
27+
// A /etc/resolv.conf file managed by kubelet looks like this:
28+
// nameserver DNS_CLUSTER_IP
29+
// search test-dns.svc.cluster.local svc.cluster.local cluster.local q53aahaikqaehcai3ylfqdtc5b.bx.internal.cloudapp.net
30+
// options ndots:5
31+
func getDNSSuffixList() []string {
32+
fileData := readFile("/etc/resolv.conf")
33+
lines := strings.Split(fileData, "\n")
3834
for _, line := range lines {
3935
if strings.HasPrefix(line, "search") {
4036
// omit the starting "search".
@@ -44,3 +40,16 @@ func getDNSSuffixList() []string {
4440

4541
panic("Could not find DNS search list!")
4642
}
43+
44+
func getDNSServerList() []string {
45+
fileData := readFile("/etc/resolv.conf")
46+
lines := strings.Split(fileData, "\n")
47+
for _, line := range lines {
48+
if strings.HasPrefix(line, "nameserver") {
49+
// omit the starting "nameserver".
50+
return strings.Split(line, " ")[1:]
51+
}
52+
}
53+
54+
panic("Could not find DNS search list!")
55+
}

test/images/agnhost/utils_windows.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@ limitations under the License.
1717
package main
1818

1919
import (
20-
"bytes"
21-
"os/exec"
2220
"strings"
2321
)
2422

25-
func getDNSSuffixList() []string {
26-
var out bytes.Buffer
27-
cmd := exec.Command("powershell", "-Command", "(Get-DnsClient)[0].SuffixSearchList")
28-
cmd.Stdout = &out
23+
const etcHostsFile = "C:/Windows/System32/drivers/etc/hosts"
2924

30-
err := cmd.Run()
31-
if err != nil {
32-
panic(err)
25+
func getDNSSuffixList() []string {
26+
output := runCommand("powershell", "-Command", "(Get-DnsClient)[0].SuffixSearchList")
27+
if len(output) > 0 {
28+
return strings.Split(output, "\r\n")
3329
}
3430

35-
output := strings.TrimSpace(out.String())
31+
panic("Could not find DNS search list!")
32+
}
33+
34+
func getDNSServerList() []string {
35+
output := runCommand("powershell", "-Command", "(Get-DnsClientServerAddress).ServerAddresses")
3636
if len(output) > 0 {
3737
return strings.Split(output, "\r\n")
3838
}
3939

40-
panic("Could not find DNS search list!")
40+
panic("Could not find DNS Server list!")
4141
}

0 commit comments

Comments
 (0)