| package main |
| |
| import ( |
| "context" |
| "io/ioutil" |
| "os" |
| "path/filepath" |
| "text/template" |
| |
| "github.com/docker/docker/client" |
| ) |
| |
| const composeTemplate = `# generated by integration-cli-on-swarm |
| version: "3" |
| |
| services: |
| worker: |
| image: "{{.WorkerImage}}" |
| command: ["-worker-image-digest={{.WorkerImageDigest}}", "-dry-run={{.DryRun}}", "-keep-executor={{.KeepExecutor}}"] |
| networks: |
| - net |
| volumes: |
| # Bind-mount the API socket so that we can invoke "docker run --privileged" within the service containers |
| - /var/run/docker.sock:/var/run/docker.sock |
| environment: |
| - DOCKER_GRAPHDRIVER={{.EnvDockerGraphDriver}} |
| - DOCKER_EXPERIMENTAL={{.EnvDockerExperimental}} |
| deploy: |
| mode: replicated |
| replicas: {{.Replicas}} |
| restart_policy: |
| # The restart condition needs to be any for funker function |
| condition: any |
| |
| master: |
| image: "{{.MasterImage}}" |
| command: ["-worker-service=worker", "-input=/mnt/input", "-chunks={{.Chunks}}", "-shuffle={{.Shuffle}}", "-rand-seed={{.RandSeed}}"] |
| networks: |
| - net |
| volumes: |
| - {{.Volume}}:/mnt |
| deploy: |
| mode: replicated |
| replicas: 1 |
| restart_policy: |
| condition: none |
| placement: |
| # Make sure the master can access the volume |
| constraints: [node.id == {{.SelfNodeID}}] |
| |
| networks: |
| net: |
| |
| volumes: |
| {{.Volume}}: |
| external: true |
| ` |
| |
| type composeOptions struct { |
| Replicas int |
| Chunks int |
| MasterImage string |
| WorkerImage string |
| Volume string |
| Shuffle bool |
| RandSeed int64 |
| DryRun bool |
| KeepExecutor bool |
| } |
| |
| type composeTemplateOptions struct { |
| composeOptions |
| WorkerImageDigest string |
| SelfNodeID string |
| EnvDockerGraphDriver string |
| EnvDockerExperimental string |
| } |
| |
| // createCompose creates "dir/docker-compose.yml". |
| // If dir is empty, TempDir() is used. |
| func createCompose(dir string, cli *client.Client, opts composeOptions) (string, error) { |
| if dir == "" { |
| var err error |
| dir, err = ioutil.TempDir("", "integration-cli-on-swarm-") |
| if err != nil { |
| return "", err |
| } |
| } |
| resolved := composeTemplateOptions{} |
| resolved.composeOptions = opts |
| workerImageInspect, _, err := cli.ImageInspectWithRaw(context.Background(), defaultWorkerImageName) |
| if err != nil { |
| return "", err |
| } |
| if len(workerImageInspect.RepoDigests) > 0 { |
| resolved.WorkerImageDigest = workerImageInspect.RepoDigests[0] |
| } else { |
| // fall back for non-pushed image |
| resolved.WorkerImageDigest = workerImageInspect.ID |
| } |
| info, err := cli.Info(context.Background()) |
| if err != nil { |
| return "", err |
| } |
| resolved.SelfNodeID = info.Swarm.NodeID |
| resolved.EnvDockerGraphDriver = os.Getenv("DOCKER_GRAPHDRIVER") |
| resolved.EnvDockerExperimental = os.Getenv("DOCKER_EXPERIMENTAL") |
| composeFilePath := filepath.Join(dir, "docker-compose.yml") |
| tmpl, err := template.New("").Parse(composeTemplate) |
| if err != nil { |
| return "", err |
| } |
| f, err := os.Create(composeFilePath) |
| if err != nil { |
| return "", err |
| } |
| defer f.Close() |
| if err = tmpl.Execute(f, resolved); err != nil { |
| return "", err |
| } |
| return composeFilePath, nil |
| } |