forked from cyverse-de/model
-
Notifications
You must be signed in to change notification settings - Fork 0
/
step.go
191 lines (169 loc) · 5.95 KB
/
step.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package model
import (
"bytes"
"fmt"
"path"
"sort"
"strings"
)
// StepComponent is where the settings for a tool in a job step are located.
type StepComponent struct {
Container Container `json:"container"`
Type string `json:"type"`
Name string `json:"name"`
Location string `json:"location"`
Description string `json:"description"`
TimeLimit int `json:"time_limit_seconds"`
Restricted bool `json:"restricted"`
IsInteractive bool `json:"interactive"`
}
// StepEnvironment defines the environment variables that should be set for a
// step
type StepEnvironment map[string]string
// Step describes a single step in a job. All jobs contain multiple steps.
type Step struct {
Component StepComponent
Config StepConfig
Type string `json:"type"`
StdinPath string `json:"stdin"`
StdoutPath string `json:"stdout"`
StderrPath string `json:"stderr"`
LogFile string `json:"log-file"`
Environment StepEnvironment `json:"environment"`
Input []StepInput `json:"input"`
Output []StepOutput `json:"output"`
}
// EnvOptions returns a string containing the docker command-line options
// that set the environment variables listed in the Environment field.
func (s *Step) EnvOptions() []string {
retval := []string{}
for k, v := range s.Environment {
retval = append(retval, fmt.Sprintf("--env=\"%s=%s\"", k, v))
}
return retval
}
// IsBackwardsCompatible returns true if the job submission uses the container
// image(s) put together to maintain compatibility with non-dockerized versions
// of the DE.
func (s *Step) IsBackwardsCompatible() bool {
img := s.Component.Container.Image.Name
return strings.HasPrefix(img, "discoenv/backwards-compat") ||
strings.HasPrefix(img, "gims.iplantcollaborative.org:5000/backwards-compat") ||
strings.HasPrefix(img, "docker.cyverse.org/backwards-compat") ||
strings.HasPrefix(img, "harbor.cyverse.org/legacy/backwards-compat")
}
// UsesVolumes returns a boolean value which indicates if a step uses host-mounted volumes
func (s *Step) UsesVolumes() bool {
return s.Component.Container.UsesVolumes()
}
// Executable returns a string containing the executable path as it gets placed
// inside the docker command-line.
func (s *Step) Executable() string {
if s.IsBackwardsCompatible() {
return path.Join(s.Component.Location, s.Component.Name)
}
return ""
}
// Arguments returns a []string containing all of the options passed to the
// docker run command for this step in the submission.
func (s *Step) Arguments() []string {
allLines := []string{strings.TrimSpace(s.Executable())}
for _, p := range s.Config.Parameters() {
if p.Name != "" {
allLines = append(allLines, strings.TrimSpace(p.Name))
}
if p.Value != "" {
allLines = append(allLines, strings.TrimSpace(p.Value))
}
}
var cmdLine []string
for _, l := range allLines {
if l != "" {
cmdLine = append(cmdLine, l)
}
}
return cmdLine
}
// Stdin returns the a quoted version of s.StdinPath or an empty string if it's
// not set.
func (s *Step) Stdin() string {
if s.StdinPath != "" {
return quote(s.StdinPath)
}
return s.StdinPath
}
// Stdout returns the quoted version of s.StdoutPath or a default value located in
// the logs directory of the working directory. 'suffix' is appended to the
// filename in the logs directory, but only if s.StdoutPath isn't set.
func (s *Step) Stdout(suffix string) string {
if s.StdoutPath != "" {
return s.StdoutPath
}
return path.Join("logs", fmt.Sprintf("%s%s", "condor-stdout-", suffix))
}
// Stderr returns the quoted version of s.StderrPath or a default value located in
// the logs directory of the working directory. 'suffix' is appended to the
// filename in the logs directory, but only if s.StderrPath isn't set.
func (s *Step) Stderr(suffix string) string {
if s.StderrPath != "" {
return s.StderrPath
}
return path.Join("logs", fmt.Sprintf("%s%s", "condor-stderr-", suffix))
}
// LogPath uses the value of step.LogFile and params to generate a path to a
// log file. If Step.LogFile isn't empty, it's placed inside the directory
// specified by parent. If it is empty, a path like
// "<parent>/logs/condor-log-<suffix>" is returned.
func (s *Step) LogPath(parent, suffix string) string {
if s.LogFile != "" {
return path.Join(parent, s.LogFile)
}
return path.Join(parent, "logs", fmt.Sprintf("condor-log-%s", suffix))
}
// StepConfig is where configuration settings for a job step are located.
type StepConfig struct {
Params []StepParam `json:"params"`
Inputs []StepInput `json:"input"`
Outputs []StepOutput `json:"output"`
}
// Parameters returns the StepParams associated with a Step in the correct order.
// Use this to get the list of Params rather than accessing the field directory.
func (c *StepConfig) Parameters() []StepParam {
sort.Stable(ByOrder(c.Params))
return c.Params
}
// StepParam is where the params for a step are located.
type StepParam struct {
ID string `json:"id"`
Name string `json:"name"`
Value string `json:"value"`
Order int `json:"order"`
Type string `json:"type"`
Path string `json:"path"`
}
// ByOrder implements the sort interface for a []StepParam based on the Order
// field.
type ByOrder []StepParam
// Len returns the number of elements in a ByOrder
func (o ByOrder) Len() int {
return len(o)
}
// Swap swaps two positions in a []StepParam
func (o ByOrder) Swap(i, j int) {
o[i], o[j] = o[j], o[i]
}
// Less returns true if position i is less than position j.
func (o ByOrder) Less(i, j int) bool {
return o[i].Order < o[j].Order
}
// PreviewableStepParam is a list of StepParams that can be returned as a string
// that previews the command-line for a submission.
type PreviewableStepParam []StepParam
func (p PreviewableStepParam) String() string {
var buffer bytes.Buffer
sort.Sort(ByOrder(p))
for _, param := range p {
buffer.WriteString(fmt.Sprintf("%s %s ", param.Name, param.Value))
}
return strings.TrimSpace(buffer.String())
}