compose.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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}}"]
  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. }
  61. type composeTemplateOptions struct {
  62. composeOptions
  63. WorkerImageDigest string
  64. SelfNodeID string
  65. EnvDockerGraphDriver string
  66. EnvDockerExperimental string
  67. }
  68. // createCompose creates "dir/docker-compose.yml".
  69. // If dir is empty, TempDir() is used.
  70. func createCompose(dir string, cli *client.Client, opts composeOptions) (string, error) {
  71. if dir == "" {
  72. var err error
  73. dir, err = ioutil.TempDir("", "integration-cli-on-swarm-")
  74. if err != nil {
  75. return "", err
  76. }
  77. }
  78. resolved := composeTemplateOptions{}
  79. resolved.composeOptions = opts
  80. workerImageInspect, _, err := cli.ImageInspectWithRaw(context.Background(), defaultWorkerImageName)
  81. if err != nil {
  82. return "", err
  83. }
  84. if len(workerImageInspect.RepoDigests) > 0 {
  85. resolved.WorkerImageDigest = workerImageInspect.RepoDigests[0]
  86. } else {
  87. // fall back for non-pushed image
  88. resolved.WorkerImageDigest = workerImageInspect.ID
  89. }
  90. info, err := cli.Info(context.Background())
  91. if err != nil {
  92. return "", err
  93. }
  94. resolved.SelfNodeID = info.Swarm.NodeID
  95. resolved.EnvDockerGraphDriver = os.Getenv("DOCKER_GRAPHDRIVER")
  96. resolved.EnvDockerExperimental = os.Getenv("DOCKER_EXPERIMENTAL")
  97. composeFilePath := filepath.Join(dir, "docker-compose.yml")
  98. tmpl, err := template.New("").Parse(composeTemplate)
  99. if err != nil {
  100. return "", err
  101. }
  102. f, err := os.Create(composeFilePath)
  103. if err != nil {
  104. return "", err
  105. }
  106. defer f.Close()
  107. if err = tmpl.Execute(f, resolved); err != nil {
  108. return "", err
  109. }
  110. return composeFilePath, nil
  111. }