Skip to content

Commit 7ef5e8e

Browse files
authored
feat: playbook runners (#770)
* feat: playbook runners [skip ci] * feat: add pull playbooks job [skip ci] * feat: add push playbook action job [skip ci] * feat: action consumers [skip ci] * feat: remove old runner [skip ci] * feat: handle delays and filters on agent runners * chore: revert playbook tests package to 'playbook' * feat: add templatesOn * fix: existing playbook tests * tests: playbook runners
1 parent c836f18 commit 7ef5e8e

33 files changed

+1017
-234
lines changed

api/v1/playbook_actions.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"github.com/flanksource/duty"
1212
"github.com/flanksource/duty/models"
1313
"github.com/flanksource/duty/types"
14-
"github.com/flanksource/gomplate/v3"
1514
"k8s.io/client-go/kubernetes"
1615
)
1716

@@ -325,6 +324,17 @@ type PlaybookAction struct {
325324
// skip(): skip running this action
326325
Filter string `yaml:"if,omitempty" json:"if,omitempty"`
327326

327+
// RunsOn specifies the agents that can run this action.
328+
// When left empty, the action will run on the main instance itself.
329+
RunsOn []string `json:"runsOn,omitempty" yaml:"runsOn,omitempty"`
330+
331+
// TemplatesOn specifies where the templating happens.
332+
// Available options:
333+
// - host
334+
// - agent
335+
// When left empty, the templating is done on the main instance(host) itself.
336+
TemplatesOn string `json:"templatesOn,omitempty" yaml:"templatesOn,omitempty"`
337+
328338
Exec *ExecAction `json:"exec,omitempty" yaml:"exec,omitempty" template:"true"`
329339
GitOps *GitOpsAction `json:"gitops,omitempty" yaml:"gitops,omitempty" template:"true"`
330340
HTTP *HTTPAction `json:"http,omitempty" yaml:"http,omitempty" template:"true"`
@@ -333,7 +343,7 @@ type PlaybookAction struct {
333343
Notification *NotificationAction `json:"notification,omitempty" yaml:"notification,omitempty" template:"true"`
334344
}
335345

336-
func (p *PlaybookAction) DelayDuration(templateEnv map[string]any) (time.Duration, error) {
346+
func (p *PlaybookAction) DelayDuration() (time.Duration, error) {
337347
if p.delay != nil {
338348
return *p.delay, nil
339349
}
@@ -342,12 +352,7 @@ func (p *PlaybookAction) DelayDuration(templateEnv map[string]any) (time.Duratio
342352
return 0, nil
343353
}
344354

345-
exprResult, err := gomplate.RunTemplate(templateEnv, gomplate.Template{Expression: p.Delay})
346-
if err != nil {
347-
return 0, fmt.Errorf("error running action delay expression(%s): %w", p.Delay, err)
348-
}
349-
350-
d, err := duration.ParseDuration(exprResult)
355+
d, err := duration.ParseDuration(p.Delay)
351356
if err != nil {
352357
return 0, err
353358
}

api/v1/playbook_types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,17 @@ type PlaybookSpec struct {
133133
// If multiple triggering events occur at the same time, multiple playbook runs will be triggered.
134134
On *PlaybookTrigger `json:"on,omitempty" yaml:"on,omitempty"`
135135

136+
// RunsOn specifies the agents that can run this playbook.
137+
// When left empty, the playbook will run on the main instance itself.
138+
RunsOn []string `json:"runsOn,omitempty" yaml:"runsOn,omitempty"`
139+
140+
// TemplatesOn specifies where the templating happens.
141+
// Available options:
142+
// - host
143+
// - agent
144+
// When left empty, the templating is done on the main instance(host) itself.
145+
TemplatesOn string `json:"templatesOn,omitempty" yaml:"templatesOn,omitempty"`
146+
136147
// Permissions ...
137148
Permissions []Permission `json:"permissions,omitempty" yaml:"permissions,omitempty"`
138149

api/v1/zz_generated.deepcopy.go

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

auth/kratos.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,20 @@ func (k *kratosMiddleware) validateSession(ctx context.Context, r *http.Request)
9090
return &client.Session{Active: lo.ToPtr(false)}, nil
9191
}
9292

93+
var agent models.Agent
94+
if err := ctx.DB().Where("person_id = ?", accessToken.PersonID.String()).Find(&agent).Error; err != nil {
95+
return nil, err
96+
}
97+
9398
s := &client.Session{
9499
Id: uuid.NewString(),
95100
Active: lo.ToPtr(true),
96101
ExpiresAt: &accessToken.ExpiresAt,
97102
Identity: client.Identity{
98103
Id: accessToken.PersonID.String(),
104+
Traits: map[string]any{
105+
"agent": agent,
106+
},
99107
},
100108
}
101109

@@ -163,6 +171,10 @@ func (k *kratosMiddleware) Session(next echo.HandlerFunc) echo.HandlerFunc {
163171
if e, ok := traits["email"].(string); ok {
164172
email = e
165173
}
174+
175+
if agent, ok := traits["agent"].(models.Agent); ok {
176+
ctx = ctx.WithAgent(agent)
177+
}
166178
}
167179

168180
uid, err := uuid.Parse(session.Identity.GetId())

auth/mock.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package auth
22

33
import (
4+
"errors"
45
"net/http"
56

67
"github.com/flanksource/duty/context"
78
"github.com/flanksource/duty/models"
89
"github.com/labstack/echo/v4"
10+
"gorm.io/gorm"
911
)
1012

1113
// mockAuthMiddleware doesn't actually authenticate since we never store auth data.
@@ -25,6 +27,14 @@ func MockMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
2527
}
2628

2729
ctx = ctx.WithUser(&models.Person{ID: person.ID, Email: person.Email})
30+
31+
var agent models.Agent
32+
if err := ctx.DB().Where("person_id = ?", person.ID.String()).First(&agent).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
33+
return err
34+
} else {
35+
ctx = ctx.WithAgent(agent)
36+
}
37+
2838
c.SetRequest(c.Request().WithContext(ctx))
2939
return next(c)
3040
}

config/crds/mission-control.flanksource.com_playbooks.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,13 @@ spec:
877877
- name
878878
- spec
879879
type: object
880+
runsOn:
881+
description: RunsOn specifies the agents that can run this action.
882+
When left empty, the action will run on the main instance
883+
itself.
884+
items:
885+
type: string
886+
type: array
880887
sql:
881888
properties:
882889
connection:
@@ -896,6 +903,11 @@ spec:
896903
- driver
897904
- query
898905
type: object
906+
templatesOn:
907+
description: 'TemplatesOn specifies where the templating happens.
908+
Available options: - host - agent When left empty, the templating
909+
is done on the main instance(host) itself.'
910+
type: string
899911
timeout:
900912
description: Timeout is the maximum duration to let an action
901913
run before it's cancelled.
@@ -1302,6 +1314,17 @@ spec:
13021314
type: string
13031315
type: object
13041316
type: array
1317+
runsOn:
1318+
description: RunsOn specifies the agents that can run this playbook.
1319+
When left empty, the playbook will run on the main instance itself.
1320+
items:
1321+
type: string
1322+
type: array
1323+
templatesOn:
1324+
description: 'TemplatesOn specifies where the templating happens.
1325+
Available options: - host - agent When left empty, the templating
1326+
is done on the main instance(host) itself.'
1327+
type: string
13051328
required:
13061329
- actions
13071330
type: object

0 commit comments

Comments
 (0)