This repository has been archived by the owner on Apr 14, 2020. It is now read-only.
/
load.go
142 lines (129 loc) · 3.54 KB
/
load.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
package runner
import (
"context"
"fmt"
"go/parser"
"go/token"
"io/ioutil"
"github.com/gravitational/force"
"github.com/gravitational/trace"
)
// LoadAction
type LoadAction struct {
g *gParser
path force.Expression
reload bool
}
func (s *LoadAction) Type() interface{} {
return 0
}
// Eval runs shell script and returns output as a string
func (s *LoadAction) Eval(ctx force.ExecutionContext) (interface{}, error) {
log := force.Log(ctx)
path, err := force.EvalString(ctx, s.path)
if err != nil {
return nil, trace.Wrap(err)
}
content, err := ioutil.ReadFile(path)
if err != nil {
return nil, trace.Wrap(err)
}
script := Script{
Filename: path,
Content: string(content),
}
f := token.NewFileSet()
expr, err := parser.ParseExprFrom(f, "", content, 0)
if err != nil {
return nil, trace.Wrap(convertScanError(err, script))
}
runnerCtx, cancel := context.WithCancel(ctx)
runner := &Runner{
LexScope: force.WithLexicalScope(nil),
debugOverride: s.g.runner.debugOverride,
cancel: cancel,
ctx: runnerCtx,
eventsC: make(chan force.Event, cap(s.g.runner.eventsC)),
plugins: make(map[interface{}]interface{}),
logger: s.g.runner.Logger(),
}
localParser, err := newParser(s.g.scope.ID(), runner)
if err != nil {
return nil, trace.Wrap(err)
}
actionI, err := localParser.parseExpr(f, runner, expr)
if err != nil {
return nil, trace.Wrap(convertScanError(err, script))
}
proc, ok := actionI.(force.Process)
if !ok {
action, ok := actionI.(force.Action)
if !ok {
defer runner.Close()
return nil, trace.BadParameter("expected action, got %T", actionI)
}
var err error
proc, err = runner.Oneshot(force.KeyForce, action)
if err != nil {
defer runner.Close()
return nil, trace.Wrap(err)
}
}
// reload tracks all the runners for processes by name,
// and stops the previous version if necessary
if s.reload {
defer s.g.runner.RemoveRunner(proc.Name(), runner)
prevRunner := s.g.runner.SwapRunner(proc.Name(), runner)
if prevRunner != nil {
prevRunner.Close()
select {
case <-prevRunner.Done():
log.Infof("Reload: previous runner for the process %v has completed.", proc)
event := runner.ExitEvent()
if event == nil {
log.Debugf("Process group has shut down with unkown status.")
} else {
log.Debugf("Process group has shut down with event: %v.", event)
}
case <-ctx.Done():
defer runner.Close()
return nil, trace.ConnectionProblem(ctx.Err(), "parent context is closing")
}
}
}
log.Infof("Started subprocess %v.", proc.Name())
runner.AddChannel(proc.Channel())
runner.AddProcess(proc)
runner.Start()
select {
case <-runner.Done():
log.Infof("Runner for process %v is done.", proc)
event := runner.ExitEvent()
if event == nil {
log.Debugf("Process group has shut down with unkown status.")
return 0, nil
}
log.Debugf("Process group has shut down with event: %v.", event)
if event.ExitCode() != 0 {
return event.ExitCode(), trace.BadParameter("runner failed with exit code %v", event.ExitCode())
}
return 0, nil
case <-ctx.Done():
return nil, trace.ConnectionProblem(ctx.Err(), "parent context is closing")
}
}
// MarshalCode marshals action into code representation
func (s *LoadAction) MarshalCode(ctx force.ExecutionContext) ([]byte, error) {
call := &force.FnCall{
Args: []interface{}{s.path},
}
if s.reload {
call.Fn = s.g.Reload
} else {
call.Fn = s.g.Load
}
return call.MarshalCode(ctx)
}
func (s *LoadAction) String() string {
return fmt.Sprintf("Load(reload=%v)", s.reload)
}