docker_utils.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net/http"
  6. "net/http/httptest"
  7. "os"
  8. "os/exec"
  9. "path"
  10. "path/filepath"
  11. "strconv"
  12. "strings"
  13. "testing"
  14. )
  15. func deleteContainer(container string) error {
  16. container = strings.Replace(container, "\n", " ", -1)
  17. container = strings.Trim(container, " ")
  18. killArgs := fmt.Sprintf("kill %v", container)
  19. killSplitArgs := strings.Split(killArgs, " ")
  20. killCmd := exec.Command(dockerBinary, killSplitArgs...)
  21. runCommand(killCmd)
  22. rmArgs := fmt.Sprintf("rm %v", container)
  23. rmSplitArgs := strings.Split(rmArgs, " ")
  24. rmCmd := exec.Command(dockerBinary, rmSplitArgs...)
  25. exitCode, err := runCommand(rmCmd)
  26. // set error manually if not set
  27. if exitCode != 0 && err == nil {
  28. err = fmt.Errorf("failed to remove container: `docker rm` exit is non-zero")
  29. }
  30. return err
  31. }
  32. func getAllContainers() (string, error) {
  33. getContainersCmd := exec.Command(dockerBinary, "ps", "-q", "-a")
  34. out, exitCode, err := runCommandWithOutput(getContainersCmd)
  35. if exitCode != 0 && err == nil {
  36. err = fmt.Errorf("failed to get a list of containers: %v\n", out)
  37. }
  38. return out, err
  39. }
  40. func deleteAllContainers() error {
  41. containers, err := getAllContainers()
  42. if err != nil {
  43. fmt.Println(containers)
  44. return err
  45. }
  46. if err = deleteContainer(containers); err != nil {
  47. return err
  48. }
  49. return nil
  50. }
  51. func deleteImages(images string) error {
  52. rmiCmd := exec.Command(dockerBinary, "rmi", images)
  53. exitCode, err := runCommand(rmiCmd)
  54. // set error manually if not set
  55. if exitCode != 0 && err == nil {
  56. err = fmt.Errorf("failed to remove image: `docker rmi` exit is non-zero")
  57. }
  58. return err
  59. }
  60. func imageExists(image string) error {
  61. inspectCmd := exec.Command(dockerBinary, "inspect", image)
  62. exitCode, err := runCommand(inspectCmd)
  63. if exitCode != 0 && err == nil {
  64. err = fmt.Errorf("couldn't find image '%s'", image)
  65. }
  66. return err
  67. }
  68. func pullImageIfNotExist(image string) (err error) {
  69. if err := imageExists(image); err != nil {
  70. pullCmd := exec.Command(dockerBinary, "pull", image)
  71. _, exitCode, err := runCommandWithOutput(pullCmd)
  72. if err != nil || exitCode != 0 {
  73. err = fmt.Errorf("image '%s' wasn't found locally and it couldn't be pulled: %s", image, err)
  74. }
  75. }
  76. return
  77. }
  78. // deprecated, use dockerCmd instead
  79. func cmd(t *testing.T, args ...string) (string, int, error) {
  80. return dockerCmd(t, args...)
  81. }
  82. func dockerCmd(t *testing.T, args ...string) (string, int, error) {
  83. out, status, err := runCommandWithOutput(exec.Command(dockerBinary, args...))
  84. errorOut(err, t, fmt.Sprintf("'%s' failed with errors: %v (%v)", strings.Join(args, " "), err, out))
  85. return out, status, err
  86. }
  87. // execute a docker command in a directory
  88. func dockerCmdInDir(t *testing.T, path string, args ...string) (string, int, error) {
  89. dockerCommand := exec.Command(dockerBinary, args...)
  90. dockerCommand.Dir = path
  91. out, status, err := runCommandWithOutput(dockerCommand)
  92. errorOut(err, t, fmt.Sprintf("'%s' failed with errors: %v (%v)", strings.Join(args, " "), err, out))
  93. return out, status, err
  94. }
  95. func findContainerIp(t *testing.T, id string) string {
  96. cmd := exec.Command(dockerBinary, "inspect", "--format='{{ .NetworkSettings.IPAddress }}'", id)
  97. out, _, err := runCommandWithOutput(cmd)
  98. if err != nil {
  99. t.Fatal(err, out)
  100. }
  101. return strings.Trim(out, " \r\n'")
  102. }
  103. func getContainerCount() (int, error) {
  104. const containers = "Containers:"
  105. cmd := exec.Command(dockerBinary, "info")
  106. out, _, err := runCommandWithOutput(cmd)
  107. if err != nil {
  108. return 0, err
  109. }
  110. lines := strings.Split(out, "\n")
  111. for _, line := range lines {
  112. if strings.Contains(line, containers) {
  113. output := stripTrailingCharacters(line)
  114. output = strings.TrimLeft(output, containers)
  115. output = strings.Trim(output, " ")
  116. containerCount, err := strconv.Atoi(output)
  117. if err != nil {
  118. return 0, err
  119. }
  120. return containerCount, nil
  121. }
  122. }
  123. return 0, fmt.Errorf("couldn't find the Container count in the output")
  124. }
  125. type FakeContext struct {
  126. Dir string
  127. }
  128. func (f *FakeContext) Add(file, content string) error {
  129. filepath := path.Join(f.Dir, file)
  130. dirpath := path.Dir(filepath)
  131. if dirpath != "." {
  132. if err := os.MkdirAll(dirpath, 0755); err != nil {
  133. return err
  134. }
  135. }
  136. return ioutil.WriteFile(filepath, []byte(content), 0644)
  137. }
  138. func (f *FakeContext) Delete(file string) error {
  139. filepath := path.Join(f.Dir, file)
  140. return os.RemoveAll(filepath)
  141. }
  142. func (f *FakeContext) Close() error {
  143. return os.RemoveAll(f.Dir)
  144. }
  145. func fakeContext(dockerfile string, files map[string]string) (*FakeContext, error) {
  146. tmp, err := ioutil.TempDir("", "fake-context")
  147. if err != nil {
  148. return nil, err
  149. }
  150. ctx := &FakeContext{tmp}
  151. for file, content := range files {
  152. if err := ctx.Add(file, content); err != nil {
  153. ctx.Close()
  154. return nil, err
  155. }
  156. }
  157. if err := ctx.Add("Dockerfile", dockerfile); err != nil {
  158. ctx.Close()
  159. return nil, err
  160. }
  161. return ctx, nil
  162. }
  163. type FakeStorage struct {
  164. *FakeContext
  165. *httptest.Server
  166. }
  167. func (f *FakeStorage) Close() error {
  168. f.Server.Close()
  169. return f.FakeContext.Close()
  170. }
  171. func fakeStorage(files map[string]string) (*FakeStorage, error) {
  172. tmp, err := ioutil.TempDir("", "fake-storage")
  173. if err != nil {
  174. return nil, err
  175. }
  176. ctx := &FakeContext{tmp}
  177. for file, content := range files {
  178. if err := ctx.Add(file, content); err != nil {
  179. ctx.Close()
  180. return nil, err
  181. }
  182. }
  183. handler := http.FileServer(http.Dir(ctx.Dir))
  184. server := httptest.NewServer(handler)
  185. return &FakeStorage{
  186. FakeContext: ctx,
  187. Server: server,
  188. }, nil
  189. }
  190. func inspectField(name, field string) (string, error) {
  191. format := fmt.Sprintf("{{.%s}}", field)
  192. inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)
  193. out, exitCode, err := runCommandWithOutput(inspectCmd)
  194. if err != nil || exitCode != 0 {
  195. return "", fmt.Errorf("failed to inspect %s: %s", name, out)
  196. }
  197. return strings.TrimSpace(out), nil
  198. }
  199. func inspectFieldJSON(name, field string) (string, error) {
  200. format := fmt.Sprintf("{{json .%s}}", field)
  201. inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)
  202. out, exitCode, err := runCommandWithOutput(inspectCmd)
  203. if err != nil || exitCode != 0 {
  204. return "", fmt.Errorf("failed to inspect %s: %s", name, out)
  205. }
  206. return strings.TrimSpace(out), nil
  207. }
  208. func getIDByName(name string) (string, error) {
  209. return inspectField(name, "Id")
  210. }
  211. func buildImageWithOut(name, dockerfile string, useCache bool) (string, string, error) {
  212. args := []string{"build", "-t", name}
  213. if !useCache {
  214. args = append(args, "--no-cache")
  215. }
  216. args = append(args, "-")
  217. buildCmd := exec.Command(dockerBinary, args...)
  218. buildCmd.Stdin = strings.NewReader(dockerfile)
  219. out, exitCode, err := runCommandWithOutput(buildCmd)
  220. if err != nil || exitCode != 0 {
  221. return "", out, fmt.Errorf("failed to build the image: %s", out)
  222. }
  223. id, err := getIDByName(name)
  224. if err != nil {
  225. return "", out, err
  226. }
  227. return id, out, nil
  228. }
  229. func buildImage(name, dockerfile string, useCache bool) (string, error) {
  230. id, _, err := buildImageWithOut(name, dockerfile, useCache)
  231. return id, err
  232. }
  233. func buildImageFromContext(name string, ctx *FakeContext, useCache bool) (string, error) {
  234. args := []string{"build", "-t", name}
  235. if !useCache {
  236. args = append(args, "--no-cache")
  237. }
  238. args = append(args, ".")
  239. buildCmd := exec.Command(dockerBinary, args...)
  240. buildCmd.Dir = ctx.Dir
  241. out, exitCode, err := runCommandWithOutput(buildCmd)
  242. if err != nil || exitCode != 0 {
  243. return "", fmt.Errorf("failed to build the image: %s", out)
  244. }
  245. return getIDByName(name)
  246. }
  247. func buildImageFromPath(name, path string, useCache bool) (string, error) {
  248. args := []string{"build", "-t", name}
  249. if !useCache {
  250. args = append(args, "--no-cache")
  251. }
  252. args = append(args, path)
  253. buildCmd := exec.Command(dockerBinary, args...)
  254. out, exitCode, err := runCommandWithOutput(buildCmd)
  255. if err != nil || exitCode != 0 {
  256. return "", fmt.Errorf("failed to build the image: %s", out)
  257. }
  258. return getIDByName(name)
  259. }
  260. type FakeGIT struct {
  261. *httptest.Server
  262. Root string
  263. RepoURL string
  264. }
  265. func (g *FakeGIT) Close() {
  266. g.Server.Close()
  267. os.RemoveAll(g.Root)
  268. }
  269. func fakeGIT(name string, files map[string]string) (*FakeGIT, error) {
  270. tmp, err := ioutil.TempDir("", "fake-git-repo")
  271. if err != nil {
  272. return nil, err
  273. }
  274. ctx := &FakeContext{tmp}
  275. for file, content := range files {
  276. if err := ctx.Add(file, content); err != nil {
  277. ctx.Close()
  278. return nil, err
  279. }
  280. }
  281. defer ctx.Close()
  282. curdir, err := os.Getwd()
  283. if err != nil {
  284. return nil, err
  285. }
  286. defer os.Chdir(curdir)
  287. if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
  288. return nil, fmt.Errorf("Error trying to init repo: %s (%s)", err, output)
  289. }
  290. err = os.Chdir(ctx.Dir)
  291. if err != nil {
  292. return nil, err
  293. }
  294. if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
  295. return nil, fmt.Errorf("Error trying to add files to repo: %s (%s)", err, output)
  296. }
  297. if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
  298. return nil, fmt.Errorf("Error trying to commit to repo: %s (%s)", err, output)
  299. }
  300. root, err := ioutil.TempDir("", "docker-test-git-repo")
  301. if err != nil {
  302. return nil, err
  303. }
  304. repoPath := filepath.Join(root, name+".git")
  305. if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
  306. os.RemoveAll(root)
  307. return nil, fmt.Errorf("Error trying to clone --bare: %s (%s)", err, output)
  308. }
  309. err = os.Chdir(repoPath)
  310. if err != nil {
  311. os.RemoveAll(root)
  312. return nil, err
  313. }
  314. if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
  315. os.RemoveAll(root)
  316. return nil, fmt.Errorf("Error trying to git update-server-info: %s (%s)", err, output)
  317. }
  318. err = os.Chdir(curdir)
  319. if err != nil {
  320. os.RemoveAll(root)
  321. return nil, err
  322. }
  323. handler := http.FileServer(http.Dir(root))
  324. server := httptest.NewServer(handler)
  325. return &FakeGIT{
  326. Server: server,
  327. Root: root,
  328. RepoURL: fmt.Sprintf("%s/%s.git", server.URL, name),
  329. }, nil
  330. }