compose.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package main
  2. import (
  3. "context"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "text/template"
  8. "github.com/docker/docker/client"
  9. )
  10. const composeTemplate = `# generated by integration-cli-on-swarm
  11. version: "3"
  12. services:
  13. worker:
  14. image: "{{.WorkerImage}}"
  15. command: ["-worker-image-digest={{.WorkerImageDigest}}", "-dry-run={{.DryRun}}", "-keep-executor={{.KeepExecutor}}"]
  16. networks:
  17. - net
  18. volumes:
  19. # Bind-mount the API socket so that we can invoke "docker run --privileged" within the service containers
  20. - /var/run/docker.sock:/var/run/docker.sock
  21. environment:
  22. - DOCKER_GRAPHDRIVER={{.EnvDockerGraphDriver}}
  23. - DOCKER_EXPERIMENTAL={{.EnvDockerExperimental}}
  24. deploy:
  25. mode: replicated
  26. replicas: {{.Replicas}}
  27. restart_policy:
  28. # The restart condition needs to be any for funker function
  29. condition: any
  30. master:
  31. image: "{{.MasterImage}}"
  32. command: ["-worker-service=worker", "-input=/mnt/input", "-chunks={{.Chunks}}", "-shuffle={{.Shuffle}}", "-rand-seed={{.RandSeed}}"]
  33. networks:
  34. - net
  35. volumes:
  36. - {{.Volume}}:/mnt
  37. deploy:
  38. mode: replicated
  39. replicas: 1
  40. restart_policy:
  41. condition: none
  42. placement:
  43. # Make sure the master can access the volume
  44. constraints: [node.id == {{.SelfNodeID}}]
  45. networks:
  46. net:
  47. volumes:
  48. {{.Volume}}:
  49. external: true
  50. `
  51. type composeOptions struct {
  52. Replicas int
  53. Chunks int
  54. MasterImage string
  55. WorkerImage string
  56. Volume string
  57. Shuffle bool
  58. RandSeed int64
  59. DryRun bool
  60. KeepExecutor bool
  61. }
  62. type composeTemplateOptions struct {
  63. composeOptions
  64. WorkerImageDigest string
  65. SelfNodeID string
  66. EnvDockerGraphDriver string
  67. EnvDockerExperimental string
  68. }
  69. // createCompose creates "dir/docker-compose.yml".
  70. // If dir is empty, TempDir() is used.
  71. func createCompose(dir string, cli *client.Client, opts composeOptions) (string, error) {
  72. if dir == "" {
  73. var err error
  74. dir, err = ioutil.TempDir("", "integration-cli-on-swarm-")
  75. if err != nil {
  76. return "", err
  77. }
  78. }
  79. resolved := composeTemplateOptions{}
  80. resolved.composeOptions = opts
  81. workerImageInspect, _, err := cli.ImageInspectWithRaw(context.Background(), defaultWorkerImageName)
  82. if err != nil {
  83. return "", err
  84. }
  85. if len(workerImageInspect.RepoDigests) > 0 {
  86. resolved.WorkerImageDigest = workerImageInspect.RepoDigests[0]
  87. } else {
  88. // fall back for non-pushed image
  89. resolved.WorkerImageDigest = workerImageInspect.ID
  90. }
  91. info, err := cli.Info(context.Background())
  92. if err != nil {
  93. return "", err
  94. }
  95. resolved.SelfNodeID = info.Swarm.NodeID
  96. resolved.EnvDockerGraphDriver = os.Getenv("DOCKER_GRAPHDRIVER")
  97. resolved.EnvDockerExperimental = os.Getenv("DOCKER_EXPERIMENTAL")
  98. composeFilePath := filepath.Join(dir, "docker-compose.yml")
  99. tmpl, err := template.New("").Parse(composeTemplate)
  100. if err != nil {
  101. return "", err
  102. }
  103. f, err := os.Create(composeFilePath)
  104. if err != nil {
  105. return "", err
  106. }
  107. defer f.Close()
  108. if err = tmpl.Execute(f, resolved); err != nil {
  109. return "", err
  110. }
  111. return composeFilePath, nil
  112. }