Add admin_api and database logging of runs #9 #10

This commit is contained in:
2023-01-31 20:25:52 -07:00
parent 724757b23c
commit 4bda3c7a3b
11 changed files with 400 additions and 136 deletions
+10 -5
View File
@@ -8,14 +8,14 @@ import (
"context"
"fmt"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/op/go-logging"
)
var log = logging.MustGetLogger("cursorius-server")
type Database struct {
Conn *pgx.Conn
Conn *pgxpool.Pool
}
func LaunchDB(conf config.DBConfig) (Database, error) {
@@ -41,8 +41,9 @@ func LaunchDB(conf config.DBConfig) (Database, error) {
var err error
for i := 0; i < 10; i++ {
// TODO: retry logic is broken with pgxpool
log.Infof("Connecting to database with URL \"%v\" (attempt %v)", dbURLNoPasswd, i)
db.Conn, err = pgx.Connect(context.Background(), dbURL)
db.Conn, err = pgxpool.New(context.Background(), dbURL)
if err == nil {
break
}
@@ -80,12 +81,13 @@ SELECT EXISTS (
return db, nil
}
func initDB(conn *pgx.Conn) error {
func initDB(conn *pgxpool.Pool) error {
createTablesQuery := `
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE version (
version INT NOT NULL
);
CREATE TABLE pipelines (
@@ -115,7 +117,10 @@ CREATE TABLE runners (
CREATE TABLE runs (
id UUID PRIMARY KEY,
pipeline UUID,
result BOOLEAN NOT NULL,
in_progress BOOLEAN DEFAULT NULL,
result BIGINT DEFAULT NULL,
stdout TEXT DEFAULT NULL,
stderr TEXT DEFAULT NULL,
CONSTRAINT fk_pipeline
FOREIGN KEY(pipeline)
+112 -13
View File
@@ -7,7 +7,37 @@ import (
"github.com/google/uuid"
)
func (d *Database) GetPipelineById(id uuid.UUID) (Pipeline, error) {
func (db *Database) GetPipelines() ([]Pipeline, error) {
query := `
SELECT id, name, url, poll_interval
FROM pipelines;`
pipelines := make([]Pipeline, 0)
rows, err := db.Conn.Query(context.Background(), query)
if err != nil {
return pipelines, fmt.Errorf("Could not query database for pipelines: %w", err)
}
defer rows.Close()
for rows.Next() {
var pipeline Pipeline
var idStr string
if err := rows.Scan(&idStr, &pipeline.Name, &pipeline.Url, &pipeline.PollInterval); err != nil {
return pipelines, err
}
pipeline.Id, err = uuid.Parse(idStr)
if err != nil {
return pipelines, err
}
pipelines = append(pipelines, pipeline)
}
return pipelines, nil
}
func (db *Database) GetPipelineById(id uuid.UUID) (Pipeline, error) {
query := `
SELECT name, url, poll_interval
FROM pipelines
@@ -17,7 +47,7 @@ WHERE id=$1;`
Id: id,
}
err := d.Conn.QueryRow(context.Background(), query, id).Scan(&pipeline.Name, &pipeline.Url, &pipeline.PollInterval)
err := db.Conn.QueryRow(context.Background(), query, id).Scan(&pipeline.Name, &pipeline.Url, &pipeline.PollInterval)
if err != nil {
return pipeline, fmt.Errorf("Could not query database for pipeline with id %v: %w", id.String(), err)
}
@@ -25,7 +55,7 @@ WHERE id=$1;`
return pipeline, nil
}
func (d *Database) CreatePipeline(name string, url string, pollInterval int) (Pipeline, error) {
func (db *Database) CreatePipeline(name string, url string, pollInterval int) (Pipeline, error) {
query := `
INSERT INTO pipelines (id, name, url, poll_interval)
VALUES (uuid_generate_v4(), $1, $2, $3)
@@ -33,14 +63,14 @@ RETURNING id, name, url, poll_interval;`
pipeline := Pipeline{}
var idStr string
err := d.Conn.QueryRow(context.Background(), query, name, url, pollInterval).Scan(&idStr, &pipeline.Name, &pipeline.Url, &pipeline.PollInterval)
err := db.Conn.QueryRow(context.Background(), query, name, url, pollInterval).Scan(&idStr, &pipeline.Name, &pipeline.Url, &pipeline.PollInterval)
if err != nil {
return pipeline, err
return pipeline, fmt.Errorf("Could not create pipeline: %w", err)
}
id, err := uuid.Parse(idStr)
if err != nil {
return pipeline, err
return pipeline, fmt.Errorf("Could not parse UUID generated by DB: %w", err)
}
pipeline.Id = id
@@ -58,7 +88,7 @@ WHERE pipeline=$1;`
rows, err := db.Conn.Query(context.Background(), query, id)
if err != nil {
log.Fatal(err)
return webhooks, fmt.Errorf("Could not get webhooks for pipeline with id \"%v\": %w", id, err)
}
defer rows.Close()
@@ -79,7 +109,7 @@ WHERE pipeline=$1;`
return webhooks, nil
}
func (d *Database) GetWebhookById(id uuid.UUID) (Webhook, error) {
func (db *Database) GetWebhookById(id uuid.UUID) (Webhook, error) {
query := `
SELECT server_type, secret, pipeline
FROM webhooks
@@ -89,7 +119,7 @@ WHERE id=$1;`
Id: id,
}
err := d.Conn.QueryRow(context.Background(), query, id).Scan(&webhook.ServerType, &webhook.Secret, &webhook.Pipeline)
err := db.Conn.QueryRow(context.Background(), query, id).Scan(&webhook.ServerType, &webhook.Secret, &webhook.Pipeline)
if err != nil {
return webhook, fmt.Errorf("Could not query database for webhook with id %v: %w", id.String(), err)
}
@@ -97,9 +127,7 @@ WHERE id=$1;`
return webhook, nil
}
func (d *Database) CreateWebhook(serverType WebhookSender, pipelineId uuid.UUID) (Webhook, error) {
//WITH secret_val as (select substr(md5(random()::text), 0, 50)),
func (db *Database) CreateWebhook(serverType WebhookSender, pipelineId uuid.UUID) (Webhook, error) {
query := `
INSERT INTO webhooks (id, server_type, secret, pipeline)
@@ -108,7 +136,7 @@ RETURNING id, server_type, secret, pipeline;`
webhook := Webhook{}
var idStr string
err := d.Conn.QueryRow(context.Background(), query, string(serverType), pipelineId).Scan(&idStr, &webhook.ServerType, &webhook.Secret, &webhook.Pipeline)
err := db.Conn.QueryRow(context.Background(), query, string(serverType), pipelineId).Scan(&idStr, &webhook.ServerType, &webhook.Secret, &webhook.Pipeline)
if err != nil {
return webhook, err
}
@@ -122,3 +150,74 @@ RETURNING id, server_type, secret, pipeline;`
return webhook, nil
}
func (db *Database) CreateRun(pipelineId uuid.UUID) (Run, error) {
query := `
INSERT INTO runs (id, pipeline, in_progress)
VALUES(uuid_generate_v4(), $1, true)
RETURNING id, pipeline, in_progress;`
run := Run{}
var idStr string
err := db.Conn.QueryRow(context.Background(), query, pipelineId).Scan(&idStr, &run.Pipeline, &run.InProgress)
if err != nil {
return run, err
}
run.Id, err = uuid.Parse(idStr)
if err != nil {
return run, err
}
return run, nil
}
func (db *Database) UpdateRunResult(r Run) error {
query := `
UPDATE runs
SET in_progress=$1, result=$2, stdout=$3, stderr=$4
WHERE id=$3;`
// TODO: does r.Result need a pointer derefrence?
_, err := db.Conn.Exec(context.Background(),
query, r.InProgress, r.Result, r.Stdout, r.Stderr)
return err
}
func (db *Database) GetRunsForPipeline(pipelineId uuid.UUID) ([]Run, error) {
query := `
SELECT id, in_progress, result, stdout, stderr
FROM runs
WHERE pipeline=$1;`
runs := make([]Run, 0)
rows, err := db.Conn.Query(context.Background(), query, pipelineId)
if err != nil {
return runs, fmt.Errorf("Could not get runs for pipeline with id \"%v\": %w", pipelineId, err)
}
defer rows.Close()
for rows.Next() {
var run Run
var idStr string
if err := rows.Scan(
&idStr,
&run.InProgress,
&run.Result,
&run.Stdout,
&run.Stderr,
); err != nil {
return runs, err
}
run.Id, err = uuid.Parse(idStr)
if err != nil {
return runs, err
}
runs = append(runs, run)
}
return runs, nil
}
+7 -4
View File
@@ -33,15 +33,18 @@ type Runner struct {
}
type Run struct {
Id uuid.UUID
Pipeline uuid.UUID
Result bool
Id uuid.UUID
Pipeline uuid.UUID
InProgress bool
Result *int64
Stdout []byte
Stderr []byte
}
type CommandExecution struct {
Id uuid.UUID
RunId uuid.UUID
Command string
Command []string
ReturnCode int
Stdout string
Stderr string