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

Tink CLI now flags an error if template ID does not exist, while creating a workflow #286

Merged
merged 2 commits into from
Sep 10, 2020
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
7 changes: 7 additions & 0 deletions db/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import (
"context"
"time"

"github.com/google/uuid"
"github.com/tinkerbell/tink/db"
pb "github.com/tinkerbell/tink/protos/workflow"
)

// DB is the mocked implementation of Database interface
type DB struct {
// workflow
CreateWorkflowFunc func(ctx context.Context, wf db.Workflow, data string, id uuid.UUID) error
GetfromWfDataTableFunc func(ctx context.Context, req *pb.GetWorkflowDataRequest) ([]byte, error)
InsertIntoWfDataTableFunc func(ctx context.Context, req *pb.UpdateWorkflowDataRequest) error
GetWorkflowMetadataFunc func(ctx context.Context, req *pb.GetWorkflowDataRequest) ([]byte, error)
Expand All @@ -18,4 +22,7 @@ type DB struct {
GetWorkflowActionsFunc func(ctx context.Context, wfID string) (*pb.WorkflowActionList, error)
UpdateWorkflowStateFunc func(ctx context.Context, wfContext *pb.WorkflowContext) error
InsertIntoWorkflowEventTableFunc func(ctx context.Context, wfEvent *pb.WorkflowActionStatus, time time.Time) error

// template
GetTemplateFunc func(ctx context.Context, id string) (string, string, error)
}
2 changes: 1 addition & 1 deletion db/mock/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,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, id string) (string, string, error) {
return "", "", nil
return d.GetTemplateFunc(ctx, id)
}

// DeleteTemplate deletes a workflow template
Expand Down
2 changes: 1 addition & 1 deletion db/mock/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

// CreateWorkflow creates a new workflow
func (d DB) CreateWorkflow(ctx context.Context, wf db.Workflow, data string, id uuid.UUID) error {
return nil
return d.CreateWorkflowFunc(ctx, wf, data, id)
}

// InsertIntoWfDataTable : Insert ephemeral data in workflow_data table
Expand Down
4 changes: 1 addition & 3 deletions db/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,11 @@ func (d TinkDB) GetTemplate(ctx context.Context, id string) (string, string, err
if err == nil {
return string(name), string(data), nil
}

if err != sql.ErrNoRows {
err = errors.Wrap(err, "SELECT")
logger.Error(err)
}

return "", "", nil
return "", "", err
}

// DeleteTemplate deletes a workflow template
Expand Down
20 changes: 14 additions & 6 deletions grpc-server/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ var state = map[int32]workflow.State{
4: workflow.State_SUCCESS,
}

const (
errFailedToGetTemplate = "failed to get template with ID: %s"
errTemplateParsing = "failed to parse template with ID: %s"
)

// CreateWorkflow implements workflow.CreateWorkflow
func (s *server) CreateWorkflow(ctx context.Context, in *workflow.CreateRequest) (*workflow.CreateResponse, error) {
logger.Info("createworkflow")
Expand All @@ -47,7 +52,6 @@ func (s *server) CreateWorkflow(ctx context.Context, in *workflow.CreateRequest)
data, err := createYaml(ctx, s.db, in.Template, in.Hardware)
if err != nil {
metrics.CacheErrors.With(labels).Inc()
err = errors.Wrap(err, "failed to create Yaml")
logger.Error(err)
return &workflow.CreateResponse{}, err
}
Expand Down Expand Up @@ -269,30 +273,34 @@ func (s *server) ShowWorkflowEvents(req *workflow.GetRequest, stream workflow.Wo
func createYaml(ctx context.Context, db db.Database, temp string, devices string) (string, error) {
_, tempData, err := db.GetTemplate(ctx, temp)
if err != nil {
return "", err
return "", errors.Wrapf(err, errFailedToGetTemplate, temp)
}
return renderTemplate(string(tempData), []byte(devices))
return renderTemplate(temp, tempData, []byte(devices))
}

func renderTemplate(tempData string, devices []byte) (string, error) {
func renderTemplate(templateID, tempData string, devices []byte) (string, error) {
var hardware map[string]interface{}
err := json.Unmarshal(devices, &hardware)
if err != nil {
err = errors.Wrapf(err, errTemplateParsing, templateID)
logger.Error(err)
return "", nil
return "", err
}

t := template.New("workflow-template")
_, err = t.Parse(string(tempData))
if err != nil {
err = errors.Wrapf(err, errTemplateParsing, templateID)
logger.Error(err)
return "", nil
}

buf := new(bytes.Buffer)
err = t.Execute(buf, hardware)
if err != nil {
return "", nil
err = errors.Wrapf(err, errTemplateParsing, templateID)
logger.Error(err)
return "", err
}
return buf.String(), nil
}
112 changes: 112 additions & 0 deletions grpc-server/workflow_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package grpcserver

import (
"context"
"testing"

"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/tinkerbell/tink/db"
"github.com/tinkerbell/tink/db/mock"
"github.com/tinkerbell/tink/protos/workflow"
)

const (
templateID = "e29b6444-1de7-4a69-bf25-6ea4ae869005"
hw = `{"device_1": "08:00:27:00:00:01"}`
templateData = `version: "0.1"
name: hello_world_workflow
global_timeout: 600
tasks:
- name: "hello world"
worker: "{{.device_1}}"
actions:
- name: "hello_world"
image: hello-world
timeout: 60`
)

func TestCreateWorkflow(t *testing.T) {
type (
args struct {
db mock.DB
wfTemplate, wfHardware string
}
want struct {
expectedError bool
}
)
testCases := map[string]struct {
args args
want want
}{
"FailedToGetTempalte": {
args: args{
db: mock.DB{
GetTemplateFunc: func(ctx context.Context, id string) (string, string, error) {
return "", "", errors.New("failed to get template")
},
},
wfTemplate: templateID,
wfHardware: hw,
},
want: want{
expectedError: true,
},
},
"FailedCreatingWorkflow": {
args: args{
db: mock.DB{
GetTemplateFunc: func(ctx context.Context, id string) (string, string, error) {
return "", templateData, nil
},
CreateWorkflowFunc: func(ctx context.Context, wf db.Workflow, data string, id uuid.UUID) error {
return errors.New("failed to create a workfow")
},
},
wfTemplate: templateID,
wfHardware: hw,
},
want: want{
expectedError: true,
},
},
"SuccessCreatingWorkflow": {
args: args{
db: mock.DB{
GetTemplateFunc: func(ctx context.Context, id string) (string, string, error) {
return "", templateData, nil
},
CreateWorkflowFunc: func(ctx context.Context, wf db.Workflow, data string, id uuid.UUID) error {
return nil
},
},
wfTemplate: templateID,
wfHardware: hw,
},
want: want{
expectedError: false,
},
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
s := testServer(tc.args.db)
res, err := s.CreateWorkflow(context.TODO(), &workflow.CreateRequest{
Hardware: tc.args.wfHardware,
Template: tc.args.wfTemplate,
})
if err != nil {
assert.Error(t, err)
assert.Empty(t, res)
assert.True(t, tc.want.expectedError)
return
}
assert.NoError(t, err)
assert.NotEmpty(t, res)
assert.False(t, tc.want.expectedError)
})
}
}