docker_utils.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. func cmd(t *testing.T, args ...string) (string, int, error) {
  79. out, status, err := runCommandWithOutput(exec.Command(dockerBinary, args...))
  80. errorOut(err, t, fmt.Sprintf("'%s' failed with errors: %v (%v)", strings.Join(args, " "), err, out))
  81. return out, status, err
  82. }
  83. func findContainerIp(t *testing.T, id string) string {
  84. cmd := exec.Command(dockerBinary, "inspect", "--format='{{ .NetworkSettings.IPAddress }}'", id)
  85. out, _, err := runCommandWithOutput(cmd)
  86. if err != nil {
  87. t.Fatal(err, out)
  88. }
  89. return strings.Trim(out, " \r\n'")
  90. }
  91. func getContainerCount() (int, error) {
  92. const containers = "Containers:"
  93. cmd := exec.Command(dockerBinary, "info")
  94. out, _, err := runCommandWithOutput(cmd)
  95. if err != nil {
  96. return 0, err
  97. }
  98. lines := strings.Split(out, "\n")
  99. for _, line := range lines {
  100. if strings.Contains(line, containers) {
  101. output := stripTrailingCharacters(line)
  102. output = strings.TrimLeft(output, containers)
  103. output = strings.Trim(output, " ")
  104. containerCount, err := strconv.Atoi(output)
  105. if err != nil {
  106. return 0, err
  107. }
  108. return containerCount, nil
  109. }
  110. }
  111. return 0, fmt.Errorf("couldn't find the Container count in the output")
  112. }
  113. type FakeContext struct {
  114. Dir string
  115. }
  116. func (f *FakeContext) Add(file, content string) error {
  117. filepath := path.Join(f.Dir, file)
  118. dirpath := path.Dir(filepath)
  119. if dirpath != "." {
  120. if err := os.MkdirAll(dirpath, 0755); err != nil {
  121. return err
  122. }
  123. }
  124. return ioutil.WriteFile(filepath, []byte(content), 0644)
  125. }
  126. func (f *FakeContext) Delete(file string) error {
  127. filepath := path.Join(f.Dir, file)
  128. return os.RemoveAll(filepath)
  129. }
  130. func (f *FakeContext) Close() error {
  131. return os.RemoveAll(f.Dir)
  132. }
  133. func fakeContext(dockerfile string, files map[string]string) (*FakeContext, error) {
  134. tmp, err := ioutil.TempDir("", "fake-context")
  135. if err != nil {
  136. return nil, err
  137. }
  138. ctx := &FakeContext{tmp}
  139. for file, content := range files {
  140. if err := ctx.Add(file, content); err != nil {
  141. ctx.Close()
  142. return nil, err
  143. }
  144. }
  145. if err := ctx.Add("Dockerfile", dockerfile); err != nil {
  146. ctx.Close()
  147. return nil, err
  148. }
  149. return ctx, nil
  150. }
  151. type FakeStorage struct {
  152. *FakeContext
  153. *httptest.Server
  154. }
  155. func (f *FakeStorage) Close() error {
  156. f.Server.Close()
  157. return f.FakeContext.Close()
  158. }
  159. func fakeStorage(files map[string]string) (*FakeStorage, error) {
  160. tmp, err := ioutil.TempDir("", "fake-storage")
  161. if err != nil {
  162. return nil, err
  163. }
  164. ctx := &FakeContext{tmp}
  165. for file, content := range files {
  166. if err := ctx.Add(file, content); err != nil {
  167. ctx.Close()
  168. return nil, err
  169. }
  170. }
  171. handler := http.FileServer(http.Dir(ctx.Dir))
  172. server := httptest.NewServer(handler)
  173. return &FakeStorage{
  174. FakeContext: ctx,
  175. Server: server,
  176. }, nil
  177. }
  178. func inspectField(name, field string) (string, error) {
  179. format := fmt.Sprintf("{{.%s}}", field)
  180. inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)
  181. out, exitCode, err := runCommandWithOutput(inspectCmd)
  182. if err != nil || exitCode != 0 {
  183. return "", fmt.Errorf("failed to inspect %s: %s", name, out)
  184. }
  185. return strings.TrimSpace(out), nil
  186. }
  187. func inspectFieldJSON(name, field string) (string, error) {
  188. format := fmt.Sprintf("{{json .%s}}", field)
  189. inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)
  190. out, exitCode, err := runCommandWithOutput(inspectCmd)
  191. if err != nil || exitCode != 0 {
  192. return "", fmt.Errorf("failed to inspect %s: %s", name, out)
  193. }
  194. return strings.TrimSpace(out), nil
  195. }
  196. func getIDByName(name string) (string, error) {
  197. return inspectField(name, "Id")
  198. }
  199. func buildImage(name, dockerfile string, useCache bool) (string, error) {
  200. args := []string{"build", "-t", name}
  201. if !useCache {
  202. args = append(args, "--no-cache")
  203. }
  204. args = append(args, "-")
  205. buildCmd := exec.Command(dockerBinary, args...)
  206. buildCmd.Stdin = strings.NewReader(dockerfile)
  207. out, exitCode, err := runCommandWithOutput(buildCmd)
  208. if err != nil || exitCode != 0 {
  209. return "", fmt.Errorf("failed to build the image: %s", out)
  210. }
  211. return getIDByName(name)
  212. }
  213. func buildImageFromContext(name string, ctx *FakeContext, useCache bool) (string, error) {
  214. args := []string{"build", "-t", name}
  215. if !useCache {
  216. args = append(args, "--no-cache")
  217. }
  218. args = append(args, ".")
  219. buildCmd := exec.Command(dockerBinary, args...)
  220. buildCmd.Dir = ctx.Dir
  221. out, exitCode, err := runCommandWithOutput(buildCmd)
  222. if err != nil || exitCode != 0 {
  223. return "", fmt.Errorf("failed to build the image: %s", out)
  224. }
  225. return getIDByName(name)
  226. }
  227. func buildImageFromPath(name, path string, useCache bool) (string, error) {
  228. args := []string{"build", "-t", name}
  229. if !useCache {
  230. args = append(args, "--no-cache")
  231. }
  232. args = append(args, path)
  233. buildCmd := exec.Command(dockerBinary, args...)
  234. out, exitCode, err := runCommandWithOutput(buildCmd)
  235. if err != nil || exitCode != 0 {
  236. return "", fmt.Errorf("failed to build the image: %s", out)
  237. }
  238. return getIDByName(name)
  239. }
  240. type FakeGIT struct {
  241. *httptest.Server
  242. Root string
  243. RepoURL string
  244. }
  245. func (g *FakeGIT) Close() {
  246. g.Server.Close()
  247. os.RemoveAll(g.Root)
  248. }
  249. func fakeGIT(name string, files map[string]string) (*FakeGIT, error) {
  250. tmp, err := ioutil.TempDir("", "fake-git-repo")
  251. if err != nil {
  252. return nil, err
  253. }
  254. ctx := &FakeContext{tmp}
  255. for file, content := range files {
  256. if err := ctx.Add(file, content); err != nil {
  257. ctx.Close()
  258. return nil, err
  259. }
  260. }
  261. defer ctx.Close()
  262. curdir, err := os.Getwd()
  263. if err != nil {
  264. return nil, err
  265. }
  266. defer os.Chdir(curdir)
  267. if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
  268. return nil, fmt.Errorf("Error trying to init repo: %s (%s)", err, output)
  269. }
  270. err = os.Chdir(ctx.Dir)
  271. if err != nil {
  272. return nil, err
  273. }
  274. if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
  275. return nil, fmt.Errorf("Error trying to add files to repo: %s (%s)", err, output)
  276. }
  277. if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
  278. return nil, fmt.Errorf("Error trying to commit to repo: %s (%s)", err, output)
  279. }
  280. root, err := ioutil.TempDir("", "docker-test-git-repo")
  281. if err != nil {
  282. return nil, err
  283. }
  284. repoPath := filepath.Join(root, name+".git")
  285. if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
  286. os.RemoveAll(root)
  287. return nil, fmt.Errorf("Error trying to clone --bare: %s (%s)", err, output)
  288. }
  289. err = os.Chdir(repoPath)
  290. if err != nil {
  291. os.RemoveAll(root)
  292. return nil, err
  293. }
  294. if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
  295. os.RemoveAll(root)
  296. return nil, fmt.Errorf("Error trying to git update-server-info: %s (%s)", err, output)
  297. }
  298. err = os.Chdir(curdir)
  299. if err != nil {
  300. os.RemoveAll(root)
  301. return nil, err
  302. }
  303. handler := http.FileServer(http.Dir(root))
  304. server := httptest.NewServer(handler)
  305. return &FakeGIT{
  306. Server: server,
  307. Root: root,
  308. RepoURL: fmt.Sprintf("%s/%s.git", server.URL, name),
  309. }, nil
  310. }