diff --git a/db/db.go b/db/db.go index 12efc4676..e4107bca8 100644 --- a/db/db.go +++ b/db/db.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" migrate "github.com/rubenv/sql-migrate" "github.com/tinkerbell/tink/db/migration" + tb "github.com/tinkerbell/tink/protos/template" pb "github.com/tinkerbell/tink/protos/workflow" ) @@ -34,7 +35,7 @@ type hardware interface { type template interface { CreateTemplate(ctx context.Context, name string, data string, id uuid.UUID) error - GetTemplate(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) + GetTemplate(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) DeleteTemplate(ctx context.Context, name string) error ListTemplates(in string, fn func(id, n string, in, del *timestamp.Timestamp) error) error UpdateTemplate(ctx context.Context, name string, data string, id uuid.UUID) error diff --git a/db/mock/mock.go b/db/mock/mock.go index 9ec26e995..bccd3976f 100644 --- a/db/mock/mock.go +++ b/db/mock/mock.go @@ -6,6 +6,7 @@ import ( "github.com/google/uuid" "github.com/tinkerbell/tink/db" + tb "github.com/tinkerbell/tink/protos/template" pb "github.com/tinkerbell/tink/protos/workflow" ) @@ -25,5 +26,5 @@ type DB struct { InsertIntoWorkflowEventTableFunc func(ctx context.Context, wfEvent *pb.WorkflowActionStatus, time time.Time) error // template TemplateDB map[string]interface{} - GetTemplateFunc func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) + GetTemplateFunc func(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) } diff --git a/db/mock/template.go b/db/mock/template.go index 40e72a240..0447fbb79 100644 --- a/db/mock/template.go +++ b/db/mock/template.go @@ -6,6 +6,7 @@ import ( "github.com/golang/protobuf/ptypes/timestamp" "github.com/google/uuid" + tb "github.com/tinkerbell/tink/protos/template" ) type Template struct { @@ -41,7 +42,7 @@ func (d DB) CreateTemplate(ctx context.Context, name string, data string, id uui } // GetTemplate returns a workflow template -func (d DB) GetTemplate(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { +func (d DB) GetTemplate(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) { return d.GetTemplateFunc(ctx, fields, deleted) } diff --git a/db/template.go b/db/template.go index dccdc2a9b..9e84ec2e2 100644 --- a/db/template.go +++ b/db/template.go @@ -10,6 +10,7 @@ import ( "github.com/golang/protobuf/ptypes/timestamp" "github.com/google/uuid" "github.com/pkg/errors" + tb "github.com/tinkerbell/tink/protos/template" wflow "github.com/tinkerbell/tink/workflow" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -48,16 +49,16 @@ func (d TinkDB) CreateTemplate(ctx context.Context, name string, data string, id } // GetTemplate returns template which is not deleted -func (d TinkDB) GetTemplate(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { +func (d TinkDB) GetTemplate(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) { getCondition, err := buildGetCondition(fields) if err != nil { - return "", "", "", errors.Wrap(err, "failed to get template") + return &tb.WorkflowTemplate{}, errors.Wrap(err, "failed to get template") } var query string if !deleted { query = ` - SELECT id, name, data + SELECT id, name, data, created_at, updated_at FROM template WHERE ` + getCondition + ` AND @@ -65,7 +66,7 @@ func (d TinkDB) GetTemplate(ctx context.Context, fields map[string]string, delet ` } else { query = ` - SELECT id, name, data + SELECT id, name, data, created_at, updated_at FROM template WHERE ` + getCondition + ` @@ -73,18 +74,30 @@ func (d TinkDB) GetTemplate(ctx context.Context, fields map[string]string, delet } row := d.instance.QueryRowContext(ctx, query) - id := []byte{} - name := []byte{} - data := []byte{} - err = row.Scan(&id, &name, &data) + var ( + id string + name string + data string + createdAt time.Time + updatedAt time.Time + ) + err = row.Scan(&id, &name, &data, &createdAt, &updatedAt) if err == nil { - return string(id), string(name), string(data), nil + crAt, _ := ptypes.TimestampProto(createdAt) + upAt, _ := ptypes.TimestampProto(updatedAt) + return &tb.WorkflowTemplate{ + Id: id, + Name: name, + Data: data, + CreatedAt: crAt, + UpdatedAt: upAt, + }, nil } if err != sql.ErrNoRows { err = errors.Wrap(err, "SELECT") d.logger.Error(err) } - return "", "", "", err + return &tb.WorkflowTemplate{}, err } // DeleteTemplate deletes a workflow template by id diff --git a/db/template_test.go b/db/template_test.go index 3ac816a58..4e003c626 100644 --- a/db/template_test.go +++ b/db/template_test.go @@ -45,13 +45,13 @@ func TestCreateTemplate(t *testing.T) { }(), }, Expectation: func(t *testing.T, input []*workflow.Workflow, tinkDB *db.TinkDB) { - wID, wName, wData, err := tinkDB.GetTemplate(ctx, map[string]string{"id": input[0].ID}, false) + wtmpl, err := tinkDB.GetTemplate(ctx, map[string]string{"id": input[0].ID}, false) if err != nil { t.Error(err) } - w := workflow.MustParse([]byte(wData)) - w.ID = wID - w.Name = wName + w := workflow.MustParse([]byte(wtmpl.GetData())) + w.ID = wtmpl.GetId() + w.Name = wtmpl.GetName() if dif := cmp.Diff(input[0], w); dif != "" { t.Errorf(dif) } @@ -96,12 +96,12 @@ func TestCreateTemplate(t *testing.T) { }(), }, Expectation: func(t *testing.T, input []*workflow.Workflow, tinkDB *db.TinkDB) { - _, wName, _, err := tinkDB.GetTemplate(context.Background(), map[string]string{"id": input[0].ID}, false) + wtmpl, err := tinkDB.GetTemplate(context.Background(), map[string]string{"id": input[0].ID}, false) if err != nil { t.Error(err) } - if wName != "updated-name" { - t.Errorf("expected name to be \"%s\", got \"%s\"", "updated-name", wName) + if wtmpl.GetName() != "updated-name" { + t.Errorf("expected name to be \"%s\", got \"%s\"", "updated-name", wtmpl.GetName()) } }, }, @@ -251,13 +251,13 @@ func TestDeleteTemplate(t *testing.T) { func TestGetTemplate(t *testing.T) { ctx := context.Background() expectation := func(t *testing.T, input *workflow.Workflow, tinkDB *db.TinkDB) { - wID, wName, wData, err := tinkDB.GetTemplate(ctx, map[string]string{"id": input.ID}, false) + wtmpl, err := tinkDB.GetTemplate(ctx, map[string]string{"id": input.ID}, false) if err != nil { t.Error(err) } - w := workflow.MustParse([]byte(wData)) - w.ID = wID - w.Name = wName + w := workflow.MustParse([]byte(wtmpl.GetData())) + w.ID = wtmpl.GetId() + w.Name = wtmpl.GetName() if dif := cmp.Diff(input, w); dif != "" { t.Errorf(dif) } @@ -353,7 +353,7 @@ func TestGetTemplateWithInvalidID(t *testing.T) { }() id := uuid.New().String() - _, _, _, err := tinkDB.GetTemplate(ctx, map[string]string{"id": id}, false) + _, err := tinkDB.GetTemplate(ctx, map[string]string{"id": id}, false) if err == nil { t.Error("expected error, got nil") } diff --git a/db/workflow.go b/db/workflow.go index 533fa0767..34a8c8701 100644 --- a/db/workflow.go +++ b/db/workflow.go @@ -337,7 +337,7 @@ func (d TinkDB) GetWorkflowsForWorker(id string) ([]string, error) { // GetWorkflow returns a workflow func (d TinkDB) GetWorkflow(ctx context.Context, id string) (Workflow, error) { query := ` - SELECT template, devices + SELECT template, devices, created_at, updated_at FROM workflow WHERE id = $1 @@ -345,10 +345,21 @@ func (d TinkDB) GetWorkflow(ctx context.Context, id string) (Workflow, error) { deleted_at IS NULL; ` row := d.instance.QueryRowContext(ctx, query, id) - var tmp, tar string - err := row.Scan(&tmp, &tar) + var ( + tmp, tar string + crAt, upAt time.Time + ) + err := row.Scan(&tmp, &tar, &crAt, &upAt) if err == nil { - return Workflow{ID: id, Template: tmp, Hardware: tar}, nil + createdAt, _ := ptypes.TimestampProto(crAt) + updatedAt, _ := ptypes.TimestampProto(upAt) + return Workflow{ + ID: id, + Template: tmp, + Hardware: tar, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + }, nil } if err != sql.ErrNoRows { err = errors.Wrap(err, "SELECT") diff --git a/db/workflow_test.go b/db/workflow_test.go index 2181f954f..259e5499c 100644 --- a/db/workflow_test.go +++ b/db/workflow_test.go @@ -357,12 +357,12 @@ func TestGetWorkflow(t *testing.T) { } func createWorkflow(ctx context.Context, tinkDB *db.TinkDB, in *input) (string, error) { - _, _, tmpData, err := tinkDB.GetTemplate(context.Background(), map[string]string{"id": in.template.ID}, false) + wtmpl, err := tinkDB.GetTemplate(context.Background(), map[string]string{"id": in.template.ID}, false) if err != nil { return "", err } - data, err := workflow.RenderTemplate(in.template.ID, tmpData, []byte(in.devices)) + data, err := workflow.RenderTemplate(in.template.ID, wtmpl.GetData(), []byte(in.devices)) if err != nil { return "", err } diff --git a/grpc-server/template.go b/grpc-server/template.go index 44b054f09..b8bc44ddb 100644 --- a/grpc-server/template.go +++ b/grpc-server/template.go @@ -62,7 +62,7 @@ func (s *server) GetTemplate(ctx context.Context, in *template.GetRequest) (*tem "id": in.GetId(), "name": in.GetName(), } - id, n, d, err := s.db.GetTemplate(ctx, fields, false) + wtmpl, err := s.db.GetTemplate(ctx, fields, false) s.logger.Info("done " + msg) if err != nil { metrics.CacheErrors.With(labels).Inc() @@ -72,7 +72,7 @@ func (s *server) GetTemplate(ctx context.Context, in *template.GetRequest) (*tem } l.Error(err) } - return &template.WorkflowTemplate{Id: id, Name: n, Data: d}, err + return wtmpl, err } // DeleteTemplate implements template.DeleteTemplate diff --git a/grpc-server/template_test.go b/grpc-server/template_test.go index 56acad8b7..599834227 100644 --- a/grpc-server/template_test.go +++ b/grpc-server/template_test.go @@ -173,13 +173,21 @@ func TestGetTemplate(t *testing.T) { TemplateDB: map[string]interface{}{ templateName1: template1, }, - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*pb.WorkflowTemplate, error) { t.Log("in get template func") if fields["id"] == templateID1 || fields["name"] == templateName1 { - return templateID1, templateName1, template1, nil + return &pb.WorkflowTemplate{ + Id: templateID1, + Name: templateName1, + Data: template1, + }, nil } - return templateNotFoundID, templateNotFoundName, templateNotFoundTemplate, errors.New("failed to get template") + return &pb.WorkflowTemplate{ + Id: templateNotFoundID, + Name: templateNotFoundName, + Data: templateNotFoundTemplate, + }, errors.New("failed to get template") }, }, getRequest: &pb.GetRequest{GetBy: &pb.GetRequest_Name{Name: templateName1}}, @@ -196,13 +204,21 @@ func TestGetTemplate(t *testing.T) { TemplateDB: map[string]interface{}{ templateName1: template1, }, - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*pb.WorkflowTemplate, error) { t.Log("in get template func") if fields["id"] == templateID1 || fields["name"] == templateName1 { - return templateID1, templateName1, template1, nil + return &pb.WorkflowTemplate{ + Id: templateID1, + Name: templateName1, + Data: template1, + }, nil } - return templateNotFoundID, templateNotFoundName, templateNotFoundTemplate, errors.New("failed to get template") + return &pb.WorkflowTemplate{ + Id: templateNotFoundID, + Name: templateNotFoundName, + Data: templateNotFoundTemplate, + }, errors.New("failed to get template") }, }, getRequest: &pb.GetRequest{GetBy: &pb.GetRequest_Name{Name: templateName2}}, @@ -219,13 +235,21 @@ func TestGetTemplate(t *testing.T) { TemplateDB: map[string]interface{}{ templateName1: template1, }, - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*pb.WorkflowTemplate, error) { t.Log("in get template func") if fields["id"] == templateID1 || fields["name"] == templateName1 { - return templateID1, templateName1, template1, nil + return &pb.WorkflowTemplate{ + Id: templateID1, + Name: templateName1, + Data: template1, + }, nil } - return templateNotFoundID, templateNotFoundName, templateNotFoundTemplate, errors.New("failed to get template") + return &pb.WorkflowTemplate{ + Id: templateNotFoundID, + Name: templateNotFoundName, + Data: templateNotFoundTemplate, + }, errors.New("failed to get template") }, }, getRequest: &pb.GetRequest{GetBy: &pb.GetRequest_Id{Id: templateID1}}, @@ -242,13 +266,21 @@ func TestGetTemplate(t *testing.T) { TemplateDB: map[string]interface{}{ templateName1: template1, }, - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*pb.WorkflowTemplate, error) { t.Log("in get template func") if fields["id"] == templateID1 || fields["name"] == templateName1 { - return templateID1, templateName1, template1, nil + return &pb.WorkflowTemplate{ + Id: templateID1, + Name: templateName1, + Data: template1, + }, nil } - return templateNotFoundID, templateNotFoundName, templateNotFoundTemplate, errors.New("failed to get template") + return &pb.WorkflowTemplate{ + Id: templateNotFoundID, + Name: templateNotFoundName, + Data: templateNotFoundTemplate, + }, errors.New("failed to get template") }, }, getRequest: &pb.GetRequest{GetBy: &pb.GetRequest_Id{Id: templateID2}}, @@ -265,13 +297,21 @@ func TestGetTemplate(t *testing.T) { TemplateDB: map[string]interface{}{ templateName1: template1, }, - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*pb.WorkflowTemplate, error) { t.Log("in get template func") if fields["id"] == templateID1 || fields["name"] == templateName1 { - return templateID1, templateName1, template1, nil + return &pb.WorkflowTemplate{ + Id: templateID1, + Name: templateName1, + Data: template1, + }, nil } - return templateNotFoundID, templateNotFoundName, templateNotFoundTemplate, errors.New("failed to get template") + return &pb.WorkflowTemplate{ + Id: templateNotFoundID, + Name: templateNotFoundName, + Data: templateNotFoundTemplate, + }, errors.New("failed to get template") }, }, getRequest: &pb.GetRequest{}, @@ -288,13 +328,21 @@ func TestGetTemplate(t *testing.T) { TemplateDB: map[string]interface{}{ templateName1: template1, }, - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*pb.WorkflowTemplate, error) { t.Log("in get template func") if fields["id"] == templateID1 || fields["name"] == templateName1 { - return templateID1, templateName1, template1, nil + return &pb.WorkflowTemplate{ + Id: templateID1, + Name: templateName1, + Data: template1, + }, nil } - return templateNotFoundID, templateNotFoundName, templateNotFoundTemplate, errors.New("failed to get template") + return &pb.WorkflowTemplate{ + Id: templateNotFoundID, + Name: templateNotFoundName, + Data: templateNotFoundTemplate, + }, errors.New("failed to get template") }, }, }, diff --git a/grpc-server/workflow.go b/grpc-server/workflow.go index 1167e25e1..44c96a044 100644 --- a/grpc-server/workflow.go +++ b/grpc-server/workflow.go @@ -37,11 +37,11 @@ func (s *server) CreateWorkflow(ctx context.Context, in *workflow.CreateRequest) fields := map[string]string{ "id": in.GetTemplate(), } - _, _, templateData, err := s.db.GetTemplate(ctx, fields, false) + wtmpl, err := s.db.GetTemplate(ctx, fields, false) if err != nil { return &workflow.CreateResponse{}, errors.Wrapf(err, errFailedToGetTemplate, in.GetTemplate()) } - data, err := wkf.RenderTemplate(in.GetTemplate(), templateData, []byte(in.Hardware)) + data, err := wkf.RenderTemplate(in.GetTemplate(), wtmpl.GetData(), []byte(in.Hardware)) if err != nil { metrics.CacheErrors.With(labels).Inc() @@ -99,21 +99,23 @@ func (s *server) GetWorkflow(ctx context.Context, in *workflow.GetRequest) (*wor fields := map[string]string{ "id": w.Template, } - _, _, templateData, err := s.db.GetTemplate(ctx, fields, true) + wtmpl, err := s.db.GetTemplate(ctx, fields, true) if err != nil { return &workflow.Workflow{}, errors.Wrapf(err, errFailedToGetTemplate, w.Template) } - data, err := wkf.RenderTemplate(w.Template, templateData, []byte(w.Hardware)) + data, err := wkf.RenderTemplate(w.Template, wtmpl.GetData(), []byte(w.Hardware)) if err != nil { return &workflow.Workflow{}, err } wf := &workflow.Workflow{ - Id: w.ID, - Template: w.Template, - Hardware: w.Hardware, - State: getWorkflowState(s.db, ctx, in.Id), - Data: data, + Id: w.ID, + Template: w.Template, + Hardware: w.Hardware, + State: getWorkflowState(s.db, ctx, in.Id), + CreatedAt: w.CreatedAt, + UpdatedAt: w.UpdatedAt, + Data: data, } l := s.logger.With("workflowID", w.ID) l.Info("done " + msg) diff --git a/grpc-server/workflow_test.go b/grpc-server/workflow_test.go index 32e666cdf..076878799 100644 --- a/grpc-server/workflow_test.go +++ b/grpc-server/workflow_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/tinkerbell/tink/db" "github.com/tinkerbell/tink/db/mock" + tb "github.com/tinkerbell/tink/protos/template" "github.com/tinkerbell/tink/protos/workflow" ) @@ -44,8 +45,12 @@ func TestCreateWorkflow(t *testing.T) { "FailedToGetTemplate": { args: args{ db: mock.DB{ - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { - return "", "", "", errors.New("failed to get template") + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) { + return &tb.WorkflowTemplate{ + Id: "", + Name: "", + Data: "", + }, errors.New("failed to get template") }, }, wfTemplate: templateID, @@ -58,8 +63,12 @@ func TestCreateWorkflow(t *testing.T) { "FailedCreatingWorkflow": { args: args{ db: mock.DB{ - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { - return "", "", templateData, nil + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) { + return &tb.WorkflowTemplate{ + Id: "", + Name: "", + Data: templateData, + }, nil }, CreateWorkflowFunc: func(ctx context.Context, wf db.Workflow, data string, id uuid.UUID) error { return errors.New("failed to create a workfow") @@ -75,8 +84,12 @@ func TestCreateWorkflow(t *testing.T) { "SuccessCreatingWorkflow": { args: args{ db: mock.DB{ - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { - return "", "", templateData, nil + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) { + return &tb.WorkflowTemplate{ + Id: "", + Name: "", + Data: templateData, + }, nil }, CreateWorkflowFunc: func(ctx context.Context, wf db.Workflow, data string, id uuid.UUID) error { return nil @@ -145,8 +158,12 @@ func TestGetWorkflow(t *testing.T) { TotalNumberOfActions: 1, }, nil }, - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { - return "", "", templateData, nil + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) { + return &tb.WorkflowTemplate{ + Id: "", + Name: "", + Data: templateData, + }, nil }, }, state: workflow.State_STATE_SUCCESS, @@ -186,8 +203,12 @@ func TestGetWorkflow(t *testing.T) { TotalNumberOfActions: 2, }, nil }, - GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (string, string, string, error) { - return "", "", templateData, nil + GetTemplateFunc: func(ctx context.Context, fields map[string]string, deleted bool) (*tb.WorkflowTemplate, error) { + return &tb.WorkflowTemplate{ + Id: "", + Name: "", + Data: templateData, + }, nil }, }, state: workflow.State_STATE_RUNNING,