Skip to content

Commit

Permalink
✨ Structured task errors. (#425)
Browse files Browse the repository at this point in the history
Task.Error and TaskReport.Error renamed:

Task.Errors []TaskError

TaskReport.Errors []TaskError

closes #411

---------

Signed-off-by: Jeff Ortel <jortel@redhat.com>
  • Loading branch information
jortel authored Jul 3, 2023
1 parent f8f1e0d commit 8e75205
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 17 deletions.
27 changes: 24 additions & 3 deletions addon/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,34 @@ func (h *Task) Succeeded() {
// Failed report addon failed.
// The reason can be a printf style format.
func (h *Task) Failed(reason string, x ...interface{}) {
reason = fmt.Sprintf(reason, x...)
h.report.Status = task.Failed
h.report.Error = fmt.Sprintf(reason, x...)
h.report.Errors = append(
h.report.Errors,
api.TaskError{
Severity: "Error",
Description: reason,
})
h.pushReport()
Log.Info(
"Addon reported: failed.",
"error",
h.report.Error)
"reason",
reason)
return
}

//
// Error report addon error.
// The description can be a printf style format.
func (h *Task) Error(severity, description string, x ...interface{}) {
description = fmt.Sprintf(description, x...)
h.report.Errors = append(
h.report.Errors,
api.TaskError{
Severity: severity,
Description: description,
})
h.pushReport()
return
}

Expand Down
23 changes: 18 additions & 5 deletions api/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,13 @@ type TTL struct {
Failed int `json:"failed,omitempty"`
}

//
// TaskError used in Task.Errors.
type TaskError struct {
Severity string `json:"severity"`
Description string `json:"description"`
}

//
// Task REST resource.
type Task struct {
Expand All @@ -515,7 +522,7 @@ type Task struct {
Purged bool `json:"purged,omitempty" yaml:",omitempty"`
Started *time.Time `json:"started,omitempty" yaml:",omitempty"`
Terminated *time.Time `json:"terminated,omitempty" yaml:",omitempty"`
Error string `json:"error,omitempty" yaml:",omitempty"`
Errors []TaskError `json:"errors,omitempty" yaml:",omitempty"`
Pod string `json:"pod,omitempty" yaml:",omitempty"`
Retries int `json:"retries,omitempty" yaml:",omitempty"`
Canceled bool `json:"canceled,omitempty" yaml:",omitempty"`
Expand All @@ -538,7 +545,6 @@ func (r *Task) With(m *model.Task) {
r.State = m.State
r.Started = m.Started
r.Terminated = m.Terminated
r.Error = m.Error
r.Pod = m.Pod
r.Retries = m.Retries
r.Canceled = m.Canceled
Expand All @@ -551,6 +557,9 @@ func (r *Task) With(m *model.Task) {
if m.TTL != nil {
_ = json.Unmarshal(m.TTL, &r.TTL)
}
if m.Errors != nil {
_ = json.Unmarshal(m.Errors, &r.Errors)
}
}

//
Expand Down Expand Up @@ -579,7 +588,7 @@ func (r *Task) Model() (m *model.Task) {
type TaskReport struct {
Resource `yaml:",inline"`
Status string `json:"status"`
Error string `json:"error,omitempty" yaml:",omitempty"`
Errors []TaskError `json:"errors,omitempty" yaml:",omitempty"`
Total int `json:"total,omitempty" yaml:",omitempty"`
Completed int `json:"completed,omitempty" yaml:",omitempty"`
Activity []string `json:"activity,omitempty" yaml:",omitempty"`
Expand All @@ -592,13 +601,15 @@ type TaskReport struct {
func (r *TaskReport) With(m *model.TaskReport) {
r.Resource.With(&m.Model)
r.Status = m.Status
r.Error = m.Error
r.Total = m.Total
r.Completed = m.Completed
r.TaskID = m.TaskID
if m.Activity != nil {
_ = json.Unmarshal(m.Activity, &r.Activity)
}
if m.Errors != nil {
_ = json.Unmarshal(m.Errors, &r.Errors)
}
if m.Result != nil {
_ = json.Unmarshal(m.Result, &r.Result)
}
Expand All @@ -612,7 +623,6 @@ func (r *TaskReport) Model() (m *model.TaskReport) {
}
m = &model.TaskReport{
Status: r.Status,
Error: r.Error,
Total: r.Total,
Completed: r.Completed,
TaskID: r.TaskID,
Expand All @@ -623,6 +633,9 @@ func (r *TaskReport) Model() (m *model.TaskReport) {
if r.Result != nil {
m.Result, _ = json.Marshal(r.Result)
}
if r.Errors != nil {
m.Errors, _ = json.Marshal(r.Errors)
}
m.ID = r.ID

return
Expand Down
5 changes: 5 additions & 0 deletions hack/add/analysis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ indirect: "true"
version: 4.6
" >> ${file}
echo -n "---
name: github.com/hybernate
indirect: "true"
version: 5.0
" >> ${file}
echo -n "---
name: github.com/ejb
indirect: "true"
version: 4.3
Expand Down
2 changes: 2 additions & 0 deletions hack/cmd/addon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ func main() {
}
return
})

addon.Error("Warning", "Test warning.")
}

//
Expand Down
68 changes: 68 additions & 0 deletions migration/v6/migrate.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v6

import (
"encoding/json"
"github.com/jortel/go-utils/logr"
"github.com/konveyor/tackle2-hub/migration/v6/model"
"gorm.io/gorm"
Expand All @@ -21,9 +22,76 @@ func (r Migration) Apply(db *gorm.DB) (err error) {
return
}
err = db.AutoMigrate(r.Models()...)
if err != nil {
return
}
err = r.taskReportError(db)
if err != nil {
return
}
err = r.taskError(db)
if err != nil {
return
}
return
}

func (r Migration) Models() []interface{} {
return model.All()
}

func (r Migration) taskError(db *gorm.DB) (err error) {
type Task struct {
model.Task
Error string
}
var list []Task
err = db.Find(&Task{}, &list).Error
if err != nil {
return
}
for i := range list {
m := &list[i]
if m.Error == "" {
continue
}
m.Errors, _ = json.Marshal(
[]model.TaskError{
{
Severity: "Error",
Description: m.Error,
},
})
}
m := db.Migrator()
err = m.DropColumn(&model.Task{}, "Error")
return
}

func (r Migration) taskReportError(db *gorm.DB) (err error) {
type TaskReport struct {
model.TaskReport
Error string
}
var list []TaskReport
err = db.Find(&TaskReport{}, &list).Error
if err != nil {
return
}
for i := range list {
m := &list[i]
if m.Error == "" {
continue
}
m.Errors, _ = json.Marshal(
[]model.TaskError{
{
Severity: "Error",
Description: m.Error,
},
})
}
m := db.Migrator()
err = m.DropColumn(&model.TaskReport{}, "Error")
return
}
4 changes: 0 additions & 4 deletions migration/v6/model/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,8 @@ type Stakeholder = model.Stakeholder
type StakeholderGroup = model.StakeholderGroup
type Tag = model.Tag
type TagCategory = model.TagCategory
type Task = model.Task
type TaskGroup = model.TaskGroup
type TaskReport = model.TaskReport
type Ticket = model.Ticket
type Tracker = model.Tracker
type TTL = model.TTL
type ApplicationTag = model.ApplicationTag
type DependencyCyclicError = model.DependencyCyclicError

Expand Down
92 changes: 92 additions & 0 deletions migration/v6/model/task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package model

import (
"encoding/json"
"fmt"
"gorm.io/gorm"
"time"
)

type Task struct {
Model
BucketOwner
Name string `gorm:"index"`
Addon string `gorm:"index"`
Locator string `gorm:"index"`
Priority int
Image string
Variant string
Policy string
TTL JSON
Data JSON
Started *time.Time
Terminated *time.Time
State string `gorm:"index"`
Errors JSON
Pod string `gorm:"index"`
Retries int
Canceled bool
Report *TaskReport `gorm:"constraint:OnDelete:CASCADE"`
ApplicationID *uint
Application *Application
TaskGroupID *uint `gorm:"<-:create"`
TaskGroup *TaskGroup
}

func (m *Task) Reset() {
m.Started = nil
m.Terminated = nil
m.Report = nil
m.Errors = nil
}

func (m *Task) BeforeCreate(db *gorm.DB) (err error) {
err = m.BucketOwner.BeforeCreate(db)
m.Reset()
return
}

//
// Error appends an error.
func (m *Task) Error(severity, description string, x ...interface{}) {
var list []TaskError
description = fmt.Sprintf(description, x...)
te := TaskError{Severity: severity, Description: description}
_ = json.Unmarshal(m.Errors, &list)
list = append(list, te)
m.Errors, _ = json.Marshal(list)
}

//
// Map alias.
type Map = map[string]interface{}

//
// TTL time-to-live.
type TTL struct {
Created int `json:"created,omitempty"`
Pending int `json:"pending,omitempty"`
Postponed int `json:"postponed,omitempty"`
Running int `json:"running,omitempty"`
Succeeded int `json:"succeeded,omitempty"`
Failed int `json:"failed,omitempty"`
}

//
// TaskError used in Task.Errors.
type TaskError struct {
Severity string `json:"severity"`
Description string `json:"description"`
}

type TaskReport struct {
Model
Status string
Errors JSON
Total int
Completed int
Activity JSON `gorm:"type:json"`
Result JSON `gorm:"type:json"`
TaskID uint `gorm:"<-:create;uniqueIndex"`
Task *Task
}
Loading

0 comments on commit 8e75205

Please sign in to comment.