feat: target workflow runs by tag selector

This commit is contained in:
2026-08-04 13:36:43 +01:00
parent e00a0da5d9
commit d1b3cd2f74
4 changed files with 18 additions and 13 deletions
+4
View File
@@ -343,6 +343,10 @@ func deleteWorkflow(c *gin.Context) {
func runWorkflow(c *gin.Context) {
runID, err := services.TriggerWorkflow(auth.InstanceID(c), c.Param("id"), actorFromCtx(c))
if err != nil {
if errors.Is(err, services.ErrNoTargets) {
c.JSON(http.StatusBadRequest, gin.H{"error": "this workflow matches no servers"})
return
}
c.JSON(http.StatusServiceUnavailable, gin.H{"error": err.Error()})
return
}
+1
View File
@@ -50,6 +50,7 @@ type Workflow struct {
WorkflowID string `bson:"workflow_id" json:"workflow_id"`
Name string `bson:"name" json:"name"`
TargetServerIDs []string `bson:"target_server_ids" json:"target_server_ids"`
TargetTags map[string]string `bson:"target_tags,omitempty" json:"target_tags,omitempty"`
Steps []WorkflowStepRef `bson:"steps" json:"steps"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
+6 -13
View File
@@ -22,17 +22,14 @@ func TriggerWorkflow(instanceID, workflowID, actor string) (string, error) {
if err != nil {
return "", err
}
if len(wf.TargetServerIDs) == 0 {
return "", fmt.Errorf("workflow has no target servers")
targets, err := ResolveTargets(instanceID, wf.TargetServerIDs, wf.TargetTags)
if err != nil {
return "", err
}
if len(wf.Steps) == 0 {
return "", fmt.Errorf("workflow has no steps")
}
if err := validateTargetServers(instanceID, wf.TargetServerIDs); err != nil {
return "", err
}
ctx, cancel := wfCtx()
running := db.Col("workflow_runs").FindOne(ctx, bson.M{"instance_id": instanceID, "workflow_id": workflowID, "status": "running"})
cancel()
@@ -54,14 +51,10 @@ func TriggerWorkflow(instanceID, workflowID, actor string) (string, error) {
Status: "running",
TriggeredBy: actor,
StartedAt: time.Now(),
ServerRuns: make([]models.ServerRun, 0, len(wf.TargetServerIDs)),
ServerRuns: make([]models.ServerRun, 0, len(targets)),
}
for _, sid := range wf.TargetServerIDs {
hostname := sid
if s, e := getServerByID(sid); e == nil {
hostname = s.Hostname
}
sr := models.ServerRun{ServerID: sid, Hostname: hostname, Status: "queued", RunEnv: map[string]string{}}
for _, srv := range targets {
sr := models.ServerRun{ServerID: srv.ServerID, Hostname: srv.Hostname, Status: "queued", RunEnv: map[string]string{}}
for _, rs := range resolved {
sr.Steps = append(sr.Steps, models.StepRun{Order: rs.Order, Name: rs.Name, Status: "queued", OutputEnv: map[string]string{}})
}
+7
View File
@@ -249,6 +249,9 @@ func CreateWorkflow(instanceID string, w models.Workflow) (*models.Workflow, err
if err := ValidateWorkflow(w); err != nil {
return nil, err
}
if err := ValidateTags(w.TargetTags); err != nil {
return nil, err
}
if err := validateTargetServers(instanceID, w.TargetServerIDs); err != nil {
return nil, err
}
@@ -265,6 +268,9 @@ func UpdateWorkflow(instanceID, id string, w models.Workflow) error {
if err := ValidateWorkflow(w); err != nil {
return err
}
if err := ValidateTags(w.TargetTags); err != nil {
return err
}
if err := validateTargetServers(instanceID, w.TargetServerIDs); err != nil {
return err
}
@@ -272,6 +278,7 @@ func UpdateWorkflow(instanceID, id string, w models.Workflow) error {
_, err := db.Col("workflows").UpdateOne(ctx, bson.M{"workflow_id": id, "instance_id": instanceID}, bson.M{"$set": bson.M{
"name": w.Name,
"target_server_ids": w.TargetServerIDs,
"target_tags": w.TargetTags,
"steps": w.Steps,
"updated_at": time.Now(),
}})