diff --git a/engine/api/api_routes.go b/engine/api/api_routes.go index 452fde35ac..1275acc433 100644 --- a/engine/api/api_routes.go +++ b/engine/api/api_routes.go @@ -318,7 +318,7 @@ func (api *API) InitRouter() { r.Handle("/queue/workflows/{permJobID}/book", Scope(sdk.AuthConsumerScopeRunExecution), r.POST(api.postBookWorkflowJobHandler, EnableTracing(), MaintenanceAware()), r.DELETE(api.deleteBookWorkflowJobHandler, EnableTracing(), MaintenanceAware())) r.Handle("/queue/workflows/{permJobID}/infos", Scope(sdk.AuthConsumerScopeRunExecution), r.GET(api.getWorkflowJobHandler, EnableTracing(), MaintenanceAware())) r.Handle("/queue/workflows/{permJobID}/vulnerability", Scope(sdk.AuthConsumerScopeRunExecution), r.POSTEXECUTE(api.postVulnerabilityReportHandler, EnableTracing(), MaintenanceAware())) - r.Handle("/queue/workflows/{permJobID}/spawn/infos", Scope(sdk.AuthConsumerScopeRunExecution), r.POST(r.Asynchronous(api.postSpawnInfosWorkflowJobHandler, 1), EnableTracing(), MaintenanceAware())) + r.Handle("/queue/workflows/{permJobID}/spawn/infos", Scope(sdk.AuthConsumerScopeRunExecution), r.POST(api.postSpawnInfosWorkflowJobHandler, EnableTracing(), MaintenanceAware())) r.Handle("/queue/workflows/{permJobID}/result", Scope(sdk.AuthConsumerScopeRunExecution), r.POSTEXECUTE(api.postWorkflowJobResultHandler, EnableTracing(), MaintenanceAware())) r.Handle("/queue/workflows/{permJobID}/log", Scope(sdk.AuthConsumerScopeRunExecution), r.POSTEXECUTE(api.postWorkflowJobLogsHandler, MaintenanceAware())) r.Handle("/queue/workflows/log/service", Scope(sdk.AuthConsumerScopeRunExecution), r.POSTEXECUTE(r.Asynchronous(api.postWorkflowJobServiceLogsHandler, 1), MaintenanceAware())) diff --git a/engine/api/router_middleware_auth.go b/engine/api/router_middleware_auth.go index 26a0157f79..076c83e96b 100644 --- a/engine/api/router_middleware_auth.go +++ b/engine/api/router_middleware_auth.go @@ -55,7 +55,6 @@ func (api *API) authMiddleware(ctx context.Context, w http.ResponseWriter, req * if ok { claims := jwt.Claims.(*sdk.AuthSessionJWTClaims) sessionID := claims.StandardClaims.Id - log.Debug("authMiddleware> try to retrieve session for given jwt with id: %s", sessionID) // Check for session based on jwt from context session, err = authentication.CheckSession(ctx, api.mustDB(), sessionID) if err != nil { @@ -65,7 +64,6 @@ func (api *API) authMiddleware(ctx context.Context, w http.ResponseWriter, req * if session != nil { ctx = context.WithValue(ctxWithJWT, contextSession, session) - log.Debug("authMiddleware> try to retrieve consumer for given session with id: %s", session.ConsumerID) // Load auth consumer for current session in database with authentified user and contacts c, err := authentication.LoadConsumerByID(ctx, api.mustDB(), session.ConsumerID, authentication.LoadConsumerOptions.WithAuthentifiedUser) @@ -102,8 +100,6 @@ func (api *API) authMiddleware(ctx context.Context, w http.ResponseWriter, req * } if consumer != nil { - log.Debug("authMiddleware> check scope for current consumer") - ctx = context.WithValue(ctx, contextAPIConsumer, consumer) // Checks scopes, one of expected scopes should be in actual scopes diff --git a/engine/api/workflow/execute_node_job_run.go b/engine/api/workflow/execute_node_job_run.go index f87cfcba51..6be1a18274 100644 --- a/engine/api/workflow/execute_node_job_run.go +++ b/engine/api/workflow/execute_node_job_run.go @@ -198,6 +198,13 @@ func UpdateNodeJobRunStatus(ctx context.Context, db gorp.SqlExecutor, store cach report.Merge(ctx, r) return report, err } + + spawnInfos, err := LoadNodeRunJobInfo(ctx, db, job.ID) + if err != nil { + return report, sdk.WrapError(err, "unable to load spawn infos for runJob: %d", job.ID) + } + job.SpawnInfos = spawnInfos + syncJobInNodeRun(nodeRun, job, stageIndex) if job.Status != sdk.StatusStopped { @@ -209,8 +216,10 @@ func UpdateNodeJobRunStatus(ctx context.Context, db gorp.SqlExecutor, store cach } // AddSpawnInfosNodeJobRun saves spawn info before starting worker -func AddSpawnInfosNodeJobRun(db gorp.SqlExecutor, jobID int64, infos []sdk.SpawnInfo) error { +func AddSpawnInfosNodeJobRun(db gorp.SqlExecutor, nodeID, jobID int64, infos []sdk.SpawnInfo) error { + wnjri := &sdk.WorkflowNodeJobRunInfo{ + WorkflowNodeRunID: nodeID, WorkflowNodeJobRunID: jobID, SpawnInfos: PrepareSpawnInfos(infos), } @@ -276,7 +285,7 @@ func TakeNodeJobRun(ctx context.Context, db gorp.SqlExecutor, store cache.Store, return nil, nil, sdk.WrapError(err, "cannot update worker_id in node job run %d", jobID) } - if err := AddSpawnInfosNodeJobRun(db, jobID, PrepareSpawnInfos(infos)); err != nil { + if err := AddSpawnInfosNodeJobRun(db, job.WorkflowNodeRunID, jobID, PrepareSpawnInfos(infos)); err != nil { return nil, nil, sdk.WrapError(err, "cannot save spawn info on node job run %d", jobID) } diff --git a/engine/api/workflow/execute_node_run.go b/engine/api/workflow/execute_node_run.go index 951bf3a68d..ed27e9345f 100644 --- a/engine/api/workflow/execute_node_run.go +++ b/engine/api/workflow/execute_node_run.go @@ -36,6 +36,7 @@ func syncJobInNodeRun(n *sdk.WorkflowNodeRun, j *sdk.WorkflowNodeJobRun, stageIn rj.Job = j.Job rj.Header = j.Header rj.Parameters = j.Parameters + rj.SpawnInfos = j.SpawnInfos } } } @@ -535,7 +536,7 @@ jobLoop: } next() - if err := AddSpawnInfosNodeJobRun(db, wjob.ID, PrepareSpawnInfos(wjob.SpawnInfos)); err != nil { + if err := AddSpawnInfosNodeJobRun(db, wjob.WorkflowNodeRunID, wjob.ID, PrepareSpawnInfos(wjob.SpawnInfos)); err != nil { return nil, sdk.WrapError(err, "cannot save spawn info job %d", wjob.ID) } @@ -932,7 +933,7 @@ func stopWorkflowNodeJobRun(ctx context.Context, dbFunc func() *gorp.DbMap, stor return report } - if err := AddSpawnInfosNodeJobRun(tx, njr.ID, []sdk.SpawnInfo{stopInfos}); err != nil { + if err := AddSpawnInfosNodeJobRun(tx, njr.WorkflowNodeRunID, njr.ID, []sdk.SpawnInfo{stopInfos}); err != nil { chanErr <- sdk.WrapError(err, "Cannot save spawn info job %d", njr.ID) tx.Rollback() wg.Done() diff --git a/engine/api/workflow/run_workflow_test.go b/engine/api/workflow/run_workflow_test.go index fb40f8704e..fa5f14a952 100644 --- a/engine/api/workflow/run_workflow_test.go +++ b/engine/api/workflow/run_workflow_test.go @@ -589,7 +589,7 @@ queueRun: } //AddSpawnInfosNodeJobRun - err := workflow.AddSpawnInfosNodeJobRun(db, j.ID, []sdk.SpawnInfo{ + err := workflow.AddSpawnInfosNodeJobRun(db, j.WorkflowNodeRunID, j.ID, []sdk.SpawnInfo{ { APITime: time.Now(), RemoteTime: time.Now(), diff --git a/engine/api/workflow_queue.go b/engine/api/workflow_queue.go index 4a75f62f3f..d4f03ca9b6 100644 --- a/engine/api/workflow_queue.go +++ b/engine/api/workflow_queue.go @@ -294,14 +294,14 @@ func (api *API) postVulnerabilityReportHandler() service.Handler { } } -func (api *API) postSpawnInfosWorkflowJobHandler() service.AsynchronousHandler { - return func(ctx context.Context, r *http.Request) error { +func (api *API) postSpawnInfosWorkflowJobHandler() service.Handler { + return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { id, err := requestVarInt(r, "permJobID") if err != nil { return sdk.WrapError(err, "invalid id") } - if ok := isHatchery(ctx); !ok { + if ok := isHatchery(ctx) || isWorker(ctx); !ok { return sdk.WithStack(sdk.ErrForbidden) } @@ -318,13 +318,12 @@ func (api *API) postSpawnInfosWorkflowJobHandler() service.AsynchronousHandler { } defer tx.Rollback() // nolint - if _, err := workflow.LoadNodeJobRun(ctx, tx, api.Cache, id); err != nil { - if !sdk.ErrorIs(err, sdk.ErrWorkflowNodeRunJobNotFound) { - return err - } - return nil + jobRun, err := workflow.LoadNodeJobRun(ctx, tx, api.Cache, id) + if err != nil { + return err } - if err := workflow.AddSpawnInfosNodeJobRun(tx, id, s); err != nil { + + if err := workflow.AddSpawnInfosNodeJobRun(tx, jobRun.WorkflowNodeRunID, jobRun.ID, s); err != nil { return err } @@ -435,7 +434,7 @@ func postJobResult(ctx context.Context, dbFunc func(context.Context) *gorp.DbMap Message: sdk.SpawnMsg{ID: sdk.MsgSpawnInfoWorkerEnd.ID, Args: []interface{}{wr.Name, res.Duration}}, }} - if err := workflow.AddSpawnInfosNodeJobRun(tx, job.ID, workflow.PrepareSpawnInfos(infos)); err != nil { + if err := workflow.AddSpawnInfosNodeJobRun(tx, job.WorkflowNodeRunID, job.ID, workflow.PrepareSpawnInfos(infos)); err != nil { return nil, sdk.WrapError(err, "Cannot save spawn info job %d", job.ID) } diff --git a/engine/api/workflow_queue_test.go b/engine/api/workflow_queue_test.go index 8998371cb5..570d8a6778 100644 --- a/engine/api/workflow_queue_test.go +++ b/engine/api/workflow_queue_test.go @@ -591,7 +591,7 @@ func Test_postWorkflowJobTestsResultsHandler(t *testing.T) { req := assets.NewJWTAuthentifiedRequest(t, ctx.hatcheryToken, "POST", uri, info) rec := httptest.NewRecorder() router.Mux.ServeHTTP(rec, req) - require.Equal(t, 202, rec.Code) + require.Equal(t, 204, rec.Code) //spawn uri = router.GetRoute("POST", api.postTakeWorkflowJobHandler, map[string]string{ diff --git a/engine/worker/internal/action/test_helper.go b/engine/worker/internal/action/test_helper.go index 71686d6a75..caa324aa8a 100644 --- a/engine/worker/internal/action/test_helper.go +++ b/engine/worker/internal/action/test_helper.go @@ -71,8 +71,8 @@ func (_ TestWorker) Register(ctx context.Context) error { func (_ TestWorker) Take(ctx context.Context, job sdk.WorkflowNodeJobRun) error { return nil } -func (_ TestWorker) ProcessJob(job sdk.WorkflowNodeJobRunData) (sdk.Result, error) { - return sdk.Result{}, nil +func (_ TestWorker) ProcessJob(job sdk.WorkflowNodeJobRunData) sdk.Result { + return sdk.Result{} } func (w TestWorker) SendLog(ctx context.Context, level workerruntime.Level, format string) { w.t.Log("SendLog> [" + string(level) + "] " + format) diff --git a/engine/worker/internal/run.go b/engine/worker/internal/run.go index dca9b36232..c9a7108774 100644 --- a/engine/worker/internal/run.go +++ b/engine/worker/internal/run.go @@ -90,7 +90,7 @@ func processActionVariables(a *sdk.Action, parent *sdk.Action, jobParameters []s // replaces placeholder in all children recursively for i := range a.Actions { if err := processActionVariables(&a.Actions[i], a, jobParameters, secrets); err != nil { - return nil + return err } } @@ -109,7 +109,7 @@ func (w *CurrentWorker) replaceVariablesPlaceholder(a *sdk.Action, params []sdk. return nil } -func (w *CurrentWorker) runJob(ctx context.Context, a *sdk.Action, jobID int64, secrets []sdk.Variable) (sdk.Result, error) { +func (w *CurrentWorker) runJob(ctx context.Context, a *sdk.Action, jobID int64, secrets []sdk.Variable) sdk.Result { log.Info(ctx, "runJob> start job %s (%d)", a.Name, jobID) defer func() { log.Info(ctx, "runJob> job %s (%d)", a.Name, jobID) }() @@ -124,7 +124,7 @@ func (w *CurrentWorker) runJob(ctx context.Context, a *sdk.Action, jobID int64, if err := w.updateStepStatus(ctx, jobID, jobStepIndex, sdk.StatusBuilding); err != nil { jobResult.Status = sdk.StatusFail jobResult.Reason = fmt.Sprintf("Cannot update step (%d) status (%s): %v", jobStepIndex, sdk.StatusBuilding, err) - return jobResult, err + return jobResult } var stepResult = sdk.Result{ Status: sdk.StatusNeverBuilt, @@ -163,7 +163,7 @@ func (w *CurrentWorker) runJob(ctx context.Context, a *sdk.Action, jobID int64, if err := w.updateStepStatus(ctx, jobID, jobStepIndex, stepResult.Status); err != nil { jobResult.Status = sdk.StatusFail jobResult.Reason = fmt.Sprintf("Cannot update step (%d) status (%s): %v", jobStepIndex, sdk.StatusBuilding, err) - return jobResult, err + return jobResult } } @@ -178,7 +178,7 @@ func (w *CurrentWorker) runJob(ctx context.Context, a *sdk.Action, jobID int64, if nCriticalFailed > 0 { jobResult.Status = sdk.StatusFail } - return jobResult, nil + return jobResult } func (w *CurrentWorker) runAction(ctx context.Context, a sdk.Action, jobID int64, secrets []sdk.Variable, actionName string) sdk.Result { @@ -459,7 +459,7 @@ func (w *CurrentWorker) setupKeysDirectory(ctx context.Context, jobInfo sdk.Work return kdFile, kdAbs, nil } -func (w *CurrentWorker) ProcessJob(jobInfo sdk.WorkflowNodeJobRunData) (sdk.Result, error) { +func (w *CurrentWorker) ProcessJob(jobInfo sdk.WorkflowNodeJobRunData) (res sdk.Result) { ctx := w.currentJob.context t0 := time.Now() @@ -472,6 +472,8 @@ func (w *CurrentWorker) ProcessJob(jobInfo sdk.WorkflowNodeJobRunData) (sdk.Resu defer cancel() ctx = workerruntime.SetJobID(ctx, jobInfo.NodeJobRun.ID) + ctx = workerruntime.SetStepOrder(ctx, 0) + // start logger routine with a large buffer w.logger.logChan = make(chan sdk.Log, 100000) go func() { @@ -484,13 +486,16 @@ func (w *CurrentWorker) ProcessJob(jobInfo sdk.WorkflowNodeJobRunData) (sdk.Resu log.Error(ctx, "processJob> Drain logs error: %v", err) } }() + defer func() { + log.Error(ctx, "processJob> Status: %s | Reason: %s", res.Status, res.Reason) + }() wdFile, wdAbs, err := w.setupWorkingDirectory(ctx, jobInfo) if err != nil { return sdk.Result{ Status: sdk.StatusFail, Reason: fmt.Sprintf("Error: unable to setup workfing directory: %v", err), - }, err + } } ctx = workerruntime.SetWorkingDirectory(ctx, wdFile) log.Debug("processJob> Setup workspace - %s", wdFile.Name()) @@ -500,7 +505,7 @@ func (w *CurrentWorker) ProcessJob(jobInfo sdk.WorkflowNodeJobRunData) (sdk.Resu return sdk.Result{ Status: sdk.StatusFail, Reason: fmt.Sprintf("Error: unable to setup keys directory: %v", err), - }, err + } } ctx = workerruntime.SetKeysDirectory(ctx, kdFile) log.Debug("processJob> Setup key directory - %s", kdFile.Name()) @@ -527,8 +532,8 @@ func (w *CurrentWorker) ProcessJob(jobInfo sdk.WorkflowNodeJobRunData) (sdk.Resu if err := processVariablesAndParameters(&jobInfo.NodeJobRun.Job.Action, jobParameters, jobInfo.Secrets); err != nil { return sdk.Result{ Status: sdk.StatusFail, - Reason: fmt.Sprintf("Error: cannot process job %s parameters", jobInfo.NodeJobRun.Job.Action.Name), - }, err + Reason: fmt.Sprintf("unable to process job %s: %v", jobInfo.NodeJobRun.Job.Action.Name, err), + } } // Add secrets as string or password in ActionBuild.Args @@ -544,7 +549,7 @@ func (w *CurrentWorker) ProcessJob(jobInfo sdk.WorkflowNodeJobRunData) (sdk.Resu w.currentJob.params = jobParameters - res, err := w.runJob(ctx, &jobInfo.NodeJobRun.Job.Action, jobInfo.NodeJobRun.ID, jobInfo.Secrets) + res = w.runJob(ctx, &jobInfo.NodeJobRun.Job.Action, jobInfo.NodeJobRun.ID, jobInfo.Secrets) if len(res.NewVariables) > 0 { log.Debug("processJob> new variables: %v", res.NewVariables) @@ -563,5 +568,5 @@ func (w *CurrentWorker) ProcessJob(jobInfo sdk.WorkflowNodeJobRunData) (sdk.Resu log.Error(ctx, "Cannot remove basedir content: %s", err) } - return res, err + return res } diff --git a/engine/worker/internal/take.go b/engine/worker/internal/take.go index 46e43b004d..173f4238d3 100644 --- a/engine/worker/internal/take.go +++ b/engine/worker/internal/take.go @@ -82,8 +82,7 @@ func (w *CurrentWorker) Take(ctx context.Context, job sdk.WorkflowNodeJobRun) er }(cancel, job.ID, tick) //Run ! - res, err := w.ProcessJob(*info) - // We keep the err for later usage + res := w.ProcessJob(*info) tick.Stop() res.RemoteTime = time.Now() @@ -92,6 +91,17 @@ func (w *CurrentWorker) Take(ctx context.Context, job sdk.WorkflowNodeJobRun) er //Wait until the logchannel is empty res.BuildID = job.ID + // Send the reason as a spawninfo + if res.Status != sdk.StatusSuccess && res.Reason != "" { + infos := []sdk.SpawnInfo{{ + RemoteTime: time.Now(), + Message: sdk.SpawnMsg{ID: sdk.MsgWorkflowError.ID, Args: []interface{}{res.Reason}}, + }} + if err := w.Client().QueueJobSendSpawnInfo(ctx, job.ID, infos); err != nil { + log.Error(ctx, "processJob> Unable to send spawn info: %v", err) + } + } + var lasterr error for try := 1; try <= 10; try++ { log.Info(ctx, "takeWorkflowJob> Sending build result...") diff --git a/engine/worker/pkg/workerruntime/types.go b/engine/worker/pkg/workerruntime/types.go index 7b794bc1cd..6d07029b67 100644 --- a/engine/worker/pkg/workerruntime/types.go +++ b/engine/worker/pkg/workerruntime/types.go @@ -62,7 +62,7 @@ type Runtime interface { Name() string Register(ctx context.Context) error Take(ctx context.Context, job sdk.WorkflowNodeJobRun) error - ProcessJob(job sdk.WorkflowNodeJobRunData) (sdk.Result, error) + ProcessJob(job sdk.WorkflowNodeJobRunData) sdk.Result SendLog(ctx context.Context, level Level, format string) InstallKey(key sdk.Variable) (*KeyResponse, error) InstallKeyTo(key sdk.Variable, destinationPath string) (*KeyResponse, error) diff --git a/go.mod b/go.mod index 7138e19cea..e17fc68317 100644 --- a/go.mod +++ b/go.mod @@ -169,7 +169,7 @@ require ( github.com/spf13/viper v1.4.0 github.com/streadway/amqp v0.0.0-20180528204448-e5adc2ada8b8 github.com/stretchr/objx v0.2.0 // indirect - github.com/stretchr/testify v1.4.0 + github.com/stretchr/testify v1.5.1 github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect github.com/ugorji/go v1.1.7 // indirect diff --git a/go.sum b/go.sum index 692713148e..aa7f0ca50e 100644 --- a/go.sum +++ b/go.sum @@ -533,6 +533,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 h1:hNna6Fi0eP1f2sMBe/rJicDmaHmoXGe1Ta84FPYHLuE= github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= diff --git a/sdk/interpolate/go.mod b/sdk/interpolate/go.mod index 21d665d2e3..5faf34b277 100644 --- a/sdk/interpolate/go.mod +++ b/sdk/interpolate/go.mod @@ -3,6 +3,7 @@ module github.com/ovh/cds/sdk/interpolate require ( github.com/aokoli/goutils v1.1.0 github.com/huandu/xstrings v1.2.0 + github.com/stretchr/testify v1.5.1 ) go 1.13 diff --git a/sdk/interpolate/go.sum b/sdk/interpolate/go.sum index 9185d7044b..1ca5de0ec1 100644 --- a/sdk/interpolate/go.sum +++ b/sdk/interpolate/go.sum @@ -1,4 +1,14 @@ github.com/aokoli/goutils v1.1.0 h1:jy4ghdcYvs5EIoGssZNslIASX5m+KNMfyyKvRQ0TEVE= github.com/aokoli/goutils v1.1.0/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/sdk/interpolate/interpolate.go b/sdk/interpolate/interpolate.go index 29f3994c6f..480bafd28d 100644 --- a/sdk/interpolate/interpolate.go +++ b/sdk/interpolate/interpolate.go @@ -159,12 +159,12 @@ func Do(input string, vars map[string]string) (string, error) { t, err := template.New("input").Funcs(InterpolateHelperFuncs).Parse(input) if err != nil { - return "", fmt.Errorf("Invalid template format: %s", err.Error()) + return "", fmt.Errorf("invalid template format \"%s\": %s", input, err.Error()) } var buff bytes.Buffer if err := t.Execute(&buff, data); err != nil { - return "", fmt.Errorf("Failed to execute template: %s", err.Error()) + return "", fmt.Errorf("failed to execute template: %s", err.Error()) } return buff.String(), nil