diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 4d571509..41064a62 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -2284,9 +2284,9 @@
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -8737,12 +8737,12 @@
}
},
"globule": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz",
- "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz",
+ "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==",
"requires": {
"glob": "~7.1.1",
- "lodash": "~4.17.10",
+ "lodash": "~4.17.12",
"minimatch": "~3.0.2"
}
},
@@ -12006,9 +12006,9 @@
}
},
"node-sass": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz",
- "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==",
+ "version": "4.13.1",
+ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz",
+ "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==",
"requires": {
"async-foreach": "^0.1.3",
"chalk": "^1.1.1",
@@ -12017,7 +12017,7 @@
"get-stdin": "^4.0.1",
"glob": "^7.0.3",
"in-publish": "^2.0.0",
- "lodash": "^4.17.11",
+ "lodash": "^4.17.15",
"meow": "^3.7.0",
"mkdirp": "^0.5.1",
"nan": "^2.13.2",
@@ -12046,6 +12046,11 @@
"supports-color": "^2.0.0"
}
},
+ "lodash": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+ },
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
@@ -19840,9 +19845,9 @@
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
diff --git a/frontend/package.json b/frontend/package.json
index 13e0fd0c..bbdf37b9 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -76,7 +76,7 @@
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
- "node-sass": "^4.9.0",
+ "node-sass": "^4.13.1",
"sass-loader": "^7.1.0",
"vue-runtime-helpers": "^1.0.1",
"vue-template-compiler": "^2.6.10"
diff --git a/frontend/src/views/pipeline/detail.vue b/frontend/src/views/pipeline/detail.vue
index 4b00bcdd..4156f378 100755
--- a/frontend/src/views/pipeline/detail.vue
+++ b/frontend/src/views/pipeline/detail.vue
@@ -86,6 +86,7 @@
{{ props.row.status }}
{{ calculateDuration(props.row.startdate, props.row.finishdate) }}
+ {{ props.row.started_reason }}
@@ -165,6 +166,10 @@ export default {
label: 'Duration',
field: 'duration'
},
+ {
+ label: 'Reason',
+ field: 'reason'
+ },
{
label: 'Action',
field: 'action'
diff --git a/gaia.go b/gaia.go
index a9345b4b..da7952bc 100644
--- a/gaia.go
+++ b/gaia.go
@@ -139,6 +139,15 @@ const (
// ExecutablePermission is the permission used for gaia created executables.
ExecutablePermission = 0700
+
+ // StartReasonRemote label for pipelines which were triggered through a remote token.
+ StartReasonRemote = "remote"
+
+ // StartReasonManual label for pipelines which were triggered through the admin site.
+ StartReasonManual = "manual"
+
+ // StartReasonScheduled label for pipelines which were triggered automated process, i.e. cron job.
+ StartReasonScheduled = "scheduled"
)
// User is the user object
@@ -254,6 +263,7 @@ type PipelineRun struct {
ID int `json:"id"`
PipelineID int `json:"pipelineid"`
StartDate time.Time `json:"startdate,omitempty"`
+ StartReason string `json:"started_reason"`
FinishDate time.Time `json:"finishdate,omitempty"`
ScheduleDate time.Time `json:"scheduledate,omitempty"`
Status PipelineRunStatus `json:"status,omitempty"`
diff --git a/handlers/pipeline.go b/handlers/pipeline.go
index 7e09a1e8..7b5babba 100644
--- a/handlers/pipeline.go
+++ b/handlers/pipeline.go
@@ -196,7 +196,7 @@ func PipelineUpdate(c echo.Context) error {
// Iterate over all cron schedules.
for _, schedule := range p.PeriodicSchedules {
err := foundPipeline.CronInst.AddFunc(schedule, func() {
- _, err := schedulerService.SchedulePipeline(&foundPipeline, []*gaia.Argument{})
+ _, err := schedulerService.SchedulePipeline(&foundPipeline, gaia.StartReasonScheduled, []*gaia.Argument{})
if err != nil {
gaia.Cfg.Logger.Error("cannot schedule pipeline from periodic schedule", "error", err, "pipeline", foundPipeline)
return
@@ -342,7 +342,7 @@ func PipelineTrigger(c echo.Context) error {
schedulerService, _ := services.SchedulerService()
var args []*gaia.Argument
_ = c.Bind(&args)
- pipelineRun, err := schedulerService.SchedulePipeline(&foundPipeline, args)
+ pipelineRun, err := schedulerService.SchedulePipeline(&foundPipeline, gaia.StartReasonRemote, args)
if err != nil {
return c.String(http.StatusBadRequest, err.Error())
} else if pipelineRun != nil {
@@ -456,7 +456,7 @@ func PipelineStart(c echo.Context) error {
foundPipeline.Docker = docker
if foundPipeline.Name != "" {
- pipelineRun, err := schedulerService.SchedulePipeline(&foundPipeline, args)
+ pipelineRun, err := schedulerService.SchedulePipeline(&foundPipeline, gaia.StartReasonManual, args)
if err != nil {
return c.String(http.StatusBadRequest, err.Error())
} else if pipelineRun != nil {
diff --git a/handlers/pipeline_test.go b/handlers/pipeline_test.go
index 1ea5948e..14bdc851 100644
--- a/handlers/pipeline_test.go
+++ b/handlers/pipeline_test.go
@@ -28,7 +28,7 @@ type mockScheduleService struct {
err error
}
-func (ms *mockScheduleService) SchedulePipeline(p *gaia.Pipeline, args []*gaia.Argument) (*gaia.PipelineRun, error) {
+func (ms *mockScheduleService) SchedulePipeline(p *gaia.Pipeline, startReason string, args []*gaia.Argument) (*gaia.PipelineRun, error) {
return ms.pipelineRun, ms.err
}
@@ -442,7 +442,7 @@ func TestPipelineStart(t *testing.T) {
t.Fatalf("expected response code %v got %v", http.StatusCreated, rec.Code)
}
- expectedBody := `{"uniqueid":"","id":999,"pipelineid":0,"startdate":"0001-01-01T00:00:00Z","finishdate":"0001-01-01T00:00:00Z","scheduledate":"0001-01-01T00:00:00Z"}
+ expectedBody := `{"uniqueid":"","id":999,"pipelineid":0,"startdate":"0001-01-01T00:00:00Z","started_reason":"","finishdate":"0001-01-01T00:00:00Z","scheduledate":"0001-01-01T00:00:00Z"}
`
body, _ := ioutil.ReadAll(rec.Body)
if string(body) != expectedBody {
diff --git a/workers/agent/agent_test.go b/workers/agent/agent_test.go
index c9db855e..978d852f 100644
--- a/workers/agent/agent_test.go
+++ b/workers/agent/agent_test.go
@@ -42,7 +42,7 @@ type mockScheduler struct {
func (ms *mockScheduler) SetPipelineJobs(p *gaia.Pipeline) error { return ms.err }
func (ms *mockScheduler) GetFreeWorkers() int32 { return int32(0) }
-func (ms *mockScheduler) SchedulePipeline(p *gaia.Pipeline, args []*gaia.Argument) (*gaia.PipelineRun, error) {
+func (ms *mockScheduler) SchedulePipeline(p *gaia.Pipeline, startedBy string, args []*gaia.Argument) (*gaia.PipelineRun, error) {
return nil, ms.err
}
diff --git a/workers/pipeline/create_pipeline_test.go b/workers/pipeline/create_pipeline_test.go
index bf8f8392..a89b0118 100644
--- a/workers/pipeline/create_pipeline_test.go
+++ b/workers/pipeline/create_pipeline_test.go
@@ -32,7 +32,7 @@ type mockScheduler struct {
}
func (ms *mockScheduler) Init() {}
-func (ms *mockScheduler) SchedulePipeline(p *gaia.Pipeline, args []*gaia.Argument) (*gaia.PipelineRun, error) {
+func (ms *mockScheduler) SchedulePipeline(p *gaia.Pipeline, startedBy string, args []*gaia.Argument) (*gaia.PipelineRun, error) {
return nil, nil
}
func (ms *mockScheduler) SetPipelineJobs(p *gaia.Pipeline) error { return ms.Error }
diff --git a/workers/pipeline/ticker.go b/workers/pipeline/ticker.go
index 5dd44318..812d4fcd 100644
--- a/workers/pipeline/ticker.go
+++ b/workers/pipeline/ticker.go
@@ -217,7 +217,7 @@ func checkActivePipelines() {
// Iterate over all cron schedules.
for _, schedule := range pipeline.PeriodicSchedules {
err := pipeline.CronInst.AddFunc(schedule, func() {
- _, err := schedulerService.SchedulePipeline(pipeline, []*gaia.Argument{})
+ _, err := schedulerService.SchedulePipeline(pipeline, gaia.StartReasonScheduled, []*gaia.Argument{})
if err != nil {
gaia.Cfg.Logger.Error("cannot schedule pipeline from periodic schedule", "error", err, "pipeline", pipeline)
return
diff --git a/workers/scheduler/scheduler.go b/workers/scheduler/scheduler.go
index 28f56327..0c730f2a 100644
--- a/workers/scheduler/scheduler.go
+++ b/workers/scheduler/scheduler.go
@@ -62,7 +62,7 @@ var (
// GaiaScheduler is a job scheduler for gaia pipeline runs.
type GaiaScheduler interface {
Init()
- SchedulePipeline(p *gaia.Pipeline, args []*gaia.Argument) (*gaia.PipelineRun, error)
+ SchedulePipeline(p *gaia.Pipeline, startedBy string, args []*gaia.Argument) (*gaia.PipelineRun, error)
SetPipelineJobs(p *gaia.Pipeline) error
StopPipelineRun(p *gaia.Pipeline, runID int) error
GetFreeWorkers() int32
@@ -368,7 +368,7 @@ var schedulerLock = sync.RWMutex{}
// SchedulePipeline schedules a pipeline. We create a new schedule object
// and save it in our store. The scheduler will later pick this up and will continue the work.
-func (s *Scheduler) SchedulePipeline(p *gaia.Pipeline, args []*gaia.Argument) (*gaia.PipelineRun, error) {
+func (s *Scheduler) SchedulePipeline(p *gaia.Pipeline, startedReason string, args []*gaia.Argument) (*gaia.PipelineRun, error) {
// Introduce a semaphore locking here because this function can be called
// in parallel if multiple users happen to trigger a pipeline run at the same time.
@@ -443,6 +443,7 @@ func (s *Scheduler) SchedulePipeline(p *gaia.Pipeline, args []*gaia.Argument) (*
PipelineType: p.Type,
PipelineTags: p.Tags,
Docker: p.Docker,
+ StartReason: startedReason,
}
// Put run into store
diff --git a/workers/scheduler/scheduler_test.go b/workers/scheduler/scheduler_test.go
index 9351e1ea..ba7d6dfb 100644
--- a/workers/scheduler/scheduler_test.go
+++ b/workers/scheduler/scheduler_test.go
@@ -407,7 +407,7 @@ func TestSchedulePipeline(t *testing.T) {
t.Fatal(err)
}
s.Init()
- _, err = s.SchedulePipeline(&p, prepareArgs())
+ _, err = s.SchedulePipeline(&p, gaia.StartReasonManual, prepareArgs())
if err != nil {
t.Fatal(err)
}
@@ -453,11 +453,11 @@ func TestSchedulePipelineParallel(t *testing.T) {
var wg sync.WaitGroup
wg.Add(2)
go func() {
- run1, _ = s.SchedulePipeline(&p1, prepareArgs())
+ run1, _ = s.SchedulePipeline(&p1, gaia.StartReasonManual, prepareArgs())
wg.Done()
}()
go func() {
- run2, _ = s.SchedulePipeline(&p2, prepareArgs())
+ run2, _ = s.SchedulePipeline(&p2, gaia.StartReasonManual, prepareArgs())
wg.Done()
}()
wg.Wait()
@@ -488,7 +488,7 @@ func TestSchedule(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- _, err = s.SchedulePipeline(&p, prepareArgs())
+ _, err = s.SchedulePipeline(&p, gaia.StartReasonManual, prepareArgs())
if err != nil {
t.Fatal(err)
}