docs(apiserver): fix swag annotations and regenerate the swagger spec (bug-1966)

Cause: the handler annotations referenced types that do not exist
(models.Error, ErrorResponse, JobsResponse, JobSignalRequest,
JobControlResponseSummary, unqualified JobSubmitRequest), had malformed
@Param/@Failure lines and /api/v1 paths, and there was no general API
info, so `swag init -g cmd/main.go` failed and docs/ stayed a stale stub.

Fix: use the real response envelopes (JsonStruct / JsonErrStruct) and
request models, the real routes under @BasePath /xce/v1, add general info
to cmd/main.go, and regenerate docs/ with `swag init -g cmd/main.go -o
docs`; the spec now has /jobs/{jobids}/control and /jobs/control.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-10 10:29:02 +00:00
parent 1ff068f6e7
commit f7fef278f6
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
6 changed files with 1700 additions and 684 deletions

View file

@ -64,6 +64,14 @@ func composeVersionDisplay(gitCommit, dirtyFingerprint string) string {
return strings.TrimSuffix(gitCommit, "-dirty") + "-" + dirtyFingerprint
}
// General API info for swag; regenerate docs/ from src/frontend/apiserver
// with `swag init -g cmd/main.go -o docs`.
//
// @title XCE API Server
// @version 1.0
// @description XCE cluster management REST API.
// @host localhost:8443
// @BasePath /xce/v1
func main() {
gin.SetMode(gin.ReleaseMode)
gin.DefaultWriter = io.Discard

View file

@ -26,9 +26,9 @@ type HostHandler struct {
// @Tags hosts
// @Accept json
// @Produce json
// @Success 200
// @Failure 400 {object} models.Error
// @Router /api/v1/hosts [get]
// @Success 200 {object} JsonStruct
// @Failure 400 {object} JsonErrStruct
// @Router /hosts [get]
func (h *HostHandler) GetHostsInfo(ctx *gin.Context) {
logger.Debug("Enter GetAllHosts() function from ", zap.String("client_ip", ctx.ClientIP()))

View file

@ -49,11 +49,11 @@ type JobController struct{}
// @Tags jobs
// @Accept json
// @Produce json
// @Param filter query string "filter=[{user:eq:user1},{queue:eq:queue1}]"
// @Param fields query string "fields=jobid,status,queue"
// @Success 200 {array} models.JobInfo "Response for jobs info"
// @Failure 400 {object} models.Error
// @Router /api/v1/jobs [get]
// @Param filter query string false "filter, e.g. user:eq:user1,queue:eq:queue1"
// @Param fields query string false "fields, e.g. jobid,status,queue"
// @Success 200 {object} JsonStruct "Response for jobs info"
// @Failure 400 {object} JsonErrStruct
// @Router /jobs [get]
func (j JobController) GetJobsInfo(ctx *gin.Context) {
logger.Debug("Enter GetJobsInfo() function from ", zap.String("client_ip", ctx.ClientIP()))
var fields []string
@ -545,11 +545,9 @@ func returnSelectionError(ctx *gin.Context, raw string, err error) {
// @Produce json
// @Param jobids path string true "Comma-separated list of job IDs (e.g., 1001,1002,1003)"
// @Param fields query string false "Comma-separated list of fields to return (e.g., jobid,status,queue)"
// @Success 200 {object} JobsResponse "Successfully retrieved jobs"
// @Failure 400 INVALID_PARAMS_CODE "invalid parameters"
// @Failure 500 ERROR_MSG
// @Example {curl} Example Usage:
// @Example curl -X GET "http://localhost:8080/jobs/1001,1002,1003?fields=jobid,status,queue"
// @Success 200 {object} JsonStruct "Successfully retrieved jobs"
// @Failure 400 {object} JsonErrStruct "invalid parameters"
// @Failure 500 {object} JsonErrStruct "Internal server error"
// @Router /jobs/{jobids} [get]
func (j JobController) GetJobByIDs(ctx *gin.Context) {
logger.Debug("Enter GetJobByIDs() function from ", zap.String("client_ip", ctx.ClientIP()))
@ -1087,13 +1085,13 @@ func (j JobController) RestartJobByID(ctx *gin.Context) {
// @Tags jobs
// @Accept json
// @Produce json
// @Param job body JobSubmitRequest true "Job submission parameters"
// @Success 201 {object} JobSubmitResponse "Job successfully created"
// @Failure 400 {object} ErrorResponse "Invalid request body or parameters"
// @Failure 401 {object} ErrorResponse "Unauthorized - Invalid or missing credentials"
// @Failure 403 {object} ErrorResponse "Forbidden - User lacks permission"
// @Failure 500 {object} ErrorResponse "Internal server error"
// @Router /jobs [post]
// @Param job body models.JobSubmitRequest true "Job submission parameters"
// @Success 201 {object} JsonStruct "Job successfully created"
// @Failure 400 {object} JsonErrStruct "Invalid request body or parameters"
// @Failure 401 {object} JsonErrStruct "Unauthorized - Invalid or missing credentials"
// @Failure 403 {object} JsonErrStruct "Forbidden - User lacks permission"
// @Failure 500 {object} JsonErrStruct "Internal server error"
// @Router /jobs/create [post]
func (j JobController) CreateJob(ctx *gin.Context) {
logger.Debug("Enter CreateJob() function from ", zap.String("client_ip", ctx.ClientIP()))
@ -2046,11 +2044,11 @@ func postJobRequest(job *models.JobInfo) error {
// @Accept json
// @Produce json
// @Param jobids path string true "Job ID"
// @Param action body JobSignalRequest true "Action to be performed"
// @Success 202 {object} JobControlResponseSummary "Action successfully accepted"
// @Failure 400 {object} ErrorResponse "Invalid request body or parameters"
// @Failure 404 {object} ErrorResponse "Job not found"
// @Failure 500 {object} ErrorResponse "Internal server error"
// @Param action body models.JobControlJobIDRequest true "Action to be performed"
// @Success 202 {object} JsonStruct "Action successfully accepted"
// @Failure 400 {object} JsonErrStruct "Invalid request body or parameters"
// @Failure 404 {object} JsonErrStruct "Job not found"
// @Failure 500 {object} JsonErrStruct "Internal server error"
// @Router /jobs/{jobids}/control [post]
func (j JobController) ControlJobByID(ctx *gin.Context) {
logger.Debug("Enter ControlJobByID() function from ", zap.String("client_ip", ctx.ClientIP()))
@ -2322,12 +2320,11 @@ func (j JobController) ControlJobByID(ctx *gin.Context) {
// @Tags jobs
// @Accept json
// @Produce json
// @Param jobids path string true "Job ID"
// @Param action body JobControlRequest true "Action to be performed"
// @Success 202 {object} JobControlResponseSummary "Action successfully accepted"
// @Failure 400 {object} ErrorResponse "Invalid request body or parameters"
// @Failure 404 {object} ErrorResponse "Job not found"
// @Failure 500 {object} ErrorResponse "Internal server error"
// @Param action body models.JobControlRequest true "Action to be performed"
// @Success 202 {object} JsonStruct "Action successfully accepted"
// @Failure 400 {object} JsonErrStruct "Invalid request body or parameters"
// @Failure 404 {object} JsonErrStruct "Job not found"
// @Failure 500 {object} JsonErrStruct "Internal server error"
// @Router /jobs/control [post]
func (j JobController) ControlJob(ctx *gin.Context) {
logger.Debug("Enter ControlJob() function from ", zap.String("client_ip", ctx.ClientIP()))

View file

@ -15,9 +15,9 @@ const docTemplate = `{
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/api/v1/hosts": {
"/hosts": {
"get": {
"description": "Get basic or full host information",
"description": "Get host information",
"consumes": [
"application/json"
],
@ -28,29 +28,279 @@ const docTemplate = `{
"hosts"
],
"summary": "Get host information",
"parameters": [
{
"type": "string",
"description": "Host type (basic or full)",
"name": "type",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "Response for full host type",
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/models.FullHost"
}
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/models.Error"
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs": {
"get": {
"description": "Get jobs information",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Get jobs information",
"parameters": [
{
"type": "string",
"description": "filter, e.g. user:eq:user1,queue:eq:queue1",
"name": "filter",
"in": "query"
},
{
"type": "string",
"description": "fields, e.g. jobid,status,queue",
"name": "fields",
"in": "query"
}
],
"responses": {
"200": {
"description": "Response for jobs info",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs/control": {
"post": {
"description": "Submit an action to be performed on specific jobs identified by filter in request body.\nkill/stop/resume signals as for POST /jobs/{jobids}/control.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Perform an action on filtered out jobs",
"parameters": [
{
"description": "Action to be performed",
"name": "action",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.JobControlRequest"
}
}
],
"responses": {
"202": {
"description": "Action successfully accepted",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Invalid request body or parameters",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"404": {
"description": "Job not found",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs/create": {
"post": {
"description": "Submit a new job with specified requirements and parameters",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Create a new job",
"parameters": [
{
"description": "Job submission parameters",
"name": "job",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.JobSubmitRequest"
}
}
],
"responses": {
"201": {
"description": "Job successfully created",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Invalid request body or parameters",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"401": {
"description": "Unauthorized - Invalid or missing credentials",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"403": {
"description": "Forbidden - User lacks permission",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs/{jobids}": {
"get": {
"description": "Retrieve information for multiple jobs in a single request with optional field selection",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Get multiple jobs by their IDs",
"parameters": [
{
"type": "string",
"description": "Comma-separated list of job IDs (e.g., 1001,1002,1003)",
"name": "jobids",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Comma-separated list of fields to return (e.g., jobid,status,queue)",
"name": "fields",
"in": "query"
}
],
"responses": {
"200": {
"description": "Successfully retrieved jobs",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "invalid parameters",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs/{jobids}/control": {
"post": {
"description": "Submit an action to be performed on a specific job identified by jobids.\nkill without a signal: SIGINT, SIGTERM, then SIGKILL, job.terminate_interval\nseconds apart while the job runs; with a signal: that signal once; with\nforce_kill: SIGKILL at once. stop: SIGTSTP, then SIGSTOP after the interval\nif the job has not stopped. resume: SIGCONT (cancels a stop in progress).",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Perform an action on a job",
"parameters": [
{
"type": "string",
"description": "Job ID",
"name": "jobids",
"in": "path",
"required": true
},
{
"description": "Action to be performed",
"name": "action",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.JobControlJobIDRequest"
}
}
],
"responses": {
"202": {
"description": "Action successfully accepted",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Invalid request body or parameters",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"404": {
"description": "Job not found",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
@ -58,267 +308,395 @@ const docTemplate = `{
}
},
"definitions": {
"models.BasicHost": {
"controllers.JsonErrStruct": {
"type": "object",
"properties": {
"DResources": {
"type": "array",
"items": {
"type": "string"
}
},
"busyThreshold": {
"type": "array",
"items": {
"type": "number"
}
},
"cores": {
"code": {
"type": "integer"
},
"cores_per_proc": {
"details": {},
"msg": {}
}
},
"controllers.JsonStruct": {
"type": "object",
"properties": {
"code": {
"type": "integer"
},
"cpuFactor": {
"type": "number"
},
"hostAddr": {
"type": "string"
},
"hostModel": {
"type": "string"
},
"hostName": {
"type": "string"
},
"hostType": {
"type": "string"
},
"isServer": {
"type": "boolean"
},
"maxCpus": {
"data": {},
"msg": {}
}
},
"models.CustomInt": {
"type": "object",
"properties": {
"seconds": {
"type": "integer"
},
"maxMem": {
"type": "integer"
},
"maxSwap": {
"type": "integer"
},
"maxTmp": {
"type": "integer"
},
"nDRes": {
"type": "integer"
},
"nDisks": {
"type": "integer"
},
"nRes": {
"type": "integer"
},
"numIndx": {
"type": "integer"
},
"pprocs": {
"type": "integer"
},
"resources": {
"type": "array",
"items": {
"type": "string"
}
},
"threads_per_core": {
"type": "integer"
},
"windows": {
}
}
},
"models.CustomLimit": {
"type": "object",
"properties": {
"mb": {
"type": "number",
"format": "float64"
}
}
},
"models.CustomTime": {
"type": "object",
"properties": {
"time": {
"type": "string"
}
}
},
"models.Error": {
"models.JobControlFilter": {
"type": "object",
"properties": {
"error": {
"all_jobs": {
"type": "boolean"
},
"exec_hosts": {
"type": "string"
},
"job_group_name": {
"type": "string"
},
"job_name": {
"type": "string"
},
"queue_name": {
"type": "string"
},
"sla": {
"type": "string"
},
"users": {
"type": "string"
}
}
},
"models.FullHost": {
"models.JobControlJobIDRequest": {
"type": "object",
"required": [
"action"
],
"properties": {
"DResources": {
"type": "array",
"items": {
"type": "string"
}
},
"affinityCpulist": {
"action": {
"type": "string"
},
"attr": {
"type": "integer"
},
"busySched": {
"type": "number"
},
"busyStop": {
"type": "number"
},
"busyThreshold": {
"type": "array",
"items": {
"type": "number"
}
},
"chkSig": {
"type": "integer"
},
"cnsmrAvail": {
"type": "number"
},
"cnsmrUsage": {
"type": "number"
},
"cores": {
"type": "integer"
},
"cores_per_proc": {
"type": "integer"
},
"cpuFactor": {
"type": "number"
},
"cycleTimeLeft": {
"type": "integer"
},
"hCtrlMsg": {
"type": "integer"
},
"hStatus": {
"comment": {
"type": "string"
},
"hostAddr": {
"type": "string"
},
"hostModel": {
"type": "string"
},
"hostName": {
"type": "string"
},
"hostType": {
"type": "string"
},
"idleTime": {
"type": "integer"
},
"isServer": {
"force_kill": {
"description": "kill: SIGKILL at once (no graceful sequence)",
"type": "boolean"
},
"load": {
"type": "array",
"items": {
"type": "number"
}
"method": {
"description": "\"criu\" as default",
"type": "string"
},
"loadSched": {
"type": "array",
"items": {
"type": "number"
}
"signal": {
"description": "kill only: send this signal once instead of the graceful sequence",
"type": "string"
}
}
},
"models.JobControlRequest": {
"type": "object",
"required": [
"action",
"filter"
],
"properties": {
"action": {
"type": "string"
},
"loadStop": {
"type": "array",
"items": {
"type": "number"
}
"comment": {
"type": "string"
},
"maxAvail": {
"type": "number"
"filter": {
"$ref": "#/definitions/models.JobControlFilter"
},
"maxCpus": {
"force_kill": {
"description": "kill: SIGKILL at once (no graceful sequence)",
"type": "boolean"
},
"method": {
"description": "\"criu\" as default",
"type": "string"
},
"signal": {
"description": "kill only: send this signal once instead of the graceful sequence",
"type": "string"
}
}
},
"models.JobSubmitRequest": {
"type": "object",
"required": [
"command"
],
"properties": {
"affinity": {
"type": "string"
},
"asked_hosts": {
"type": "string"
},
"begin_time": {
"description": "k change type",
"allOf": [
{
"$ref": "#/definitions/models.CustomTime"
}
]
},
"chkpnt_dir": {
"type": "string"
},
"chkpnt_period": {
"type": "integer"
},
"maxExitRate": {
"type": "integer"
"command": {
"type": "string"
},
"maxJobs": {
"type": "integer"
"core_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"maxMem": {
"type": "integer"
"cpu_limit": {
"description": "k change type",
"allOf": [
{
"$ref": "#/definitions/models.CustomInt"
}
]
},
"maxSwap": {
"type": "integer"
"cwd": {
"type": "string"
},
"maxTmp": {
"type": "integer"
"data_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"mig": {
"type": "integer"
"data_spec_file": {
"type": "string"
},
"nDRes": {
"type": "integer"
"depend_cond": {
"type": "string"
},
"nDisks": {
"type": "integer"
},
"nIdx": {
"type": "integer"
},
"nRes": {
"type": "integer"
},
"numExitRate": {
"type": "integer"
},
"numIndx": {
"type": "integer"
},
"numJobs": {
"type": "integer"
},
"numRESERVE": {
"type": "integer"
},
"numRUN": {
"type": "integer"
},
"numSSUSP": {
"type": "integer"
},
"numUSUSP": {
"type": "integer"
},
"pprocs": {
"type": "integer"
},
"prvdrAvail": {
"type": "number"
},
"prvdrUsage": {
"type": "number"
},
"realLoad": {
"type": "number"
},
"resources": {
"env": {
"type": "array",
"items": {
"type": "string"
}
},
"threads_per_core": {
"type": "integer"
},
"userJobLimit": {
"type": "integer"
},
"windows": {
"err_file": {
"type": "string"
},
"except_list": {
"type": "string"
},
"exclusive": {
"type": "boolean"
},
"extend_data": {
"type": "string"
},
"file_limit": {
"description": "fsize",
"allOf": [
{
"$ref": "#/definitions/models.CustomLimit"
}
]
},
"from_host": {
"description": "client-asserted submitting hostname (bug-1676) -- passed through unchanged, not derived server-side",
"type": "string"
},
"gpureq": {
"type": "string"
},
"host_spec": {
"type": "string"
},
"in_file": {
"type": "string"
},
"init_chkpnt_period": {
"type": "integer"
},
"interactive": {
"type": "integer"
},
"job_description": {
"type": "string"
},
"job_group": {
"type": "string"
},
"job_name": {
"type": "string"
},
"job_priority": {
"type": "integer"
},
"launch_type": {
"type": "string"
},
"license_project": {
"type": "string"
},
"login_shell": {
"type": "string"
},
"mailuser": {
"type": "string"
},
"maxnum_processors": {
"type": "integer"
},
"mem_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"mig_threshold": {
"type": "integer"
},
"num_files": {
"type": "integer"
},
"num_processors": {
"type": "integer"
},
"out_dir": {
"type": "string"
},
"out_file": {
"type": "string"
},
"post_exec_cmd": {
"type": "string"
},
"pre_exec_cmd": {
"type": "string"
},
"process_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"project_name": {
"description": "default project: \"default\"",
"type": "string"
},
"queue_name": {
"description": "set to DEFAULT_QUEUE in config",
"type": "string"
},
"requeue_error_values": {
"type": "string"
},
"rerunable": {
"type": "boolean"
},
"resreq": {
"description": "default: \"type == local\"",
"type": "string"
},
"rsv_id": {
"type": "string"
},
"run_limit": {
"description": "k change type",
"allOf": [
{
"$ref": "#/definitions/models.CustomInt"
}
]
},
"run_time_estimation": {
"type": "integer"
},
"shell_limit": {
"$ref": "#/definitions/models.ShellLimit"
},
"sla": {
"type": "string"
},
"stack_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"swap_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"term_time": {
"description": "k change type",
"allOf": [
{
"$ref": "#/definitions/models.CustomTime"
}
]
},
"thread_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"transfer_files": {
"type": "array",
"items": {
"type": "string"
}
},
"user_group": {
"type": "string"
},
"warning_action": {
"type": "string"
},
"warning_time_period": {
"type": "integer"
}
}
},
"models.ShellLimit": {
"type": "object",
"properties": {
"core_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"cpu_limit": {
"description": "in milliseconds",
"type": "integer"
},
"data_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"file_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"mem_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"num_files": {
"type": "integer"
},
"process_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"stack_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"swap_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"thread_limit": {
"$ref": "#/definitions/models.CustomLimit"
}
}
}
@ -327,18 +705,18 @@ const docTemplate = `{
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "1.0",
Host: "localhost:8443",
BasePath: "/",
Schemes: []string{},
Title: "Host Management API",
Description: "API Server",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
Version: "1.0",
Host: "localhost:8443",
BasePath: "/xce/v1",
Schemes: []string{},
Title: "XCE API Server",
Description: "XCE cluster management REST API.",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
}
func init() {
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}

View file

@ -1,17 +1,17 @@
{
"swagger": "2.0",
"info": {
"description": "API Server",
"title": "Host Management API",
"description": "XCE cluster management REST API.",
"title": "XCE API Server",
"contact": {},
"version": "1.0"
},
"host": "localhost:8443",
"basePath": "/",
"basePath": "/xce/v1",
"paths": {
"/api/v1/hosts": {
"/hosts": {
"get": {
"description": "Get basic or full host information",
"description": "Get host information",
"consumes": [
"application/json"
],
@ -22,29 +22,279 @@
"hosts"
],
"summary": "Get host information",
"parameters": [
{
"type": "string",
"description": "Host type (basic or full)",
"name": "type",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "Response for full host type",
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/models.FullHost"
}
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/models.Error"
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs": {
"get": {
"description": "Get jobs information",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Get jobs information",
"parameters": [
{
"type": "string",
"description": "filter, e.g. user:eq:user1,queue:eq:queue1",
"name": "filter",
"in": "query"
},
{
"type": "string",
"description": "fields, e.g. jobid,status,queue",
"name": "fields",
"in": "query"
}
],
"responses": {
"200": {
"description": "Response for jobs info",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs/control": {
"post": {
"description": "Submit an action to be performed on specific jobs identified by filter in request body.\nkill/stop/resume signals as for POST /jobs/{jobids}/control.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Perform an action on filtered out jobs",
"parameters": [
{
"description": "Action to be performed",
"name": "action",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.JobControlRequest"
}
}
],
"responses": {
"202": {
"description": "Action successfully accepted",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Invalid request body or parameters",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"404": {
"description": "Job not found",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs/create": {
"post": {
"description": "Submit a new job with specified requirements and parameters",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Create a new job",
"parameters": [
{
"description": "Job submission parameters",
"name": "job",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.JobSubmitRequest"
}
}
],
"responses": {
"201": {
"description": "Job successfully created",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Invalid request body or parameters",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"401": {
"description": "Unauthorized - Invalid or missing credentials",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"403": {
"description": "Forbidden - User lacks permission",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs/{jobids}": {
"get": {
"description": "Retrieve information for multiple jobs in a single request with optional field selection",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Get multiple jobs by their IDs",
"parameters": [
{
"type": "string",
"description": "Comma-separated list of job IDs (e.g., 1001,1002,1003)",
"name": "jobids",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Comma-separated list of fields to return (e.g., jobid,status,queue)",
"name": "fields",
"in": "query"
}
],
"responses": {
"200": {
"description": "Successfully retrieved jobs",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "invalid parameters",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
}
},
"/jobs/{jobids}/control": {
"post": {
"description": "Submit an action to be performed on a specific job identified by jobids.\nkill without a signal: SIGINT, SIGTERM, then SIGKILL, job.terminate_interval\nseconds apart while the job runs; with a signal: that signal once; with\nforce_kill: SIGKILL at once. stop: SIGTSTP, then SIGSTOP after the interval\nif the job has not stopped. resume: SIGCONT (cancels a stop in progress).",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"jobs"
],
"summary": "Perform an action on a job",
"parameters": [
{
"type": "string",
"description": "Job ID",
"name": "jobids",
"in": "path",
"required": true
},
{
"description": "Action to be performed",
"name": "action",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.JobControlJobIDRequest"
}
}
],
"responses": {
"202": {
"description": "Action successfully accepted",
"schema": {
"$ref": "#/definitions/controllers.JsonStruct"
}
},
"400": {
"description": "Invalid request body or parameters",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"404": {
"description": "Job not found",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/controllers.JsonErrStruct"
}
}
}
@ -52,267 +302,395 @@
}
},
"definitions": {
"models.BasicHost": {
"controllers.JsonErrStruct": {
"type": "object",
"properties": {
"DResources": {
"type": "array",
"items": {
"type": "string"
}
},
"busyThreshold": {
"type": "array",
"items": {
"type": "number"
}
},
"cores": {
"code": {
"type": "integer"
},
"cores_per_proc": {
"details": {},
"msg": {}
}
},
"controllers.JsonStruct": {
"type": "object",
"properties": {
"code": {
"type": "integer"
},
"cpuFactor": {
"type": "number"
},
"hostAddr": {
"type": "string"
},
"hostModel": {
"type": "string"
},
"hostName": {
"type": "string"
},
"hostType": {
"type": "string"
},
"isServer": {
"type": "boolean"
},
"maxCpus": {
"data": {},
"msg": {}
}
},
"models.CustomInt": {
"type": "object",
"properties": {
"seconds": {
"type": "integer"
},
"maxMem": {
"type": "integer"
},
"maxSwap": {
"type": "integer"
},
"maxTmp": {
"type": "integer"
},
"nDRes": {
"type": "integer"
},
"nDisks": {
"type": "integer"
},
"nRes": {
"type": "integer"
},
"numIndx": {
"type": "integer"
},
"pprocs": {
"type": "integer"
},
"resources": {
"type": "array",
"items": {
"type": "string"
}
},
"threads_per_core": {
"type": "integer"
},
"windows": {
}
}
},
"models.CustomLimit": {
"type": "object",
"properties": {
"mb": {
"type": "number",
"format": "float64"
}
}
},
"models.CustomTime": {
"type": "object",
"properties": {
"time": {
"type": "string"
}
}
},
"models.Error": {
"models.JobControlFilter": {
"type": "object",
"properties": {
"error": {
"all_jobs": {
"type": "boolean"
},
"exec_hosts": {
"type": "string"
},
"job_group_name": {
"type": "string"
},
"job_name": {
"type": "string"
},
"queue_name": {
"type": "string"
},
"sla": {
"type": "string"
},
"users": {
"type": "string"
}
}
},
"models.FullHost": {
"models.JobControlJobIDRequest": {
"type": "object",
"required": [
"action"
],
"properties": {
"DResources": {
"type": "array",
"items": {
"type": "string"
}
},
"affinityCpulist": {
"action": {
"type": "string"
},
"attr": {
"type": "integer"
},
"busySched": {
"type": "number"
},
"busyStop": {
"type": "number"
},
"busyThreshold": {
"type": "array",
"items": {
"type": "number"
}
},
"chkSig": {
"type": "integer"
},
"cnsmrAvail": {
"type": "number"
},
"cnsmrUsage": {
"type": "number"
},
"cores": {
"type": "integer"
},
"cores_per_proc": {
"type": "integer"
},
"cpuFactor": {
"type": "number"
},
"cycleTimeLeft": {
"type": "integer"
},
"hCtrlMsg": {
"type": "integer"
},
"hStatus": {
"comment": {
"type": "string"
},
"hostAddr": {
"type": "string"
},
"hostModel": {
"type": "string"
},
"hostName": {
"type": "string"
},
"hostType": {
"type": "string"
},
"idleTime": {
"type": "integer"
},
"isServer": {
"force_kill": {
"description": "kill: SIGKILL at once (no graceful sequence)",
"type": "boolean"
},
"load": {
"type": "array",
"items": {
"type": "number"
}
"method": {
"description": "\"criu\" as default",
"type": "string"
},
"loadSched": {
"type": "array",
"items": {
"type": "number"
}
"signal": {
"description": "kill only: send this signal once instead of the graceful sequence",
"type": "string"
}
}
},
"models.JobControlRequest": {
"type": "object",
"required": [
"action",
"filter"
],
"properties": {
"action": {
"type": "string"
},
"loadStop": {
"type": "array",
"items": {
"type": "number"
}
"comment": {
"type": "string"
},
"maxAvail": {
"type": "number"
"filter": {
"$ref": "#/definitions/models.JobControlFilter"
},
"maxCpus": {
"force_kill": {
"description": "kill: SIGKILL at once (no graceful sequence)",
"type": "boolean"
},
"method": {
"description": "\"criu\" as default",
"type": "string"
},
"signal": {
"description": "kill only: send this signal once instead of the graceful sequence",
"type": "string"
}
}
},
"models.JobSubmitRequest": {
"type": "object",
"required": [
"command"
],
"properties": {
"affinity": {
"type": "string"
},
"asked_hosts": {
"type": "string"
},
"begin_time": {
"description": "k change type",
"allOf": [
{
"$ref": "#/definitions/models.CustomTime"
}
]
},
"chkpnt_dir": {
"type": "string"
},
"chkpnt_period": {
"type": "integer"
},
"maxExitRate": {
"type": "integer"
"command": {
"type": "string"
},
"maxJobs": {
"type": "integer"
"core_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"maxMem": {
"type": "integer"
"cpu_limit": {
"description": "k change type",
"allOf": [
{
"$ref": "#/definitions/models.CustomInt"
}
]
},
"maxSwap": {
"type": "integer"
"cwd": {
"type": "string"
},
"maxTmp": {
"type": "integer"
"data_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"mig": {
"type": "integer"
"data_spec_file": {
"type": "string"
},
"nDRes": {
"type": "integer"
"depend_cond": {
"type": "string"
},
"nDisks": {
"type": "integer"
},
"nIdx": {
"type": "integer"
},
"nRes": {
"type": "integer"
},
"numExitRate": {
"type": "integer"
},
"numIndx": {
"type": "integer"
},
"numJobs": {
"type": "integer"
},
"numRESERVE": {
"type": "integer"
},
"numRUN": {
"type": "integer"
},
"numSSUSP": {
"type": "integer"
},
"numUSUSP": {
"type": "integer"
},
"pprocs": {
"type": "integer"
},
"prvdrAvail": {
"type": "number"
},
"prvdrUsage": {
"type": "number"
},
"realLoad": {
"type": "number"
},
"resources": {
"env": {
"type": "array",
"items": {
"type": "string"
}
},
"threads_per_core": {
"type": "integer"
},
"userJobLimit": {
"type": "integer"
},
"windows": {
"err_file": {
"type": "string"
},
"except_list": {
"type": "string"
},
"exclusive": {
"type": "boolean"
},
"extend_data": {
"type": "string"
},
"file_limit": {
"description": "fsize",
"allOf": [
{
"$ref": "#/definitions/models.CustomLimit"
}
]
},
"from_host": {
"description": "client-asserted submitting hostname (bug-1676) -- passed through unchanged, not derived server-side",
"type": "string"
},
"gpureq": {
"type": "string"
},
"host_spec": {
"type": "string"
},
"in_file": {
"type": "string"
},
"init_chkpnt_period": {
"type": "integer"
},
"interactive": {
"type": "integer"
},
"job_description": {
"type": "string"
},
"job_group": {
"type": "string"
},
"job_name": {
"type": "string"
},
"job_priority": {
"type": "integer"
},
"launch_type": {
"type": "string"
},
"license_project": {
"type": "string"
},
"login_shell": {
"type": "string"
},
"mailuser": {
"type": "string"
},
"maxnum_processors": {
"type": "integer"
},
"mem_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"mig_threshold": {
"type": "integer"
},
"num_files": {
"type": "integer"
},
"num_processors": {
"type": "integer"
},
"out_dir": {
"type": "string"
},
"out_file": {
"type": "string"
},
"post_exec_cmd": {
"type": "string"
},
"pre_exec_cmd": {
"type": "string"
},
"process_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"project_name": {
"description": "default project: \"default\"",
"type": "string"
},
"queue_name": {
"description": "set to DEFAULT_QUEUE in config",
"type": "string"
},
"requeue_error_values": {
"type": "string"
},
"rerunable": {
"type": "boolean"
},
"resreq": {
"description": "default: \"type == local\"",
"type": "string"
},
"rsv_id": {
"type": "string"
},
"run_limit": {
"description": "k change type",
"allOf": [
{
"$ref": "#/definitions/models.CustomInt"
}
]
},
"run_time_estimation": {
"type": "integer"
},
"shell_limit": {
"$ref": "#/definitions/models.ShellLimit"
},
"sla": {
"type": "string"
},
"stack_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"swap_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"term_time": {
"description": "k change type",
"allOf": [
{
"$ref": "#/definitions/models.CustomTime"
}
]
},
"thread_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"transfer_files": {
"type": "array",
"items": {
"type": "string"
}
},
"user_group": {
"type": "string"
},
"warning_action": {
"type": "string"
},
"warning_time_period": {
"type": "integer"
}
}
},
"models.ShellLimit": {
"type": "object",
"properties": {
"core_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"cpu_limit": {
"description": "in milliseconds",
"type": "integer"
},
"data_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"file_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"mem_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"num_files": {
"type": "integer"
},
"process_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"stack_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"swap_limit": {
"$ref": "#/definitions/models.CustomLimit"
},
"thread_limit": {
"$ref": "#/definitions/models.CustomLimit"
}
}
}

View file

@ -1,212 +1,467 @@
basePath: /
basePath: /xce/v1
definitions:
models.BasicHost:
controllers.JsonErrStruct:
properties:
DResources:
items:
type: string
type: array
busyThreshold:
items:
type: number
type: array
cores:
code:
type: integer
cores_per_proc:
details: {}
msg: {}
type: object
controllers.JsonStruct:
properties:
code:
type: integer
cpuFactor:
data: {}
msg: {}
type: object
models.CustomInt:
properties:
seconds:
type: integer
type: object
models.CustomLimit:
properties:
mb:
format: float64
type: number
hostAddr:
type: string
hostModel:
type: string
hostName:
type: string
hostType:
type: string
isServer:
type: boolean
maxCpus:
type: integer
maxMem:
type: integer
maxSwap:
type: integer
maxTmp:
type: integer
nDRes:
type: integer
nDisks:
type: integer
nRes:
type: integer
numIndx:
type: integer
pprocs:
type: integer
resources:
items:
type: string
type: array
threads_per_core:
type: integer
windows:
type: object
models.CustomTime:
properties:
time:
type: string
type: object
models.Error:
models.JobControlFilter:
properties:
error:
all_jobs:
type: boolean
exec_hosts:
type: string
job_group_name:
type: string
job_name:
type: string
queue_name:
type: string
sla:
type: string
users:
type: string
type: object
models.FullHost:
models.JobControlJobIDRequest:
properties:
DResources:
items:
type: string
type: array
affinityCpulist:
action:
type: string
attr:
type: integer
busySched:
type: number
busyStop:
type: number
busyThreshold:
items:
type: number
type: array
chkSig:
type: integer
cnsmrAvail:
type: number
cnsmrUsage:
type: number
cores:
type: integer
cores_per_proc:
type: integer
cpuFactor:
type: number
cycleTimeLeft:
type: integer
hCtrlMsg:
type: integer
hStatus:
comment:
type: string
hostAddr:
type: string
hostModel:
type: string
hostName:
type: string
hostType:
type: string
idleTime:
type: integer
isServer:
force_kill:
description: 'kill: SIGKILL at once (no graceful sequence)'
type: boolean
load:
items:
type: number
type: array
loadSched:
items:
type: number
type: array
loadStop:
items:
type: number
type: array
maxAvail:
type: number
maxCpus:
method:
description: '"criu" as default'
type: string
signal:
description: 'kill only: send this signal once instead of the graceful sequence'
type: string
required:
- action
type: object
models.JobControlRequest:
properties:
action:
type: string
comment:
type: string
filter:
$ref: '#/definitions/models.JobControlFilter'
force_kill:
description: 'kill: SIGKILL at once (no graceful sequence)'
type: boolean
method:
description: '"criu" as default'
type: string
signal:
description: 'kill only: send this signal once instead of the graceful sequence'
type: string
required:
- action
- filter
type: object
models.JobSubmitRequest:
properties:
affinity:
type: string
asked_hosts:
type: string
begin_time:
allOf:
- $ref: '#/definitions/models.CustomTime'
description: k change type
chkpnt_dir:
type: string
chkpnt_period:
type: integer
maxExitRate:
type: integer
maxJobs:
type: integer
maxMem:
type: integer
maxSwap:
type: integer
maxTmp:
type: integer
mig:
type: integer
nDRes:
type: integer
nDisks:
type: integer
nIdx:
type: integer
nRes:
type: integer
numExitRate:
type: integer
numIndx:
type: integer
numJobs:
type: integer
numRESERVE:
type: integer
numRUN:
type: integer
numSSUSP:
type: integer
numUSUSP:
type: integer
pprocs:
type: integer
prvdrAvail:
type: number
prvdrUsage:
type: number
realLoad:
type: number
resources:
command:
type: string
core_limit:
$ref: '#/definitions/models.CustomLimit'
cpu_limit:
allOf:
- $ref: '#/definitions/models.CustomInt'
description: k change type
cwd:
type: string
data_limit:
$ref: '#/definitions/models.CustomLimit'
data_spec_file:
type: string
depend_cond:
type: string
env:
items:
type: string
type: array
threads_per_core:
type: integer
userJobLimit:
type: integer
windows:
err_file:
type: string
except_list:
type: string
exclusive:
type: boolean
extend_data:
type: string
file_limit:
allOf:
- $ref: '#/definitions/models.CustomLimit'
description: fsize
from_host:
description: client-asserted submitting hostname (bug-1676) -- passed through
unchanged, not derived server-side
type: string
gpureq:
type: string
host_spec:
type: string
in_file:
type: string
init_chkpnt_period:
type: integer
interactive:
type: integer
job_description:
type: string
job_group:
type: string
job_name:
type: string
job_priority:
type: integer
launch_type:
type: string
license_project:
type: string
login_shell:
type: string
mailuser:
type: string
maxnum_processors:
type: integer
mem_limit:
$ref: '#/definitions/models.CustomLimit'
mig_threshold:
type: integer
num_files:
type: integer
num_processors:
type: integer
out_dir:
type: string
out_file:
type: string
post_exec_cmd:
type: string
pre_exec_cmd:
type: string
process_limit:
$ref: '#/definitions/models.CustomLimit'
project_name:
description: 'default project: "default"'
type: string
queue_name:
description: set to DEFAULT_QUEUE in config
type: string
requeue_error_values:
type: string
rerunable:
type: boolean
resreq:
description: 'default: "type == local"'
type: string
rsv_id:
type: string
run_limit:
allOf:
- $ref: '#/definitions/models.CustomInt'
description: k change type
run_time_estimation:
type: integer
shell_limit:
$ref: '#/definitions/models.ShellLimit'
sla:
type: string
stack_limit:
$ref: '#/definitions/models.CustomLimit'
swap_limit:
$ref: '#/definitions/models.CustomLimit'
tags:
items:
type: string
type: array
term_time:
allOf:
- $ref: '#/definitions/models.CustomTime'
description: k change type
thread_limit:
$ref: '#/definitions/models.CustomLimit'
transfer_files:
items:
type: string
type: array
user_group:
type: string
warning_action:
type: string
warning_time_period:
type: integer
required:
- command
type: object
models.ShellLimit:
properties:
core_limit:
$ref: '#/definitions/models.CustomLimit'
cpu_limit:
description: in milliseconds
type: integer
data_limit:
$ref: '#/definitions/models.CustomLimit'
file_limit:
$ref: '#/definitions/models.CustomLimit'
mem_limit:
$ref: '#/definitions/models.CustomLimit'
num_files:
type: integer
process_limit:
$ref: '#/definitions/models.CustomLimit'
stack_limit:
$ref: '#/definitions/models.CustomLimit'
swap_limit:
$ref: '#/definitions/models.CustomLimit'
thread_limit:
$ref: '#/definitions/models.CustomLimit'
type: object
host: localhost:8443
info:
contact: {}
description: API Server
title: Host Management API
description: XCE cluster management REST API.
title: XCE API Server
version: "1.0"
paths:
/api/v1/hosts:
/hosts:
get:
consumes:
- application/json
description: Get basic or full host information
description: Get host information
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.JsonStruct'
"400":
description: Bad Request
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
summary: Get host information
tags:
- hosts
/jobs:
get:
consumes:
- application/json
description: Get jobs information
parameters:
- description: Host type (basic or full)
- description: filter, e.g. user:eq:user1,queue:eq:queue1
in: query
name: type
required: true
name: filter
type: string
- description: fields, e.g. jobid,status,queue
in: query
name: fields
type: string
produces:
- application/json
responses:
"200":
description: Response for full host type
description: Response for jobs info
schema:
items:
$ref: '#/definitions/models.FullHost'
type: array
$ref: '#/definitions/controllers.JsonStruct'
"400":
description: Bad Request
schema:
$ref: '#/definitions/models.Error'
summary: Get host information
$ref: '#/definitions/controllers.JsonErrStruct'
summary: Get jobs information
tags:
- hosts
- jobs
/jobs/{jobids}:
get:
consumes:
- application/json
description: Retrieve information for multiple jobs in a single request with
optional field selection
parameters:
- description: Comma-separated list of job IDs (e.g., 1001,1002,1003)
in: path
name: jobids
required: true
type: string
- description: Comma-separated list of fields to return (e.g., jobid,status,queue)
in: query
name: fields
type: string
produces:
- application/json
responses:
"200":
description: Successfully retrieved jobs
schema:
$ref: '#/definitions/controllers.JsonStruct'
"400":
description: invalid parameters
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
"500":
description: Internal server error
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
summary: Get multiple jobs by their IDs
tags:
- jobs
/jobs/{jobids}/control:
post:
consumes:
- application/json
description: |-
Submit an action to be performed on a specific job identified by jobids.
kill without a signal: SIGINT, SIGTERM, then SIGKILL, job.terminate_interval
seconds apart while the job runs; with a signal: that signal once; with
force_kill: SIGKILL at once. stop: SIGTSTP, then SIGSTOP after the interval
if the job has not stopped. resume: SIGCONT (cancels a stop in progress).
parameters:
- description: Job ID
in: path
name: jobids
required: true
type: string
- description: Action to be performed
in: body
name: action
required: true
schema:
$ref: '#/definitions/models.JobControlJobIDRequest'
produces:
- application/json
responses:
"202":
description: Action successfully accepted
schema:
$ref: '#/definitions/controllers.JsonStruct'
"400":
description: Invalid request body or parameters
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
"404":
description: Job not found
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
"500":
description: Internal server error
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
summary: Perform an action on a job
tags:
- jobs
/jobs/control:
post:
consumes:
- application/json
description: |-
Submit an action to be performed on specific jobs identified by filter in request body.
kill/stop/resume signals as for POST /jobs/{jobids}/control.
parameters:
- description: Action to be performed
in: body
name: action
required: true
schema:
$ref: '#/definitions/models.JobControlRequest'
produces:
- application/json
responses:
"202":
description: Action successfully accepted
schema:
$ref: '#/definitions/controllers.JsonStruct'
"400":
description: Invalid request body or parameters
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
"404":
description: Job not found
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
"500":
description: Internal server error
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
summary: Perform an action on filtered out jobs
tags:
- jobs
/jobs/create:
post:
consumes:
- application/json
description: Submit a new job with specified requirements and parameters
parameters:
- description: Job submission parameters
in: body
name: job
required: true
schema:
$ref: '#/definitions/models.JobSubmitRequest'
produces:
- application/json
responses:
"201":
description: Job successfully created
schema:
$ref: '#/definitions/controllers.JsonStruct'
"400":
description: Invalid request body or parameters
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
"401":
description: Unauthorized - Invalid or missing credentials
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
"403":
description: Forbidden - User lacks permission
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
"500":
description: Internal server error
schema:
$ref: '#/definitions/controllers.JsonErrStruct'
summary: Create a new job
tags:
- jobs
swagger: "2.0"