17756: Add lsf dispatcher.
[arvados.git] / lib / lsf / lsfcli.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package lsf
6
7 import (
8         "bytes"
9         "fmt"
10         "os"
11         "os/exec"
12         "strings"
13
14         "git.arvados.org/arvados.git/sdk/go/arvados"
15         "github.com/sirupsen/logrus"
16 )
17
18 type bjobsEntry struct {
19         id   int
20         name string
21         stat string
22 }
23
24 type lsfcli struct {
25         logger logrus.FieldLogger
26         // (for testing) if non-nil, call stubCommand() instead of
27         // exec.Command() when running lsf command line programs.
28         stubCommand func(string, ...string) *exec.Cmd
29 }
30
31 func (cli lsfcli) command(prog string, args ...string) *exec.Cmd {
32         if f := cli.stubCommand; f != nil {
33                 return f(prog, args...)
34         } else {
35                 return exec.Command(prog, args...)
36         }
37 }
38
39 func (cli lsfcli) Bsub(script []byte, args []string, arv *arvados.Client) error {
40         cli.logger.Infof("bsub command %q script %q", args, script)
41         cmd := cli.command(args[0], args[1:]...)
42         cmd.Env = append([]string(nil), os.Environ()...)
43         cmd.Env = append(cmd.Env, "ARVADOS_API_HOST="+arv.APIHost)
44         cmd.Env = append(cmd.Env, "ARVADOS_API_TOKEN="+arv.AuthToken)
45         if arv.Insecure {
46                 cmd.Env = append(cmd.Env, "ARVADOS_API_HOST_INSECURE=1")
47         }
48         cmd.Stdin = bytes.NewReader(script)
49         out, err := cmd.Output()
50         cli.logger.WithField("stdout", string(out)).Infof("bsub finished")
51         return errWithStderr(err)
52 }
53
54 func (cli lsfcli) Bjobs() ([]bjobsEntry, error) {
55         cli.logger.Debugf("Bjobs()")
56         cmd := cli.command("bjobs", "-u", "all", "-noheader", "-o", "jobid stat job_name:30")
57         buf, err := cmd.Output()
58         if err != nil {
59                 return nil, errWithStderr(err)
60         }
61         var bjobs []bjobsEntry
62         for _, line := range strings.Split(string(buf), "\n") {
63                 if line == "" {
64                         continue
65                 }
66                 var ent bjobsEntry
67                 if _, err := fmt.Sscan(line, &ent.id, &ent.stat, &ent.name); err != nil {
68                         cli.logger.Warnf("ignoring unparsed line in bjobs output: %q", line)
69                         continue
70                 }
71                 bjobs = append(bjobs, ent)
72         }
73         return bjobs, nil
74 }
75
76 func (cli lsfcli) Bkill(id int) error {
77         cli.logger.Infof("Bkill(%d)", id)
78         cmd := cli.command("bkill", fmt.Sprintf("%d", id))
79         buf, err := cmd.CombinedOutput()
80         if err == nil || strings.Index(string(buf), "already finished") >= 0 {
81                 return nil
82         } else {
83                 return fmt.Errorf("%s (%q)", err, buf)
84         }
85 }
86
87 func errWithStderr(err error) error {
88         if err, ok := err.(*exec.ExitError); ok {
89                 return fmt.Errorf("%s (%q)", err, err.Stderr)
90         }
91         return err
92 }