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