docker_utils_test.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "net"
  10. "net/http"
  11. "net/http/httptest"
  12. "net/url"
  13. "os"
  14. "os/exec"
  15. "path"
  16. "path/filepath"
  17. "strconv"
  18. "strings"
  19. "time"
  20. "github.com/docker/docker/api/types"
  21. "github.com/docker/docker/integration-cli/checker"
  22. "github.com/docker/docker/integration-cli/daemon"
  23. "github.com/docker/docker/integration-cli/registry"
  24. "github.com/docker/docker/integration-cli/request"
  25. "github.com/docker/docker/pkg/stringutils"
  26. icmd "github.com/docker/docker/pkg/testutil/cmd"
  27. "github.com/go-check/check"
  28. )
  29. // Deprecated
  30. func daemonHost() string {
  31. return request.DaemonHost()
  32. }
  33. // FIXME(vdemeester) move this away are remove ignoreNoSuchContainer bool
  34. func deleteContainer(container ...string) error {
  35. return icmd.RunCommand(dockerBinary, append([]string{"rm", "-fv"}, container...)...).Compare(icmd.Success)
  36. }
  37. func getAllContainers(c *check.C) string {
  38. result := icmd.RunCommand(dockerBinary, "ps", "-q", "-a")
  39. result.Assert(c, icmd.Success)
  40. return result.Combined()
  41. }
  42. // Deprecated
  43. func deleteAllContainers(c *check.C) {
  44. containers := getAllContainers(c)
  45. if containers != "" {
  46. err := deleteContainer(strings.Split(strings.TrimSpace(containers), "\n")...)
  47. c.Assert(err, checker.IsNil)
  48. }
  49. }
  50. func getPausedContainers(c *check.C) []string {
  51. result := icmd.RunCommand(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
  52. result.Assert(c, icmd.Success)
  53. return strings.Fields(result.Combined())
  54. }
  55. func unpauseContainer(c *check.C, container string) {
  56. dockerCmd(c, "unpause", container)
  57. }
  58. // Deprecated
  59. func unpauseAllContainers(c *check.C) {
  60. containers := getPausedContainers(c)
  61. for _, value := range containers {
  62. unpauseContainer(c, value)
  63. }
  64. }
  65. func deleteImages(images ...string) error {
  66. args := []string{dockerBinary, "rmi", "-f"}
  67. return icmd.RunCmd(icmd.Cmd{Command: append(args, images...)}).Error
  68. }
  69. func dockerCmdWithError(args ...string) (string, int, error) {
  70. if err := validateArgs(args...); err != nil {
  71. return "", 0, err
  72. }
  73. result := icmd.RunCommand(dockerBinary, args...)
  74. if result.Error != nil {
  75. return result.Combined(), result.ExitCode, result.Compare(icmd.Success)
  76. }
  77. return result.Combined(), result.ExitCode, result.Error
  78. }
  79. func dockerCmdWithStdoutStderr(c *check.C, args ...string) (string, string, int) {
  80. if err := validateArgs(args...); err != nil {
  81. c.Fatalf(err.Error())
  82. }
  83. result := icmd.RunCommand(dockerBinary, args...)
  84. c.Assert(result, icmd.Matches, icmd.Success)
  85. return result.Stdout(), result.Stderr(), result.ExitCode
  86. }
  87. func dockerCmd(c *check.C, args ...string) (string, int) {
  88. if err := validateArgs(args...); err != nil {
  89. c.Fatalf(err.Error())
  90. }
  91. result := icmd.RunCommand(dockerBinary, args...)
  92. c.Assert(result, icmd.Matches, icmd.Success)
  93. return result.Combined(), result.ExitCode
  94. }
  95. func dockerCmdWithResult(args ...string) *icmd.Result {
  96. return icmd.RunCommand(dockerBinary, args...)
  97. }
  98. func binaryWithArgs(args ...string) []string {
  99. return append([]string{dockerBinary}, args...)
  100. }
  101. // execute a docker command with a timeout
  102. func dockerCmdWithTimeout(timeout time.Duration, args ...string) *icmd.Result {
  103. if err := validateArgs(args...); err != nil {
  104. return &icmd.Result{Error: err}
  105. }
  106. return icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Timeout: timeout})
  107. }
  108. // execute a docker command in a directory
  109. func dockerCmdInDir(c *check.C, path string, args ...string) (string, int, error) {
  110. if err := validateArgs(args...); err != nil {
  111. c.Fatalf(err.Error())
  112. }
  113. result := icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Dir: path})
  114. return result.Combined(), result.ExitCode, result.Error
  115. }
  116. // validateArgs is a checker to ensure tests are not running commands which are
  117. // not supported on platforms. Specifically on Windows this is 'busybox top'.
  118. func validateArgs(args ...string) error {
  119. if testEnv.DaemonPlatform() != "windows" {
  120. return nil
  121. }
  122. foundBusybox := -1
  123. for key, value := range args {
  124. if strings.ToLower(value) == "busybox" {
  125. foundBusybox = key
  126. }
  127. if (foundBusybox != -1) && (key == foundBusybox+1) && (strings.ToLower(value) == "top") {
  128. return errors.New("cannot use 'busybox top' in tests on Windows. Use runSleepingContainer()")
  129. }
  130. }
  131. return nil
  132. }
  133. func findContainerIP(c *check.C, id string, network string) string {
  134. out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", network), id)
  135. return strings.Trim(out, " \r\n'")
  136. }
  137. func getContainerCount(c *check.C) int {
  138. const containers = "Containers:"
  139. result := icmd.RunCommand(dockerBinary, "info")
  140. result.Assert(c, icmd.Success)
  141. lines := strings.Split(result.Combined(), "\n")
  142. for _, line := range lines {
  143. if strings.Contains(line, containers) {
  144. output := strings.TrimSpace(line)
  145. output = strings.TrimLeft(output, containers)
  146. output = strings.Trim(output, " ")
  147. containerCount, err := strconv.Atoi(output)
  148. c.Assert(err, checker.IsNil)
  149. return containerCount
  150. }
  151. }
  152. return 0
  153. }
  154. // FakeContext creates directories that can be used as a build context
  155. type FakeContext struct {
  156. Dir string
  157. }
  158. // Add a file at a path, creating directories where necessary
  159. func (f *FakeContext) Add(file, content string) error {
  160. return f.addFile(file, []byte(content))
  161. }
  162. func (f *FakeContext) addFile(file string, content []byte) error {
  163. fp := filepath.Join(f.Dir, filepath.FromSlash(file))
  164. dirpath := filepath.Dir(fp)
  165. if dirpath != "." {
  166. if err := os.MkdirAll(dirpath, 0755); err != nil {
  167. return err
  168. }
  169. }
  170. return ioutil.WriteFile(fp, content, 0644)
  171. }
  172. // Delete a file at a path
  173. func (f *FakeContext) Delete(file string) error {
  174. fp := filepath.Join(f.Dir, filepath.FromSlash(file))
  175. return os.RemoveAll(fp)
  176. }
  177. // Close deletes the context
  178. func (f *FakeContext) Close() error {
  179. return os.RemoveAll(f.Dir)
  180. }
  181. func fakeContextFromNewTempDir(c *check.C) *FakeContext {
  182. tmp, err := ioutil.TempDir("", "fake-context")
  183. c.Assert(err, checker.IsNil)
  184. if err := os.Chmod(tmp, 0755); err != nil {
  185. c.Fatal(err)
  186. }
  187. return fakeContextFromDir(tmp)
  188. }
  189. func fakeContextFromDir(dir string) *FakeContext {
  190. return &FakeContext{dir}
  191. }
  192. func fakeContextWithFiles(c *check.C, files map[string]string) *FakeContext {
  193. ctx := fakeContextFromNewTempDir(c)
  194. for file, content := range files {
  195. if err := ctx.Add(file, content); err != nil {
  196. ctx.Close()
  197. c.Fatal(err)
  198. }
  199. }
  200. return ctx
  201. }
  202. func fakeContextAddDockerfile(c *check.C, ctx *FakeContext, dockerfile string) {
  203. if err := ctx.Add("Dockerfile", dockerfile); err != nil {
  204. ctx.Close()
  205. c.Fatal(err)
  206. }
  207. }
  208. func fakeContext(c *check.C, dockerfile string, files map[string]string) *FakeContext {
  209. ctx := fakeContextWithFiles(c, files)
  210. fakeContextAddDockerfile(c, ctx, dockerfile)
  211. return ctx
  212. }
  213. // FakeStorage is a static file server. It might be running locally or remotely
  214. // on test host.
  215. type FakeStorage interface {
  216. Close() error
  217. URL() string
  218. CtxDir() string
  219. }
  220. func fakeBinaryStorage(c *check.C, archives map[string]*bytes.Buffer) FakeStorage {
  221. ctx := fakeContextFromNewTempDir(c)
  222. for name, content := range archives {
  223. if err := ctx.addFile(name, content.Bytes()); err != nil {
  224. c.Fatal(err)
  225. }
  226. }
  227. return fakeStorageWithContext(c, ctx)
  228. }
  229. // fakeStorage returns either a local or remote (at daemon machine) file server
  230. func fakeStorage(c *check.C, files map[string]string) FakeStorage {
  231. ctx := fakeContextWithFiles(c, files)
  232. return fakeStorageWithContext(c, ctx)
  233. }
  234. // fakeStorageWithContext returns either a local or remote (at daemon machine) file server
  235. func fakeStorageWithContext(c *check.C, ctx *FakeContext) FakeStorage {
  236. if testEnv.LocalDaemon() {
  237. return newLocalFakeStorage(c, ctx)
  238. }
  239. return newRemoteFileServer(c, ctx)
  240. }
  241. // localFileStorage is a file storage on the running machine
  242. type localFileStorage struct {
  243. *FakeContext
  244. *httptest.Server
  245. }
  246. func (s *localFileStorage) URL() string {
  247. return s.Server.URL
  248. }
  249. func (s *localFileStorage) CtxDir() string {
  250. return s.FakeContext.Dir
  251. }
  252. func (s *localFileStorage) Close() error {
  253. defer s.Server.Close()
  254. return s.FakeContext.Close()
  255. }
  256. func newLocalFakeStorage(c *check.C, ctx *FakeContext) *localFileStorage {
  257. handler := http.FileServer(http.Dir(ctx.Dir))
  258. server := httptest.NewServer(handler)
  259. return &localFileStorage{
  260. FakeContext: ctx,
  261. Server: server,
  262. }
  263. }
  264. // remoteFileServer is a containerized static file server started on the remote
  265. // testing machine to be used in URL-accepting docker build functionality.
  266. type remoteFileServer struct {
  267. host string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
  268. container string
  269. image string
  270. ctx *FakeContext
  271. }
  272. func (f *remoteFileServer) URL() string {
  273. u := url.URL{
  274. Scheme: "http",
  275. Host: f.host}
  276. return u.String()
  277. }
  278. func (f *remoteFileServer) CtxDir() string {
  279. return f.ctx.Dir
  280. }
  281. func (f *remoteFileServer) Close() error {
  282. defer func() {
  283. if f.ctx != nil {
  284. f.ctx.Close()
  285. }
  286. if f.image != "" {
  287. deleteImages(f.image)
  288. }
  289. }()
  290. if f.container == "" {
  291. return nil
  292. }
  293. return deleteContainer(f.container)
  294. }
  295. func newRemoteFileServer(c *check.C, ctx *FakeContext) *remoteFileServer {
  296. var (
  297. image = fmt.Sprintf("fileserver-img-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
  298. container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
  299. )
  300. ensureHTTPServerImage(c)
  301. // Build the image
  302. fakeContextAddDockerfile(c, ctx, `FROM httpserver
  303. COPY . /static`)
  304. buildImageSuccessfully(c, image, withoutCache, withExternalBuildContext(ctx))
  305. // Start the container
  306. dockerCmd(c, "run", "-d", "-P", "--name", container, image)
  307. // Find out the system assigned port
  308. out, _ := dockerCmd(c, "port", container, "80/tcp")
  309. fileserverHostPort := strings.Trim(out, "\n")
  310. _, port, err := net.SplitHostPort(fileserverHostPort)
  311. if err != nil {
  312. c.Fatalf("unable to parse file server host:port: %v", err)
  313. }
  314. dockerHostURL, err := url.Parse(daemonHost())
  315. if err != nil {
  316. c.Fatalf("unable to parse daemon host URL: %v", err)
  317. }
  318. host, _, err := net.SplitHostPort(dockerHostURL.Host)
  319. if err != nil {
  320. c.Fatalf("unable to parse docker daemon host:port: %v", err)
  321. }
  322. return &remoteFileServer{
  323. container: container,
  324. image: image,
  325. host: fmt.Sprintf("%s:%s", host, port),
  326. ctx: ctx}
  327. }
  328. func inspectFieldAndUnmarshall(c *check.C, name, field string, output interface{}) {
  329. str := inspectFieldJSON(c, name, field)
  330. err := json.Unmarshal([]byte(str), output)
  331. if c != nil {
  332. c.Assert(err, check.IsNil, check.Commentf("failed to unmarshal: %v", err))
  333. }
  334. }
  335. func inspectFilter(name, filter string) (string, error) {
  336. format := fmt.Sprintf("{{%s}}", filter)
  337. result := icmd.RunCommand(dockerBinary, "inspect", "-f", format, name)
  338. if result.Error != nil || result.ExitCode != 0 {
  339. return "", fmt.Errorf("failed to inspect %s: %s", name, result.Combined())
  340. }
  341. return strings.TrimSpace(result.Combined()), nil
  342. }
  343. func inspectFieldWithError(name, field string) (string, error) {
  344. return inspectFilter(name, fmt.Sprintf(".%s", field))
  345. }
  346. func inspectField(c *check.C, name, field string) string {
  347. out, err := inspectFilter(name, fmt.Sprintf(".%s", field))
  348. if c != nil {
  349. c.Assert(err, check.IsNil)
  350. }
  351. return out
  352. }
  353. func inspectFieldJSON(c *check.C, name, field string) string {
  354. out, err := inspectFilter(name, fmt.Sprintf("json .%s", field))
  355. if c != nil {
  356. c.Assert(err, check.IsNil)
  357. }
  358. return out
  359. }
  360. func inspectFieldMap(c *check.C, name, path, field string) string {
  361. out, err := inspectFilter(name, fmt.Sprintf("index .%s %q", path, field))
  362. if c != nil {
  363. c.Assert(err, check.IsNil)
  364. }
  365. return out
  366. }
  367. func inspectMountSourceField(name, destination string) (string, error) {
  368. m, err := inspectMountPoint(name, destination)
  369. if err != nil {
  370. return "", err
  371. }
  372. return m.Source, nil
  373. }
  374. func inspectMountPoint(name, destination string) (types.MountPoint, error) {
  375. out, err := inspectFilter(name, "json .Mounts")
  376. if err != nil {
  377. return types.MountPoint{}, err
  378. }
  379. return inspectMountPointJSON(out, destination)
  380. }
  381. var errMountNotFound = errors.New("mount point not found")
  382. func inspectMountPointJSON(j, destination string) (types.MountPoint, error) {
  383. var mp []types.MountPoint
  384. if err := json.Unmarshal([]byte(j), &mp); err != nil {
  385. return types.MountPoint{}, err
  386. }
  387. var m *types.MountPoint
  388. for _, c := range mp {
  389. if c.Destination == destination {
  390. m = &c
  391. break
  392. }
  393. }
  394. if m == nil {
  395. return types.MountPoint{}, errMountNotFound
  396. }
  397. return *m, nil
  398. }
  399. func inspectImage(c *check.C, name, filter string) string {
  400. args := []string{"inspect", "--type", "image"}
  401. if filter != "" {
  402. format := fmt.Sprintf("{{%s}}", filter)
  403. args = append(args, "-f", format)
  404. }
  405. args = append(args, name)
  406. result := icmd.RunCommand(dockerBinary, args...)
  407. result.Assert(c, icmd.Success)
  408. return strings.TrimSpace(result.Combined())
  409. }
  410. func getIDByName(c *check.C, name string) string {
  411. id, err := inspectFieldWithError(name, "Id")
  412. c.Assert(err, checker.IsNil)
  413. return id
  414. }
  415. func buildImageSuccessfully(c *check.C, name string, cmdOperators ...func(*icmd.Cmd) func()) {
  416. buildImage(name, cmdOperators...).Assert(c, icmd.Success)
  417. }
  418. func buildImage(name string, cmdOperators ...func(*icmd.Cmd) func()) *icmd.Result {
  419. cmd := icmd.Command(dockerBinary, "build", "-t", name)
  420. for _, op := range cmdOperators {
  421. deferFn := op(&cmd)
  422. if deferFn != nil {
  423. defer deferFn()
  424. }
  425. }
  426. return icmd.RunCmd(cmd)
  427. }
  428. func withBuildContextPath(path string) func(*icmd.Cmd) func() {
  429. return func(cmd *icmd.Cmd) func() {
  430. cmd.Command = append(cmd.Command, path)
  431. return nil
  432. }
  433. }
  434. func withExternalBuildContext(ctx *FakeContext) func(*icmd.Cmd) func() {
  435. return func(cmd *icmd.Cmd) func() {
  436. cmd.Dir = ctx.Dir
  437. cmd.Command = append(cmd.Command, ".")
  438. return nil
  439. }
  440. }
  441. func withBuildContext(c *check.C, contextOperators ...func(*FakeContext) error) func(*icmd.Cmd) func() {
  442. ctx := fakeContextFromNewTempDir(c)
  443. for _, op := range contextOperators {
  444. if err := op(ctx); err != nil {
  445. c.Fatal(err)
  446. }
  447. }
  448. return func(cmd *icmd.Cmd) func() {
  449. cmd.Dir = ctx.Dir
  450. cmd.Command = append(cmd.Command, ".")
  451. return closeBuildContext(c, ctx)
  452. }
  453. }
  454. func withBuildFlags(flags ...string) func(*icmd.Cmd) func() {
  455. return func(cmd *icmd.Cmd) func() {
  456. cmd.Command = append(cmd.Command, flags...)
  457. return nil
  458. }
  459. }
  460. func withoutCache(cmd *icmd.Cmd) func() {
  461. cmd.Command = append(cmd.Command, "--no-cache")
  462. return nil
  463. }
  464. func withFile(name, content string) func(*FakeContext) error {
  465. return func(ctx *FakeContext) error {
  466. return ctx.Add(name, content)
  467. }
  468. }
  469. func closeBuildContext(c *check.C, ctx *FakeContext) func() {
  470. return func() {
  471. if err := ctx.Close(); err != nil {
  472. c.Fatal(err)
  473. }
  474. }
  475. }
  476. func withDockerfile(dockerfile string) func(*icmd.Cmd) func() {
  477. return func(cmd *icmd.Cmd) func() {
  478. cmd.Command = append(cmd.Command, "-")
  479. cmd.Stdin = strings.NewReader(dockerfile)
  480. return nil
  481. }
  482. }
  483. func trustedBuild(cmd *icmd.Cmd) func() {
  484. trustedCmd(cmd)
  485. return nil
  486. }
  487. func withEnvironmentVariales(envs ...string) func(cmd *icmd.Cmd) func() {
  488. return func(cmd *icmd.Cmd) func() {
  489. cmd.Env = envs
  490. return nil
  491. }
  492. }
  493. type gitServer interface {
  494. URL() string
  495. Close() error
  496. }
  497. type localGitServer struct {
  498. *httptest.Server
  499. }
  500. func (r *localGitServer) Close() error {
  501. r.Server.Close()
  502. return nil
  503. }
  504. func (r *localGitServer) URL() string {
  505. return r.Server.URL
  506. }
  507. type fakeGit struct {
  508. root string
  509. server gitServer
  510. RepoURL string
  511. }
  512. func (g *fakeGit) Close() {
  513. g.server.Close()
  514. os.RemoveAll(g.root)
  515. }
  516. func newFakeGit(c *check.C, name string, files map[string]string, enforceLocalServer bool) *fakeGit {
  517. ctx := fakeContextWithFiles(c, files)
  518. defer ctx.Close()
  519. curdir, err := os.Getwd()
  520. if err != nil {
  521. c.Fatal(err)
  522. }
  523. defer os.Chdir(curdir)
  524. if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
  525. c.Fatalf("error trying to init repo: %s (%s)", err, output)
  526. }
  527. err = os.Chdir(ctx.Dir)
  528. if err != nil {
  529. c.Fatal(err)
  530. }
  531. if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil {
  532. c.Fatalf("error trying to set 'user.name': %s (%s)", err, output)
  533. }
  534. if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil {
  535. c.Fatalf("error trying to set 'user.email': %s (%s)", err, output)
  536. }
  537. if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
  538. c.Fatalf("error trying to add files to repo: %s (%s)", err, output)
  539. }
  540. if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
  541. c.Fatalf("error trying to commit to repo: %s (%s)", err, output)
  542. }
  543. root, err := ioutil.TempDir("", "docker-test-git-repo")
  544. if err != nil {
  545. c.Fatal(err)
  546. }
  547. repoPath := filepath.Join(root, name+".git")
  548. if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
  549. os.RemoveAll(root)
  550. c.Fatalf("error trying to clone --bare: %s (%s)", err, output)
  551. }
  552. err = os.Chdir(repoPath)
  553. if err != nil {
  554. os.RemoveAll(root)
  555. c.Fatal(err)
  556. }
  557. if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
  558. os.RemoveAll(root)
  559. c.Fatalf("error trying to git update-server-info: %s (%s)", err, output)
  560. }
  561. err = os.Chdir(curdir)
  562. if err != nil {
  563. os.RemoveAll(root)
  564. c.Fatal(err)
  565. }
  566. var server gitServer
  567. if !enforceLocalServer {
  568. // use fakeStorage server, which might be local or remote (at test daemon)
  569. server = fakeStorageWithContext(c, fakeContextFromDir(root))
  570. } else {
  571. // always start a local http server on CLI test machine
  572. httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
  573. server = &localGitServer{httpServer}
  574. }
  575. return &fakeGit{
  576. root: root,
  577. server: server,
  578. RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name),
  579. }
  580. }
  581. // Write `content` to the file at path `dst`, creating it if necessary,
  582. // as well as any missing directories.
  583. // The file is truncated if it already exists.
  584. // Fail the test when error occurs.
  585. func writeFile(dst, content string, c *check.C) {
  586. // Create subdirectories if necessary
  587. c.Assert(os.MkdirAll(path.Dir(dst), 0700), check.IsNil)
  588. f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
  589. c.Assert(err, check.IsNil)
  590. defer f.Close()
  591. // Write content (truncate if it exists)
  592. _, err = io.Copy(f, strings.NewReader(content))
  593. c.Assert(err, check.IsNil)
  594. }
  595. // Return the contents of file at path `src`.
  596. // Fail the test when error occurs.
  597. func readFile(src string, c *check.C) (content string) {
  598. data, err := ioutil.ReadFile(src)
  599. c.Assert(err, check.IsNil)
  600. return string(data)
  601. }
  602. func containerStorageFile(containerID, basename string) string {
  603. return filepath.Join(testEnv.ContainerStoragePath(), containerID, basename)
  604. }
  605. // docker commands that use this function must be run with the '-d' switch.
  606. func runCommandAndReadContainerFile(c *check.C, filename string, command string, args ...string) []byte {
  607. result := icmd.RunCommand(command, args...)
  608. result.Assert(c, icmd.Success)
  609. contID := strings.TrimSpace(result.Combined())
  610. if err := waitRun(contID); err != nil {
  611. c.Fatalf("%v: %q", contID, err)
  612. }
  613. return readContainerFile(c, contID, filename)
  614. }
  615. func readContainerFile(c *check.C, containerID, filename string) []byte {
  616. f, err := os.Open(containerStorageFile(containerID, filename))
  617. c.Assert(err, checker.IsNil)
  618. defer f.Close()
  619. content, err := ioutil.ReadAll(f)
  620. c.Assert(err, checker.IsNil)
  621. return content
  622. }
  623. func readContainerFileWithExec(c *check.C, containerID, filename string) []byte {
  624. result := icmd.RunCommand(dockerBinary, "exec", containerID, "cat", filename)
  625. result.Assert(c, icmd.Success)
  626. return []byte(result.Combined())
  627. }
  628. // daemonTime provides the current time on the daemon host
  629. func daemonTime(c *check.C) time.Time {
  630. if testEnv.LocalDaemon() {
  631. return time.Now()
  632. }
  633. status, body, err := request.SockRequest("GET", "/info", nil, daemonHost())
  634. c.Assert(err, check.IsNil)
  635. c.Assert(status, check.Equals, http.StatusOK)
  636. type infoJSON struct {
  637. SystemTime string
  638. }
  639. var info infoJSON
  640. err = json.Unmarshal(body, &info)
  641. c.Assert(err, check.IsNil, check.Commentf("unable to unmarshal GET /info response"))
  642. dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
  643. c.Assert(err, check.IsNil, check.Commentf("invalid time format in GET /info response"))
  644. return dt
  645. }
  646. // daemonUnixTime returns the current time on the daemon host with nanoseconds precision.
  647. // It return the time formatted how the client sends timestamps to the server.
  648. func daemonUnixTime(c *check.C) string {
  649. return parseEventTime(daemonTime(c))
  650. }
  651. func parseEventTime(t time.Time) string {
  652. return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond()))
  653. }
  654. func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *registry.V2 {
  655. reg, err := registry.NewV2(schema1, auth, tokenURL, privateRegistryURL)
  656. c.Assert(err, check.IsNil)
  657. // Wait for registry to be ready to serve requests.
  658. for i := 0; i != 50; i++ {
  659. if err = reg.Ping(); err == nil {
  660. break
  661. }
  662. time.Sleep(100 * time.Millisecond)
  663. }
  664. c.Assert(err, check.IsNil, check.Commentf("Timeout waiting for test registry to become available: %v", err))
  665. return reg
  666. }
  667. func setupNotary(c *check.C) *testNotary {
  668. ts, err := newTestNotary(c)
  669. c.Assert(err, check.IsNil)
  670. return ts
  671. }
  672. // appendBaseEnv appends the minimum set of environment variables to exec the
  673. // docker cli binary for testing with correct configuration to the given env
  674. // list.
  675. func appendBaseEnv(isTLS bool, env ...string) []string {
  676. preserveList := []string{
  677. // preserve remote test host
  678. "DOCKER_HOST",
  679. // windows: requires preserving SystemRoot, otherwise dial tcp fails
  680. // with "GetAddrInfoW: A non-recoverable error occurred during a database lookup."
  681. "SystemRoot",
  682. // testing help text requires the $PATH to dockerd is set
  683. "PATH",
  684. }
  685. if isTLS {
  686. preserveList = append(preserveList, "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH")
  687. }
  688. for _, key := range preserveList {
  689. if val := os.Getenv(key); val != "" {
  690. env = append(env, fmt.Sprintf("%s=%s", key, val))
  691. }
  692. }
  693. return env
  694. }
  695. func createTmpFile(c *check.C, content string) string {
  696. f, err := ioutil.TempFile("", "testfile")
  697. c.Assert(err, check.IsNil)
  698. filename := f.Name()
  699. err = ioutil.WriteFile(filename, []byte(content), 0644)
  700. c.Assert(err, check.IsNil)
  701. return filename
  702. }
  703. func waitForContainer(contID string, args ...string) error {
  704. args = append([]string{dockerBinary, "run", "--name", contID}, args...)
  705. result := icmd.RunCmd(icmd.Cmd{Command: args})
  706. if result.Error != nil {
  707. return result.Error
  708. }
  709. return waitRun(contID)
  710. }
  711. // waitRestart will wait for the specified container to restart once
  712. func waitRestart(contID string, duration time.Duration) error {
  713. return waitInspect(contID, "{{.RestartCount}}", "1", duration)
  714. }
  715. // waitRun will wait for the specified container to be running, maximum 5 seconds.
  716. func waitRun(contID string) error {
  717. return waitInspect(contID, "{{.State.Running}}", "true", 5*time.Second)
  718. }
  719. // waitExited will wait for the specified container to state exit, subject
  720. // to a maximum time limit in seconds supplied by the caller
  721. func waitExited(contID string, duration time.Duration) error {
  722. return waitInspect(contID, "{{.State.Status}}", "exited", duration)
  723. }
  724. // waitInspect will wait for the specified container to have the specified string
  725. // in the inspect output. It will wait until the specified timeout (in seconds)
  726. // is reached.
  727. func waitInspect(name, expr, expected string, timeout time.Duration) error {
  728. return waitInspectWithArgs(name, expr, expected, timeout)
  729. }
  730. func waitInspectWithArgs(name, expr, expected string, timeout time.Duration, arg ...string) error {
  731. return daemon.WaitInspectWithArgs(dockerBinary, name, expr, expected, timeout, arg...)
  732. }
  733. func getInspectBody(c *check.C, version, id string) []byte {
  734. endpoint := fmt.Sprintf("/%s/containers/%s/json", version, id)
  735. status, body, err := request.SockRequest("GET", endpoint, nil, daemonHost())
  736. c.Assert(err, check.IsNil)
  737. c.Assert(status, check.Equals, http.StatusOK)
  738. return body
  739. }
  740. // Run a long running idle task in a background container using the
  741. // system-specific default image and command.
  742. func runSleepingContainer(c *check.C, extraArgs ...string) (string, int) {
  743. return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...)
  744. }
  745. // Run a long running idle task in a background container using the specified
  746. // image and the system-specific command.
  747. func runSleepingContainerInImage(c *check.C, image string, extraArgs ...string) (string, int) {
  748. args := []string{"run", "-d"}
  749. args = append(args, extraArgs...)
  750. args = append(args, image)
  751. args = append(args, sleepCommandForDaemonPlatform()...)
  752. return dockerCmd(c, args...)
  753. }
  754. // minimalBaseImage returns the name of the minimal base image for the current
  755. // daemon platform.
  756. func minimalBaseImage() string {
  757. return testEnv.MinimalBaseImage()
  758. }
  759. func getGoroutineNumber() (int, error) {
  760. i := struct {
  761. NGoroutines int
  762. }{}
  763. status, b, err := request.SockRequest("GET", "/info", nil, daemonHost())
  764. if err != nil {
  765. return 0, err
  766. }
  767. if status != http.StatusOK {
  768. return 0, fmt.Errorf("http status code: %d", status)
  769. }
  770. if err := json.Unmarshal(b, &i); err != nil {
  771. return 0, err
  772. }
  773. return i.NGoroutines, nil
  774. }
  775. func waitForGoroutines(expected int) error {
  776. t := time.After(30 * time.Second)
  777. for {
  778. select {
  779. case <-t:
  780. n, err := getGoroutineNumber()
  781. if err != nil {
  782. return err
  783. }
  784. if n > expected {
  785. return fmt.Errorf("leaked goroutines: expected less than or equal to %d, got: %d", expected, n)
  786. }
  787. default:
  788. n, err := getGoroutineNumber()
  789. if err != nil {
  790. return err
  791. }
  792. if n <= expected {
  793. return nil
  794. }
  795. time.Sleep(200 * time.Millisecond)
  796. }
  797. }
  798. }
  799. // getErrorMessage returns the error message from an error API response
  800. func getErrorMessage(c *check.C, body []byte) string {
  801. var resp types.ErrorResponse
  802. c.Assert(json.Unmarshal(body, &resp), check.IsNil)
  803. return strings.TrimSpace(resp.Message)
  804. }
  805. func waitAndAssert(c *check.C, timeout time.Duration, f checkF, checker check.Checker, args ...interface{}) {
  806. after := time.After(timeout)
  807. for {
  808. v, comment := f(c)
  809. assert, _ := checker.Check(append([]interface{}{v}, args...), checker.Info().Params)
  810. select {
  811. case <-after:
  812. assert = true
  813. default:
  814. }
  815. if assert {
  816. if comment != nil {
  817. args = append(args, comment)
  818. }
  819. c.Assert(v, checker, args...)
  820. return
  821. }
  822. time.Sleep(100 * time.Millisecond)
  823. }
  824. }
  825. type checkF func(*check.C) (interface{}, check.CommentInterface)
  826. type reducer func(...interface{}) interface{}
  827. func reducedCheck(r reducer, funcs ...checkF) checkF {
  828. return func(c *check.C) (interface{}, check.CommentInterface) {
  829. var values []interface{}
  830. var comments []string
  831. for _, f := range funcs {
  832. v, comment := f(c)
  833. values = append(values, v)
  834. if comment != nil {
  835. comments = append(comments, comment.CheckCommentString())
  836. }
  837. }
  838. return r(values...), check.Commentf("%v", strings.Join(comments, ", "))
  839. }
  840. }
  841. func sumAsIntegers(vals ...interface{}) interface{} {
  842. var s int
  843. for _, v := range vals {
  844. s += v.(int)
  845. }
  846. return s
  847. }