|
1 | 1 | package daemon // import "github.com/docker/docker/integration/daemon"
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + "net/http" |
| 7 | + "net/http/httptest" |
4 | 8 | "os"
|
5 | 9 | "os/exec"
|
6 | 10 | "path/filepath"
|
7 | 11 | "runtime"
|
8 | 12 | "testing"
|
9 | 13 |
|
| 14 | + "github.com/docker/docker/api/types" |
10 | 15 | "github.com/docker/docker/daemon/config"
|
11 | 16 | "github.com/docker/docker/testutil/daemon"
|
12 | 17 | "gotest.tools/v3/assert"
|
13 | 18 | is "gotest.tools/v3/assert/cmp"
|
| 19 | + "gotest.tools/v3/env" |
14 | 20 | "gotest.tools/v3/skip"
|
15 | 21 | )
|
16 | 22 |
|
@@ -146,3 +152,150 @@ func TestConfigDaemonSeccompProfiles(t *testing.T) {
|
146 | 152 | })
|
147 | 153 | }
|
148 | 154 | }
|
| 155 | + |
| 156 | +func TestDaemonProxy(t *testing.T) { |
| 157 | + skip.If(t, runtime.GOOS == "windows", "cannot start multiple daemons on windows") |
| 158 | + |
| 159 | + var received string |
| 160 | + proxyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 161 | + received = r.Host |
| 162 | + w.Header().Set("Content-Type", "application/json") |
| 163 | + _, _ = w.Write([]byte("OK")) |
| 164 | + })) |
| 165 | + defer proxyServer.Close() |
| 166 | + |
| 167 | + // Configure proxy through env-vars |
| 168 | + t.Run("environment variables", func(t *testing.T) { |
| 169 | + defer env.Patch(t, "HTTP_PROXY", proxyServer.URL)() |
| 170 | + defer env.Patch(t, "HTTPS_PROXY", proxyServer.URL)() |
| 171 | + defer env.Patch(t, "NO_PROXY", "example.com")() |
| 172 | + |
| 173 | + d := daemon.New(t) |
| 174 | + c := d.NewClientT(t) |
| 175 | + defer func() { _ = c.Close() }() |
| 176 | + ctx := context.Background() |
| 177 | + d.Start(t) |
| 178 | + |
| 179 | + _, err := c.ImagePull(ctx, "example.org:5000/some/image:latest", types.ImagePullOptions{}) |
| 180 | + assert.ErrorContains(t, err, "", "pulling should have failed") |
| 181 | + assert.Equal(t, received, "example.org:5000") |
| 182 | + |
| 183 | + // Test NoProxy: example.com should not hit the proxy, and "received" variable should not be changed. |
| 184 | + _, err = c.ImagePull(ctx, "example.com/some/image:latest", types.ImagePullOptions{}) |
| 185 | + assert.ErrorContains(t, err, "", "pulling should have failed") |
| 186 | + assert.Equal(t, received, "example.org:5000", "should not have used proxy") |
| 187 | + |
| 188 | + info := d.Info(t) |
| 189 | + assert.Equal(t, info.HTTPProxy, proxyServer.URL) |
| 190 | + assert.Equal(t, info.HTTPSProxy, proxyServer.URL) |
| 191 | + assert.Equal(t, info.NoProxy, "example.com") |
| 192 | + d.Stop(t) |
| 193 | + }) |
| 194 | + |
| 195 | + // Configure proxy through command-line flags |
| 196 | + t.Run("command-line options", func(t *testing.T) { |
| 197 | + defer env.Patch(t, "HTTP_PROXY", "http://from-env-http.invalid")() |
| 198 | + defer env.Patch(t, "http_proxy", "http://from-env-http.invalid")() |
| 199 | + defer env.Patch(t, "HTTPS_PROXY", "https://from-env-https.invalid")() |
| 200 | + defer env.Patch(t, "https_proxy", "https://from-env-http.invalid")() |
| 201 | + defer env.Patch(t, "NO_PROXY", "ignore.invalid")() |
| 202 | + defer env.Patch(t, "no_proxy", "ignore.invalid")() |
| 203 | + |
| 204 | + d := daemon.New(t) |
| 205 | + d.Start(t, "--http-proxy", proxyServer.URL, "--https-proxy", proxyServer.URL, "--no-proxy", "example.com") |
| 206 | + |
| 207 | + logs, err := d.ReadLogFile() |
| 208 | + assert.NilError(t, err) |
| 209 | + assert.Assert(t, is.Contains(string(logs), "overriding existing proxy variable with value from configuration")) |
| 210 | + for _, v := range []string{"http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY", "no_proxy", "NO_PROXY"} { |
| 211 | + assert.Assert(t, is.Contains(string(logs), "name="+v)) |
| 212 | + } |
| 213 | + |
| 214 | + c := d.NewClientT(t) |
| 215 | + defer func() { _ = c.Close() }() |
| 216 | + ctx := context.Background() |
| 217 | + |
| 218 | + _, err = c.ImagePull(ctx, "example.org:5001/some/image:latest", types.ImagePullOptions{}) |
| 219 | + assert.ErrorContains(t, err, "", "pulling should have failed") |
| 220 | + assert.Equal(t, received, "example.org:5001") |
| 221 | + |
| 222 | + // Test NoProxy: example.com should not hit the proxy, and "received" variable should not be changed. |
| 223 | + _, err = c.ImagePull(ctx, "example.com/some/image:latest", types.ImagePullOptions{}) |
| 224 | + assert.ErrorContains(t, err, "", "pulling should have failed") |
| 225 | + assert.Equal(t, received, "example.org:5001", "should not have used proxy") |
| 226 | + |
| 227 | + info := d.Info(t) |
| 228 | + assert.Equal(t, info.HTTPProxy, proxyServer.URL) |
| 229 | + assert.Equal(t, info.HTTPSProxy, proxyServer.URL) |
| 230 | + assert.Equal(t, info.NoProxy, "example.com") |
| 231 | + |
| 232 | + d.Stop(t) |
| 233 | + }) |
| 234 | + |
| 235 | + // Configure proxy through configuration file |
| 236 | + t.Run("configuration file", func(t *testing.T) { |
| 237 | + defer env.Patch(t, "HTTP_PROXY", "http://from-env-http.invalid")() |
| 238 | + defer env.Patch(t, "http_proxy", "http://from-env-http.invalid")() |
| 239 | + defer env.Patch(t, "HTTPS_PROXY", "https://from-env-https.invalid")() |
| 240 | + defer env.Patch(t, "https_proxy", "https://from-env-http.invalid")() |
| 241 | + defer env.Patch(t, "NO_PROXY", "ignore.invalid")() |
| 242 | + defer env.Patch(t, "no_proxy", "ignore.invalid")() |
| 243 | + |
| 244 | + d := daemon.New(t) |
| 245 | + c := d.NewClientT(t) |
| 246 | + defer func() { _ = c.Close() }() |
| 247 | + ctx := context.Background() |
| 248 | + |
| 249 | + configFile := filepath.Join(d.RootDir(), "daemon.json") |
| 250 | + configJSON := fmt.Sprintf(`{"http-proxy":%[1]q, "https-proxy": %[1]q, "no-proxy": "example.com"}`, proxyServer.URL) |
| 251 | + assert.NilError(t, os.WriteFile(configFile, []byte(configJSON), 0644)) |
| 252 | + |
| 253 | + d.Start(t, "--config-file", configFile) |
| 254 | + |
| 255 | + logs, err := d.ReadLogFile() |
| 256 | + assert.NilError(t, err) |
| 257 | + assert.Assert(t, is.Contains(string(logs), "overriding existing proxy variable with value from configuration")) |
| 258 | + for _, v := range []string{"http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY", "no_proxy", "NO_PROXY"} { |
| 259 | + assert.Assert(t, is.Contains(string(logs), "name="+v)) |
| 260 | + } |
| 261 | + |
| 262 | + _, err = c.ImagePull(ctx, "example.org:5002/some/image:latest", types.ImagePullOptions{}) |
| 263 | + assert.ErrorContains(t, err, "", "pulling should have failed") |
| 264 | + assert.Equal(t, received, "example.org:5002") |
| 265 | + |
| 266 | + // Test NoProxy: example.com should not hit the proxy, and "received" variable should not be changed. |
| 267 | + _, err = c.ImagePull(ctx, "example.com/some/image:latest", types.ImagePullOptions{}) |
| 268 | + assert.ErrorContains(t, err, "", "pulling should have failed") |
| 269 | + assert.Equal(t, received, "example.org:5002", "should not have used proxy") |
| 270 | + |
| 271 | + info := d.Info(t) |
| 272 | + assert.Equal(t, info.HTTPProxy, proxyServer.URL) |
| 273 | + assert.Equal(t, info.HTTPSProxy, proxyServer.URL) |
| 274 | + assert.Equal(t, info.NoProxy, "example.com") |
| 275 | + |
| 276 | + d.Stop(t) |
| 277 | + }) |
| 278 | + |
| 279 | + // Conflicting options (passed both through command-line options and config file) |
| 280 | + t.Run("conflicting options", func(t *testing.T) { |
| 281 | + const ( |
| 282 | + proxyRawURL = "https://myuser:[email protected]" |
| 283 | + ) |
| 284 | + |
| 285 | + d := daemon.New(t) |
| 286 | + |
| 287 | + configFile := filepath.Join(d.RootDir(), "daemon.json") |
| 288 | + configJSON := fmt.Sprintf(`{"http-proxy":%[1]q, "https-proxy": %[1]q, "no-proxy": "example.com"}`, proxyRawURL) |
| 289 | + assert.NilError(t, os.WriteFile(configFile, []byte(configJSON), 0644)) |
| 290 | + |
| 291 | + err := d.StartWithError("--http-proxy", proxyRawURL, "--https-proxy", proxyRawURL, "--no-proxy", "example.com", "--config-file", configFile, "--validate") |
| 292 | + assert.ErrorContains(t, err, "daemon exited during startup") |
| 293 | + logs, err := d.ReadLogFile() |
| 294 | + assert.NilError(t, err) |
| 295 | + expected := fmt.Sprintf( |
| 296 | + `the following directives are specified both as a flag and in the configuration file: http-proxy: (from flag: %[1]s, from file: %[1]s), https-proxy: (from flag: %[1]s, from file: %[1]s), no-proxy: (from flag: example.com, from file: example.com)`, |
| 297 | + proxyRawURL, |
| 298 | + ) |
| 299 | + assert.Assert(t, is.Contains(string(logs), expected)) |
| 300 | + }) |
| 301 | +} |
0 commit comments