diff options
author | Harrison Healey <harrisonmhealey@gmail.com> | 2017-05-18 15:05:57 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-18 15:05:57 -0400 |
commit | 577ed27f1bb060080d311342047e31943a02ccbb (patch) | |
tree | ad57fa69b1daf143e914ea2480a475e5450cc236 /api4 | |
parent | 920bc0d8712a50691b1f698779f60132536eb214 (diff) | |
download | chat-577ed27f1bb060080d311342047e31943a02ccbb.tar.gz chat-577ed27f1bb060080d311342047e31943a02ccbb.tar.bz2 chat-577ed27f1bb060080d311342047e31943a02ccbb.zip |
PLT-6408 Framework for job server (#6404)
* Added initial job server
* Added job server to be ran as part of platform
* Added test job to the enterprise repo
* Fixed job server not loading license
* Renamed job package to jobs
* Fixed TE not being buildable
* Added JobStatus table to database
* Changed fields used by JobStatus
* Added APIs to query job status
* Added config change listener to server
* Added option to run job server from Makefile
* Added ability to enable/disable jobs from config
* Commented out placeholder for search indexing job
* Fixed govet
* Removed debug messages and fixed job api init message
Diffstat (limited to 'api4')
-rw-r--r-- | api4/api.go | 4 | ||||
-rw-r--r-- | api4/context.go | 22 | ||||
-rw-r--r-- | api4/job.go | 57 | ||||
-rw-r--r-- | api4/job_test.go | 103 | ||||
-rw-r--r-- | api4/params.go | 10 |
5 files changed, 196 insertions, 0 deletions
diff --git a/api4/api.go b/api4/api.go index 4ed636593..a636581d7 100644 --- a/api4/api.go +++ b/api4/api.go @@ -81,6 +81,8 @@ type Routes struct { System *mux.Router // 'api/v4/system' + Jobs *mux.Router // 'api/v4/jobs' + Preferences *mux.Router // 'api/v4/users/{user_id:[A-Za-z0-9]+}/preferences' License *mux.Router // 'api/v4/license' @@ -168,6 +170,7 @@ func InitApi(full bool) { BaseRoutes.License = BaseRoutes.ApiRoot.PathPrefix("/license").Subrouter() BaseRoutes.Public = BaseRoutes.ApiRoot.PathPrefix("/public").Subrouter() BaseRoutes.Reactions = BaseRoutes.ApiRoot.PathPrefix("/reactions").Subrouter() + BaseRoutes.Jobs = BaseRoutes.ApiRoot.PathPrefix("/jobs").Subrouter() BaseRoutes.Emojis = BaseRoutes.ApiRoot.PathPrefix("/emoji").Subrouter() BaseRoutes.Emoji = BaseRoutes.Emojis.PathPrefix("/{emoji_id:[A-Za-z0-9]+}").Subrouter() @@ -191,6 +194,7 @@ func InitApi(full bool) { InitCluster() InitLdap() InitBrand() + InitJob() InitCommand() InitStatus() InitWebSocket() diff --git a/api4/context.go b/api4/context.go index 37af2c6d4..8d4ed7f79 100644 --- a/api4/context.go +++ b/api4/context.go @@ -540,3 +540,25 @@ func (c *Context) RequireCommandId() *Context { } return c } + +func (c *Context) RequireJobId() *Context { + if c.Err != nil { + return c + } + + if len(c.Params.JobId) != 26 { + c.SetInvalidUrlParam("job_id") + } + return c +} + +func (c *Context) RequireJobType() *Context { + if c.Err != nil { + return c + } + + if len(c.Params.JobType) == 0 || len(c.Params.JobType) > 32 { + c.SetInvalidUrlParam("job_type") + } + return c +} diff --git a/api4/job.go b/api4/job.go new file mode 100644 index 000000000..8610d9e74 --- /dev/null +++ b/api4/job.go @@ -0,0 +1,57 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package api4 + +import ( + "net/http" + + l4g "github.com/alecthomas/log4go" + "github.com/mattermost/platform/app" + "github.com/mattermost/platform/model" +) + +func InitJob() { + l4g.Info("Initializing job API routes") + + BaseRoutes.Jobs.Handle("/type/{job_type:[A-Za-z0-9_-]+}/statuses", ApiSessionRequired(getJobStatusesByType)).Methods("GET") + BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/status", ApiSessionRequired(getJobStatus)).Methods("GET") +} + +func getJobStatus(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireJobId() + if c.Err != nil { + return + } + + if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { + c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + return + } + + if status, err := app.GetJobStatus(c.Params.JobId); err != nil { + c.Err = err + return + } else { + w.Write([]byte(status.ToJson())) + } +} + +func getJobStatusesByType(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireJobType() + if c.Err != nil { + return + } + + if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { + c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + return + } + + if statuses, err := app.GetJobStatusesByTypePage(c.Params.JobType, c.Params.Page, c.Params.PerPage); err != nil { + c.Err = err + return + } else { + w.Write([]byte(model.JobStatusesToJson(statuses))) + } +} diff --git a/api4/job_test.go b/api4/job_test.go new file mode 100644 index 000000000..0f39fc306 --- /dev/null +++ b/api4/job_test.go @@ -0,0 +1,103 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package api4 + +import ( + "strings" + "testing" + + "github.com/mattermost/platform/app" + "github.com/mattermost/platform/model" + "github.com/mattermost/platform/store" +) + +func TestGetJobStatus(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + + status := &model.JobStatus{ + Id: model.NewId(), + Status: model.NewId(), + } + if result := <-app.Srv.Store.JobStatus().SaveOrUpdate(status); result.Err != nil { + t.Fatal(result.Err) + } + + defer app.Srv.Store.JobStatus().Delete(status.Id) + + received, resp := th.SystemAdminClient.GetJobStatus(status.Id) + CheckNoError(t, resp) + + if received.Id != status.Id || received.Status != status.Status { + t.Fatal("incorrect job status received") + } + + _, resp = th.SystemAdminClient.GetJobStatus("1234") + CheckBadRequestStatus(t, resp) + + _, resp = th.Client.GetJobStatus(status.Id) + CheckForbiddenStatus(t, resp) + + _, resp = th.SystemAdminClient.GetJobStatus(model.NewId()) + CheckNotFoundStatus(t, resp) +} + +func TestGetJobStatusesByType(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + + jobType := model.NewId() + + statuses := []*model.JobStatus{ + { + Id: model.NewId(), + Type: jobType, + StartAt: 1000, + }, + { + Id: model.NewId(), + Type: jobType, + StartAt: 999, + }, + { + Id: model.NewId(), + Type: jobType, + StartAt: 1001, + }, + } + + for _, status := range statuses { + store.Must(app.Srv.Store.JobStatus().SaveOrUpdate(status)) + defer app.Srv.Store.JobStatus().Delete(status.Id) + } + + received, resp := th.SystemAdminClient.GetJobStatusesByType(jobType, 0, 2) + CheckNoError(t, resp) + + if len(received) != 2 { + t.Fatal("received wrong number of statuses") + } else if received[0].Id != statuses[1].Id { + t.Fatal("should've received newest job first") + } else if received[1].Id != statuses[0].Id { + t.Fatal("should've received second newest job second") + } + + received, resp = th.SystemAdminClient.GetJobStatusesByType(jobType, 1, 2) + CheckNoError(t, resp) + + if len(received) != 1 { + t.Fatal("received wrong number of statuses") + } else if received[0].Id != statuses[2].Id { + t.Fatal("should've received oldest job last") + } + + _, resp = th.SystemAdminClient.GetJobStatusesByType("", 0, 60) + CheckNotFoundStatus(t, resp) + + _, resp = th.SystemAdminClient.GetJobStatusesByType(strings.Repeat("a", 33), 0, 60) + CheckBadRequestStatus(t, resp) + + _, resp = th.Client.GetJobStatusesByType(jobType, 0, 60) + CheckForbiddenStatus(t, resp) +} diff --git a/api4/params.go b/api4/params.go index 785b2267b..aa865fd2a 100644 --- a/api4/params.go +++ b/api4/params.go @@ -35,6 +35,8 @@ type ApiParams struct { EmojiName string Category string Service string + JobId string + JobType string Page int PerPage int } @@ -116,6 +118,14 @@ func ApiParamsFromRequest(r *http.Request) *ApiParams { params.EmojiName = val } + if val, ok := props["job_id"]; ok { + params.JobId = val + } + + if val, ok := props["job_type"]; ok { + params.JobType = val + } + if val, err := strconv.Atoi(r.URL.Query().Get("page")); err != nil || val < 0 { params.Page = PAGE_DEFAULT } else { |