diff --git a/.gitignore b/.gitignore index c077bc4..ab52275 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ bin/ *.exe -.sisyphus/ diff --git a/hpc_server_openapi.json b/hpc_server_openapi.json index d3f300e..5a1d98c 100644 --- a/hpc_server_openapi.json +++ b/hpc_server_openapi.json @@ -2,7 +2,7 @@ "openapi": "3.0.3", "info": { "title": "GCY HPC Server API", - "description": "Slurm HPC cluster management API for job submission, cluster monitoring, and job template management.", + "description": "Slurm HPC cluster management API for job submission and cluster monitoring.", "version": "0.1.0" }, "servers": [ @@ -21,8 +21,8 @@ "description": "Cluster node, partition, and diagnostic information" }, { - "name": "Templates", - "description": "Job template CRUD operations" + "name": "Applications", + "description": "Application definition CRUD and job submission" } ], "paths": { @@ -674,6 +674,395 @@ } } }, + "/applications": { + "get": { + "tags": ["Applications"], + "summary": "List applications", + "description": "Retrieves a paginated list of application definitions.", + "operationId": "listApplications", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (starts from 1)", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "default": 1 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "default": 20 + } + } + ], + "responses": { + "200": { + "description": "Paginated list of applications", + "content": { + "application/json": { + "schema": { + "allOf": [ + { "$ref": "#/components/schemas/ApiResponseSuccess" }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/ApplicationListResponse" + } + } + } + ] + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + } + } + }, + "post": { + "tags": ["Applications"], + "summary": "Create an application", + "description": "Creates a new application definition.", + "operationId": "createApplication", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApplicationRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Application created successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { "$ref": "#/components/schemas/ApiResponseSuccess" }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Created application ID" + } + } + } + } + } + ] + } + } + } + }, + "400": { + "description": "Invalid request body or missing required fields", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + } + } + } + }, + "/applications/{id}": { + "get": { + "tags": ["Applications"], + "summary": "Get application by ID", + "description": "Retrieves a specific application definition.", + "operationId": "getApplication", + "parameters": [ + { "$ref": "#/components/parameters/ApplicationId" } + ], + "responses": { + "200": { + "description": "Application details", + "content": { + "application/json": { + "schema": { + "allOf": [ + { "$ref": "#/components/schemas/ApiResponseSuccess" }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Application" + } + } + } + ] + } + } + } + }, + "404": { + "description": "Application not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + } + } + }, + "put": { + "tags": ["Applications"], + "summary": "Update an application", + "description": "Updates an existing application definition.", + "operationId": "updateApplication", + "parameters": [ + { "$ref": "#/components/parameters/ApplicationId" } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateApplicationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Application updated successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { "$ref": "#/components/schemas/ApiResponseSuccess" }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "application updated" + } + } + } + } + } + ] + } + } + } + }, + "400": { + "description": "Invalid request body", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + }, + "404": { + "description": "Application not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + } + } + }, + "delete": { + "tags": ["Applications"], + "summary": "Delete an application", + "description": "Deletes an application definition by ID.", + "operationId": "deleteApplication", + "parameters": [ + { "$ref": "#/components/parameters/ApplicationId" } + ], + "responses": { + "200": { + "description": "Application deleted successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { "$ref": "#/components/schemas/ApiResponseSuccess" }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "application deleted" + } + } + } + } + } + ] + } + } + } + }, + "404": { + "description": "Application not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + } + } + } + }, + "/applications/{id}/submit": { + "post": { + "tags": ["Applications"], + "summary": "Submit a job from an application", + "description": "Submits a Slurm job using the application's script template and provided parameter values.", + "operationId": "submitApplication", + "parameters": [ + { "$ref": "#/components/parameters/ApplicationId" } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationSubmitRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Job submitted successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { "$ref": "#/components/schemas/ApiResponseSuccess" }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/JobResponse" + } + } + } + ] + } + } + } + }, + "400": { + "description": "Invalid request body or missing required parameter values", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + }, + "404": { + "description": "Application not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + }, + "502": { + "description": "Slurm backend error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponseError" + } + } + } + } + } + } + }, "/diag": { "get": { "tags": ["Cluster"], @@ -714,350 +1103,6 @@ } } } - }, - "/templates": { - "get": { - "tags": ["Templates"], - "summary": "List all templates", - "description": "Retrieves a paginated list of job templates.", - "operationId": "listTemplates", - "parameters": [ - { - "name": "page", - "in": "query", - "description": "Page number (default: 1)", - "schema": { - "type": "integer", - "minimum": 1, - "default": 1 - } - }, - { - "name": "page_size", - "in": "query", - "description": "Items per page (default: 20)", - "schema": { - "type": "integer", - "minimum": 1, - "default": 20 - } - } - ], - "responses": { - "200": { - "description": "Paginated list of templates", - "content": { - "application/json": { - "schema": { - "allOf": [ - { "$ref": "#/components/schemas/ApiResponseSuccess" }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/TemplateListResponse" - } - } - } - ] - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - } - } - }, - "post": { - "tags": ["Templates"], - "summary": "Create a template", - "description": "Creates a new job template with the provided script and parameters.", - "operationId": "createTemplate", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateTemplateRequest" - } - } - } - }, - "responses": { - "201": { - "description": "Template created successfully", - "content": { - "application/json": { - "schema": { - "allOf": [ - { "$ref": "#/components/schemas/ApiResponseSuccess" }, - { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "The ID of the newly created template" - } - } - } - } - } - ] - } - } - } - }, - "400": { - "description": "Invalid request body or missing required fields", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - }, - "examples": { - "invalid_body": { - "value": { - "success": false, - "error": "invalid request body" - } - }, - "missing_fields": { - "value": { - "success": false, - "error": "name and script are required" - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - } - } - } - }, - "/templates/{id}": { - "get": { - "tags": ["Templates"], - "summary": "Get template by ID", - "description": "Retrieves a specific job template.", - "operationId": "getTemplate", - "parameters": [ - { - "$ref": "#/components/parameters/TemplateId" - } - ], - "responses": { - "200": { - "description": "Template details", - "content": { - "application/json": { - "schema": { - "allOf": [ - { "$ref": "#/components/schemas/ApiResponseSuccess" }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/JobTemplate" - } - } - } - ] - } - } - } - }, - "400": { - "description": "Invalid template ID", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - }, - "404": { - "description": "Template not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - } - } - }, - "put": { - "tags": ["Templates"], - "summary": "Update a template", - "description": "Updates an existing job template.", - "operationId": "updateTemplate", - "parameters": [ - { - "$ref": "#/components/parameters/TemplateId" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateTemplateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Template updated successfully", - "content": { - "application/json": { - "schema": { - "allOf": [ - { "$ref": "#/components/schemas/ApiResponseSuccess" }, - { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "template updated" - } - } - } - } - } - ] - } - } - } - }, - "400": { - "description": "Invalid template ID or request body", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - }, - "404": { - "description": "Template not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - } - } - }, - "delete": { - "tags": ["Templates"], - "summary": "Delete a template", - "description": "Deletes a job template by ID.", - "operationId": "deleteTemplate", - "parameters": [ - { - "$ref": "#/components/parameters/TemplateId" - } - ], - "responses": { - "200": { - "description": "Template deleted successfully", - "content": { - "application/json": { - "schema": { - "allOf": [ - { "$ref": "#/components/schemas/ApiResponseSuccess" }, - { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "template deleted" - } - } - } - } - } - ] - } - } - } - }, - "400": { - "description": "Invalid template ID", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseError" - } - } - } - } - } - } } }, "components": { @@ -1089,11 +1134,11 @@ "type": "string" } }, - "TemplateId": { + "ApplicationId": { "name": "id", "in": "path", "required": true, - "description": "Template ID", + "description": "Application ID", "schema": { "type": "integer", "format": "int64" @@ -1536,145 +1581,204 @@ } } }, - "JobTemplate": { + "ParameterSchema": { + "type": "object", + "required": ["name", "type"], + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "label": { + "type": "string", + "description": "Display label" + }, + "type": { + "type": "string", + "enum": ["string", "integer", "enum", "file", "directory", "boolean"], + "description": "Parameter type" + }, + "required": { + "type": "boolean", + "description": "Whether this parameter is required" + }, + "default": { + "type": "string", + "description": "Default value" + }, + "options": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Available options for enum type" + }, + "description": { + "type": "string", + "description": "Parameter description" + } + } + }, + "Application": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64", - "description": "Template ID" + "description": "Application ID" }, "name": { "type": "string", - "description": "Template name" + "description": "Application name" }, "description": { "type": "string", - "description": "Template description" + "description": "Application description" }, - "script": { + "icon": { "type": "string", - "description": "Job script content" + "description": "Application icon" }, - "partition": { + "category": { "type": "string", - "description": "Default partition" + "description": "Application category" }, - "qos": { + "script_template": { "type": "string", - "description": "Default QOS" + "description": "Job script template" }, - "cpus": { + "parameters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ParameterSchema" + }, + "description": "Parameter definitions" + }, + "scope": { + "type": "string", + "description": "Application scope", + "default": "system" + }, + "created_by": { "type": "integer", - "description": "Default CPU count" - }, - "memory": { - "type": "string", - "description": "Default memory" - }, - "time_limit": { - "type": "string", - "description": "Default time limit" + "format": "int64", + "description": "Creator user ID", + "nullable": true }, "created_at": { "type": "string", "format": "date-time", - "description": "Creation timestamp" + "description": "Creation timestamp", + "nullable": true }, "updated_at": { "type": "string", "format": "date-time", - "description": "Last update timestamp" + "description": "Last update timestamp", + "nullable": true } } }, - "CreateTemplateRequest": { + "CreateApplicationRequest": { "type": "object", - "required": ["name", "script"], + "required": ["name", "script_template"], "properties": { "name": { "type": "string", - "description": "Template name" + "description": "Application name" }, "description": { "type": "string", - "description": "Template description" + "description": "Application description" }, - "script": { + "icon": { "type": "string", - "description": "Job script content" + "description": "Application icon" }, - "partition": { + "category": { "type": "string", - "description": "Default partition" + "description": "Application category" }, - "qos": { + "script_template": { "type": "string", - "description": "Default QOS" + "description": "Job script template" }, - "cpus": { - "type": "integer", - "description": "Default CPU count" - }, - "memory": { - "type": "string", - "description": "Default memory" - }, - "time_limit": { - "type": "string", - "description": "Default time limit" - } - } - }, - "UpdateTemplateRequest": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Template name" - }, - "description": { - "type": "string", - "description": "Template description" - }, - "script": { - "type": "string", - "description": "Job script content" - }, - "partition": { - "type": "string", - "description": "Default partition" - }, - "qos": { - "type": "string", - "description": "Default QOS" - }, - "cpus": { - "type": "integer", - "description": "Default CPU count" - }, - "memory": { - "type": "string", - "description": "Default memory" - }, - "time_limit": { - "type": "string", - "description": "Default time limit" - } - } - }, - "TemplateListResponse": { - "type": "object", - "properties": { - "templates": { + "parameters": { "type": "array", "items": { - "$ref": "#/components/schemas/JobTemplate" - } + "$ref": "#/components/schemas/ParameterSchema" + }, + "description": "Parameter definitions" + }, + "scope": { + "type": "string", + "description": "Application scope", + "default": "system" + } + } + }, + "UpdateApplicationRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Application name" + }, + "description": { + "type": "string", + "description": "Application description" + }, + "icon": { + "type": "string", + "description": "Application icon" + }, + "category": { + "type": "string", + "description": "Application category" + }, + "script_template": { + "type": "string", + "description": "Job script template" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ParameterSchema" + }, + "description": "Parameter definitions" + }, + "scope": { + "type": "string", + "description": "Application scope" + } + } + }, + "ApplicationSubmitRequest": { + "type": "object", + "required": ["values"], + "properties": { + "values": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Parameter name to value mapping" + } + } + }, + "ApplicationListResponse": { + "type": "object", + "properties": { + "applications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Application" + }, + "description": "List of applications" }, "total": { "type": "integer", - "description": "Total number of templates" + "description": "Total number of applications" }, "page": { "type": "integer",