1package main
2
3import (
4	"context"
5	"fmt"
6	"io/ioutil"
7	"net/http"
8	"os"
9	"os/exec"
10	"strconv"
11	"strings"
12	"testing"
13	"time"
14
15	"github.com/docker/docker/api/types"
16	"github.com/docker/docker/api/types/swarm"
17	"github.com/docker/docker/api/types/versions"
18	"github.com/docker/docker/client"
19	"github.com/docker/docker/integration-cli/requirement"
20	"github.com/docker/docker/testutil/registry"
21)
22
23func ArchitectureIsNot(arch string) bool {
24	return os.Getenv("DOCKER_ENGINE_GOARCH") != arch
25}
26
27func DaemonIsWindows() bool {
28	return testEnv.OSType == "windows"
29}
30
31func DaemonIsWindowsAtLeastBuild(buildNumber int) func() bool {
32	return func() bool {
33		if testEnv.OSType != "windows" {
34			return false
35		}
36		version := testEnv.DaemonInfo.KernelVersion
37		numVersion, _ := strconv.Atoi(strings.Split(version, " ")[1])
38		return numVersion >= buildNumber
39	}
40}
41
42func DaemonIsLinux() bool {
43	return testEnv.OSType == "linux"
44}
45
46func MinimumAPIVersion(version string) func() bool {
47	return func() bool {
48		return versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), version)
49	}
50}
51
52func OnlyDefaultNetworks() bool {
53	cli, err := client.NewClientWithOpts(client.FromEnv)
54	if err != nil {
55		return false
56	}
57	networks, err := cli.NetworkList(context.TODO(), types.NetworkListOptions{})
58	if err != nil || len(networks) > 0 {
59		return false
60	}
61	return true
62}
63
64func IsAmd64() bool {
65	return os.Getenv("DOCKER_ENGINE_GOARCH") == "amd64"
66}
67
68func NotArm() bool {
69	return ArchitectureIsNot("arm")
70}
71
72func NotArm64() bool {
73	return ArchitectureIsNot("arm64")
74}
75
76func NotPpc64le() bool {
77	return ArchitectureIsNot("ppc64le")
78}
79
80func UnixCli() bool {
81	return isUnixCli
82}
83
84func Network() bool {
85	// Set a timeout on the GET at 15s
86	const timeout = 15 * time.Second
87	const url = "https://hub.docker.com"
88
89	client := http.Client{
90		Timeout: timeout,
91	}
92
93	resp, err := client.Get(url)
94	if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
95		panic(fmt.Sprintf("Timeout for GET request on %s", url))
96	}
97	if resp != nil {
98		resp.Body.Close()
99	}
100	return err == nil
101}
102
103func Apparmor() bool {
104	if strings.HasPrefix(testEnv.DaemonInfo.OperatingSystem, "SUSE Linux Enterprise Server ") {
105		return false
106	}
107	buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
108	return err == nil && len(buf) > 1 && buf[0] == 'Y'
109}
110
111func Devicemapper() bool {
112	return strings.HasPrefix(testEnv.DaemonInfo.Driver, "devicemapper")
113}
114
115func IPv6() bool {
116	cmd := exec.Command("test", "-f", "/proc/net/if_inet6")
117	return cmd.Run() != nil
118}
119
120func UserNamespaceROMount() bool {
121	// quick case--userns not enabled in this test run
122	if os.Getenv("DOCKER_REMAP_ROOT") == "" {
123		return true
124	}
125	if _, _, err := dockerCmdWithError("run", "--rm", "--read-only", "busybox", "date"); err != nil {
126		return false
127	}
128	return true
129}
130
131func NotUserNamespace() bool {
132	root := os.Getenv("DOCKER_REMAP_ROOT")
133	return root == ""
134}
135
136func UserNamespaceInKernel() bool {
137	if _, err := os.Stat("/proc/self/uid_map"); os.IsNotExist(err) {
138		/*
139		 * This kernel-provided file only exists if user namespaces are
140		 * supported
141		 */
142		return false
143	}
144
145	// We need extra check on redhat based distributions
146	if f, err := os.Open("/sys/module/user_namespace/parameters/enable"); err == nil {
147		defer f.Close()
148		b := make([]byte, 1)
149		_, _ = f.Read(b)
150		return string(b) != "N"
151	}
152
153	return true
154}
155
156func IsPausable() bool {
157	if testEnv.OSType == "windows" {
158		return testEnv.DaemonInfo.Isolation == "hyperv"
159	}
160	return true
161}
162
163func IsolationIs(expectedIsolation string) bool {
164	return testEnv.OSType == "windows" && string(testEnv.DaemonInfo.Isolation) == expectedIsolation
165}
166
167func IsolationIsHyperv() bool {
168	return IsolationIs("hyperv")
169}
170
171func IsolationIsProcess() bool {
172	return IsolationIs("process")
173}
174
175// RegistryHosting returns whether the host can host a registry (v2) or not
176func RegistryHosting() bool {
177	// for now registry binary is built only if we're running inside
178	// container through `make test`. Figure that out by testing if
179	// registry binary is in PATH.
180	_, err := exec.LookPath(registry.V2binary)
181	return err == nil
182}
183
184func SwarmInactive() bool {
185	return testEnv.DaemonInfo.Swarm.LocalNodeState == swarm.LocalNodeStateInactive
186}
187
188func TODOBuildkit() bool {
189	return os.Getenv("DOCKER_BUILDKIT") == ""
190}
191
192// testRequires checks if the environment satisfies the requirements
193// for the test to run or skips the tests.
194func testRequires(t *testing.T, requirements ...requirement.Test) {
195	t.Helper()
196	requirement.Is(t, requirements...)
197}
198