Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check summary #315

Merged
merged 3 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion check_summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,24 @@ import (

"github.com/flanksource/duty/models"
"github.com/jackc/pgx/v5/pgxpool"
"golang.org/x/exp/slices"
"gorm.io/gorm"
)

type CheckSummarySortBy string

var CheckSummarySortByName CheckSummarySortBy = "name"

type CheckSummaryOptions struct {
SortBy CheckSummarySortBy
}

func OrderByName() CheckSummaryOptions {
return CheckSummaryOptions{
SortBy: CheckSummarySortByName,
}
}

func CheckSummary(ctx DBContext, checkID string) (*models.CheckSummary, error) {
var checkSummary models.CheckSummary
if err := ctx.DB().First(&checkSummary, "id = ?", checkID).Error; err != nil {
Expand All @@ -24,7 +39,7 @@ func CheckSummary(ctx DBContext, checkID string) (*models.CheckSummary, error) {
return &checkSummary, nil
}

func QueryCheckSummary(ctx context.Context, dbpool *pgxpool.Pool) (models.Checks, error) {
func QueryCheckSummary(ctx context.Context, dbpool *pgxpool.Pool, opts ...CheckSummaryOptions) (models.Checks, error) {
if _, ok := ctx.Deadline(); !ok {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, DefaultQueryTimeout)
Expand All @@ -51,6 +66,25 @@ func QueryCheckSummary(ctx context.Context, dbpool *pgxpool.Pool) (models.Checks
results = append(results, checks...)
}

if len(opts) > 0 && opts[0].SortBy != "" {
slice := []*models.Check(results)
slices.SortFunc(slice, func(a, b *models.Check) int {
var _a, _b string
if opts[0].SortBy == CheckSummarySortByName {
_a = a.Name
_b = b.Name
}
if _a > _b {
return 1
}
if _a == _b {
return 0
}
return -1
})
return models.Checks(slice), nil
}

return results, nil
}

Expand Down
10 changes: 2 additions & 8 deletions check_summary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,17 @@ package duty

import (
"context"
"encoding/json"

"github.com/flanksource/duty/testutils"
ginkgo "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func testCheckSummaryJSON(path string) {
result, err := QueryCheckSummary(context.Background(), testutils.TestDBPGPool)
result, err := QueryCheckSummary(context.Background(), testutils.TestDBPGPool, OrderByName())
Expect(err).ToNot(HaveOccurred())

resultJSON, err := json.Marshal(result)
Expect(err).ToNot(HaveOccurred())

expected := readTestFile(path)
jqExpr := `del(.[].uptime.last_pass) | del(.[].uptime.last_fail) | del(.[].created_at) | del(.[].updated_at) | del(.[].agent_id)`
matchJSON([]byte(expected), resultJSON, &jqExpr)
match(path, result, `del(.[].uptime.last_pass) | del(.[].uptime.last_fail) | del(.[].created_at) | del(.[].updated_at) | del(.[].agent_id)`)
}

var _ = ginkgo.Describe("Check summary behavior", ginkgo.Ordered, func() {
Expand Down
55 changes: 23 additions & 32 deletions fixtures/dummy/check_statuses.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,44 @@ import (
)

var t1 = currentTime.Add(-15 * time.Minute)
var t2 = currentTime.Add(-10 * time.Minute)
var t3 = currentTime.Add(-5 * time.Minute)

var LogisticsAPIHealthHTTPCheckStatus1 = models.CheckStatus{
CheckID: LogisticsAPIHealthHTTPCheck.ID,
Duration: 100,
Status: true,
CreatedAt: t1,
Time: t1.Format("2006-01-02 15:04:05"),
}

var LogisticsAPIHealthHTTPCheckStatus2 = models.CheckStatus{
CheckID: LogisticsAPIHealthHTTPCheck.ID,
Duration: 100,
Status: true,
CreatedAt: t2,
Time: t2.Format("2006-01-02 15:04:05"),
}

var LogisticsAPIHealthHTTPCheckStatus3 = models.CheckStatus{
CheckID: LogisticsAPIHealthHTTPCheck.ID,
Duration: 100,
Status: true,
CreatedAt: t3,
Time: t3.Format("2006-01-02 15:04:05"),
func generateStatus(check models.Check, t time.Time, count int, passingMod int) []models.CheckStatus {
var statuses = []models.CheckStatus{}

for i := 0; i < count; i++ {
status := true
if i%passingMod == 0 {
status = false
}
statuses = append(statuses, models.CheckStatus{
CheckID: check.ID,
Status: status,
CreatedAt: t,
Duration: (1 + i) * 20,
Time: t.Add(time.Minute * time.Duration(i)).Format(time.DateTime),
})
}
return statuses
}

var LogisticsAPIHomeHTTPCheckStatus1 = models.CheckStatus{
CheckID: LogisticsAPIHomeHTTPCheck.ID,
Duration: 100,
Status: true,
CreatedAt: t1,
Time: t3.Format("2006-01-02 15:04:05"),
Time: t3.Format(time.DateTime),
}

var LogisticsDBCheckStatus1 = models.CheckStatus{
var OlderThan1H = models.CheckStatus{
CheckID: LogisticsDBCheck.ID,
Duration: 50,
Status: false,
CreatedAt: t1,
Time: t1.Format("2006-01-02 15:04:05"),
Time: time.Now().Add(-70 * time.Minute).Format(time.DateTime),
}

var AllDummyCheckStatuses = []models.CheckStatus{
LogisticsAPIHealthHTTPCheckStatus1,
LogisticsAPIHealthHTTPCheckStatus2,
LogisticsAPIHealthHTTPCheckStatus3,
var AllDummyCheckStatuses = append(
generateStatus(LogisticsAPIHealthHTTPCheck, time.Now(), 70, 5),
LogisticsAPIHomeHTTPCheckStatus1,
LogisticsDBCheckStatus1,
}
OlderThan1H)
152 changes: 96 additions & 56 deletions fixtures/expectations/check_status_summary.json
Original file line number Diff line number Diff line change
@@ -1,58 +1,98 @@
[
{
"id": "0186b7a4-0593-73e9-7e3d-5b3446336c1d",
"canary_id": "0186b7a5-a2a4-86fd-c326-3a2104a2777f",
"type": "http",
"name": "logistics-api-health-check",
"canary_name": "dummy-logistics-api-canary",
"namespace": "logistics",
"status": "healthy",
"labels": {},
"uptime": {
"passed": 3,
"failed": 0,
"last_pass": "2023-03-06T21:24:30"
},
"latency": {
"p99": 100,
"rolling1h": 0
}
},
{
"canary_id": "0186b7a5-a2a4-86fd-c326-3a2104a2777f",
"canary_name": "dummy-logistics-api-canary",
"id": "0186b7a4-625a-6a38-a9a7-e5e6b44ffec3",
"labels": {},
"latency": {
"p99": 100,
"rolling1h": 0
},
"name": "logistics-api-home-check",
"namespace": "logistics",
"status": "healthy",
"type": "http",
"uptime": {
"failed": 0,
"passed": 1
}
},
{
"id": "0186b7a4-9338-7142-1b10-25dc49030218",
"canary_id": "0186b7a5-f246-3628-0d68-30bffc13244d",
"type": "postgres",
"name": "logistics-db-check",
"canary_name": "dummy-logistics-db-canary",
"status": "unhealthy",
"namespace": "logistics",
"labels": {},
"uptime": {
"passed": 0,
"failed": 1,
"last_fail": "2023-03-06T21:14:30"
},
"latency": {
"p99": 50,
"rolling1h": 0
}
}
{
"agent_id": "00000000-0000-0000-0000-000000000000",
"canary_id": "6dc9d6dd-0b55-4801-837c-352d3abf9b70",
"canary_name": "dummy-cart-api-canary",
"created_at": "2023-11-01T21:47:47.647714+02:00",
"id": "eed7bd6e-529b-4693-aca9-43977bcc5ff1",
"labels": {},
"latency": {
"rolling1h": 0
},
"name": "cart-api-health-check",
"namespace": "cart",
"status": "healthy",
"type": "http",
"updated_at": "2023-11-01T21:47:47.647714+02:00",
"uptime": {
"failed": 0,
"passed": 0
}
},
{
"agent_id": "00000000-0000-0000-0000-000000000000",
"canary_id": "0186b7a5-a2a4-86fd-c326-3a2104a2777f",
"canary_name": "dummy-logistics-api-canary",
"created_at": "2023-11-01T21:47:47.646435+02:00",
"id": "0186b7a4-0593-73e9-7e3d-5b3446336c1d",
"labels": {},
"latency": {
"avg": 710,
"p50": 700,
"p95": 1340,
"p99": 1400,
"rolling1h": 0
},
"name": "logistics-api-health-check",
"namespace": "logistics",
"status": "healthy",
"type": "http",
"updated_at": "2023-11-01T21:47:47.646435+02:00",
"uptime": {
"failed": 14,
"last_fail": "2023-11-01T22:52:28+02:00",
"last_pass": "2023-11-01T22:56:28+02:00",
"passed": 56
}
},
{
"agent_id": "00000000-0000-0000-0000-000000000000",
"canary_id": "0186b7a5-a2a4-86fd-c326-3a2104a2777f",
"canary_name": "dummy-logistics-api-canary",
"created_at": "2023-11-01T21:47:47.64714+02:00",
"id": "0186b7a4-625a-6a38-a9a7-e5e6b44ffec3",
"labels": {},
"latency": {
"avg": 100,
"p50": 100,
"p95": 100,
"p99": 100,
"rolling1h": 0
},
"name": "logistics-api-home-check",
"namespace": "logistics",
"status": "healthy",
"type": "http",
"updated_at": "2023-11-01T21:47:47.64714+02:00",
"uptime": {
"failed": 0,
"last_pass": "2023-11-01T21:42:28+02:00",
"passed": 1
}
},
{
"agent_id": "00000000-0000-0000-0000-000000000000",
"canary_id": "0186b7a5-f246-3628-0d68-30bffc13244d",
"canary_name": "dummy-logistics-db-canary",
"created_at": "2023-11-01T21:47:47.647428+02:00",
"id": "0186b7a4-9338-7142-1b10-25dc49030218",
"labels": {},
"latency": {
"avg": 50,
"p50": 50,
"p95": 50,
"p99": 50,
"rolling1h": 0
},
"name": "logistics-db-check",
"namespace": "logistics",
"status": "unhealthy",
"type": "postgres",
"updated_at": "2023-11-01T21:47:47.647428+02:00",
"uptime": {
"failed": 1,
"last_fail": "2023-11-01T20:37:28+02:00",
"passed": 0
}
}
]
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/flanksource/postq v0.1.1
github.com/google/uuid v1.3.1
github.com/hashicorp/hcl/v2 v2.18.1
github.com/hexops/gotextdiff v1.0.3
github.com/itchyny/gojq v0.12.13
github.com/jackc/pgx/v5 v5.4.3
github.com/json-iterator/go v1.1.12
Expand All @@ -26,6 +27,7 @@ require (
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0
go.opentelemetry.io/otel/sdk v1.19.0
go.opentelemetry.io/otel/trace v1.19.0
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
gorm.io/driver/postgres v1.5.3
gorm.io/gorm v1.25.5
k8s.io/api v0.28.2
Expand Down Expand Up @@ -137,7 +139,6 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sync v0.4.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/henvic/httpretty v0.1.2 h1:EQo556sO0xeXAjP10eB+BZARMuvkdGqtfeS4Ntjvkiw=
github.com/henvic/httpretty v0.1.2/go.mod h1:ViEsly7wgdugYtymX54pYp6Vv2wqZmNHayJ6q8tlKCc=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
Expand Down
2 changes: 1 addition & 1 deletion models/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ type CheckStatus struct {
}

func (s CheckStatus) GetTime() (time.Time, error) {
return time.Parse("2006-01-02 15:04:05", s.Time)
return time.Parse(time.DateTime, s.Time)
}

func (CheckStatus) TableName() string {
Expand Down
18 changes: 10 additions & 8 deletions models/playbooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ const (
)

type Playbook struct {
ID uuid.UUID `gorm:"default:generate_ulid()" json:"id"`
Name string `json:"name"`
Spec types.JSON `json:"spec"`
Source string `json:"source"`
CreatedBy *uuid.UUID `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty" time_format:"postgres_timestamp" gorm:"<-:false"`
UpdatedAt time.Time `json:"updated_at,omitempty" time_format:"postgres_timestamp" gorm:"<-:false"`
DeletedAt *time.Time `json:"deleted_at,omitempty" time_format:"postgres_timestamp"`
ID uuid.UUID `gorm:"default:generate_ulid()" json:"id"`
Name string `json:"name"`
Icon string `json:"icon,omitempty"`
Description string `json:"description,omitempty"`
Spec types.JSON `json:"spec"`
Source string `json:"source"`
CreatedBy *uuid.UUID `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty" time_format:"postgres_timestamp" gorm:"<-:false"`
UpdatedAt time.Time `json:"updated_at,omitempty" time_format:"postgres_timestamp" gorm:"<-:false"`
DeletedAt *time.Time `json:"deleted_at,omitempty" time_format:"postgres_timestamp"`
}

func (p Playbook) AsMap(removeFields ...string) map[string]any {
Expand Down
8 changes: 8 additions & 0 deletions schema/playbooks.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ table "playbooks" {
null = false
type = text
}
column "icon" {
null = true
type = text
}
column "description" {
null = true
type = text
}
column "spec" {
null = false
type = jsonb
Expand Down
Loading
Loading