11 "git.arvados.org/arvados.git/sdk/go/arvados"
12 "git.arvados.org/arvados.git/sdk/go/arvadosclient"
13 "git.arvados.org/arvados.git/sdk/go/keepclient"
14 "golang.org/x/crypto/blake2b"
17 type arvadosContainerRunner struct {
18 Client *arvados.Client
23 Prog string // if empty, run /proc/self/exe
25 Mounts map[string]map[string]interface{}
28 func (runner *arvadosContainerRunner) Run() error {
29 if runner.ProjectUUID == "" {
30 return errors.New("cannot run arvados container: ProjectUUID not provided")
33 mounts := map[string]map[string]interface{}{
37 "capacity": 100000000000,
40 for path, mnt := range runner.Mounts {
46 prog = "/mnt/cmd/lightning"
47 cmdUUID, err := runner.makeCommandCollection()
51 mounts["/mnt/cmd"] = map[string]interface{}{
56 command := append([]string{prog}, runner.Args...)
58 rc := arvados.RuntimeConstraints{
61 KeepCacheRAM: (1 << 26) * 2 * int64(runner.VCPUs),
63 var cr arvados.ContainerRequest
64 err := runner.Client.RequestAndDecode(&cr, "POST", "arvados/v1/container_requests", nil, map[string]interface{}{
65 "container_request": map[string]interface{}{
66 "owner_uuid": runner.ProjectUUID,
68 "container_image": "lightning-runtime",
72 "output_path": "/mnt/output",
73 "runtime_constraints": rc,
75 "state": arvados.ContainerRequestStateCommitted,
82 var collectionInPathRe = regexp.MustCompile(`^(.*/)?([0-9a-f]{32}\+[0-9]+|[0-9a-z]{5}-[0-9a-z]{5}-[0-9a-z]{15})(/.*)?$`)
84 func (runner *arvadosContainerRunner) TranslatePaths(paths ...*string) error {
85 if runner.Mounts == nil {
86 runner.Mounts = make(map[string]map[string]interface{})
88 for _, path := range paths {
92 m := collectionInPathRe.FindStringSubmatch(*path)
94 return fmt.Errorf("cannot find uuid in path: %q", *path)
97 mnt, ok := runner.Mounts["/mnt/"+uuid]
99 mnt = map[string]interface{}{
100 "kind": "collection",
103 runner.Mounts["/mnt/"+uuid] = mnt
105 *path = "/mnt/" + uuid + m[3]
110 func (runner *arvadosContainerRunner) makeCommandCollection() (string, error) {
111 exe, err := ioutil.ReadFile("/proc/self/exe")
115 b2 := blake2b.Sum256(exe)
116 cname := fmt.Sprintf("lightning-%x", b2)
117 var existing arvados.CollectionList
118 err = runner.Client.RequestAndDecode(&existing, "GET", "arvados/v1/collections", nil, arvados.ListOptions{
121 Filters: []arvados.Filter{
122 {Attr: "name", Operator: "=", Operand: cname},
123 {Attr: "owner_uuid", Operator: "=", Operand: runner.ProjectUUID},
129 if len(existing.Items) > 0 {
130 uuid := existing.Items[0].UUID
131 log.Printf("using lightning binary in existing collection %s (name is %q; did not verify whether content matches)", uuid, cname)
134 log.Printf("writing lightning binary to new collection %q", cname)
135 ac, err := arvadosclient.New(runner.Client)
139 kc := keepclient.New(ac)
140 var coll arvados.Collection
141 fs, err := coll.FileSystem(runner.Client, kc)
145 f, err := fs.OpenFile("lightning", os.O_CREATE|os.O_WRONLY, 0777)
149 _, err = f.Write(exe)
157 mtxt, err := fs.MarshalManifest(".")
161 err = runner.Client.RequestAndDecode(&coll, "POST", "arvados/v1/collections", nil, map[string]interface{}{
162 "collection": map[string]interface{}{
163 "owner_uuid": runner.ProjectUUID,
164 "manifest_text": mtxt,
171 log.Printf("stored lightning binary in new collection %s", coll.UUID)
172 return coll.UUID, nil