19698: Merge branch 'main' into 19698-masked-error
[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         "encoding/json"
10         "fmt"
11         "os"
12         "os/exec"
13         "strings"
14
15         "git.arvados.org/arvados.git/sdk/go/arvados"
16         "github.com/sirupsen/logrus"
17 )
18
19 type bjobsEntry struct {
20         ID         string `json:"JOBID"`
21         Name       string `json:"JOB_NAME"`
22         Stat       string `json:"STAT"`
23         PendReason string `json:"PEND_REASON"`
24 }
25
26 type lsfcli struct {
27         logger logrus.FieldLogger
28         // (for testing) if non-nil, call stubCommand() instead of
29         // exec.Command() when running lsf command line programs.
30         stubCommand func(string, ...string) *exec.Cmd
31 }
32
33 func (cli lsfcli) command(prog string, args ...string) *exec.Cmd {
34         if f := cli.stubCommand; f != nil {
35                 return f(prog, args...)
36         } else {
37                 return exec.Command(prog, args...)
38         }
39 }
40
41 func (cli lsfcli) Bsub(script []byte, args []string, arv *arvados.Client) error {
42         cli.logger.Infof("bsub command %q script %q", args, script)
43         cmd := cli.command(args[0], args[1:]...)
44         cmd.Env = append([]string(nil), os.Environ()...)
45         cmd.Env = append(cmd.Env, "ARVADOS_API_HOST="+arv.APIHost)
46         cmd.Env = append(cmd.Env, "ARVADOS_API_TOKEN="+arv.AuthToken)
47         if arv.Insecure {
48                 cmd.Env = append(cmd.Env, "ARVADOS_API_HOST_INSECURE=1")
49         }
50         cmd.Stdin = bytes.NewReader(script)
51         out, err := cmd.Output()
52         cli.logger.WithField("stdout", string(out)).Infof("bsub finished")
53         return errWithStderr(err)
54 }
55
56 func (cli lsfcli) Bjobs() ([]bjobsEntry, error) {
57         cli.logger.Debugf("Bjobs()")
58         cmd := cli.command("bjobs", "-u", "all", "-o", "jobid stat job_name pend_reason", "-json")
59         buf, err := cmd.Output()
60         if err != nil {
61                 return nil, errWithStderr(err)
62         }
63         var resp struct {
64                 Records []bjobsEntry `json:"RECORDS"`
65         }
66         err = json.Unmarshal(buf, &resp)
67         return resp.Records, err
68 }
69
70 func (cli lsfcli) Bkill(id string) error {
71         cli.logger.Infof("Bkill(%s)", id)
72         cmd := cli.command("bkill", id)
73         buf, err := cmd.CombinedOutput()
74         if err == nil || strings.Index(string(buf), "already finished") >= 0 {
75                 return nil
76         } else {
77                 return fmt.Errorf("%s (%q)", err, buf)
78         }
79 }
80
81 func errWithStderr(err error) error {
82         if err, ok := err.(*exec.ExitError); ok {
83                 return fmt.Errorf("%s (%q)", err, err.Stderr)
84         }
85         return err
86 }