-
Notifications
You must be signed in to change notification settings - Fork 263
/
dashboard_run.go
181 lines (154 loc) · 5.5 KB
/
dashboard_run.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
package dashboardexecute
import (
"context"
"fmt"
"log"
"github.com/turbot/steampipe/pkg/dashboard/dashboardtypes"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
)
// DashboardRun is a struct representing a container run
type DashboardRun struct {
runtimeDependencyPublisherImpl
parent dashboardtypes.DashboardParent
dashboard *modconfig.Dashboard
}
func (r *DashboardRun) AsTreeNode() *dashboardtypes.SnapshotTreeNode {
res := &dashboardtypes.SnapshotTreeNode{
Name: r.Name,
NodeType: r.NodeType,
Children: make([]*dashboardtypes.SnapshotTreeNode, 0, len(r.children)),
}
for _, c := range r.children {
// NOTE: exclude with runs
if c.GetNodeType() != modconfig.BlockTypeWith {
res.Children = append(res.Children, c.AsTreeNode())
}
}
return res
}
func NewDashboardRun(dashboard *modconfig.Dashboard, parent dashboardtypes.DashboardParent, executionTree *DashboardExecutionTree) (*DashboardRun, error) {
r := &DashboardRun{
parent: parent,
dashboard: dashboard,
}
// create RuntimeDependencyPublisherImpl- this handles 'with' run creation and resolving runtime dependency resolution
// (we must create after creating the run as it requires a ref to the run)
r.runtimeDependencyPublisherImpl = newRuntimeDependencyPublisherImpl(dashboard, parent, r, executionTree)
// add r into execution tree BEFORE creating child runs or initialising runtime depdencies
// - this is so child runs can find this dashboard run
executionTree.runs[r.Name] = r
// set inputs map on RuntimeDependencyPublisherImpl BEFORE creating child runs
r.inputs = dashboard.GetInputs()
// after setting inputs, init runtime dependencies. this creates with runs and adds them to our children
err := r.initWiths()
if err != nil {
return nil, err
}
err = r.createChildRuns(executionTree)
if err != nil {
return nil, err
}
// create buffered channel for children to report their completion
r.createChildCompleteChan()
return r, nil
}
// Initialise implements DashboardTreeRun
func (r *DashboardRun) Initialise(ctx context.Context) {
// initialise our children
if err := r.initialiseChildren(ctx); err != nil {
r.SetError(ctx, err)
}
}
// Execute implements DashboardTreeRun
// execute all children and wait for them to complete
func (r *DashboardRun) Execute(ctx context.Context) {
r.executeChildrenAsync(ctx)
// try to set status as running (will be set to blocked if any children are blocked)
r.setRunning(ctx)
// wait for children to complete
err := <-r.waitForChildrenAsync(ctx)
if err == nil {
log.Printf("[TRACE] Execute run %s all children complete, success", r.Name)
// set complete status on dashboard
r.SetComplete(ctx)
} else {
log.Printf("[TRACE] Execute run %s all children complete, error: %s", r.Name, err.Error())
r.SetError(ctx, err)
}
}
// IsSnapshotPanel implements SnapshotPanel
func (*DashboardRun) IsSnapshotPanel() {}
// GetInput searches for an input with the given name
func (r *DashboardRun) GetInput(name string) (*modconfig.DashboardInput, bool) {
return r.dashboard.GetInput(name)
}
// GetInputsDependingOn returns a list o DashboardInputs which have a runtime dependency on the given input
func (r *DashboardRun) GetInputsDependingOn(changedInputName string) []string {
var res []string
for _, input := range r.dashboard.Inputs {
if input.DependsOnInput(changedInputName) {
res = append(res, input.UnqualifiedName)
}
}
return res
}
func (r *DashboardRun) createChildRuns(executionTree *DashboardExecutionTree) error {
// ask our resource for its children
children := r.dashboard.GetChildren()
for _, child := range children {
var childRun dashboardtypes.DashboardTreeRun
var err error
switch i := child.(type) {
case *modconfig.DashboardWith:
// ignore as with runs are created by RuntimeDependencyPublisherImpl
continue
case *modconfig.Dashboard:
childRun, err = NewDashboardRun(i, r, executionTree)
if err != nil {
return err
}
case *modconfig.DashboardContainer:
childRun, err = NewDashboardContainerRun(i, r, executionTree)
if err != nil {
return err
}
case *modconfig.Benchmark, *modconfig.Control:
childRun, err = NewCheckRun(i.(modconfig.DashboardLeafNode), r, executionTree)
if err != nil {
return err
}
case *modconfig.DashboardInput:
// NOTE: clone the input to avoid mutating the original
// TODO remove the need for this when we refactor input values resolution
// TODO https://github.com/turbot/steampipe/issues/2864
// TACTICAL: as this is a runtime dependency, set the run name to the 'scoped name'
// this is to match the name in the panel dependendencies
// TODO [node_reuse] consider naming https://github.com/turbot/steampipe/issues/2921
inputRunName := fmt.Sprintf("%s.%s", r.DashboardName, i.UnqualifiedName)
childRun, err = NewLeafRun(i.Clone(), r, executionTree, setName(inputRunName))
if err != nil {
return err
}
default:
// ensure this item is a DashboardLeafNode
leafNode, ok := i.(modconfig.DashboardLeafNode)
if !ok {
return fmt.Errorf("child %s does not implement DashboardLeafNode", i.Name())
}
childRun, err = NewLeafRun(leafNode, r, executionTree)
if err != nil {
return err
}
}
// should never happen - container children must be either container or counter
if childRun == nil {
continue
}
// if our child has not completed, we have not completed
if childRun.GetRunStatus() == dashboardtypes.RunInitialized {
r.Status = dashboardtypes.RunInitialized
}
r.children = append(r.children, childRun)
}
return nil
}