Skip to content

Commit

Permalink
Merge pull request #51 from whywaita/feat/devide-runners-table
Browse files Browse the repository at this point in the history
divide runner tables
  • Loading branch information
whywaita authored May 26, 2021
2 parents e4f7999 + badccf4 commit 450608a
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 18 deletions.
2 changes: 1 addition & 1 deletion pkg/datastore/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ type Job struct {

// Runner is a runner
type Runner struct {
UUID uuid.UUID `db:"uuid"`
UUID uuid.UUID `db:"runner_id"`
ShoesType string `db:"shoes_type"`
IPAddress string `db:"ip_address"`
TargetID uuid.UUID `db:"target_id"`
Expand Down
50 changes: 42 additions & 8 deletions pkg/datastore/mysql/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,38 @@ import (

// CreateRunner add a runner
func (m *MySQL) CreateRunner(ctx context.Context, runner datastore.Runner) error {
query := `INSERT INTO runners(uuid, shoes_type, ip_address, target_id, cloud_id, deleted) VALUES (?, ?, ?, ?, ?, ?)`
if _, err := m.Conn.ExecContext(ctx, query, runner.UUID.String(), runner.ShoesType, runner.IPAddress, runner.TargetID.String(), runner.CloudID, false); err != nil {
return fmt.Errorf("failed to execute INSERT query: %w", err)
tx := m.Conn.MustBegin()

queryRunner := `INSERT INTO runners(uuid) VALUES (?)`
if _, err := tx.ExecContext(ctx, queryRunner, runner.UUID.String()); err != nil {
tx.Rollback()
return fmt.Errorf("failed to execute INSERT query runners: %w", err)
}

queryDetail := `INSERT INTO runner_detail(runner_id, shoes_type, ip_address, target_id, cloud_id) VALUES (?, ?, ?, ?, ?)`
if _, err := tx.ExecContext(ctx, queryDetail, runner.UUID.String(), runner.ShoesType, runner.IPAddress, runner.TargetID.String(), runner.CloudID); err != nil {
tx.Rollback()
return fmt.Errorf("failed to execute INSERT query runner_detail: %w", err)
}

queryRunning := `INSERT INTO runners_running(runner_id) VALUES (?)`
if _, err := tx.ExecContext(ctx, queryRunning, runner.UUID.String()); err != nil {
tx.Rollback()
return fmt.Errorf("failed to execute INSERT query runners_running: %w", err)
}

if err := tx.Commit(); err != nil {
tx.Rollback()
return fmt.Errorf("failed to execute COMMIT: %w", err)
}
return nil
}

// ListRunners get a not deleted runners
func (m *MySQL) ListRunners(ctx context.Context) ([]datastore.Runner, error) {
var runners []datastore.Runner
query := `SELECT uuid, shoes_type, ip_address, target_id, cloud_id, deleted, status, created_at, updated_at, deleted_at FROM runners WHERE deleted = false`
query := `SELECT runner.runner_id, detail.shoes_type, detail.ip_address, detail.target_id, detail.cloud_id, detail.created_at, detail.updated_at
FROM runners_running AS runner JOIN runner_detail AS detail ON runner.runner_id = detail.runner_id`
err := m.Conn.SelectContext(ctx, &runners, query)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
Expand All @@ -41,7 +61,7 @@ func (m *MySQL) ListRunners(ctx context.Context) ([]datastore.Runner, error) {
func (m *MySQL) GetRunner(ctx context.Context, id uuid.UUID) (*datastore.Runner, error) {
var r datastore.Runner

query := `SELECT uuid, shoes_type, ip_address, target_id, cloud_id, deleted, status, created_at, updated_at, deleted_at FROM runners WHERE uuid = ? AND deleted = false`
query := `SELECT runner_id, shoes_type, ip_address, target_id, cloud_id, created_at, updated_at FROM runner_detail WHERE runner_id = ?`
if err := m.Conn.GetContext(ctx, &r, query, id.String()); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, datastore.ErrNotFound
Expand All @@ -55,9 +75,23 @@ func (m *MySQL) GetRunner(ctx context.Context, id uuid.UUID) (*datastore.Runner,

// DeleteRunner delete a runner
func (m *MySQL) DeleteRunner(ctx context.Context, id uuid.UUID, deletedAt time.Time, reason datastore.RunnerStatus) error {
query := `UPDATE runners SET deleted=1, deleted_at = ?, status = ? WHERE uuid = ? `
if _, err := m.Conn.ExecContext(ctx, query, deletedAt, reason, id.String()); err != nil {
return fmt.Errorf("failed to execute UPDATE query: %w", err)
tx := m.Conn.MustBegin()

queryDelete := `DELETE FROM runners_running WHERE runner_id = ?`
if _, err := tx.ExecContext(ctx, queryDelete, id.String()); err != nil {
tx.Rollback()
return fmt.Errorf("failed to execute DELETE query: %w", err)
}

queryInsert := `INSERT INTO runners_deleted(runner_id, reason) VALUES (?, ?)`
if _, err := tx.ExecContext(ctx, queryInsert, id.String(), reason); err != nil {
tx.Rollback()
return fmt.Errorf("failed to execute INSERT query: %w", err)
}

if err := tx.Commit(); err != nil {
tx.Rollback()
return fmt.Errorf("failed to execute COMMIT: %w", err)
}

return nil
Expand Down
95 changes: 90 additions & 5 deletions pkg/datastore/mysql/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package mysql_test
import (
"context"
"database/sql"
"errors"
"fmt"
"testing"
"time"
Expand All @@ -22,8 +23,6 @@ var testRunner = datastore.Runner{
IPAddress: "",
TargetID: testTargetID,
CloudID: "mycloud-uuid",
Deleted: false,
Status: datastore.RunnerStatusCreated,
}

func TestMySQL_CreateRunner(t *testing.T) {
Expand Down Expand Up @@ -127,6 +126,57 @@ func TestMySQL_ListRunners(t *testing.T) {
}
}

func TestMySQL_ListRunnersNotReturnDeleted(t *testing.T) {
testDatastore, teardown := testutils.GetTestDatastore()
defer teardown()

if err := testDatastore.CreateTarget(context.Background(), datastore.Target{
UUID: testTargetID,
Scope: testScopeRepo,
GitHubPersonalToken: testGitHubPersonalToken,
ResourceType: datastore.ResourceTypeNano,
}); err != nil {
t.Fatalf("failed to create target: %+v", err)
}

u := "00000000-0000-0000-0000-00000000000%d"

for i := 0; i < 3; i++ {
input := testRunner
input.UUID = uuid.FromStringOrNil(fmt.Sprintf(u, i))
err := testDatastore.CreateRunner(context.Background(), input)
if err != nil {
t.Fatalf("failed to create runner: %+v", err)
}
}

err := testDatastore.DeleteRunner(context.Background(), uuid.FromStringOrNil(fmt.Sprintf(u, 0)), time.Now(), "deleted")
if err != nil {
t.Fatalf("failed to delete runner: %+v", err)
}

got, err := testDatastore.ListRunners(context.Background())
if err != nil {
t.Fatalf("failed to get runners: %+v", err)
}
for i := range got {
got[i].CreatedAt = time.Time{}
got[i].UpdatedAt = time.Time{}
}

var want []datastore.Runner
for i := 1; i < 3; i++ {
r := testRunner
r.UUID = uuid.FromStringOrNil(fmt.Sprintf(u, i))
want = append(want, r)
}

if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}

}

func TestMySQL_GetRunner(t *testing.T) {
testDatastore, teardown := testutils.GetTestDatastore()
defer teardown()
Expand Down Expand Up @@ -191,8 +241,6 @@ func TestMySQL_DeleteRunner(t *testing.T) {
}

deleted := testRunner
deleted.Deleted = true
deleted.Status = datastore.RunnerStatusCompleted

tests := []struct {
input uuid.UUID
Expand Down Expand Up @@ -224,12 +272,49 @@ func TestMySQL_DeleteRunner(t *testing.T) {
if diff := cmp.Diff(test.want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}

if _, err := getRunningRunnerFromSQL(testDB, test.input); err == nil || errors.Is(err, sql.ErrNoRows) {
t.Errorf("%s is deleted, but exist in runner_running: %+v", test.input, err)
}
if _, err := getDeletedRunnerFromSQL(testDB, test.input); err != nil {
t.Fatalf("%s is not exist in runners_deleted: %+v", test.input, err)
}
}
}

func getRunnerFromSQL(testDB *sqlx.DB, id uuid.UUID) (*datastore.Runner, error) {
var r datastore.Runner
query := `SELECT uuid, shoes_type, ip_address, target_id, cloud_id, deleted, status, created_at, updated_at, deleted_at FROM runners WHERE uuid = ?`
query := `SELECT runner_id, shoes_type, ip_address, target_id, cloud_id, created_at, updated_at FROM runner_detail WHERE runner_id = ?`
stmt, err := testDB.Preparex(query)
if err != nil {
return nil, fmt.Errorf("failed to prepare: %w", err)
}
err = stmt.Get(&r, id)
if err != nil {
return nil, fmt.Errorf("failed to get runner: %w", err)
}
return &r, nil
}

func getRunningRunnerFromSQL(testDB *sqlx.DB, id uuid.UUID) (*datastore.Runner, error) {
var r datastore.Runner
query := `SELECT detail.runner_id, shoes_type, ip_address, target_id, cloud_id, detail.created_at, updated_at
FROM runner_detail AS detail JOIN runnesr_running AS running ON detail.runner_id = running.runner_id WHERE detail.runner_id = ?`
stmt, err := testDB.Preparex(query)
if err != nil {
return nil, fmt.Errorf("failed to prepare: %w", err)
}
err = stmt.Get(&r, id)
if err != nil {
return nil, fmt.Errorf("failed to get runner: %w", err)
}
return &r, nil
}

func getDeletedRunnerFromSQL(testDB *sqlx.DB, id uuid.UUID) (*datastore.Runner, error) {
var r datastore.Runner
query := `SELECT detail.runner_id, shoes_type, ip_address, target_id, cloud_id, detail.created_at, updated_at
FROM runner_detail AS detail JOIN runners_deleted AS deleted ON detail.runner_id = deleted.runner_id WHERE detail.runner_id = ?`
stmt, err := testDB.Preparex(query)
if err != nil {
return nil, fmt.Errorf("failed to prepare: %w", err)
Expand Down
27 changes: 23 additions & 4 deletions pkg/datastore/mysql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,36 @@ CREATE TABLE `targets` (

CREATE TABLE `runners` (
`uuid` VARCHAR(36) NOT NULL PRIMARY KEY,
`created_at` TIMESTAMP NOT NULL DEFAULT current_timestamp
);

CREATE TABLE `runner_detail` (
`runner_id` VARCHAR(36) NOT NULL,
`shoes_type` VARCHAR(255) NOT NULL,
`ip_address` VARCHAR(255) NOT NULL,
`target_id` VARCHAR(36) NOT NULL,
`cloud_id` TEXT NOT NULL,
`deleted` bool DEFAULT false NOT NULL,
`status` VARCHAR(255) NOT NULL DEFAULT 'created',
`created_at` TIMESTAMP NOT NULL DEFAULT current_timestamp,
`updated_at` TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
`deleted_at` TIMESTAMP,
KEY `fk_runner_target_id` (`target_id`),
CONSTRAINT `runners_ibfk_1` FOREIGN KEY fk_runner_target_id(`target_id`) REFERENCES targets(`uuid`) ON DELETE RESTRICT
CONSTRAINT `runners_ibfk_1` FOREIGN KEY fk_runner_target_id(`target_id`) REFERENCES targets(`uuid`) ON DELETE RESTRICT,
KEY `fk_runner_detail_id` (`runner_id`),
CONSTRAINT `runners_ibfk_2` FOREIGN KEY fk_runner_detail_id(`runner_id`) REFERENCES runners(`uuid`) ON DELETE RESTRICT
);

CREATE TABLE `runners_running` (
`runner_id` VARCHAR(36) NOT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT current_timestamp,
KEY `fk_runner_deleted_id` (`runner_id`),
CONSTRAINT `runners_running_ibfk_1` FOREIGN KEY fk_runner_deleted_id(`runner_id`) REFERENCES runners(`uuid`) ON DELETE CASCADE
);

CREATE TABLE `runners_deleted` (
`runner_id` VARCHAR(36) NOT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT current_timestamp,
`reason` VARCHAR(255) NOT NULL,
KEY `fk_runner_deleted_id` (`runner_id`),
CONSTRAINT `runners_deleted_ibfk_1` FOREIGN KEY fk_runner_deleted_id(`runner_id`) REFERENCES runners(`uuid`) ON DELETE CASCADE
);

CREATE TABLE `jobs` (
Expand Down

0 comments on commit 450608a

Please sign in to comment.