Files
steampipe/pkg/dashboard/dashboardexecute/check_run.go

123 lines
4.5 KiB
Go

package dashboardexecute
import (
"context"
"github.com/turbot/steampipe/pkg/control/controlexecute"
"github.com/turbot/steampipe/pkg/control/controlstatus"
"github.com/turbot/steampipe/pkg/dashboard/dashboardtypes"
"github.com/turbot/steampipe/pkg/statushooks"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/turbot/steampipe/pkg/utils"
)
// CheckRun is a struct representing the execution of a control or benchmark
type CheckRun struct {
DashboardParentImpl
Summary *controlexecute.GroupSummary `json:"summary"`
SessionId string `json:"-"`
// if the dashboard node is a control, serialise to json as 'properties'
Control *modconfig.Control `json:"properties,omitempty"`
Root controlexecute.ExecutionTreeNode `json:"-"`
controlExecutionTree *controlexecute.ExecutionTree
}
func (r *CheckRun) AsTreeNode() *dashboardtypes.SnapshotTreeNode {
return r.Root.AsTreeNode()
}
func NewCheckRun(resource modconfig.DashboardLeafNode, parent dashboardtypes.DashboardParent, executionTree *DashboardExecutionTree) (*CheckRun, error) {
c := &CheckRun{SessionId: executionTree.sessionId}
// create NewDashboardTreeRunImpl
// (we must create after creating the run as it requires a ref to the run)
// TODO [node_reuse] do this a different way https://github.com/turbot/steampipe/issues/2919
c.DashboardTreeRunImpl = NewDashboardTreeRunImpl(resource, parent, c, executionTree)
c.NodeType = resource.BlockType()
// set status to initialized
c.Status = dashboardtypes.RunInitialized
// add r into execution tree
executionTree.runs[c.Name] = c
return c, nil
}
// Initialise implements DashboardTreeRun
func (r *CheckRun) Initialise(ctx context.Context) {
// build control execution tree during init, rather than in Execute, so that it is populated when the ExecutionStarted event is sent
executionTree, err := controlexecute.NewExecutionTree(ctx, r.executionTree.workspace, r.executionTree.client, r.resource.Name(), "")
if err != nil {
// set the error status on the counter - this will raise counter error event
r.SetError(ctx, err)
return
}
r.controlExecutionTree = executionTree
r.Root = executionTree.Root.Children[0]
}
// Execute implements DashboardTreeRun
func (r *CheckRun) Execute(ctx context.Context) {
utils.LogTime("CheckRun.execute start")
defer utils.LogTime("CheckRun.execute end")
// set status to running (this sends update event)
r.setRunning(ctx)
// create a context with a DashboardEventControlHooks to report control execution progress
ctx = controlstatus.AddControlHooksToContext(ctx, NewDashboardEventControlHooks(r))
r.controlExecutionTree.Execute(ctx)
// set the summary on the CheckRun
r.Summary = r.controlExecutionTree.Root.Summary
// set complete status on counter - this will raise counter complete event
r.SetComplete(ctx)
}
// ChildrenComplete implements DashboardTreeRun (override base)
func (r *CheckRun) ChildrenComplete() bool {
return r.RunComplete()
}
// IsSnapshotPanel implements SnapshotPanel
func (*CheckRun) IsSnapshotPanel() {}
// SetError implements DashboardTreeRun (override to set snapshothook status
func (r *CheckRun) SetError(ctx context.Context, err error) {
// increment error count for snapshot hook
statushooks.SnapshotError(ctx)
r.DashboardTreeRunImpl.SetError(ctx, err)
}
// SetComplete implements DashboardTreeRun (override to set snapshothook status
func (r *CheckRun) SetComplete(ctx context.Context) {
// call snapshot hooks with progress
statushooks.UpdateSnapshotProgress(ctx, 1)
r.DashboardTreeRunImpl.SetComplete(ctx)
}
// BuildSnapshotPanels is a custom implementation of BuildSnapshotPanels - be nice to just use the DashboardExecutionTree but work is needed on common interface types/generics
func (r *CheckRun) BuildSnapshotPanels(leafNodeMap map[string]dashboardtypes.SnapshotPanel) map[string]dashboardtypes.SnapshotPanel {
// if this check run is for a control, just add the controlRUn
if controlRun, ok := r.Root.(*controlexecute.ControlRun); ok {
leafNodeMap[controlRun.Control.Name()] = controlRun
return leafNodeMap
}
leafNodeMap[r.GetName()] = r
return r.buildSnapshotPanelsUnder(r.Root, leafNodeMap)
}
func (r *CheckRun) buildSnapshotPanelsUnder(parent controlexecute.ExecutionTreeNode, res map[string]dashboardtypes.SnapshotPanel) map[string]dashboardtypes.SnapshotPanel {
for _, c := range parent.GetChildren() {
// if this node is a snapshot node, add to map
if snapshotNode, ok := c.(dashboardtypes.SnapshotPanel); ok {
res[c.GetName()] = snapshotNode
}
res = r.buildSnapshotPanelsUnder(c, res)
}
return res
}