[MM-56074] mmctl job commands (#26855)
* add job list and update job status command to mmctl
Этот коммит содержится в:
@@ -25,7 +25,17 @@
|
|||||||
description: The number of jobs per page.
|
description: The number of jobs per page.
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
default: 60
|
default: 5
|
||||||
|
- name: job_type
|
||||||
|
in: query
|
||||||
|
description: The type of jobs to fetch.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: status
|
||||||
|
in: query
|
||||||
|
description: The status of jobs to fetch.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Job list retrieval successful
|
description: Job list retrieval successful
|
||||||
@@ -223,3 +233,51 @@
|
|||||||
$ref: "#/components/responses/Unauthorized"
|
$ref: "#/components/responses/Unauthorized"
|
||||||
"403":
|
"403":
|
||||||
$ref: "#/components/responses/Forbidden"
|
$ref: "#/components/responses/Forbidden"
|
||||||
|
"/api/v4/jobs/{job_id}/status":
|
||||||
|
patch:
|
||||||
|
tags:
|
||||||
|
- jobs
|
||||||
|
summary: Update the status of a job
|
||||||
|
description: >
|
||||||
|
Update the status of a job. Valid status updates:
|
||||||
|
- 'in_progress' -> 'pending'
|
||||||
|
- 'in_progress' | 'pending' -> 'cancel_requested'
|
||||||
|
- 'cancel_requested' -> 'canceled'
|
||||||
|
|
||||||
|
Add force to the body of the PATCH request to bypass the given rules, the only statuses you can go to are: pending, cancel_requested and canceled. This can have unexpected consequences and should be used with caution.
|
||||||
|
operationId: UpdateJobStatus
|
||||||
|
parameters:
|
||||||
|
- name: job_id
|
||||||
|
in: path
|
||||||
|
description: Job GUID
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
description: The status you want to set
|
||||||
|
force:
|
||||||
|
type: boolean
|
||||||
|
description: Set this to true to bypass status restrictions
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Status successfully set.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/StatusOK"
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/BadRequest"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/Forbidden"
|
||||||
|
|||||||
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
@@ -23,6 +23,7 @@ func (api *API) InitJob() {
|
|||||||
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/download", api.APISessionRequiredTrustRequester(downloadJob)).Methods("GET")
|
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/download", api.APISessionRequiredTrustRequester(downloadJob)).Methods("GET")
|
||||||
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/cancel", api.APISessionRequired(cancelJob)).Methods("POST")
|
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/cancel", api.APISessionRequired(cancelJob)).Methods("POST")
|
||||||
api.BaseRoutes.Jobs.Handle("/type/{job_type:[A-Za-z0-9_-]+}", api.APISessionRequired(getJobsByType)).Methods("GET")
|
api.BaseRoutes.Jobs.Handle("/type/{job_type:[A-Za-z0-9_-]+}", api.APISessionRequired(getJobsByType)).Methods("GET")
|
||||||
|
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/status", api.APISessionRequired(updateJobStatus)).Methods("PATCH")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getJob(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getJob(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -147,23 +148,58 @@ func getJobs(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jobType := r.URL.Query().Get("job_type")
|
||||||
var validJobTypes []string
|
var validJobTypes []string
|
||||||
for _, jobType := range model.AllJobTypes {
|
|
||||||
|
if jobType != "" {
|
||||||
|
isValidJobType := model.IsValidJobType(jobType)
|
||||||
|
if !isValidJobType {
|
||||||
|
c.SetInvalidURLParam("job_type")
|
||||||
|
return
|
||||||
|
}
|
||||||
hasPermission, permissionRequired := c.App.SessionHasPermissionToReadJob(*c.AppContext.Session(), jobType)
|
hasPermission, permissionRequired := c.App.SessionHasPermissionToReadJob(*c.AppContext.Session(), jobType)
|
||||||
if permissionRequired == nil {
|
if permissionRequired == nil {
|
||||||
c.Logger.Warn("The job types of a job you are trying to retrieve does not contain permissions", mlog.String("jobType", jobType))
|
c.Err = model.NewAppError("getJobsByType", "api.job.retrieve.nopermissions", nil, "", http.StatusBadRequest)
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
if hasPermission {
|
if !hasPermission {
|
||||||
validJobTypes = append(validJobTypes, jobType)
|
c.SetPermissionError(permissionRequired)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
validJobTypes = append(validJobTypes, jobType)
|
||||||
|
} else {
|
||||||
|
for _, jType := range model.AllJobTypes {
|
||||||
|
hasPermission, permissionRequired := c.App.SessionHasPermissionToReadJob(*c.AppContext.Session(), jType)
|
||||||
|
if permissionRequired == nil {
|
||||||
|
c.Logger.Warn("The job types of a job you are trying to retrieve does not contain permissions", mlog.String("jobType", jType))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if hasPermission {
|
||||||
|
validJobTypes = append(validJobTypes, jType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(validJobTypes) == 0 {
|
if len(validJobTypes) == 0 {
|
||||||
c.SetPermissionError()
|
c.SetPermissionError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jobs, appErr := c.App.GetJobsByTypesPage(c.AppContext, validJobTypes, c.Params.Page, c.Params.PerPage)
|
status := r.URL.Query().Get("status")
|
||||||
|
isValidStatus := model.IsValidJobStatus(status)
|
||||||
|
if status != "" && !isValidStatus {
|
||||||
|
c.Err = model.NewAppError("getJobs", "api.job.status.invalid", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
var jobs []*model.Job
|
||||||
|
var appErr *model.AppError
|
||||||
|
|
||||||
|
if status == "" {
|
||||||
|
jobs, appErr = c.App.GetJobsByTypesPage(c.AppContext, validJobTypes, c.Params.Page, c.Params.PerPage)
|
||||||
|
} else {
|
||||||
|
jobs, appErr = c.App.GetJobsByTypeAndStatus(c.AppContext, validJobTypes, status, c.Params.Page, c.Params.PerPage)
|
||||||
|
}
|
||||||
|
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
c.Err = appErr
|
c.Err = appErr
|
||||||
return
|
return
|
||||||
@@ -248,3 +284,60 @@ func cancelJob(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
ReturnStatusOK(w)
|
ReturnStatusOK(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateJobStatus(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireJobId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("updateJobStatus", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
audit.AddEventParameter(auditRec, "job_id", c.Params.JobId)
|
||||||
|
|
||||||
|
props := model.StringInterfaceFromJSON(r.Body)
|
||||||
|
status, ok := props["status"].(string)
|
||||||
|
if !ok {
|
||||||
|
c.SetInvalidParam("status")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
force, ok := props["force"].(bool)
|
||||||
|
if !ok {
|
||||||
|
force = false
|
||||||
|
}
|
||||||
|
|
||||||
|
job, err := c.App.GetJob(c.AppContext, c.Params.JobId)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.AddEventPriorState(job)
|
||||||
|
auditRec.AddEventObjectType("job")
|
||||||
|
|
||||||
|
hasPermission, permissionRequired := c.App.SessionHasPermissionToManageJob(*c.AppContext.Session(), job)
|
||||||
|
if permissionRequired == nil {
|
||||||
|
c.Err = model.NewAppError("updateJobStatus", "api.job.unable_to_manage_job.incorrect_job_type", nil, "", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasPermission {
|
||||||
|
c.SetPermissionError(permissionRequired)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !force && !job.IsValidStatusChange(status) {
|
||||||
|
c.Err = model.NewAppError("updateJobStatus", "api.job.status.invalid", nil, "", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.App.UpdateJobStatus(c.AppContext, job, status); err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
|
||||||
|
ReturnStatusOK(w)
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ func (api *API) InitJobLocal() {
|
|||||||
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}", api.APILocal(getJob)).Methods("GET")
|
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}", api.APILocal(getJob)).Methods("GET")
|
||||||
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/cancel", api.APILocal(cancelJob)).Methods("POST")
|
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/cancel", api.APILocal(cancelJob)).Methods("POST")
|
||||||
api.BaseRoutes.Jobs.Handle("/type/{job_type:[A-Za-z0-9_-]+}", api.APILocal(getJobsByType)).Methods("GET")
|
api.BaseRoutes.Jobs.Handle("/type/{job_type:[A-Za-z0-9_-]+}", api.APILocal(getJobsByType)).Methods("GET")
|
||||||
|
api.BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/status", api.APILocal(updateJobStatus)).Methods("PATCH")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ func TestGetJobs(t *testing.T) {
|
|||||||
Type: jobType,
|
Type: jobType,
|
||||||
CreateAt: t0 + 2,
|
CreateAt: t0 + 2,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: model.JobTypeLdapSync,
|
||||||
|
CreateAt: t0 + 3,
|
||||||
|
Status: model.JobStatusPending,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, job := range jobs {
|
for _, job := range jobs {
|
||||||
@@ -110,21 +116,47 @@ func TestGetJobs(t *testing.T) {
|
|||||||
defer th.App.Srv().Store().Job().Delete(job.Id)
|
defer th.App.Srv().Store().Job().Delete(job.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
received, _, err := th.SystemAdminClient.GetJobs(context.Background(), 0, 2)
|
t.Run("Get 2 jobs", func(t *testing.T) {
|
||||||
require.NoError(t, err)
|
received, _, err := th.SystemAdminClient.GetJobs(context.Background(), "", "", 0, 2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Len(t, received, 2, "received wrong number of jobs")
|
require.Len(t, received, 2, "received wrong number of jobs")
|
||||||
require.Equal(t, jobs[2].Id, received[0].Id, "should've received newest job first")
|
require.Equal(t, jobs[3].Id, received[0].Id, "should've received newest job first")
|
||||||
require.Equal(t, jobs[0].Id, received[1].Id, "should've received second newest job second")
|
require.Equal(t, jobs[2].Id, received[1].Id, "should've received second newest job second")
|
||||||
|
})
|
||||||
|
|
||||||
received, _, err = th.SystemAdminClient.GetJobs(context.Background(), 1, 2)
|
t.Run("Get oldest job using paging", func(t *testing.T) {
|
||||||
require.NoError(t, err)
|
received, _, err := th.SystemAdminClient.GetJobs(context.Background(), "", "", 1, 3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, jobs[1].Id, received[0].Id, "should've received oldest job last")
|
||||||
|
})
|
||||||
|
|
||||||
require.Equal(t, jobs[1].Id, received[0].Id, "should've received oldest job last")
|
t.Run("Return error fetching job without permissions", func(t *testing.T) {
|
||||||
|
_, resp, err := th.Client.GetJobs(context.Background(), "", "", 0, 60)
|
||||||
|
require.Error(t, err)
|
||||||
|
CheckForbiddenStatus(t, resp)
|
||||||
|
})
|
||||||
|
|
||||||
_, resp, err := th.Client.GetJobs(context.Background(), 0, 60)
|
t.Run("Get job by type", func(t *testing.T) {
|
||||||
require.Error(t, err)
|
received, _, err := th.SystemAdminClient.GetJobs(context.Background(), model.JobTypeLdapSync, "", 0, 3)
|
||||||
CheckForbiddenStatus(t, resp)
|
require.NoError(t, err)
|
||||||
|
require.Len(t, received, 1, "received wrong number of jobs")
|
||||||
|
require.Equal(t, jobs[3].Id, received[0].Id, "should've received the ldap sync job")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get job by status", func(t *testing.T) {
|
||||||
|
received, _, err := th.SystemAdminClient.GetJobs(context.Background(), "", model.JobStatusPending, 0, 3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, received, 1, "received wrong number of jobs")
|
||||||
|
require.Equal(t, jobs[3].Id, received[0].Id, "should've received the ldap sync job")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get job by type and status", func(t *testing.T) {
|
||||||
|
received, _, err := th.SystemAdminClient.GetJobs(context.Background(), model.JobTypeLdapSync, model.JobStatusPending, 0, 3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, received, 1, "received wrong number of jobs")
|
||||||
|
require.Equal(t, jobs[3].Id, received[0].Id, "should've received the ldap sync job")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetJobsByType(t *testing.T) {
|
func TestGetJobsByType(t *testing.T) {
|
||||||
@@ -336,3 +368,69 @@ func TestCancelJob(t *testing.T) {
|
|||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
CheckNotFoundStatus(t, resp)
|
CheckNotFoundStatus(t, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateJobStatus(t *testing.T) {
|
||||||
|
th := Setup(t)
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
jobType := model.JobTypeDataRetention
|
||||||
|
jobs := []*model.Job{
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: jobType,
|
||||||
|
Status: model.JobStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: jobType,
|
||||||
|
Status: model.JobStatusInProgress,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: jobType,
|
||||||
|
Status: model.JobStatusSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: jobType,
|
||||||
|
Status: model.JobStatusPending,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, job := range jobs {
|
||||||
|
_, err := th.App.Srv().Store().Job().Save(job)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer th.App.Srv().Store().Job().Delete(job.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Fail to update job status without permission", func(t *testing.T) {
|
||||||
|
resp, err := th.Client.UpdateJobStatus(context.Background(), jobs[0].Id, model.JobStatusCancelRequested, false)
|
||||||
|
require.Error(t, err)
|
||||||
|
CheckForbiddenStatus(t, resp)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Change a pending job to cancel requested without force with sysadmin client", func(t *testing.T) {
|
||||||
|
_, err := th.SystemAdminClient.UpdateJobStatus(context.Background(), jobs[0].Id, model.JobStatusCancelRequested, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Change a pending job to cancel requested without force with local client", func(t *testing.T) {
|
||||||
|
_, err := th.LocalClient.UpdateJobStatus(context.Background(), jobs[3].Id, model.JobStatusCancelRequested, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Fail to change a pending job to canceled without force", func(t *testing.T) {
|
||||||
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
||||||
|
resp, err := client.UpdateJobStatus(context.Background(), jobs[0].Id, model.JobStatusCanceled, false)
|
||||||
|
require.Error(t, err)
|
||||||
|
CheckBadRequestStatus(t, resp)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Change a pending job to canceled with force", func(t *testing.T) {
|
||||||
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
||||||
|
_, err := client.UpdateJobStatus(context.Background(), jobs[0].Id, model.JobStatusCanceled, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -720,6 +720,7 @@ type AppIface interface {
|
|||||||
GetIncomingWebhooksPageByUser(userID string, page, perPage int) ([]*model.IncomingWebhook, *model.AppError)
|
GetIncomingWebhooksPageByUser(userID string, page, perPage int) ([]*model.IncomingWebhook, *model.AppError)
|
||||||
GetJob(c request.CTX, id string) (*model.Job, *model.AppError)
|
GetJob(c request.CTX, id string) (*model.Job, *model.AppError)
|
||||||
GetJobsByType(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, *model.AppError)
|
GetJobsByType(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, *model.AppError)
|
||||||
|
GetJobsByTypeAndStatus(c request.CTX, jobTypes []string, status string, page int, perPage int) ([]*model.Job, *model.AppError)
|
||||||
GetJobsByTypePage(c request.CTX, jobType string, page int, perPage int) ([]*model.Job, *model.AppError)
|
GetJobsByTypePage(c request.CTX, jobType string, page int, perPage int) ([]*model.Job, *model.AppError)
|
||||||
GetJobsByTypes(c request.CTX, jobTypes []string, offset int, limit int) ([]*model.Job, *model.AppError)
|
GetJobsByTypes(c request.CTX, jobTypes []string, offset int, limit int) ([]*model.Job, *model.AppError)
|
||||||
GetJobsByTypesPage(c request.CTX, jobType []string, page int, perPage int) ([]*model.Job, *model.AppError)
|
GetJobsByTypesPage(c request.CTX, jobType []string, page int, perPage int) ([]*model.Job, *model.AppError)
|
||||||
@@ -1099,6 +1100,7 @@ type AppIface interface {
|
|||||||
SessionHasPermissionToChannelByPost(session model.Session, postID string, permission *model.Permission) bool
|
SessionHasPermissionToChannelByPost(session model.Session, postID string, permission *model.Permission) bool
|
||||||
SessionHasPermissionToCreateJob(session model.Session, job *model.Job) (bool, *model.Permission)
|
SessionHasPermissionToCreateJob(session model.Session, job *model.Job) (bool, *model.Permission)
|
||||||
SessionHasPermissionToGroup(session model.Session, groupID string, permission *model.Permission) bool
|
SessionHasPermissionToGroup(session model.Session, groupID string, permission *model.Permission) bool
|
||||||
|
SessionHasPermissionToManageJob(session model.Session, job *model.Job) (bool, *model.Permission)
|
||||||
SessionHasPermissionToReadJob(session model.Session, jobType string) (bool, *model.Permission)
|
SessionHasPermissionToReadJob(session model.Session, jobType string) (bool, *model.Permission)
|
||||||
SessionHasPermissionToTeam(session model.Session, teamID string, permission *model.Permission) bool
|
SessionHasPermissionToTeam(session model.Session, teamID string, permission *model.Permission) bool
|
||||||
SessionHasPermissionToUser(session model.Session, userID string) bool
|
SessionHasPermissionToUser(session model.Session, userID string) bool
|
||||||
@@ -1173,6 +1175,7 @@ type AppIface interface {
|
|||||||
UpdateHashedPassword(user *model.User, newHashedPassword string) *model.AppError
|
UpdateHashedPassword(user *model.User, newHashedPassword string) *model.AppError
|
||||||
UpdateHashedPasswordByUserId(userID, newHashedPassword string) *model.AppError
|
UpdateHashedPasswordByUserId(userID, newHashedPassword string) *model.AppError
|
||||||
UpdateIncomingWebhook(oldHook, updatedHook *model.IncomingWebhook) (*model.IncomingWebhook, *model.AppError)
|
UpdateIncomingWebhook(oldHook, updatedHook *model.IncomingWebhook) (*model.IncomingWebhook, *model.AppError)
|
||||||
|
UpdateJobStatus(c request.CTX, job *model.Job, newStatus string) *model.AppError
|
||||||
UpdateMfa(c request.CTX, activate bool, userID, token string) *model.AppError
|
UpdateMfa(c request.CTX, activate bool, userID, token string) *model.AppError
|
||||||
UpdateMobileAppBadge(userID string)
|
UpdateMobileAppBadge(userID string)
|
||||||
UpdateOAuthApp(oldApp, updatedApp *model.OAuthApp) (*model.OAuthApp, *model.AppError)
|
UpdateOAuthApp(oldApp, updatedApp *model.OAuthApp) (*model.OAuthApp, *model.AppError)
|
||||||
|
|||||||
@@ -52,6 +52,14 @@ func (a *App) GetJobsByTypes(c request.CTX, jobTypes []string, offset int, limit
|
|||||||
return jobs, nil
|
return jobs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) GetJobsByTypeAndStatus(c request.CTX, jobTypes []string, status string, page int, perPage int) ([]*model.Job, *model.AppError) {
|
||||||
|
jobs, err := a.Srv().Store().Job().GetAllByTypeAndStatusPage(c, jobTypes, status, page*perPage, perPage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("GetAllByTypeAndStatusPage", "app.job.get_all.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
|
}
|
||||||
|
return jobs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) CreateJob(c request.CTX, job *model.Job) (*model.Job, *model.AppError) {
|
func (a *App) CreateJob(c request.CTX, job *model.Job) (*model.Job, *model.AppError) {
|
||||||
return a.Srv().Jobs.CreateJob(c, job.Type, job.Data)
|
return a.Srv().Jobs.CreateJob(c, job.Type, job.Data)
|
||||||
}
|
}
|
||||||
@@ -60,6 +68,19 @@ func (a *App) CancelJob(c request.CTX, jobId string) *model.AppError {
|
|||||||
return a.Srv().Jobs.RequestCancellation(c, jobId)
|
return a.Srv().Jobs.RequestCancellation(c, jobId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) UpdateJobStatus(c request.CTX, job *model.Job, newStatus string) *model.AppError {
|
||||||
|
switch newStatus {
|
||||||
|
case model.JobStatusPending:
|
||||||
|
return a.Srv().Jobs.SetJobPending(job)
|
||||||
|
case model.JobStatusCancelRequested:
|
||||||
|
return a.Srv().Jobs.RequestCancellation(c, job.Id)
|
||||||
|
case model.JobStatusCanceled:
|
||||||
|
return a.Srv().Jobs.SetJobCanceled(job)
|
||||||
|
default:
|
||||||
|
return model.NewAppError("UpdateJobStatus", "app.job.update_status.app_error", nil, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) SessionHasPermissionToCreateJob(session model.Session, job *model.Job) (bool, *model.Permission) {
|
func (a *App) SessionHasPermissionToCreateJob(session model.Session, job *model.Job) (bool, *model.Permission) {
|
||||||
switch job.Type {
|
switch job.Type {
|
||||||
case model.JobTypeBlevePostIndexing:
|
case model.JobTypeBlevePostIndexing:
|
||||||
@@ -92,6 +113,44 @@ func (a *App) SessionHasPermissionToCreateJob(session model.Session, job *model.
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) SessionHasPermissionToManageJob(session model.Session, job *model.Job) (bool, *model.Permission) {
|
||||||
|
var permission *model.Permission
|
||||||
|
|
||||||
|
switch job.Type {
|
||||||
|
case model.JobTypeBlevePostIndexing:
|
||||||
|
permission = model.PermissionManagePostBleveIndexesJob
|
||||||
|
case model.JobTypeDataRetention:
|
||||||
|
permission = model.PermissionManageDataRetentionJob
|
||||||
|
case model.JobTypeMessageExport:
|
||||||
|
permission = model.PermissionManageComplianceExportJob
|
||||||
|
case model.JobTypeElasticsearchPostIndexing:
|
||||||
|
permission = model.PermissionManageElasticsearchPostIndexingJob
|
||||||
|
case model.JobTypeElasticsearchPostAggregation:
|
||||||
|
permission = model.PermissionManageElasticsearchPostAggregationJob
|
||||||
|
case model.JobTypeLdapSync:
|
||||||
|
permission = model.PermissionManageLdapSyncJob
|
||||||
|
case
|
||||||
|
model.JobTypeMigrations,
|
||||||
|
model.JobTypePlugins,
|
||||||
|
model.JobTypeProductNotices,
|
||||||
|
model.JobTypeExpiryNotify,
|
||||||
|
model.JobTypeActiveUsers,
|
||||||
|
model.JobTypeImportProcess,
|
||||||
|
model.JobTypeImportDelete,
|
||||||
|
model.JobTypeExportProcess,
|
||||||
|
model.JobTypeExportDelete,
|
||||||
|
model.JobTypeCloud,
|
||||||
|
model.JobTypeExtractContent:
|
||||||
|
permission = model.PermissionManageJobs
|
||||||
|
}
|
||||||
|
|
||||||
|
if permission == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.SessionHasPermissionTo(session, permission), permission
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) SessionHasPermissionToReadJob(session model.Session, jobType string) (bool, *model.Permission) {
|
func (a *App) SessionHasPermissionToReadJob(session model.Session, jobType string) (bool, *model.Permission) {
|
||||||
switch jobType {
|
switch jobType {
|
||||||
case model.JobTypeDataRetention:
|
case model.JobTypeDataRetention:
|
||||||
|
|||||||
@@ -7308,6 +7308,28 @@ func (a *OpenTracingAppLayer) GetJobsByType(c request.CTX, jobType string, offse
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) GetJobsByTypeAndStatus(c request.CTX, jobTypes []string, status string, page int, perPage int) ([]*model.Job, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetJobsByTypeAndStatus")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store().SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store().SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.GetJobsByTypeAndStatus(c, jobTypes, status, page, perPage)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) GetJobsByTypePage(c request.CTX, jobType string, page int, perPage int) ([]*model.Job, *model.AppError) {
|
func (a *OpenTracingAppLayer) GetJobsByTypePage(c request.CTX, jobType string, page int, perPage int) ([]*model.Job, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetJobsByTypePage")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetJobsByTypePage")
|
||||||
@@ -16316,6 +16338,23 @@ func (a *OpenTracingAppLayer) SessionHasPermissionToManageBot(rctx request.CTX,
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) SessionHasPermissionToManageJob(session model.Session, job *model.Job) (bool, *model.Permission) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToManageJob")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store().SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store().SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.SessionHasPermissionToManageJob(session, job)
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) SessionHasPermissionToReadJob(session model.Session, jobType string) (bool, *model.Permission) {
|
func (a *OpenTracingAppLayer) SessionHasPermissionToReadJob(session model.Session, jobType string) (bool, *model.Permission) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToReadJob")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToReadJob")
|
||||||
@@ -18083,6 +18122,28 @@ func (a *OpenTracingAppLayer) UpdateIncomingWebhook(oldHook *model.IncomingWebho
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) UpdateJobStatus(c request.CTX, job *model.Job, newStatus string) *model.AppError {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateJobStatus")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store().SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store().SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.UpdateJobStatus(c, job, newStatus)
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) UpdateMfa(c request.CTX, activate bool, userID string, token string) *model.AppError {
|
func (a *OpenTracingAppLayer) UpdateMfa(c request.CTX, activate bool, userID string, token string) *model.AppError {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateMfa")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateMfa")
|
||||||
|
|||||||
@@ -1181,6 +1181,40 @@ func (a *App) getAddChannelBookmarksPermissionsMigration() (permissionsMap, erro
|
|||||||
return transformations, nil
|
return transformations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) getAddManageJobAncillaryPermissionsMigration() (permissionsMap, error) {
|
||||||
|
transformations := []permissionTransformation{}
|
||||||
|
|
||||||
|
transformations = append(transformations, permissionTransformation{
|
||||||
|
On: permissionExists(model.PermissionSysconsoleWriteAuthenticationLdap.Id),
|
||||||
|
Add: []string{model.PermissionManageLdapSyncJob.Id},
|
||||||
|
})
|
||||||
|
|
||||||
|
transformations = append(transformations, permissionTransformation{
|
||||||
|
On: permissionExists(model.PermissionSysconsoleWriteComplianceDataRetentionPolicy.Id),
|
||||||
|
Add: []string{model.PermissionManageDataRetentionJob.Id},
|
||||||
|
})
|
||||||
|
|
||||||
|
transformations = append(transformations, permissionTransformation{
|
||||||
|
On: permissionExists(model.PermissionSysconsoleWriteExperimentalBleve.Id),
|
||||||
|
Add: []string{model.PermissionManagePostBleveIndexesJob.Id},
|
||||||
|
})
|
||||||
|
|
||||||
|
transformations = append(transformations, permissionTransformation{
|
||||||
|
On: permissionExists(model.PermissionSysconsoleWriteComplianceComplianceExport.Id),
|
||||||
|
Add: []string{model.PermissionManageComplianceExportJob.Id},
|
||||||
|
})
|
||||||
|
|
||||||
|
transformations = append(transformations, permissionTransformation{
|
||||||
|
On: permissionExists(model.PermissionSysconsoleWriteEnvironmentElasticsearch.Id),
|
||||||
|
Add: []string{
|
||||||
|
model.PermissionManageElasticsearchPostIndexingJob.Id,
|
||||||
|
model.PermissionManageElasticsearchPostAggregationJob.Id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return transformations, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DoPermissionsMigrations execute all the permissions migrations need by the current version.
|
// DoPermissionsMigrations execute all the permissions migrations need by the current version.
|
||||||
func (a *App) DoPermissionsMigrations() error {
|
func (a *App) DoPermissionsMigrations() error {
|
||||||
return a.Srv().doPermissionsMigrations()
|
return a.Srv().doPermissionsMigrations()
|
||||||
@@ -1228,6 +1262,7 @@ func (s *Server) doPermissionsMigrations() error {
|
|||||||
{Key: model.MigrationKeyAddIPFilteringPermissions, Migration: a.getAddIPFilterPermissionsMigration},
|
{Key: model.MigrationKeyAddIPFilteringPermissions, Migration: a.getAddIPFilterPermissionsMigration},
|
||||||
{Key: model.MigrationKeyAddOutgoingOAuthConnectionsPermissions, Migration: a.getAddOutgoingOAuthConnectionsPermissions},
|
{Key: model.MigrationKeyAddOutgoingOAuthConnectionsPermissions, Migration: a.getAddOutgoingOAuthConnectionsPermissions},
|
||||||
{Key: model.MigrationKeyAddChannelBookmarksPermissions, Migration: a.getAddChannelBookmarksPermissionsMigration},
|
{Key: model.MigrationKeyAddChannelBookmarksPermissions, Migration: a.getAddChannelBookmarksPermissionsMigration},
|
||||||
|
{Key: model.MigrationKeyAddManageJobAncillaryPermissions, Migration: a.getAddManageJobAncillaryPermissionsMigration},
|
||||||
}
|
}
|
||||||
|
|
||||||
roles, err := s.Store().Role().GetAll()
|
roles, err := s.Store().Role().GetAll()
|
||||||
|
|||||||
@@ -5212,6 +5212,24 @@ func (s *OpenTracingLayerJobStore) GetAllByTypeAndStatus(c request.CTX, jobType
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerJobStore) GetAllByTypeAndStatusPage(c request.CTX, jobType []string, status string, offset int, limit int) ([]*model.Job, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "JobStore.GetAllByTypeAndStatusPage")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
result, err := s.JobStore.GetAllByTypeAndStatusPage(c, jobType, status, offset, limit)
|
||||||
|
if err != nil {
|
||||||
|
span.LogFields(spanlog.Error(err))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerJobStore) GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error) {
|
func (s *OpenTracingLayerJobStore) GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "JobStore.GetAllByTypePage")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "JobStore.GetAllByTypePage")
|
||||||
|
|||||||
@@ -5903,6 +5903,27 @@ func (s *RetryLayerJobStore) GetAllByTypeAndStatus(c request.CTX, jobType string
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RetryLayerJobStore) GetAllByTypeAndStatusPage(c request.CTX, jobType []string, status string, offset int, limit int) ([]*model.Job, error) {
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
|
result, err := s.JobStore.GetAllByTypeAndStatusPage(c, jobType, status, offset, limit)
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
if !isRepeatableError(err) {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= 3 {
|
||||||
|
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
timepkg.Sleep(100 * timepkg.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *RetryLayerJobStore) GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error) {
|
func (s *RetryLayerJobStore) GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
|
|||||||
@@ -316,6 +316,26 @@ func (jss SqlJobStore) GetAllByStatus(c request.CTX, status string) ([]*model.Jo
|
|||||||
return statuses, nil
|
return statuses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (jss SqlJobStore) GetAllByTypeAndStatusPage(c request.CTX, jobType []string, status string, offset int, limit int) ([]*model.Job, error) {
|
||||||
|
query, args, err := jss.getQueryBuilder().
|
||||||
|
Select("*").
|
||||||
|
From("Jobs").
|
||||||
|
Where(sq.Eq{"Type": jobType, "Status": status}).
|
||||||
|
OrderBy("CreateAt DESC").
|
||||||
|
Limit(uint64(limit)).
|
||||||
|
Offset(uint64(offset)).ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "job_tosql")
|
||||||
|
}
|
||||||
|
|
||||||
|
jobs := []*model.Job{}
|
||||||
|
if err = jss.GetReplicaX().Select(&jobs, query, args...); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to find Jobs with type=%s and status=%s", strings.Join(jobType, ","), status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (jss SqlJobStore) GetNewestJobByStatusAndType(status string, jobType string) (*model.Job, error) {
|
func (jss SqlJobStore) GetNewestJobByStatusAndType(status string, jobType string) (*model.Job, error) {
|
||||||
return jss.GetNewestJobByStatusesAndType([]string{status}, jobType)
|
return jss.GetNewestJobByStatusesAndType([]string{status}, jobType)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -761,6 +761,7 @@ type JobStore interface {
|
|||||||
GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error)
|
GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error)
|
||||||
GetAllByTypesPage(c request.CTX, jobTypes []string, offset int, limit int) ([]*model.Job, error)
|
GetAllByTypesPage(c request.CTX, jobTypes []string, offset int, limit int) ([]*model.Job, error)
|
||||||
GetAllByStatus(c request.CTX, status string) ([]*model.Job, error)
|
GetAllByStatus(c request.CTX, status string) ([]*model.Job, error)
|
||||||
|
GetAllByTypeAndStatusPage(c request.CTX, jobType []string, status string, offset int, limit int) ([]*model.Job, error)
|
||||||
GetNewestJobByStatusAndType(status string, jobType string) (*model.Job, error)
|
GetNewestJobByStatusAndType(status string, jobType string) (*model.Job, error)
|
||||||
GetNewestJobByStatusesAndType(statuses []string, jobType string) (*model.Job, error)
|
GetNewestJobByStatusesAndType(statuses []string, jobType string) (*model.Job, error)
|
||||||
GetCountByStatusAndType(status string, jobType string) (int64, error)
|
GetCountByStatusAndType(status string, jobType string) (int64, error)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ func TestJobStore(t *testing.T, rctx request.CTX, ss store.Store) {
|
|||||||
t.Run("JobGetAllByTypeAndStatus", func(t *testing.T) { testJobGetAllByTypeAndStatus(t, rctx, ss) })
|
t.Run("JobGetAllByTypeAndStatus", func(t *testing.T) { testJobGetAllByTypeAndStatus(t, rctx, ss) })
|
||||||
t.Run("JobGetAllByTypePage", func(t *testing.T) { testJobGetAllByTypePage(t, rctx, ss) })
|
t.Run("JobGetAllByTypePage", func(t *testing.T) { testJobGetAllByTypePage(t, rctx, ss) })
|
||||||
t.Run("JobGetAllByTypesPage", func(t *testing.T) { testJobGetAllByTypesPage(t, rctx, ss) })
|
t.Run("JobGetAllByTypesPage", func(t *testing.T) { testJobGetAllByTypesPage(t, rctx, ss) })
|
||||||
|
t.Run("JobGetAllByTypeAndStatusPage", func(t *testing.T) { testJobGetAllByTypeAndStatusPage(t, rctx, ss) })
|
||||||
t.Run("JobGetAllByStatus", func(t *testing.T) { testJobGetAllByStatus(t, rctx, ss) })
|
t.Run("JobGetAllByStatus", func(t *testing.T) { testJobGetAllByStatus(t, rctx, ss) })
|
||||||
t.Run("GetNewestJobByStatusAndType", func(t *testing.T) { testJobStoreGetNewestJobByStatusAndType(t, rctx, ss) })
|
t.Run("GetNewestJobByStatusAndType", func(t *testing.T) { testJobStoreGetNewestJobByStatusAndType(t, rctx, ss) })
|
||||||
t.Run("GetNewestJobByStatusesAndType", func(t *testing.T) { testJobStoreGetNewestJobByStatusesAndType(t, rctx, ss) })
|
t.Run("GetNewestJobByStatusesAndType", func(t *testing.T) { testJobStoreGetNewestJobByStatusesAndType(t, rctx, ss) })
|
||||||
@@ -259,6 +260,62 @@ func testJobGetAllByTypesPage(t *testing.T, rctx request.CTX, ss store.Store) {
|
|||||||
require.Equal(t, received[0].Id, jobs[1].Id, "should've received oldest job last")
|
require.Equal(t, received[0].Id, jobs[1].Id, "should've received oldest job last")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testJobGetAllByTypeAndStatusPage(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||||
|
jobType := model.NewId()
|
||||||
|
jobType2 := model.NewId()
|
||||||
|
t0 := model.GetMillis()
|
||||||
|
|
||||||
|
jobs := []*model.Job{
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: jobType,
|
||||||
|
Status: model.JobStatusPending,
|
||||||
|
CreateAt: t0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: jobType,
|
||||||
|
Status: model.JobStatusPending,
|
||||||
|
CreateAt: t0 + 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: jobType2,
|
||||||
|
Status: model.JobStatusCanceled,
|
||||||
|
CreateAt: t0 + 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: jobType2,
|
||||||
|
Status: model.JobStatusCanceled,
|
||||||
|
CreateAt: t0 + 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, job := range jobs {
|
||||||
|
_, err := ss.Job().Save(job)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer ss.Job().Delete(job.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
jobTypes := []string{jobType, jobType2}
|
||||||
|
received, err := ss.Job().GetAllByTypeAndStatusPage(rctx, jobTypes, model.JobStatusPending, 0, 4)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, received, 2)
|
||||||
|
require.Equal(t, received[0].Id, jobs[1].Id, "should've received newest job first")
|
||||||
|
require.Equal(t, received[1].Id, jobs[0].Id, "should've received oldest job last")
|
||||||
|
|
||||||
|
received, err = ss.Job().GetAllByTypeAndStatusPage(rctx, jobTypes, model.JobStatusPending, 1, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, received, 1)
|
||||||
|
require.Equal(t, received[0].Id, jobs[0].Id, "should've received the oldest pending job")
|
||||||
|
|
||||||
|
received, err = ss.Job().GetAllByTypeAndStatusPage(rctx, []string{jobType2}, model.JobStatusCanceled, 1, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, received, 1)
|
||||||
|
require.Equal(t, received[0].Id, jobs[2].Id, "should've received the oldest canceled job")
|
||||||
|
}
|
||||||
|
|
||||||
func testJobGetAllByStatus(t *testing.T, rctx request.CTX, ss store.Store) {
|
func testJobGetAllByStatus(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||||
jobType := model.NewId()
|
jobType := model.NewId()
|
||||||
status := model.NewId()
|
status := model.NewId()
|
||||||
|
|||||||
@@ -181,6 +181,36 @@ func (_m *JobStore) GetAllByTypeAndStatus(c request.CTX, jobType string, status
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllByTypeAndStatusPage provides a mock function with given fields: c, jobType, status, offset, limit
|
||||||
|
func (_m *JobStore) GetAllByTypeAndStatusPage(c request.CTX, jobType []string, status string, offset int, limit int) ([]*model.Job, error) {
|
||||||
|
ret := _m.Called(c, jobType, status, offset, limit)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GetAllByTypeAndStatusPage")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Job
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, []string, string, int, int) ([]*model.Job, error)); ok {
|
||||||
|
return rf(c, jobType, status, offset, limit)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, []string, string, int, int) []*model.Job); ok {
|
||||||
|
r0 = rf(c, jobType, status, offset, limit)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Job)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, []string, string, int, int) error); ok {
|
||||||
|
r1 = rf(c, jobType, status, offset, limit)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetAllByTypePage provides a mock function with given fields: c, jobType, offset, limit
|
// GetAllByTypePage provides a mock function with given fields: c, jobType, offset, limit
|
||||||
func (_m *JobStore) GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error) {
|
func (_m *JobStore) GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error) {
|
||||||
ret := _m.Called(c, jobType, offset, limit)
|
ret := _m.Called(c, jobType, offset, limit)
|
||||||
|
|||||||
@@ -4731,6 +4731,22 @@ func (s *TimerLayerJobStore) GetAllByTypeAndStatus(c request.CTX, jobType string
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerJobStore) GetAllByTypeAndStatusPage(c request.CTX, jobType []string, status string, offset int, limit int) ([]*model.Job, error) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
result, err := s.JobStore.GetAllByTypeAndStatusPage(c, jobType, status, offset, limit)
|
||||||
|
|
||||||
|
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if err == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("JobStore.GetAllByTypeAndStatusPage", success, elapsed)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerJobStore) GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error) {
|
func (s *TimerLayerJobStore) GetAllByTypePage(c request.CTX, jobType string, offset int, limit int) ([]*model.Job, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ func GetMockStoreForSetupFunctions() *mocks.Store {
|
|||||||
systemStore.On("GetByName", model.MigrationKeyAddIPFilteringPermissions).Return(&model.System{Name: model.MigrationKeyAddIPFilteringPermissions, Value: "true"}, nil)
|
systemStore.On("GetByName", model.MigrationKeyAddIPFilteringPermissions).Return(&model.System{Name: model.MigrationKeyAddIPFilteringPermissions, Value: "true"}, nil)
|
||||||
systemStore.On("GetByName", model.MigrationKeyAddOutgoingOAuthConnectionsPermissions).Return(&model.System{Name: model.MigrationKeyAddOutgoingOAuthConnectionsPermissions, Value: "true"}, nil)
|
systemStore.On("GetByName", model.MigrationKeyAddOutgoingOAuthConnectionsPermissions).Return(&model.System{Name: model.MigrationKeyAddOutgoingOAuthConnectionsPermissions, Value: "true"}, nil)
|
||||||
systemStore.On("GetByName", model.MigrationKeyAddChannelBookmarksPermissions).Return(&model.System{Name: model.MigrationKeyAddChannelBookmarksPermissions, Value: "true"}, nil)
|
systemStore.On("GetByName", model.MigrationKeyAddChannelBookmarksPermissions).Return(&model.System{Name: model.MigrationKeyAddChannelBookmarksPermissions, Value: "true"}, nil)
|
||||||
|
systemStore.On("GetByName", model.MigrationKeyAddManageJobAncillaryPermissions).Return(&model.System{Name: model.MigrationKeyAddManageJobAncillaryPermissions, Value: "true"}, nil)
|
||||||
systemStore.On("GetByName", "CustomGroupAdminRoleCreationMigrationComplete").Return(&model.System{Name: model.MigrationKeyAddPlayboosksManageRolesPermissions, Value: "true"}, nil)
|
systemStore.On("GetByName", "CustomGroupAdminRoleCreationMigrationComplete").Return(&model.System{Name: model.MigrationKeyAddPlayboosksManageRolesPermissions, Value: "true"}, nil)
|
||||||
systemStore.On("GetByName", "products_boards").Return(&model.System{Name: "products_boards", Value: "true"}, nil)
|
systemStore.On("GetByName", "products_boards").Return(&model.System{Name: "products_boards", Value: "true"}, nil)
|
||||||
systemStore.On("GetByName", "elasticsearch_fix_channel_index_migration").Return(&model.System{Name: "elasticsearch_fix_channel_index_migration", Value: "true"}, nil)
|
systemStore.On("GetByName", "elasticsearch_fix_channel_index_migration").Return(&model.System{Name: "elasticsearch_fix_channel_index_migration", Value: "true"}, nil)
|
||||||
|
|||||||
@@ -128,10 +128,11 @@ type Client interface {
|
|||||||
UploadData(ctx context.Context, uploadID string, data io.Reader) (*model.FileInfo, *model.Response, error)
|
UploadData(ctx context.Context, uploadID string, data io.Reader) (*model.FileInfo, *model.Response, error)
|
||||||
ListImports(ctx context.Context) ([]string, *model.Response, error)
|
ListImports(ctx context.Context) ([]string, *model.Response, error)
|
||||||
GetJob(ctx context.Context, id string) (*model.Job, *model.Response, error)
|
GetJob(ctx context.Context, id string) (*model.Job, *model.Response, error)
|
||||||
GetJobs(ctx context.Context, page int, perPage int) ([]*model.Job, *model.Response, error)
|
GetJobs(ctx context.Context, jobType string, status string, page int, perPage int) ([]*model.Job, *model.Response, error)
|
||||||
GetJobsByType(ctx context.Context, jobType string, page int, perPage int) ([]*model.Job, *model.Response, error)
|
GetJobsByType(ctx context.Context, jobType string, page int, perPage int) ([]*model.Job, *model.Response, error)
|
||||||
CreateJob(ctx context.Context, job *model.Job) (*model.Job, *model.Response, error)
|
CreateJob(ctx context.Context, job *model.Job) (*model.Job, *model.Response, error)
|
||||||
CancelJob(ctx context.Context, jobID string) (*model.Response, error)
|
CancelJob(ctx context.Context, jobID string) (*model.Response, error)
|
||||||
|
UpdateJobStatus(ctx context.Context, jobId string, status string, force bool) (*model.Response, error)
|
||||||
CreateIncomingWebhook(ctx context.Context, hook *model.IncomingWebhook) (*model.IncomingWebhook, *model.Response, error)
|
CreateIncomingWebhook(ctx context.Context, hook *model.IncomingWebhook) (*model.IncomingWebhook, *model.Response, error)
|
||||||
UpdateIncomingWebhook(ctx context.Context, hook *model.IncomingWebhook) (*model.IncomingWebhook, *model.Response, error)
|
UpdateIncomingWebhook(ctx context.Context, hook *model.IncomingWebhook) (*model.IncomingWebhook, *model.Response, error)
|
||||||
GetIncomingWebhooks(ctx context.Context, page int, perPage int, etag string) ([]*model.IncomingWebhook, *model.Response, error)
|
GetIncomingWebhooks(ctx context.Context, page int, perPage int, etag string) ([]*model.IncomingWebhook, *model.Response, error)
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ func exportDownloadCmdF(c client.Client, command *cobra.Command, args []string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func exportJobListCmdF(c client.Client, command *cobra.Command, args []string) error {
|
func exportJobListCmdF(c client.Client, command *cobra.Command, args []string) error {
|
||||||
return jobListCmdF(c, command, model.JobTypeExportProcess)
|
return jobListCmdF(c, command, model.JobTypeExportProcess, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportJobShowCmdF(c client.Client, command *cobra.Command, args []string) error {
|
func exportJobShowCmdF(c client.Client, command *cobra.Command, args []string) error {
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ func extractJobShowCmdF(c client.Client, command *cobra.Command, args []string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func extractJobListCmdF(c client.Client, command *cobra.Command, args []string) error {
|
func extractJobListCmdF(c client.Client, command *cobra.Command, args []string) error {
|
||||||
return jobListCmdF(c, command, model.JobTypeExtractContent)
|
return jobListCmdF(c, command, model.JobTypeExtractContent, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func printExtractContentJob(job *model.Job) {
|
func printExtractContentJob(job *model.Job) {
|
||||||
|
|||||||
@@ -308,24 +308,6 @@ func importProcessCmdF(c client.Client, command *cobra.Command, args []string) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func printJob(job *model.Job) {
|
|
||||||
if job.StartAt > 0 {
|
|
||||||
printer.PrintT(fmt.Sprintf(` ID: {{.Id}}
|
|
||||||
Status: {{.Status}}
|
|
||||||
Created: %s
|
|
||||||
Started: %s
|
|
||||||
Data: {{.Data}}
|
|
||||||
`,
|
|
||||||
time.Unix(job.CreateAt/1000, 0), time.Unix(job.StartAt/1000, 0)), job)
|
|
||||||
} else {
|
|
||||||
printer.PrintT(fmt.Sprintf(` ID: {{.Id}}
|
|
||||||
Status: {{.Status}}
|
|
||||||
Created: %s
|
|
||||||
`,
|
|
||||||
time.Unix(job.CreateAt/1000, 0)), job)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func importJobShowCmdF(c client.Client, command *cobra.Command, args []string) error {
|
func importJobShowCmdF(c client.Client, command *cobra.Command, args []string) error {
|
||||||
job, _, err := c.GetJob(context.TODO(), args[0])
|
job, _, err := c.GetJob(context.TODO(), args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -337,53 +319,8 @@ func importJobShowCmdF(c client.Client, command *cobra.Command, args []string) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func jobListCmdF(c client.Client, command *cobra.Command, jobType string) error {
|
|
||||||
page, err := command.Flags().GetInt("page")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
perPage, err := command.Flags().GetInt("per-page")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
showAll, err := command.Flags().GetBool("all")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if showAll {
|
|
||||||
page = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
jobs, _, err := c.GetJobsByType(context.TODO(), jobType, page, perPage)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get jobs: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(jobs) == 0 {
|
|
||||||
if !showAll || page == 0 {
|
|
||||||
printer.Print("No jobs found")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, job := range jobs {
|
|
||||||
printJob(job)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !showAll {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
page++
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func importJobListCmdF(c client.Client, command *cobra.Command, args []string) error {
|
func importJobListCmdF(c client.Client, command *cobra.Command, args []string) error {
|
||||||
return jobListCmdF(c, command, model.JobTypeImportProcess)
|
return jobListCmdF(c, command, model.JobTypeImportProcess, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
type Statistics struct {
|
type Statistics struct {
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ func (s *MmctlUnitTestSuite) TestImportJobListCmdF() {
|
|||||||
|
|
||||||
s.client.
|
s.client.
|
||||||
EXPECT().
|
EXPECT().
|
||||||
GetJobsByType(context.TODO(), model.JobTypeImportProcess, 0, perPage).
|
GetJobs(context.TODO(), model.JobTypeImportProcess, "", 0, perPage).
|
||||||
Return(mockJobs, &model.Response{}, nil).
|
Return(mockJobs, &model.Response{}, nil).
|
||||||
Times(1)
|
Times(1)
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ func (s *MmctlUnitTestSuite) TestImportJobListCmdF() {
|
|||||||
|
|
||||||
s.client.
|
s.client.
|
||||||
EXPECT().
|
EXPECT().
|
||||||
GetJobsByType(context.TODO(), model.JobTypeImportProcess, 0, perPage).
|
GetJobs(context.TODO(), model.JobTypeImportProcess, "", 0, perPage).
|
||||||
Return(mockJobs, &model.Response{}, nil).
|
Return(mockJobs, &model.Response{}, nil).
|
||||||
Times(1)
|
Times(1)
|
||||||
|
|
||||||
|
|||||||
202
server/cmd/mmctl/commands/job.go
Обычный файл
202
server/cmd/mmctl/commands/job.go
Обычный файл
@@ -0,0 +1,202 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
|
"github.com/mattermost/mattermost/server/v8/cmd/mmctl/client"
|
||||||
|
"github.com/mattermost/mattermost/server/v8/cmd/mmctl/printer"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var JobCmd = &cobra.Command{
|
||||||
|
Use: "job",
|
||||||
|
Short: "Management of jobs",
|
||||||
|
}
|
||||||
|
|
||||||
|
var listJobsCmd = &cobra.Command{
|
||||||
|
Use: "list",
|
||||||
|
Short: "List the latest jobs",
|
||||||
|
Example: ` job list
|
||||||
|
job list --ids jobID1,jobID2
|
||||||
|
job list --type ldap_sync --status success
|
||||||
|
job list --type ldap_sync --status success --page 0 --per-page 10`,
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
RunE: withClient(listJobsCmdF),
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateJobCmd = &cobra.Command{
|
||||||
|
Use: "update [job] [status]",
|
||||||
|
Short: "Update the status of a job",
|
||||||
|
Long: `Update the status of a job. The following restrictions are in place:
|
||||||
|
- in_progress -> pending
|
||||||
|
- in_progress | pending -> cancel_requested
|
||||||
|
- cancel_requested -> canceled
|
||||||
|
|
||||||
|
Those restriction can be bypassed with --force=true but the only statuses you can go to are: pending, cancel_requested and canceled. This can have unexpected consequences and should be used with caution.`,
|
||||||
|
Example: ` job update myJobID pending
|
||||||
|
job update myJobID pending --force true
|
||||||
|
job update myJobID canceled --force true`,
|
||||||
|
Args: cobra.MinimumNArgs(2),
|
||||||
|
RunE: withClient(updateJobCmdF),
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
listJobsCmd.Flags().Int("page", 0, "Page number to fetch for the list of import jobs")
|
||||||
|
listJobsCmd.Flags().Int("per-page", 5, "Number of import jobs to be fetched")
|
||||||
|
listJobsCmd.Flags().Bool("all", false, "Fetch all import jobs. --page flag will be ignored if provided")
|
||||||
|
listJobsCmd.Flags().StringSlice("ids", nil, "Comma-separated list of job IDs to which the operation will be applied. All other flags are ignored")
|
||||||
|
listJobsCmd.Flags().String("status", "", "Filter by job status")
|
||||||
|
listJobsCmd.Flags().String("type", "", "Filter by job type")
|
||||||
|
|
||||||
|
updateJobCmd.Flags().Bool("force", false, "Setting a job status is restricted to certain statuses. You can overwrite these restrictions by using --force. This might cause unexpected behaviour on your Mattermost Server. Use this option with caution.")
|
||||||
|
|
||||||
|
JobCmd.AddCommand(
|
||||||
|
listJobsCmd,
|
||||||
|
updateJobCmd,
|
||||||
|
)
|
||||||
|
|
||||||
|
RootCmd.AddCommand(JobCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listJobsCmdF(c client.Client, cmd *cobra.Command, args []string) error {
|
||||||
|
ids, err := cmd.Flags().GetStringSlice("ids")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
jobType, err := cmd.Flags().GetString("type")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
status, err := cmd.Flags().GetString("status")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ids) > 0 {
|
||||||
|
jobs := make([]*model.Job, 0, len(ids))
|
||||||
|
var result *multierror.Error
|
||||||
|
for _, id := range ids {
|
||||||
|
isValidId := model.IsValidId(id)
|
||||||
|
if !isValidId {
|
||||||
|
result = multierror.Append(result, fmt.Errorf("invalid job ID: %s", id))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
job, _, err := c.GetJob(context.TODO(), id)
|
||||||
|
if err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
jobs = append(jobs, job)
|
||||||
|
}
|
||||||
|
for _, job := range jobs {
|
||||||
|
printJob(job)
|
||||||
|
}
|
||||||
|
return result.ErrorOrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobListCmdF(c, cmd, jobType, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateJobCmdF(c client.Client, cmd *cobra.Command, args []string) error {
|
||||||
|
force, err := cmd.Flags().GetBool("force")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
jobId := args[0]
|
||||||
|
if !model.IsValidId(jobId) {
|
||||||
|
return fmt.Errorf("invalid job ID: %s", jobId)
|
||||||
|
}
|
||||||
|
status := args[1]
|
||||||
|
if !model.IsValidJobStatus(status) {
|
||||||
|
return fmt.Errorf("invalid job status: %s", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.UpdateJobStatus(context.TODO(), jobId, status, force)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func jobListCmdF(c client.Client, command *cobra.Command, jobType string, status string) error {
|
||||||
|
page, err := command.Flags().GetInt("page")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
perPage, err := command.Flags().GetInt("per-page")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
showAll, err := command.Flags().GetBool("all")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if showAll {
|
||||||
|
page = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if jobType != "" && !model.IsValidJobType(jobType) {
|
||||||
|
return fmt.Errorf("invalid job type: %s", jobType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != "" && !model.IsValidJobStatus(status) {
|
||||||
|
return fmt.Errorf("invalid job status: %s", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
jobs, _, err := c.GetJobs(context.TODO(), jobType, status, page, perPage)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get jobs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(jobs) == 0 {
|
||||||
|
if !showAll || page == 0 {
|
||||||
|
printer.Print("No jobs found")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, job := range jobs {
|
||||||
|
printJob(job)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !showAll {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
page++
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printJob(job *model.Job) {
|
||||||
|
if job.StartAt > 0 {
|
||||||
|
printer.PrintT(fmt.Sprintf(` ID: {{.Id}}
|
||||||
|
Type: {{.Type}}
|
||||||
|
Status: {{.Status}}
|
||||||
|
Created: %s
|
||||||
|
Started: %s
|
||||||
|
Data: {{.Data}}
|
||||||
|
`,
|
||||||
|
time.Unix(job.CreateAt/1000, 0), time.Unix(job.StartAt/1000, 0)), job)
|
||||||
|
} else {
|
||||||
|
printer.PrintT(fmt.Sprintf(` ID: {{.Id}}
|
||||||
|
Status: {{.Status}}
|
||||||
|
Created: %s
|
||||||
|
`,
|
||||||
|
time.Unix(job.CreateAt/1000, 0)), job)
|
||||||
|
}
|
||||||
|
}
|
||||||
204
server/cmd/mmctl/commands/job_test.go
Обычный файл
204
server/cmd/mmctl/commands/job_test.go
Обычный файл
@@ -0,0 +1,204 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost/server/v8/cmd/mmctl/printer"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *MmctlUnitTestSuite) TestListJobsCmdF() {
|
||||||
|
s.Run("no jobs found", func() {
|
||||||
|
printer.Clean()
|
||||||
|
var mockJobs []*model.Job
|
||||||
|
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
perPage := 10
|
||||||
|
cmd.Flags().Int("page", 0, "")
|
||||||
|
cmd.Flags().Int("per-page", perPage, "")
|
||||||
|
cmd.Flags().Bool("all", false, "")
|
||||||
|
cmd.Flags().StringSlice("ids", []string{}, "")
|
||||||
|
cmd.Flags().String("status", "", "")
|
||||||
|
cmd.Flags().String("type", "", "")
|
||||||
|
|
||||||
|
s.client.
|
||||||
|
EXPECT().
|
||||||
|
GetJobs(context.TODO(), "", "", 0, perPage).
|
||||||
|
Return(mockJobs, &model.Response{}, nil).
|
||||||
|
Times(1)
|
||||||
|
|
||||||
|
err := listJobsCmdF(s.client, cmd, nil)
|
||||||
|
s.Require().Nil(err)
|
||||||
|
s.Len(printer.GetLines(), 1)
|
||||||
|
s.Empty(printer.GetErrorLines())
|
||||||
|
s.Equal("No jobs found", printer.GetLines()[0])
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Run("3 jobs found", func() {
|
||||||
|
printer.Clean()
|
||||||
|
mockJobs := []*model.Job{
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
perPage := 3
|
||||||
|
cmd.Flags().Int("page", 0, "")
|
||||||
|
cmd.Flags().Int("per-page", perPage, "")
|
||||||
|
cmd.Flags().Bool("all", false, "")
|
||||||
|
cmd.Flags().StringSlice("ids", []string{}, "")
|
||||||
|
cmd.Flags().String("status", "", "")
|
||||||
|
cmd.Flags().String("type", "", "")
|
||||||
|
|
||||||
|
s.client.
|
||||||
|
EXPECT().
|
||||||
|
GetJobs(context.TODO(), "", "", 0, perPage).
|
||||||
|
Return(mockJobs, &model.Response{}, nil).
|
||||||
|
Times(1)
|
||||||
|
|
||||||
|
err := listJobsCmdF(s.client, cmd, nil)
|
||||||
|
s.Require().Nil(err)
|
||||||
|
s.Len(printer.GetLines(), len(mockJobs))
|
||||||
|
s.Empty(printer.GetErrorLines())
|
||||||
|
for i, line := range printer.GetLines() {
|
||||||
|
s.Equal(mockJobs[i], line.(*model.Job))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Run("return 1 job using ids flag", func() {
|
||||||
|
printer.Clean()
|
||||||
|
id := model.NewId()
|
||||||
|
mockJob := &model.Job{
|
||||||
|
Id: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
perPage := 3
|
||||||
|
cmd.Flags().Int("page", 0, "")
|
||||||
|
cmd.Flags().Int("per-page", perPage, "")
|
||||||
|
cmd.Flags().Bool("all", false, "")
|
||||||
|
cmd.Flags().StringSlice("ids", []string{id}, "")
|
||||||
|
cmd.Flags().String("status", "", "")
|
||||||
|
cmd.Flags().String("type", "", "")
|
||||||
|
|
||||||
|
s.client.
|
||||||
|
EXPECT().
|
||||||
|
GetJob(context.TODO(), id).
|
||||||
|
Return(mockJob, &model.Response{}, nil).
|
||||||
|
Times(1)
|
||||||
|
|
||||||
|
err := listJobsCmdF(s.client, cmd, nil)
|
||||||
|
s.Require().Nil(err)
|
||||||
|
s.Len(printer.GetLines(), 1)
|
||||||
|
s.Empty(printer.GetErrorLines())
|
||||||
|
for _, line := range printer.GetLines() {
|
||||||
|
s.Equal(mockJob, line.(*model.Job))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Run("return 2 jobs by status", func() {
|
||||||
|
printer.Clean()
|
||||||
|
mockJobs := []*model.Job{
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Status: model.JobStatusSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Status: model.JobStatusSuccess,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
perPage := 2
|
||||||
|
cmd.Flags().Int("page", 0, "")
|
||||||
|
cmd.Flags().Int("per-page", perPage, "")
|
||||||
|
cmd.Flags().Bool("all", false, "")
|
||||||
|
cmd.Flags().String("status", model.JobStatusSuccess, "")
|
||||||
|
cmd.Flags().StringSlice("ids", []string{}, "")
|
||||||
|
cmd.Flags().String("type", "", "")
|
||||||
|
|
||||||
|
s.client.
|
||||||
|
EXPECT().
|
||||||
|
GetJobs(context.TODO(), "", model.JobStatusSuccess, 0, perPage).
|
||||||
|
Return(mockJobs, &model.Response{}, nil).
|
||||||
|
Times(1)
|
||||||
|
|
||||||
|
err := listJobsCmdF(s.client, cmd, nil)
|
||||||
|
s.Require().Nil(err)
|
||||||
|
s.Len(printer.GetLines(), len(mockJobs))
|
||||||
|
s.Empty(printer.GetErrorLines())
|
||||||
|
for i, line := range printer.GetLines() {
|
||||||
|
s.Equal(mockJobs[i], line.(*model.Job))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Run("return 2 jobs by type", func() {
|
||||||
|
printer.Clean()
|
||||||
|
mockJobs := []*model.Job{
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: model.JobTypeDataRetention,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Type: model.JobTypeDataRetention,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
perPage := 2
|
||||||
|
cmd.Flags().Int("page", 0, "")
|
||||||
|
cmd.Flags().Int("per-page", perPage, "")
|
||||||
|
cmd.Flags().Bool("all", false, "")
|
||||||
|
cmd.Flags().String("type", model.JobTypeDataRetention, "")
|
||||||
|
cmd.Flags().StringSlice("ids", []string{}, "")
|
||||||
|
cmd.Flags().String("status", "", "")
|
||||||
|
|
||||||
|
s.client.
|
||||||
|
EXPECT().
|
||||||
|
GetJobs(context.TODO(), model.JobTypeDataRetention, "", 0, perPage).
|
||||||
|
Return(mockJobs, &model.Response{}, nil).
|
||||||
|
Times(1)
|
||||||
|
|
||||||
|
err := listJobsCmdF(s.client, cmd, nil)
|
||||||
|
s.Require().Nil(err)
|
||||||
|
s.Len(printer.GetLines(), len(mockJobs))
|
||||||
|
s.Empty(printer.GetErrorLines())
|
||||||
|
for i, line := range printer.GetLines() {
|
||||||
|
s.Equal(mockJobs[i], line.(*model.Job))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MmctlUnitTestSuite) TestUpdateJobCmdF() {
|
||||||
|
s.Run("update job status", func() {
|
||||||
|
printer.Clean()
|
||||||
|
id := model.NewId()
|
||||||
|
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.Flags().Bool("force", true, "")
|
||||||
|
|
||||||
|
s.client.
|
||||||
|
EXPECT().
|
||||||
|
UpdateJobStatus(context.TODO(), id, model.JobStatusPending, true).
|
||||||
|
Return(&model.Response{}, nil).
|
||||||
|
Times(1)
|
||||||
|
|
||||||
|
err := updateJobCmdF(s.client, cmd, []string{id, model.JobStatusPending})
|
||||||
|
s.Require().Nil(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -121,7 +121,7 @@ func ldapIDMigrateCmdF(c client.Client, cmd *cobra.Command, args []string) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ldapJobListCmdF(c client.Client, command *cobra.Command, args []string) error {
|
func ldapJobListCmdF(c client.Client, command *cobra.Command, args []string) error {
|
||||||
return jobListCmdF(c, command, model.JobTypeLdapSync)
|
return jobListCmdF(c, command, model.JobTypeLdapSync, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ldapJobShowCmdF(c client.Client, command *cobra.Command, args []string) error {
|
func ldapJobShowCmdF(c client.Client, command *cobra.Command, args []string) error {
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ func (s *MmctlUnitTestSuite) TestLdapJobListCmdF() {
|
|||||||
|
|
||||||
s.client.
|
s.client.
|
||||||
EXPECT().
|
EXPECT().
|
||||||
GetJobsByType(context.TODO(), model.JobTypeLdapSync, 0, perPage).
|
GetJobs(context.TODO(), model.JobTypeLdapSync, "", 0, perPage).
|
||||||
Return(mockJobs, &model.Response{}, nil).
|
Return(mockJobs, &model.Response{}, nil).
|
||||||
Times(1)
|
Times(1)
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ func (s *MmctlUnitTestSuite) TestLdapJobListCmdF() {
|
|||||||
|
|
||||||
s.client.
|
s.client.
|
||||||
EXPECT().
|
EXPECT().
|
||||||
GetJobsByType(context.TODO(), model.JobTypeLdapSync, 0, perPage).
|
GetJobs(context.TODO(), model.JobTypeLdapSync, "", 0, perPage).
|
||||||
Return(mockJobs, &model.Response{}, nil).
|
Return(mockJobs, &model.Response{}, nil).
|
||||||
Times(1)
|
Times(1)
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ SEE ALSO
|
|||||||
* `mmctl group <mmctl_group.rst>`_ - Management of groups
|
* `mmctl group <mmctl_group.rst>`_ - Management of groups
|
||||||
* `mmctl import <mmctl_import.rst>`_ - Management of imports
|
* `mmctl import <mmctl_import.rst>`_ - Management of imports
|
||||||
* `mmctl integrity <mmctl_integrity.rst>`_ - Check database records integrity.
|
* `mmctl integrity <mmctl_integrity.rst>`_ - Check database records integrity.
|
||||||
|
* `mmctl job <mmctl_job.rst>`_ - Management of jobs
|
||||||
* `mmctl ldap <mmctl_ldap.rst>`_ - LDAP related utilities
|
* `mmctl ldap <mmctl_ldap.rst>`_ - LDAP related utilities
|
||||||
* `mmctl license <mmctl_license.rst>`_ - Licensing commands
|
* `mmctl license <mmctl_license.rst>`_ - Licensing commands
|
||||||
* `mmctl logs <mmctl_logs.rst>`_ - Display logs in a human-readable format
|
* `mmctl logs <mmctl_logs.rst>`_ - Display logs in a human-readable format
|
||||||
|
|||||||
42
server/cmd/mmctl/docs/mmctl_job.rst
Обычный файл
42
server/cmd/mmctl/docs/mmctl_job.rst
Обычный файл
@@ -0,0 +1,42 @@
|
|||||||
|
.. _mmctl_job:
|
||||||
|
|
||||||
|
mmctl job
|
||||||
|
---------
|
||||||
|
|
||||||
|
Management of jobs
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
Management of jobs
|
||||||
|
|
||||||
|
Options
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-h, --help help for job
|
||||||
|
|
||||||
|
Options inherited from parent commands
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
--config string path to the configuration file (default "$XDG_CONFIG_HOME/mmctl/config")
|
||||||
|
--disable-pager disables paged output
|
||||||
|
--insecure-sha1-intermediate allows to use insecure TLS protocols, such as SHA-1
|
||||||
|
--insecure-tls-version allows to use TLS versions 1.0 and 1.1
|
||||||
|
--json the output format will be in json format
|
||||||
|
--local allows communicating with the server through a unix socket
|
||||||
|
--quiet prevent mmctl to generate output for the commands
|
||||||
|
--strict will only run commands if the mmctl version matches the server one
|
||||||
|
--suppress-warnings disables printing warning messages
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
* `mmctl <mmctl.rst>`_ - Remote client for the Open Source, self-hosted Slack-alternative
|
||||||
|
* `mmctl job list <mmctl_job_list.rst>`_ - List the latest jobs
|
||||||
|
* `mmctl job update <mmctl_job_update.rst>`_ - Update the status of a job
|
||||||
|
|
||||||
60
server/cmd/mmctl/docs/mmctl_job_list.rst
Обычный файл
60
server/cmd/mmctl/docs/mmctl_job_list.rst
Обычный файл
@@ -0,0 +1,60 @@
|
|||||||
|
.. _mmctl_job_list:
|
||||||
|
|
||||||
|
mmctl job list
|
||||||
|
--------------
|
||||||
|
|
||||||
|
List the latest jobs
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
List the latest jobs
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
mmctl job list [flags]
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
job list
|
||||||
|
job list --ids jobID1,jobID2
|
||||||
|
job list --type ldap_sync --status success
|
||||||
|
job list --type ldap_sync --status success --page 0 --per-page 10
|
||||||
|
|
||||||
|
Options
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
--all Fetch all import jobs. --page flag will be ignored if provided
|
||||||
|
-h, --help help for list
|
||||||
|
--ids strings Comma-separated list of job IDs to which the operation will be applied. All other flags are ignored
|
||||||
|
--page int Page number to fetch for the list of import jobs
|
||||||
|
--per-page int Number of import jobs to be fetched (default 5)
|
||||||
|
--status string Filter by job status
|
||||||
|
--type string Filter by job type
|
||||||
|
|
||||||
|
Options inherited from parent commands
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
--config string path to the configuration file (default "$XDG_CONFIG_HOME/mmctl/config")
|
||||||
|
--disable-pager disables paged output
|
||||||
|
--insecure-sha1-intermediate allows to use insecure TLS protocols, such as SHA-1
|
||||||
|
--insecure-tls-version allows to use TLS versions 1.0 and 1.1
|
||||||
|
--json the output format will be in json format
|
||||||
|
--local allows communicating with the server through a unix socket
|
||||||
|
--quiet prevent mmctl to generate output for the commands
|
||||||
|
--strict will only run commands if the mmctl version matches the server one
|
||||||
|
--suppress-warnings disables printing warning messages
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
* `mmctl job <mmctl_job.rst>`_ - Management of jobs
|
||||||
|
|
||||||
59
server/cmd/mmctl/docs/mmctl_job_update.rst
Обычный файл
59
server/cmd/mmctl/docs/mmctl_job_update.rst
Обычный файл
@@ -0,0 +1,59 @@
|
|||||||
|
.. _mmctl_job_update:
|
||||||
|
|
||||||
|
mmctl job update
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Update the status of a job
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
Update the status of a job. The following restrictions are in place:
|
||||||
|
- in_progress -> pending
|
||||||
|
- in_progress | pending -> cancel_requested
|
||||||
|
- cancel_requested -> canceled
|
||||||
|
|
||||||
|
Those restriction can be bypassed with --force=true but the only statuses you can go to are: pending, cancel_requested and canceled. This can have unexpected consequences and should be used with caution.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
mmctl job update [job] [status] [flags]
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
job update myJobID pending
|
||||||
|
job update myJobID pending --force true
|
||||||
|
job update myJobID canceled --force true
|
||||||
|
|
||||||
|
Options
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
--force Setting a job status is restricted to certain statuses. You can overwrite these restrictions by using --force. This might cause unexpected behaviour on your Mattermost Server. Use this option with caution.
|
||||||
|
-h, --help help for update
|
||||||
|
|
||||||
|
Options inherited from parent commands
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
--config string path to the configuration file (default "$XDG_CONFIG_HOME/mmctl/config")
|
||||||
|
--disable-pager disables paged output
|
||||||
|
--insecure-sha1-intermediate allows to use insecure TLS protocols, such as SHA-1
|
||||||
|
--insecure-tls-version allows to use TLS versions 1.0 and 1.1
|
||||||
|
--json the output format will be in json format
|
||||||
|
--local allows communicating with the server through a unix socket
|
||||||
|
--quiet prevent mmctl to generate output for the commands
|
||||||
|
--strict will only run commands if the mmctl version matches the server one
|
||||||
|
--suppress-warnings disables printing warning messages
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
* `mmctl job <mmctl_job.rst>`_ - Management of jobs
|
||||||
|
|
||||||
@@ -863,9 +863,9 @@ func (mr *MockClientMockRecorder) GetJob(arg0, arg1 interface{}) *gomock.Call {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetJobs mocks base method.
|
// GetJobs mocks base method.
|
||||||
func (m *MockClient) GetJobs(arg0 context.Context, arg1, arg2 int) ([]*model.Job, *model.Response, error) {
|
func (m *MockClient) GetJobs(arg0 context.Context, arg1, arg2 string, arg3, arg4 int) ([]*model.Job, *model.Response, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "GetJobs", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "GetJobs", arg0, arg1, arg2, arg3, arg4)
|
||||||
ret0, _ := ret[0].([]*model.Job)
|
ret0, _ := ret[0].([]*model.Job)
|
||||||
ret1, _ := ret[1].(*model.Response)
|
ret1, _ := ret[1].(*model.Response)
|
||||||
ret2, _ := ret[2].(error)
|
ret2, _ := ret[2].(error)
|
||||||
@@ -873,9 +873,9 @@ func (m *MockClient) GetJobs(arg0 context.Context, arg1, arg2 int) ([]*model.Job
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetJobs indicates an expected call of GetJobs.
|
// GetJobs indicates an expected call of GetJobs.
|
||||||
func (mr *MockClientMockRecorder) GetJobs(arg0, arg1, arg2 interface{}) *gomock.Call {
|
func (mr *MockClientMockRecorder) GetJobs(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJobs", reflect.TypeOf((*MockClient)(nil).GetJobs), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJobs", reflect.TypeOf((*MockClient)(nil).GetJobs), arg0, arg1, arg2, arg3, arg4)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetJobsByType mocks base method.
|
// GetJobsByType mocks base method.
|
||||||
@@ -2105,6 +2105,21 @@ func (mr *MockClientMockRecorder) UpdateIncomingWebhook(arg0, arg1 interface{})
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateIncomingWebhook", reflect.TypeOf((*MockClient)(nil).UpdateIncomingWebhook), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateIncomingWebhook", reflect.TypeOf((*MockClient)(nil).UpdateIncomingWebhook), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateJobStatus mocks base method.
|
||||||
|
func (m *MockClient) UpdateJobStatus(arg0 context.Context, arg1, arg2 string, arg3 bool) (*model.Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "UpdateJobStatus", arg0, arg1, arg2, arg3)
|
||||||
|
ret0, _ := ret[0].(*model.Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateJobStatus indicates an expected call of UpdateJobStatus.
|
||||||
|
func (mr *MockClientMockRecorder) UpdateJobStatus(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateJobStatus", reflect.TypeOf((*MockClient)(nil).UpdateJobStatus), arg0, arg1, arg2, arg3)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateOutgoingWebhook mocks base method.
|
// UpdateOutgoingWebhook mocks base method.
|
||||||
func (m *MockClient) UpdateOutgoingWebhook(arg0 context.Context, arg1 *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.Response, error) {
|
func (m *MockClient) UpdateOutgoingWebhook(arg0 context.Context, arg1 *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.Response, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|||||||
@@ -2176,6 +2176,10 @@
|
|||||||
"id": "api.job.retrieve.nopermissions",
|
"id": "api.job.retrieve.nopermissions",
|
||||||
"translation": "The job types of a job you are trying to retrieve does not contain permissions"
|
"translation": "The job types of a job you are trying to retrieve does not contain permissions"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.job.status.invalid",
|
||||||
|
"translation": "Invalid status set"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.job.unable_to_create_job.incorrect_job_type",
|
"id": "api.job.unable_to_create_job.incorrect_job_type",
|
||||||
"translation": "The job type of the job you are trying to create is invalid"
|
"translation": "The job type of the job you are trying to create is invalid"
|
||||||
@@ -2188,6 +2192,10 @@
|
|||||||
"id": "api.job.unable_to_download_job.incorrect_job_type",
|
"id": "api.job.unable_to_download_job.incorrect_job_type",
|
||||||
"translation": "The job type you are trying to download is not supported at the moment"
|
"translation": "The job type you are trying to download is not supported at the moment"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.job.unable_to_manage_job.incorrect_job_type",
|
||||||
|
"translation": "You do not have permission to manage this job type"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.ldap_group.not_found",
|
"id": "api.ldap_group.not_found",
|
||||||
"translation": "ldap group not found"
|
"translation": "ldap group not found"
|
||||||
@@ -5670,6 +5678,10 @@
|
|||||||
"id": "app.job.update.app_error",
|
"id": "app.job.update.app_error",
|
||||||
"translation": "Unable to update the job."
|
"translation": "Unable to update the job."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "app.job.update_status.app_error",
|
||||||
|
"translation": "Unable to update job status. Invalid status set"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "app.last_accessible_file.app_error",
|
"id": "app.last_accessible_file.app_error",
|
||||||
"translation": "Error fetching last accessible file"
|
"translation": "Error fetching last accessible file"
|
||||||
|
|||||||
@@ -7018,8 +7018,8 @@ func (c *Client4) GetJob(ctx context.Context, id string) (*Job, *Response, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetJobs gets all jobs, sorted with the job that was created most recently first.
|
// GetJobs gets all jobs, sorted with the job that was created most recently first.
|
||||||
func (c *Client4) GetJobs(ctx context.Context, page int, perPage int) ([]*Job, *Response, error) {
|
func (c *Client4) GetJobs(ctx context.Context, jobType string, status string, page int, perPage int) ([]*Job, *Response, error) {
|
||||||
r, err := c.DoAPIGet(ctx, c.jobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), "")
|
r, err := c.DoAPIGet(ctx, c.jobsRoute()+fmt.Sprintf("?page=%v&per_page=%v&job_type=%v&status=%v", page, perPage, jobType, status), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, BuildResponse(r), err
|
return nil, BuildResponse(r), err
|
||||||
}
|
}
|
||||||
@@ -7088,6 +7088,23 @@ func (c *Client4) DownloadJob(ctx context.Context, jobId string) ([]byte, *Respo
|
|||||||
return data, BuildResponse(r), nil
|
return data, BuildResponse(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateJobStatus updates the status of a job
|
||||||
|
func (c *Client4) UpdateJobStatus(ctx context.Context, jobId string, status string, force bool) (*Response, error) {
|
||||||
|
buf, err := json.Marshal(map[string]any{
|
||||||
|
"status": status,
|
||||||
|
"force": force,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewAppError("UpdateJobStatus", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
|
}
|
||||||
|
r, err := c.DoAPIPatchBytes(ctx, c.jobsRoute()+fmt.Sprintf("/%v/status", jobId), buf)
|
||||||
|
if err != nil {
|
||||||
|
return BuildResponse(r), err
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
return BuildResponse(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Roles Section
|
// Roles Section
|
||||||
|
|
||||||
// GetAllRoles returns a list of all the roles.
|
// GetAllRoles returns a list of all the roles.
|
||||||
|
|||||||
@@ -108,7 +108,31 @@ func (j *Job) IsValid() *AppError {
|
|||||||
return NewAppError("Job.IsValid", "model.job.is_valid.create_at.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
return NewAppError("Job.IsValid", "model.job.is_valid.create_at.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch j.Status {
|
validStatus := IsValidJobStatus(j.Status)
|
||||||
|
if !validStatus {
|
||||||
|
return NewAppError("Job.IsValid", "model.job.is_valid.status.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *Job) IsValidStatusChange(newStatus string) bool {
|
||||||
|
currentStatus := j.Status
|
||||||
|
|
||||||
|
switch currentStatus {
|
||||||
|
case JobStatusInProgress:
|
||||||
|
return newStatus == JobStatusPending || newStatus == JobStatusCancelRequested
|
||||||
|
case JobStatusPending:
|
||||||
|
return newStatus == JobStatusCancelRequested
|
||||||
|
case JobStatusCancelRequested:
|
||||||
|
return newStatus == JobStatusCanceled
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidJobStatus(status string) bool {
|
||||||
|
switch status {
|
||||||
case JobStatusPending,
|
case JobStatusPending,
|
||||||
JobStatusInProgress,
|
JobStatusInProgress,
|
||||||
JobStatusSuccess,
|
JobStatusSuccess,
|
||||||
@@ -117,10 +141,20 @@ func (j *Job) IsValid() *AppError {
|
|||||||
JobStatusCancelRequested,
|
JobStatusCancelRequested,
|
||||||
JobStatusCanceled:
|
JobStatusCanceled:
|
||||||
default:
|
default:
|
||||||
return NewAppError("Job.IsValid", "model.job.is_valid.status.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidJobType(jobType string) bool {
|
||||||
|
for _, t := range AllJobTypes {
|
||||||
|
if t == jobType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Job) LogClone() any {
|
func (j *Job) LogClone() any {
|
||||||
|
|||||||
@@ -121,3 +121,113 @@ func TestJobIsValid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJobIsValidStatusChange(t *testing.T) {
|
||||||
|
t.Run("invalid status change", func(t *testing.T) {
|
||||||
|
job := &Job{
|
||||||
|
Id: "arandomstring0123456789012",
|
||||||
|
Type: JobTypeExportProcess,
|
||||||
|
Priority: 42,
|
||||||
|
CreateAt: 1336,
|
||||||
|
StartAt: 1337,
|
||||||
|
LastActivityAt: 1666609360813,
|
||||||
|
Status: JobStatusInProgress,
|
||||||
|
Progress: 32,
|
||||||
|
Data: StringMap{"Hello": "World"},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.False(t, job.IsValidStatusChange("invalid!"))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("valid status change from in_progress", func(t *testing.T) {
|
||||||
|
job := &Job{
|
||||||
|
Id: "arandomstring0123456789012",
|
||||||
|
Type: JobTypeExportProcess,
|
||||||
|
Priority: 42,
|
||||||
|
CreateAt: 1336,
|
||||||
|
StartAt: 1337,
|
||||||
|
LastActivityAt: 1666609360813,
|
||||||
|
Status: JobStatusInProgress,
|
||||||
|
Progress: 32,
|
||||||
|
Data: StringMap{"Hello": "World"},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.True(t, job.IsValidStatusChange(JobStatusPending))
|
||||||
|
require.True(t, job.IsValidStatusChange(JobStatusCancelRequested))
|
||||||
|
require.False(t, job.IsValidStatusChange(JobStatusCanceled))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("valid status change from pending", func(t *testing.T) {
|
||||||
|
job := &Job{
|
||||||
|
Id: "arandomstring0123456789012",
|
||||||
|
Type: JobTypeExportProcess,
|
||||||
|
Priority: 42,
|
||||||
|
CreateAt: 1336,
|
||||||
|
StartAt: 1337,
|
||||||
|
LastActivityAt: 1666609360813,
|
||||||
|
Status: JobStatusPending,
|
||||||
|
Progress: 32,
|
||||||
|
Data: StringMap{"Hello": "World"},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.True(t, job.IsValidStatusChange(JobStatusCancelRequested))
|
||||||
|
require.False(t, job.IsValidStatusChange(JobStatusInProgress))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("valid status change from cancel_requested", func(t *testing.T) {
|
||||||
|
job := &Job{
|
||||||
|
Id: "arandomstring0123456789012",
|
||||||
|
Type: JobTypeExportProcess,
|
||||||
|
Priority: 42,
|
||||||
|
CreateAt: 1336,
|
||||||
|
StartAt: 1337,
|
||||||
|
LastActivityAt: 1666609360813,
|
||||||
|
Status: JobStatusCancelRequested,
|
||||||
|
Progress: 32,
|
||||||
|
Data: StringMap{"Hello": "World"},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.True(t, job.IsValidStatusChange(JobStatusCanceled))
|
||||||
|
require.False(t, job.IsValidStatusChange(JobStatusPending))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsValidJobType(t *testing.T) {
|
||||||
|
t.Run("valid", func(t *testing.T) {
|
||||||
|
validTypes := []string{JobTypeExportProcess, JobTypeImportProcess}
|
||||||
|
for _, jobType := range validTypes {
|
||||||
|
t.Run(jobType, func(t *testing.T) {
|
||||||
|
require.True(t, IsValidJobType(jobType))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid", func(t *testing.T) {
|
||||||
|
invalidTypes := []string{"invalid!", ""}
|
||||||
|
for _, jobType := range invalidTypes {
|
||||||
|
t.Run(jobType, func(t *testing.T) {
|
||||||
|
require.False(t, IsValidJobType(jobType))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsValidJobStatus(t *testing.T) {
|
||||||
|
t.Run("valid", func(t *testing.T) {
|
||||||
|
validStatuses := []string{JobStatusCancelRequested, JobStatusCanceled, JobStatusError, JobStatusInProgress, JobStatusPending, JobStatusSuccess, JobStatusWarning}
|
||||||
|
for _, status := range validStatuses {
|
||||||
|
t.Run(status, func(t *testing.T) {
|
||||||
|
require.True(t, IsValidJobStatus(status))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid", func(t *testing.T) {
|
||||||
|
invalidStatuses := []string{"invalid!", ""}
|
||||||
|
for _, status := range invalidStatuses {
|
||||||
|
t.Run(status, func(t *testing.T) {
|
||||||
|
require.False(t, IsValidJobStatus(status))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,4 +47,5 @@ const (
|
|||||||
MigrationKeyAddIPFilteringPermissions = "add_ip_filtering_permissions"
|
MigrationKeyAddIPFilteringPermissions = "add_ip_filtering_permissions"
|
||||||
MigrationKeyAddOutgoingOAuthConnectionsPermissions = "add_outgoing_oauth_connections_permissions"
|
MigrationKeyAddOutgoingOAuthConnectionsPermissions = "add_outgoing_oauth_connections_permissions"
|
||||||
MigrationKeyAddChannelBookmarksPermissions = "add_channel_bookmarks_permissions"
|
MigrationKeyAddChannelBookmarksPermissions = "add_channel_bookmarks_permissions"
|
||||||
|
MigrationKeyAddManageJobAncillaryPermissions = "add_manage_jobs_ancillary_permissions"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -123,8 +123,10 @@ var PermissionManageSharedChannels *Permission
|
|||||||
var PermissionManageSecureConnections *Permission
|
var PermissionManageSecureConnections *Permission
|
||||||
var PermissionDownloadComplianceExportResult *Permission
|
var PermissionDownloadComplianceExportResult *Permission
|
||||||
var PermissionCreateDataRetentionJob *Permission
|
var PermissionCreateDataRetentionJob *Permission
|
||||||
|
var PermissionManageDataRetentionJob *Permission
|
||||||
var PermissionReadDataRetentionJob *Permission
|
var PermissionReadDataRetentionJob *Permission
|
||||||
var PermissionCreateComplianceExportJob *Permission
|
var PermissionCreateComplianceExportJob *Permission
|
||||||
|
var PermissionManageComplianceExportJob *Permission
|
||||||
var PermissionReadComplianceExportJob *Permission
|
var PermissionReadComplianceExportJob *Permission
|
||||||
var PermissionReadAudits *Permission
|
var PermissionReadAudits *Permission
|
||||||
var PermissionTestElasticsearch *Permission
|
var PermissionTestElasticsearch *Permission
|
||||||
@@ -136,12 +138,16 @@ var PermissionRecycleDatabaseConnections *Permission
|
|||||||
var PermissionPurgeElasticsearchIndexes *Permission
|
var PermissionPurgeElasticsearchIndexes *Permission
|
||||||
var PermissionTestEmail *Permission
|
var PermissionTestEmail *Permission
|
||||||
var PermissionCreateElasticsearchPostIndexingJob *Permission
|
var PermissionCreateElasticsearchPostIndexingJob *Permission
|
||||||
|
var PermissionManageElasticsearchPostIndexingJob *Permission
|
||||||
var PermissionCreateElasticsearchPostAggregationJob *Permission
|
var PermissionCreateElasticsearchPostAggregationJob *Permission
|
||||||
|
var PermissionManageElasticsearchPostAggregationJob *Permission
|
||||||
var PermissionReadElasticsearchPostIndexingJob *Permission
|
var PermissionReadElasticsearchPostIndexingJob *Permission
|
||||||
var PermissionReadElasticsearchPostAggregationJob *Permission
|
var PermissionReadElasticsearchPostAggregationJob *Permission
|
||||||
var PermissionPurgeBleveIndexes *Permission
|
var PermissionPurgeBleveIndexes *Permission
|
||||||
var PermissionCreatePostBleveIndexesJob *Permission
|
var PermissionCreatePostBleveIndexesJob *Permission
|
||||||
|
var PermissionManagePostBleveIndexesJob *Permission
|
||||||
var PermissionCreateLdapSyncJob *Permission
|
var PermissionCreateLdapSyncJob *Permission
|
||||||
|
var PermissionManageLdapSyncJob *Permission
|
||||||
var PermissionReadLdapSyncJob *Permission
|
var PermissionReadLdapSyncJob *Permission
|
||||||
var PermissionTestLdap *Permission
|
var PermissionTestLdap *Permission
|
||||||
var PermissionInvalidateEmailInvite *Permission
|
var PermissionInvalidateEmailInvite *Permission
|
||||||
@@ -790,6 +796,12 @@ func initializePermissions() {
|
|||||||
"",
|
"",
|
||||||
PermissionScopeSystem,
|
PermissionScopeSystem,
|
||||||
}
|
}
|
||||||
|
PermissionManageDataRetentionJob = &Permission{
|
||||||
|
"manage_data_retention_job",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
PermissionScopeSystem,
|
||||||
|
}
|
||||||
PermissionReadDataRetentionJob = &Permission{
|
PermissionReadDataRetentionJob = &Permission{
|
||||||
"read_data_retention_job",
|
"read_data_retention_job",
|
||||||
"",
|
"",
|
||||||
@@ -803,6 +815,12 @@ func initializePermissions() {
|
|||||||
"",
|
"",
|
||||||
PermissionScopeSystem,
|
PermissionScopeSystem,
|
||||||
}
|
}
|
||||||
|
PermissionManageComplianceExportJob = &Permission{
|
||||||
|
"manage_compliance_export_job",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
PermissionScopeSystem,
|
||||||
|
}
|
||||||
PermissionReadComplianceExportJob = &Permission{
|
PermissionReadComplianceExportJob = &Permission{
|
||||||
"read_compliance_export_job",
|
"read_compliance_export_job",
|
||||||
"",
|
"",
|
||||||
@@ -831,12 +849,25 @@ func initializePermissions() {
|
|||||||
PermissionScopeSystem,
|
PermissionScopeSystem,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PermissionManagePostBleveIndexesJob = &Permission{
|
||||||
|
"manage_post_bleve_indexes_job",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
PermissionScopeSystem,
|
||||||
|
}
|
||||||
|
|
||||||
PermissionCreateLdapSyncJob = &Permission{
|
PermissionCreateLdapSyncJob = &Permission{
|
||||||
"create_ldap_sync_job",
|
"create_ldap_sync_job",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
PermissionScopeSystem,
|
PermissionScopeSystem,
|
||||||
}
|
}
|
||||||
|
PermissionManageLdapSyncJob = &Permission{
|
||||||
|
"manage_ldap_sync_job",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
PermissionScopeSystem,
|
||||||
|
}
|
||||||
PermissionReadLdapSyncJob = &Permission{
|
PermissionReadLdapSyncJob = &Permission{
|
||||||
"read_ldap_sync_job",
|
"read_ldap_sync_job",
|
||||||
"",
|
"",
|
||||||
@@ -1029,12 +1060,24 @@ func initializePermissions() {
|
|||||||
"",
|
"",
|
||||||
PermissionScopeSystem,
|
PermissionScopeSystem,
|
||||||
}
|
}
|
||||||
|
PermissionManageElasticsearchPostIndexingJob = &Permission{
|
||||||
|
"manage_elasticsearch_post_indexing_job",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
PermissionScopeSystem,
|
||||||
|
}
|
||||||
PermissionCreateElasticsearchPostAggregationJob = &Permission{
|
PermissionCreateElasticsearchPostAggregationJob = &Permission{
|
||||||
"create_elasticsearch_post_aggregation_job",
|
"create_elasticsearch_post_aggregation_job",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
PermissionScopeSystem,
|
PermissionScopeSystem,
|
||||||
}
|
}
|
||||||
|
PermissionManageElasticsearchPostAggregationJob = &Permission{
|
||||||
|
"manage_elasticsearch_post_aggregation_job",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
PermissionScopeSystem,
|
||||||
|
}
|
||||||
PermissionReadElasticsearchPostIndexingJob = &Permission{
|
PermissionReadElasticsearchPostIndexingJob = &Permission{
|
||||||
"read_elasticsearch_post_indexing_job",
|
"read_elasticsearch_post_indexing_job",
|
||||||
"",
|
"",
|
||||||
@@ -2347,8 +2390,10 @@ func initializePermissions() {
|
|||||||
PermissionManageSecureConnections,
|
PermissionManageSecureConnections,
|
||||||
PermissionDownloadComplianceExportResult,
|
PermissionDownloadComplianceExportResult,
|
||||||
PermissionCreateDataRetentionJob,
|
PermissionCreateDataRetentionJob,
|
||||||
|
PermissionManageDataRetentionJob,
|
||||||
PermissionReadDataRetentionJob,
|
PermissionReadDataRetentionJob,
|
||||||
PermissionCreateComplianceExportJob,
|
PermissionCreateComplianceExportJob,
|
||||||
|
PermissionManageComplianceExportJob,
|
||||||
PermissionReadComplianceExportJob,
|
PermissionReadComplianceExportJob,
|
||||||
PermissionReadAudits,
|
PermissionReadAudits,
|
||||||
PermissionTestSiteURL,
|
PermissionTestSiteURL,
|
||||||
@@ -2360,12 +2405,16 @@ func initializePermissions() {
|
|||||||
PermissionPurgeElasticsearchIndexes,
|
PermissionPurgeElasticsearchIndexes,
|
||||||
PermissionTestEmail,
|
PermissionTestEmail,
|
||||||
PermissionCreateElasticsearchPostIndexingJob,
|
PermissionCreateElasticsearchPostIndexingJob,
|
||||||
|
PermissionManageElasticsearchPostIndexingJob,
|
||||||
PermissionCreateElasticsearchPostAggregationJob,
|
PermissionCreateElasticsearchPostAggregationJob,
|
||||||
|
PermissionManageElasticsearchPostAggregationJob,
|
||||||
PermissionReadElasticsearchPostIndexingJob,
|
PermissionReadElasticsearchPostIndexingJob,
|
||||||
PermissionReadElasticsearchPostAggregationJob,
|
PermissionReadElasticsearchPostAggregationJob,
|
||||||
PermissionPurgeBleveIndexes,
|
PermissionPurgeBleveIndexes,
|
||||||
PermissionCreatePostBleveIndexesJob,
|
PermissionCreatePostBleveIndexesJob,
|
||||||
|
PermissionManagePostBleveIndexesJob,
|
||||||
PermissionCreateLdapSyncJob,
|
PermissionCreateLdapSyncJob,
|
||||||
|
PermissionManageLdapSyncJob,
|
||||||
PermissionReadLdapSyncJob,
|
PermissionReadLdapSyncJob,
|
||||||
PermissionTestLdap,
|
PermissionTestLdap,
|
||||||
PermissionInvalidateEmailInvite,
|
PermissionInvalidateEmailInvite,
|
||||||
|
|||||||
@@ -90,7 +90,9 @@ func init() {
|
|||||||
PermissionSysconsoleWriteEnvironmentElasticsearch.Id: {
|
PermissionSysconsoleWriteEnvironmentElasticsearch.Id: {
|
||||||
PermissionTestElasticsearch,
|
PermissionTestElasticsearch,
|
||||||
PermissionCreateElasticsearchPostIndexingJob,
|
PermissionCreateElasticsearchPostIndexingJob,
|
||||||
|
PermissionManageElasticsearchPostIndexingJob,
|
||||||
PermissionCreateElasticsearchPostAggregationJob,
|
PermissionCreateElasticsearchPostAggregationJob,
|
||||||
|
PermissionManageElasticsearchPostAggregationJob,
|
||||||
PermissionPurgeElasticsearchIndexes,
|
PermissionPurgeElasticsearchIndexes,
|
||||||
},
|
},
|
||||||
PermissionSysconsoleWriteEnvironmentFileStorage.Id: {
|
PermissionSysconsoleWriteEnvironmentFileStorage.Id: {
|
||||||
@@ -145,12 +147,14 @@ func init() {
|
|||||||
},
|
},
|
||||||
PermissionSysconsoleWriteComplianceDataRetentionPolicy.Id: {
|
PermissionSysconsoleWriteComplianceDataRetentionPolicy.Id: {
|
||||||
PermissionCreateDataRetentionJob,
|
PermissionCreateDataRetentionJob,
|
||||||
|
PermissionManageDataRetentionJob,
|
||||||
},
|
},
|
||||||
PermissionSysconsoleReadComplianceDataRetentionPolicy.Id: {
|
PermissionSysconsoleReadComplianceDataRetentionPolicy.Id: {
|
||||||
PermissionReadDataRetentionJob,
|
PermissionReadDataRetentionJob,
|
||||||
},
|
},
|
||||||
PermissionSysconsoleWriteComplianceComplianceExport.Id: {
|
PermissionSysconsoleWriteComplianceComplianceExport.Id: {
|
||||||
PermissionCreateComplianceExportJob,
|
PermissionCreateComplianceExportJob,
|
||||||
|
PermissionManageComplianceExportJob,
|
||||||
PermissionDownloadComplianceExportResult,
|
PermissionDownloadComplianceExportResult,
|
||||||
},
|
},
|
||||||
PermissionSysconsoleReadComplianceComplianceExport.Id: {
|
PermissionSysconsoleReadComplianceComplianceExport.Id: {
|
||||||
@@ -163,9 +167,11 @@ func init() {
|
|||||||
PermissionSysconsoleWriteExperimentalBleve.Id: {
|
PermissionSysconsoleWriteExperimentalBleve.Id: {
|
||||||
PermissionCreatePostBleveIndexesJob,
|
PermissionCreatePostBleveIndexesJob,
|
||||||
PermissionPurgeBleveIndexes,
|
PermissionPurgeBleveIndexes,
|
||||||
|
PermissionManagePostBleveIndexesJob,
|
||||||
},
|
},
|
||||||
PermissionSysconsoleWriteAuthenticationLdap.Id: {
|
PermissionSysconsoleWriteAuthenticationLdap.Id: {
|
||||||
PermissionCreateLdapSyncJob,
|
PermissionCreateLdapSyncJob,
|
||||||
|
PermissionManageLdapSyncJob,
|
||||||
PermissionAddLdapPublicCert,
|
PermissionAddLdapPublicCert,
|
||||||
PermissionRemoveLdapPublicCert,
|
PermissionRemoveLdapPublicCert,
|
||||||
PermissionAddLdapPrivateCert,
|
PermissionAddLdapPrivateCert,
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user