1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/integration-cli/docker_cli_links_test.go
Lars Kellogg-Stedman 3559b4177e fix various problems with iptables.Exists
This modifies iptables.Exists so that it must be called with an explicit
table and chain.  This allows us (a) to generate an appropriate command
line for "iptables -C", which was not previously possible, and (b) it
allows us to limit our strings.Contains() search to just the table and
chain in question, preventing erroneous matches against unrelated rules.

Resolves #10781

Signed-off-by: Lars Kellogg-Stedman <lars@redhat.com>
2015-03-16 17:14:45 -04:00

339 lines
11 KiB
Go

package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"reflect"
"regexp"
"strings"
"testing"
"time"
"github.com/docker/docker/pkg/iptables"
)
func TestLinksEtcHostsRegularFile(t *testing.T) {
defer deleteAllContainers()
runCmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "ls", "-la", "/etc/hosts")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
t.Fatal(out, err)
}
if !strings.HasPrefix(out, "-") {
t.Errorf("/etc/hosts should be a regular file")
}
logDone("link - /etc/hosts is a regular file")
}
func TestLinksEtcHostsContentMatch(t *testing.T) {
testRequires(t, SameHostDaemon)
defer deleteAllContainers()
runCmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "cat", "/etc/hosts")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
t.Fatal(out, err)
}
hosts, err := ioutil.ReadFile("/etc/hosts")
if os.IsNotExist(err) {
t.Skip("/etc/hosts does not exist, skip this test")
}
if out != string(hosts) {
t.Errorf("container")
}
logDone("link - /etc/hosts matches hosts copy")
}
func TestLinksPingUnlinkedContainers(t *testing.T) {
runCmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
exitCode, err := runCommand(runCmd)
if exitCode == 0 {
t.Fatal("run ping did not fail")
} else if exitCode != 1 {
t.Fatalf("run ping failed with errors: %v", err)
}
logDone("links - ping unlinked container")
}
// Test for appropriate error when calling --link with an invalid target container
func TestLinksInvalidContainerTarget(t *testing.T) {
defer deleteAllContainers()
runCmd := exec.Command(dockerBinary, "run", "--link", "bogus:alias", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err == nil {
t.Fatal("an invalid container target should produce an error")
}
if !strings.Contains(out, "Could not get container") {
t.Fatal("error output expected 'Could not get container', but got %q instead; err: %v", out, err)
}
logDone("links - linking to non-existent container should not work")
}
func TestLinksPingLinkedContainers(t *testing.T) {
defer deleteAllContainers()
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "container1", "--hostname", "fred", "busybox", "top")
if _, err := runCommand(runCmd); err != nil {
t.Fatal(err)
}
runCmd = exec.Command(dockerBinary, "run", "-d", "--name", "container2", "--hostname", "wilma", "busybox", "top")
if _, err := runCommand(runCmd); err != nil {
t.Fatal(err)
}
runArgs := []string{"run", "--rm", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "sh", "-c"}
pingCmd := "ping -c 1 %s -W 1 && ping -c 1 %s -W 1"
// test ping by alias, ping by name, and ping by hostname
// 1. Ping by alias
dockerCmd(t, append(runArgs, fmt.Sprintf(pingCmd, "alias1", "alias2"))...)
// 2. Ping by container name
dockerCmd(t, append(runArgs, fmt.Sprintf(pingCmd, "container1", "container2"))...)
// 3. Ping by hostname
dockerCmd(t, append(runArgs, fmt.Sprintf(pingCmd, "fred", "wilma"))...)
logDone("links - ping linked container")
}
func TestLinksPingLinkedContainersAfterRename(t *testing.T) {
defer deleteAllContainers()
out, _, _ := dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10")
idA := stripTrailingCharacters(out)
out, _, _ = dockerCmd(t, "run", "-d", "--name", "container2", "busybox", "sleep", "10")
idB := stripTrailingCharacters(out)
dockerCmd(t, "rename", "container1", "container_new")
dockerCmd(t, "run", "--rm", "--link", "container_new:alias1", "--link", "container2:alias2", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
dockerCmd(t, "kill", idA)
dockerCmd(t, "kill", idB)
logDone("links - ping linked container after rename")
}
func TestLinksIpTablesRulesWhenLinkAndUnlink(t *testing.T) {
testRequires(t, SameHostDaemon)
defer deleteAllContainers()
dockerCmd(t, "run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "sleep", "10")
dockerCmd(t, "run", "-d", "--name", "parent", "--link", "child:http", "busybox", "sleep", "10")
childIP := findContainerIP(t, "child")
parentIP := findContainerIP(t, "parent")
sourceRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
destinationRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) {
t.Fatal("Iptables rules not found")
}
dockerCmd(t, "rm", "--link", "parent/http")
if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) {
t.Fatal("Iptables rules should be removed when unlink")
}
dockerCmd(t, "kill", "child")
dockerCmd(t, "kill", "parent")
logDone("link - verify iptables when link and unlink")
}
func TestLinksInspectLinksStarted(t *testing.T) {
var (
expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}}
result []string
)
defer deleteAllContainers()
dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10")
dockerCmd(t, "run", "-d", "--name", "container2", "busybox", "sleep", "10")
dockerCmd(t, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "sleep", "10")
links, err := inspectFieldJSON("testinspectlink", "HostConfig.Links")
if err != nil {
t.Fatal(err)
}
err = unmarshalJSON([]byte(links), &result)
if err != nil {
t.Fatal(err)
}
output := convertSliceOfStringsToMap(result)
equal := reflect.DeepEqual(output, expected)
if !equal {
t.Fatalf("Links %s, expected %s", result, expected)
}
logDone("link - links in started container inspect")
}
func TestLinksInspectLinksStopped(t *testing.T) {
var (
expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}}
result []string
)
defer deleteAllContainers()
dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10")
dockerCmd(t, "run", "-d", "--name", "container2", "busybox", "sleep", "10")
dockerCmd(t, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true")
links, err := inspectFieldJSON("testinspectlink", "HostConfig.Links")
if err != nil {
t.Fatal(err)
}
err = unmarshalJSON([]byte(links), &result)
if err != nil {
t.Fatal(err)
}
output := convertSliceOfStringsToMap(result)
equal := reflect.DeepEqual(output, expected)
if !equal {
t.Fatalf("Links %s, but expected %s", result, expected)
}
logDone("link - links in stopped container inspect")
}
func TestLinksNotStartedParentNotFail(t *testing.T) {
defer deleteAllContainers()
runCmd := exec.Command(dockerBinary, "create", "--name=first", "busybox", "top")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
t.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "create", "--name=second", "--link=first:first", "busybox", "top")
out, _, _, err = runCommandWithStdoutStderr(runCmd)
if err != nil {
t.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "start", "first")
out, _, _, err = runCommandWithStdoutStderr(runCmd)
if err != nil {
t.Fatal(out, err)
}
logDone("link - container start successfully updating stopped parent links")
}
func TestLinksHostsFilesInject(t *testing.T) {
testRequires(t, SameHostDaemon, ExecSupport)
defer deleteAllContainers()
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "--name", "one", "busybox", "top"))
if err != nil {
t.Fatal(err, out)
}
idOne := strings.TrimSpace(out)
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "--name", "two", "--link", "one:onetwo", "busybox", "top"))
if err != nil {
t.Fatal(err, out)
}
idTwo := strings.TrimSpace(out)
time.Sleep(1 * time.Second)
contentOne, err := readContainerFileWithExec(idOne, "/etc/hosts")
if err != nil {
t.Fatal(err, string(contentOne))
}
contentTwo, err := readContainerFileWithExec(idTwo, "/etc/hosts")
if err != nil {
t.Fatal(err, string(contentTwo))
}
if !strings.Contains(string(contentTwo), "onetwo") {
t.Fatal("Host is not present in updated hosts file", string(contentTwo))
}
logDone("link - ensure containers hosts files are updated with the link alias.")
}
func TestLinksNetworkHostContainer(t *testing.T) {
defer deleteAllContainers()
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--net", "host", "--name", "host_container", "busybox", "top"))
if err != nil {
t.Fatal(err, out)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "should_fail", "--link", "host_container:tester", "busybox", "true"))
if err == nil || !strings.Contains(out, "--net=host can't be used with links. This would result in undefined behavior.") {
t.Fatalf("Running container linking to a container with --net host should have failed: %s", out)
}
logDone("link - error thrown when linking to container with --net host")
}
func TestLinksUpdateOnRestart(t *testing.T) {
testRequires(t, SameHostDaemon, ExecSupport)
defer deleteAllContainers()
if out, err := exec.Command(dockerBinary, "run", "-d", "--name", "one", "busybox", "top").CombinedOutput(); err != nil {
t.Fatal(err, string(out))
}
out, err := exec.Command(dockerBinary, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top").CombinedOutput()
if err != nil {
t.Fatal(err, string(out))
}
id := strings.TrimSpace(string(out))
realIP, err := inspectField("one", "NetworkSettings.IPAddress")
if err != nil {
t.Fatal(err)
}
content, err := readContainerFileWithExec(id, "/etc/hosts")
if err != nil {
t.Fatal(err, string(content))
}
getIP := func(hosts []byte, hostname string) string {
re := regexp.MustCompile(fmt.Sprintf(`(\S*)\t%s`, regexp.QuoteMeta(hostname)))
matches := re.FindSubmatch(hosts)
if matches == nil {
t.Fatalf("Hostname %s have no matches in hosts", hostname)
}
return string(matches[1])
}
if ip := getIP(content, "one"); ip != realIP {
t.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip)
}
if ip := getIP(content, "onetwo"); ip != realIP {
t.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip)
}
if out, err := exec.Command(dockerBinary, "restart", "one").CombinedOutput(); err != nil {
t.Fatal(err, string(out))
}
realIP, err = inspectField("one", "NetworkSettings.IPAddress")
if err != nil {
t.Fatal(err)
}
content, err = readContainerFileWithExec(id, "/etc/hosts")
if err != nil {
t.Fatal(err, string(content))
}
if ip := getIP(content, "one"); ip != realIP {
t.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip)
}
if ip := getIP(content, "onetwo"); ip != realIP {
t.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip)
}
logDone("link - ensure containers hosts files are updated on restart")
}