mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
6217f2944f
Fixes newly introduced error flow from daemon.Get() in the link setup code. Also added more detail to daemon.Get() comments for clarity. Added test to test the bogus container link codepath. Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)
319 lines
10 KiB
Go
319 lines
10 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) {
|
|
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")
|
|
}
|
|
|
|
deleteAllContainers()
|
|
|
|
logDone("link - /etc/hosts is a regular file")
|
|
}
|
|
|
|
func TestLinksEtcHostsContentMatch(t *testing.T) {
|
|
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")
|
|
}
|
|
|
|
deleteAllContainers()
|
|
|
|
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) {
|
|
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)
|
|
}
|
|
deleteAllContainers()
|
|
|
|
logDone("links - linking to non-existent container should not work")
|
|
}
|
|
|
|
func TestLinksPingLinkedContainers(t *testing.T) {
|
|
var out string
|
|
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, "run", "--rm", "--link", "container1: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)
|
|
deleteAllContainers()
|
|
|
|
logDone("links - ping linked container")
|
|
}
|
|
|
|
func TestLinksPingLinkedContainersAfterRename(t *testing.T) {
|
|
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)
|
|
deleteAllContainers()
|
|
|
|
logDone("links - ping linked container after rename")
|
|
}
|
|
|
|
func TestLinksIpTablesRulesWhenLinkAndUnlink(t *testing.T) {
|
|
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{"DOCKER", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
|
|
destinationRule := []string{"DOCKER", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
|
|
if !iptables.Exists(sourceRule...) || !iptables.Exists(destinationRule...) {
|
|
t.Fatal("Iptables rules not found")
|
|
}
|
|
|
|
dockerCmd(t, "rm", "--link", "parent/http")
|
|
if iptables.Exists(sourceRule...) || iptables.Exists(destinationRule...) {
|
|
t.Fatal("Iptables rules should be removed when unlink")
|
|
}
|
|
|
|
dockerCmd(t, "kill", "child")
|
|
dockerCmd(t, "kill", "parent")
|
|
deleteAllContainers()
|
|
|
|
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) {
|
|
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 := readContainerFile(idOne, "hosts")
|
|
if err != nil {
|
|
t.Fatal(err, string(contentOne))
|
|
}
|
|
|
|
contentTwo, err := readContainerFile(idTwo, "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) {
|
|
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 := readContainerFile(id, "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 = readContainerFile(id, "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")
|
|
}
|