mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-11-04 01:25:06 +01:00 
			
		
		
		
	Merge pull request #73 from ClusterCockpit/feature-62-rest-endpoint-delete-jobs
Feature 62 rest endpoint delete jobs Fix #62
This commit is contained in:
		api
internal
pkg/schema
test
							
								
								
									
										321
									
								
								api/swagger.json
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										321
									
								
								api/swagger.json
									
									
									
									
									
								
							@@ -1,9 +1,8 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "swagger": "2.0",
 | 
					    "swagger": "2.0",
 | 
				
			||||||
    "info": {
 | 
					    "info": {
 | 
				
			||||||
        "description": "Defines a tag using name and type.",
 | 
					        "description": "API for batch job control.",
 | 
				
			||||||
        "title": "ClusterCockpit REST API",
 | 
					        "title": "ClusterCockpit REST API",
 | 
				
			||||||
        "termsOfService": "https://monitoring.nhr.fau.de/imprint",
 | 
					 | 
				
			||||||
        "contact": {
 | 
					        "contact": {
 | 
				
			||||||
            "name": "ClusterCockpit Project",
 | 
					            "name": "ClusterCockpit Project",
 | 
				
			||||||
            "url": "https://github.com/ClusterCockpit",
 | 
					            "url": "https://github.com/ClusterCockpit",
 | 
				
			||||||
@@ -13,9 +12,9 @@
 | 
				
			|||||||
            "name": "MIT License",
 | 
					            "name": "MIT License",
 | 
				
			||||||
            "url": "https://opensource.org/licenses/MIT"
 | 
					            "url": "https://opensource.org/licenses/MIT"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "version": "0.1.0"
 | 
					        "version": "0.2.0"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "host": "clustercockpit.localhost:8082",
 | 
					    "host": "localhost:8080",
 | 
				
			||||||
    "basePath": "/api",
 | 
					    "basePath": "/api",
 | 
				
			||||||
    "paths": {
 | 
					    "paths": {
 | 
				
			||||||
        "/jobs/": {
 | 
					        "/jobs/": {
 | 
				
			||||||
@@ -26,12 +25,12 @@
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                "description": "Get a list of all jobs. Filters can be applied using query parameters.\nNumber of results can be limited by page. Results are sorted by descending startTime.",
 | 
					                "description": "Get a list of all jobs. Filters can be applied using query parameters.\nNumber of results can be limited by page. Results are sorted by descending startTime.",
 | 
				
			||||||
                "consumes": [
 | 
					 | 
				
			||||||
                    "application/json"
 | 
					 | 
				
			||||||
                ],
 | 
					 | 
				
			||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "query"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Lists all jobs",
 | 
					                "summary": "Lists all jobs",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -62,13 +61,13 @@
 | 
				
			|||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        "type": "integer",
 | 
					                        "type": "integer",
 | 
				
			||||||
                        "description": "Items per page (If empty: No Limit)",
 | 
					                        "description": "Items per page (Default: 25)",
 | 
				
			||||||
                        "name": "items-per-page",
 | 
					                        "name": "items-per-page",
 | 
				
			||||||
                        "in": "query"
 | 
					                        "in": "query"
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        "type": "integer",
 | 
					                        "type": "integer",
 | 
				
			||||||
                        "description": "Page Number (If empty: No Paging)",
 | 
					                        "description": "Page Number (Default: 1)",
 | 
				
			||||||
                        "name": "page",
 | 
					                        "name": "page",
 | 
				
			||||||
                        "in": "query"
 | 
					                        "in": "query"
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
@@ -110,6 +109,221 @@
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        "/jobs/delete_job/": {
 | 
				
			||||||
 | 
					            "delete": {
 | 
				
			||||||
 | 
					                "security": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "ApiKeyAuth": []
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "description": "Job to delete is specified by request body. All fields are required in this case.",
 | 
				
			||||||
 | 
					                "consumes": [
 | 
				
			||||||
 | 
					                    "application/json"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "produces": [
 | 
				
			||||||
 | 
					                    "application/json"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "remove"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "summary": "Remove a job from the sql database",
 | 
				
			||||||
 | 
					                "parameters": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "description": "All fields required",
 | 
				
			||||||
 | 
					                        "name": "request",
 | 
				
			||||||
 | 
					                        "in": "body",
 | 
				
			||||||
 | 
					                        "required": true,
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.DeleteJobApiRequest"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "responses": {
 | 
				
			||||||
 | 
					                    "200": {
 | 
				
			||||||
 | 
					                        "description": "Success message",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.DeleteJobApiResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "400": {
 | 
				
			||||||
 | 
					                        "description": "Bad Request",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "401": {
 | 
				
			||||||
 | 
					                        "description": "Unauthorized",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "403": {
 | 
				
			||||||
 | 
					                        "description": "Forbidden",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "404": {
 | 
				
			||||||
 | 
					                        "description": "Resource not found",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "422": {
 | 
				
			||||||
 | 
					                        "description": "Unprocessable Entity: finding job failed: sql: no rows in result set",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "500": {
 | 
				
			||||||
 | 
					                        "description": "Internal Server Error",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "/jobs/delete_job/{id}": {
 | 
				
			||||||
 | 
					            "delete": {
 | 
				
			||||||
 | 
					                "security": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "ApiKeyAuth": []
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "description": "Job to remove is specified by database ID. This will not remove the job from the job archive.",
 | 
				
			||||||
 | 
					                "produces": [
 | 
				
			||||||
 | 
					                    "application/json"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "remove"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "summary": "Remove a job from the sql database",
 | 
				
			||||||
 | 
					                "parameters": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "type": "integer",
 | 
				
			||||||
 | 
					                        "description": "Database ID of Job",
 | 
				
			||||||
 | 
					                        "name": "id",
 | 
				
			||||||
 | 
					                        "in": "path",
 | 
				
			||||||
 | 
					                        "required": true
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "responses": {
 | 
				
			||||||
 | 
					                    "200": {
 | 
				
			||||||
 | 
					                        "description": "Success message",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.DeleteJobApiResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "400": {
 | 
				
			||||||
 | 
					                        "description": "Bad Request",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "401": {
 | 
				
			||||||
 | 
					                        "description": "Unauthorized",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "403": {
 | 
				
			||||||
 | 
					                        "description": "Forbidden",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "404": {
 | 
				
			||||||
 | 
					                        "description": "Resource not found",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "422": {
 | 
				
			||||||
 | 
					                        "description": "Unprocessable Entity: finding job failed: sql: no rows in result set",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "500": {
 | 
				
			||||||
 | 
					                        "description": "Internal Server Error",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "/jobs/delete_job_before/{ts}": {
 | 
				
			||||||
 | 
					            "delete": {
 | 
				
			||||||
 | 
					                "security": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "ApiKeyAuth": []
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "description": "Remove all jobs with start time before timestamp. The jobs will not be removed from the job archive.",
 | 
				
			||||||
 | 
					                "produces": [
 | 
				
			||||||
 | 
					                    "application/json"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "remove"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "summary": "Remove a job from the sql database",
 | 
				
			||||||
 | 
					                "parameters": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "type": "integer",
 | 
				
			||||||
 | 
					                        "description": "Unix epoch timestamp",
 | 
				
			||||||
 | 
					                        "name": "ts",
 | 
				
			||||||
 | 
					                        "in": "path",
 | 
				
			||||||
 | 
					                        "required": true
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "responses": {
 | 
				
			||||||
 | 
					                    "200": {
 | 
				
			||||||
 | 
					                        "description": "Success message",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.DeleteJobApiResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "400": {
 | 
				
			||||||
 | 
					                        "description": "Bad Request",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "401": {
 | 
				
			||||||
 | 
					                        "description": "Unauthorized",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "403": {
 | 
				
			||||||
 | 
					                        "description": "Forbidden",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "404": {
 | 
				
			||||||
 | 
					                        "description": "Resource not found",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "422": {
 | 
				
			||||||
 | 
					                        "description": "Unprocessable Entity: finding job failed: sql: no rows in result set",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "500": {
 | 
				
			||||||
 | 
					                        "description": "Internal Server Error",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "/jobs/start_job/": {
 | 
					        "/jobs/start_job/": {
 | 
				
			||||||
            "post": {
 | 
					            "post": {
 | 
				
			||||||
                "security": [
 | 
					                "security": [
 | 
				
			||||||
@@ -124,6 +338,9 @@
 | 
				
			|||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "add and modify"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Adds a new job as \"running\"",
 | 
					                "summary": "Adds a new job as \"running\"",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -187,6 +404,9 @@
 | 
				
			|||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "add and modify"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Marks job as completed and triggers archiving",
 | 
					                "summary": "Marks job as completed and triggers archiving",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -201,7 +421,7 @@
 | 
				
			|||||||
                ],
 | 
					                ],
 | 
				
			||||||
                "responses": {
 | 
					                "responses": {
 | 
				
			||||||
                    "200": {
 | 
					                    "200": {
 | 
				
			||||||
                        "description": "Job resource",
 | 
					                        "description": "Success message",
 | 
				
			||||||
                        "schema": {
 | 
					                        "schema": {
 | 
				
			||||||
                            "$ref": "#/definitions/schema.JobMeta"
 | 
					                            "$ref": "#/definitions/schema.JobMeta"
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@@ -259,6 +479,9 @@
 | 
				
			|||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "add and modify"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Marks job as completed and triggers archiving",
 | 
					                "summary": "Marks job as completed and triggers archiving",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -338,6 +561,9 @@
 | 
				
			|||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "add and modify"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Adds one or more tags to a job",
 | 
					                "summary": "Adds one or more tags to a job",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -355,7 +581,7 @@
 | 
				
			|||||||
                        "schema": {
 | 
					                        "schema": {
 | 
				
			||||||
                            "type": "array",
 | 
					                            "type": "array",
 | 
				
			||||||
                            "items": {
 | 
					                            "items": {
 | 
				
			||||||
                                "$ref": "#/definitions/api.Tag"
 | 
					                                "$ref": "#/definitions/api.ApiTag"
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@@ -396,8 +622,53 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "definitions": {
 | 
					    "definitions": {
 | 
				
			||||||
 | 
					        "api.ApiTag": {
 | 
				
			||||||
 | 
					            "type": "object",
 | 
				
			||||||
 | 
					            "properties": {
 | 
				
			||||||
 | 
					                "name": {
 | 
				
			||||||
 | 
					                    "description": "Tag Name",
 | 
				
			||||||
 | 
					                    "type": "string",
 | 
				
			||||||
 | 
					                    "example": "Testjob"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "type": {
 | 
				
			||||||
 | 
					                    "description": "Tag Type",
 | 
				
			||||||
 | 
					                    "type": "string",
 | 
				
			||||||
 | 
					                    "example": "Debug"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "api.DeleteJobApiRequest": {
 | 
				
			||||||
 | 
					            "type": "object",
 | 
				
			||||||
 | 
					            "required": [
 | 
				
			||||||
 | 
					                "jobId"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "properties": {
 | 
				
			||||||
 | 
					                "cluster": {
 | 
				
			||||||
 | 
					                    "description": "Cluster of job",
 | 
				
			||||||
 | 
					                    "type": "string",
 | 
				
			||||||
 | 
					                    "example": "fritz"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "jobId": {
 | 
				
			||||||
 | 
					                    "description": "Cluster Job ID of job",
 | 
				
			||||||
 | 
					                    "type": "integer",
 | 
				
			||||||
 | 
					                    "example": 123000
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "startTime": {
 | 
				
			||||||
 | 
					                    "description": "Start Time of job as epoch",
 | 
				
			||||||
 | 
					                    "type": "integer",
 | 
				
			||||||
 | 
					                    "example": 1649723812
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "api.DeleteJobApiResponse": {
 | 
				
			||||||
 | 
					            "type": "object",
 | 
				
			||||||
 | 
					            "properties": {
 | 
				
			||||||
 | 
					                "msg": {
 | 
				
			||||||
 | 
					                    "type": "string"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "api.ErrorResponse": {
 | 
					        "api.ErrorResponse": {
 | 
				
			||||||
            "description": "Error message as returned from backend.",
 | 
					 | 
				
			||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
            "properties": {
 | 
					            "properties": {
 | 
				
			||||||
                "error": {
 | 
					                "error": {
 | 
				
			||||||
@@ -411,7 +682,6 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "api.StartJobApiResponse": {
 | 
					        "api.StartJobApiResponse": {
 | 
				
			||||||
            "description": "Successful job start response with database id of new job.",
 | 
					 | 
				
			||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
            "properties": {
 | 
					            "properties": {
 | 
				
			||||||
                "id": {
 | 
					                "id": {
 | 
				
			||||||
@@ -421,7 +691,6 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "api.StopJobApiRequest": {
 | 
					        "api.StopJobApiRequest": {
 | 
				
			||||||
            "description": "Request to stop running job using stoptime and final state. They are only required if no database id was provided with endpoint.",
 | 
					 | 
				
			||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
            "required": [
 | 
					            "required": [
 | 
				
			||||||
                "jobState",
 | 
					                "jobState",
 | 
				
			||||||
@@ -462,22 +731,6 @@
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "api.Tag": {
 | 
					 | 
				
			||||||
            "description": "Defines a tag using name and type.",
 | 
					 | 
				
			||||||
            "type": "object",
 | 
					 | 
				
			||||||
            "properties": {
 | 
					 | 
				
			||||||
                "name": {
 | 
					 | 
				
			||||||
                    "description": "Tag Name",
 | 
					 | 
				
			||||||
                    "type": "string",
 | 
					 | 
				
			||||||
                    "example": "Testjob"
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                "type": {
 | 
					 | 
				
			||||||
                    "description": "Tag Type",
 | 
					 | 
				
			||||||
                    "type": "string",
 | 
					 | 
				
			||||||
                    "example": "Debug"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "schema.Job": {
 | 
					        "schema.Job": {
 | 
				
			||||||
            "description": "Information of a HPC job.",
 | 
					            "description": "Information of a HPC job.",
 | 
				
			||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
@@ -831,10 +1084,14 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "securityDefinitions": {
 | 
					    "securityDefinitions": {
 | 
				
			||||||
        "ApiKeyAuth": {
 | 
					        "ApiKeyAuth": {
 | 
				
			||||||
            "description": "JWT based authentification for general API endpoint use.",
 | 
					 | 
				
			||||||
            "type": "apiKey",
 | 
					            "type": "apiKey",
 | 
				
			||||||
            "name": "X-Auth-Token",
 | 
					            "name": "X-Auth-Token",
 | 
				
			||||||
            "in": "header"
 | 
					            "in": "header"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    },
 | 
				
			||||||
 | 
					    "tags": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "Job API"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										223
									
								
								api/swagger.yaml
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										223
									
								
								api/swagger.yaml
									
									
									
									
									
								
							@@ -1,7 +1,39 @@
 | 
				
			|||||||
basePath: /api
 | 
					basePath: /api
 | 
				
			||||||
definitions:
 | 
					definitions:
 | 
				
			||||||
 | 
					  api.ApiTag:
 | 
				
			||||||
 | 
					    properties:
 | 
				
			||||||
 | 
					      name:
 | 
				
			||||||
 | 
					        description: Tag Name
 | 
				
			||||||
 | 
					        example: Testjob
 | 
				
			||||||
 | 
					        type: string
 | 
				
			||||||
 | 
					      type:
 | 
				
			||||||
 | 
					        description: Tag Type
 | 
				
			||||||
 | 
					        example: Debug
 | 
				
			||||||
 | 
					        type: string
 | 
				
			||||||
 | 
					    type: object
 | 
				
			||||||
 | 
					  api.DeleteJobApiRequest:
 | 
				
			||||||
 | 
					    properties:
 | 
				
			||||||
 | 
					      cluster:
 | 
				
			||||||
 | 
					        description: Cluster of job
 | 
				
			||||||
 | 
					        example: fritz
 | 
				
			||||||
 | 
					        type: string
 | 
				
			||||||
 | 
					      jobId:
 | 
				
			||||||
 | 
					        description: Cluster Job ID of job
 | 
				
			||||||
 | 
					        example: 123000
 | 
				
			||||||
 | 
					        type: integer
 | 
				
			||||||
 | 
					      startTime:
 | 
				
			||||||
 | 
					        description: Start Time of job as epoch
 | 
				
			||||||
 | 
					        example: 1649723812
 | 
				
			||||||
 | 
					        type: integer
 | 
				
			||||||
 | 
					    required:
 | 
				
			||||||
 | 
					    - jobId
 | 
				
			||||||
 | 
					    type: object
 | 
				
			||||||
 | 
					  api.DeleteJobApiResponse:
 | 
				
			||||||
 | 
					    properties:
 | 
				
			||||||
 | 
					      msg:
 | 
				
			||||||
 | 
					        type: string
 | 
				
			||||||
 | 
					    type: object
 | 
				
			||||||
  api.ErrorResponse:
 | 
					  api.ErrorResponse:
 | 
				
			||||||
    description: Error message as returned from backend.
 | 
					 | 
				
			||||||
    properties:
 | 
					    properties:
 | 
				
			||||||
      error:
 | 
					      error:
 | 
				
			||||||
        description: Error Message
 | 
					        description: Error Message
 | 
				
			||||||
@@ -11,15 +43,12 @@ definitions:
 | 
				
			|||||||
        type: string
 | 
					        type: string
 | 
				
			||||||
    type: object
 | 
					    type: object
 | 
				
			||||||
  api.StartJobApiResponse:
 | 
					  api.StartJobApiResponse:
 | 
				
			||||||
    description: Successful job start response with database id of new job.
 | 
					 | 
				
			||||||
    properties:
 | 
					    properties:
 | 
				
			||||||
      id:
 | 
					      id:
 | 
				
			||||||
        description: Database ID of new job
 | 
					        description: Database ID of new job
 | 
				
			||||||
        type: integer
 | 
					        type: integer
 | 
				
			||||||
    type: object
 | 
					    type: object
 | 
				
			||||||
  api.StopJobApiRequest:
 | 
					  api.StopJobApiRequest:
 | 
				
			||||||
    description: Request to stop running job using stoptime and final state. They
 | 
					 | 
				
			||||||
      are only required if no database id was provided with endpoint.
 | 
					 | 
				
			||||||
    properties:
 | 
					    properties:
 | 
				
			||||||
      cluster:
 | 
					      cluster:
 | 
				
			||||||
        description: Cluster of job
 | 
					        description: Cluster of job
 | 
				
			||||||
@@ -51,18 +80,6 @@ definitions:
 | 
				
			|||||||
    - jobState
 | 
					    - jobState
 | 
				
			||||||
    - stopTime
 | 
					    - stopTime
 | 
				
			||||||
    type: object
 | 
					    type: object
 | 
				
			||||||
  api.Tag:
 | 
					 | 
				
			||||||
    description: Defines a tag using name and type.
 | 
					 | 
				
			||||||
    properties:
 | 
					 | 
				
			||||||
      name:
 | 
					 | 
				
			||||||
        description: Tag Name
 | 
					 | 
				
			||||||
        example: Testjob
 | 
					 | 
				
			||||||
        type: string
 | 
					 | 
				
			||||||
      type:
 | 
					 | 
				
			||||||
        description: Tag Type
 | 
					 | 
				
			||||||
        example: Debug
 | 
					 | 
				
			||||||
        type: string
 | 
					 | 
				
			||||||
    type: object
 | 
					 | 
				
			||||||
  schema.Job:
 | 
					  schema.Job:
 | 
				
			||||||
    description: Information of a HPC job.
 | 
					    description: Information of a HPC job.
 | 
				
			||||||
    properties:
 | 
					    properties:
 | 
				
			||||||
@@ -344,24 +361,21 @@ definitions:
 | 
				
			|||||||
        example: Debug
 | 
					        example: Debug
 | 
				
			||||||
        type: string
 | 
					        type: string
 | 
				
			||||||
    type: object
 | 
					    type: object
 | 
				
			||||||
host: clustercockpit.localhost:8082
 | 
					host: localhost:8080
 | 
				
			||||||
info:
 | 
					info:
 | 
				
			||||||
  contact:
 | 
					  contact:
 | 
				
			||||||
    email: support@clustercockpit.org
 | 
					    email: support@clustercockpit.org
 | 
				
			||||||
    name: ClusterCockpit Project
 | 
					    name: ClusterCockpit Project
 | 
				
			||||||
    url: https://github.com/ClusterCockpit
 | 
					    url: https://github.com/ClusterCockpit
 | 
				
			||||||
  description: Defines a tag using name and type.
 | 
					  description: API for batch job control.
 | 
				
			||||||
  license:
 | 
					  license:
 | 
				
			||||||
    name: MIT License
 | 
					    name: MIT License
 | 
				
			||||||
    url: https://opensource.org/licenses/MIT
 | 
					    url: https://opensource.org/licenses/MIT
 | 
				
			||||||
  termsOfService: https://monitoring.nhr.fau.de/imprint
 | 
					 | 
				
			||||||
  title: ClusterCockpit REST API
 | 
					  title: ClusterCockpit REST API
 | 
				
			||||||
  version: 0.1.0
 | 
					  version: 0.2.0
 | 
				
			||||||
paths:
 | 
					paths:
 | 
				
			||||||
  /jobs/:
 | 
					  /jobs/:
 | 
				
			||||||
    get:
 | 
					    get:
 | 
				
			||||||
      consumes:
 | 
					 | 
				
			||||||
      - application/json
 | 
					 | 
				
			||||||
      description: |-
 | 
					      description: |-
 | 
				
			||||||
        Get a list of all jobs. Filters can be applied using query parameters.
 | 
					        Get a list of all jobs. Filters can be applied using query parameters.
 | 
				
			||||||
        Number of results can be limited by page. Results are sorted by descending startTime.
 | 
					        Number of results can be limited by page. Results are sorted by descending startTime.
 | 
				
			||||||
@@ -385,11 +399,11 @@ paths:
 | 
				
			|||||||
        in: query
 | 
					        in: query
 | 
				
			||||||
        name: start-time
 | 
					        name: start-time
 | 
				
			||||||
        type: string
 | 
					        type: string
 | 
				
			||||||
      - description: 'Items per page (If empty: No Limit)'
 | 
					      - description: 'Items per page (Default: 25)'
 | 
				
			||||||
        in: query
 | 
					        in: query
 | 
				
			||||||
        name: items-per-page
 | 
					        name: items-per-page
 | 
				
			||||||
        type: integer
 | 
					        type: integer
 | 
				
			||||||
      - description: 'Page Number (If empty: No Paging)'
 | 
					      - description: 'Page Number (Default: 1)'
 | 
				
			||||||
        in: query
 | 
					        in: query
 | 
				
			||||||
        name: page
 | 
					        name: page
 | 
				
			||||||
        type: integer
 | 
					        type: integer
 | 
				
			||||||
@@ -421,6 +435,152 @@ paths:
 | 
				
			|||||||
      security:
 | 
					      security:
 | 
				
			||||||
      - ApiKeyAuth: []
 | 
					      - ApiKeyAuth: []
 | 
				
			||||||
      summary: Lists all jobs
 | 
					      summary: Lists all jobs
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					      - query
 | 
				
			||||||
 | 
					  /jobs/delete_job/:
 | 
				
			||||||
 | 
					    delete:
 | 
				
			||||||
 | 
					      consumes:
 | 
				
			||||||
 | 
					      - application/json
 | 
				
			||||||
 | 
					      description: Job to delete is specified by request body. All fields are required
 | 
				
			||||||
 | 
					        in this case.
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					      - description: All fields required
 | 
				
			||||||
 | 
					        in: body
 | 
				
			||||||
 | 
					        name: request
 | 
				
			||||||
 | 
					        required: true
 | 
				
			||||||
 | 
					        schema:
 | 
				
			||||||
 | 
					          $ref: '#/definitions/api.DeleteJobApiRequest'
 | 
				
			||||||
 | 
					      produces:
 | 
				
			||||||
 | 
					      - application/json
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        "200":
 | 
				
			||||||
 | 
					          description: Success message
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.DeleteJobApiResponse'
 | 
				
			||||||
 | 
					        "400":
 | 
				
			||||||
 | 
					          description: Bad Request
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "401":
 | 
				
			||||||
 | 
					          description: Unauthorized
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "403":
 | 
				
			||||||
 | 
					          description: Forbidden
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "404":
 | 
				
			||||||
 | 
					          description: Resource not found
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "422":
 | 
				
			||||||
 | 
					          description: 'Unprocessable Entity: finding job failed: sql: no rows in
 | 
				
			||||||
 | 
					            result set'
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "500":
 | 
				
			||||||
 | 
					          description: Internal Server Error
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					      security:
 | 
				
			||||||
 | 
					      - ApiKeyAuth: []
 | 
				
			||||||
 | 
					      summary: Remove a job from the sql database
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					      - remove
 | 
				
			||||||
 | 
					  /jobs/delete_job/{id}:
 | 
				
			||||||
 | 
					    delete:
 | 
				
			||||||
 | 
					      description: Job to remove is specified by database ID. This will not remove
 | 
				
			||||||
 | 
					        the job from the job archive.
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					      - description: Database ID of Job
 | 
				
			||||||
 | 
					        in: path
 | 
				
			||||||
 | 
					        name: id
 | 
				
			||||||
 | 
					        required: true
 | 
				
			||||||
 | 
					        type: integer
 | 
				
			||||||
 | 
					      produces:
 | 
				
			||||||
 | 
					      - application/json
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        "200":
 | 
				
			||||||
 | 
					          description: Success message
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.DeleteJobApiResponse'
 | 
				
			||||||
 | 
					        "400":
 | 
				
			||||||
 | 
					          description: Bad Request
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "401":
 | 
				
			||||||
 | 
					          description: Unauthorized
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "403":
 | 
				
			||||||
 | 
					          description: Forbidden
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "404":
 | 
				
			||||||
 | 
					          description: Resource not found
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "422":
 | 
				
			||||||
 | 
					          description: 'Unprocessable Entity: finding job failed: sql: no rows in
 | 
				
			||||||
 | 
					            result set'
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "500":
 | 
				
			||||||
 | 
					          description: Internal Server Error
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					      security:
 | 
				
			||||||
 | 
					      - ApiKeyAuth: []
 | 
				
			||||||
 | 
					      summary: Remove a job from the sql database
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					      - remove
 | 
				
			||||||
 | 
					  /jobs/delete_job_before/{ts}:
 | 
				
			||||||
 | 
					    delete:
 | 
				
			||||||
 | 
					      description: Remove all jobs with start time before timestamp. The jobs will
 | 
				
			||||||
 | 
					        not be removed from the job archive.
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					      - description: Unix epoch timestamp
 | 
				
			||||||
 | 
					        in: path
 | 
				
			||||||
 | 
					        name: ts
 | 
				
			||||||
 | 
					        required: true
 | 
				
			||||||
 | 
					        type: integer
 | 
				
			||||||
 | 
					      produces:
 | 
				
			||||||
 | 
					      - application/json
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        "200":
 | 
				
			||||||
 | 
					          description: Success message
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.DeleteJobApiResponse'
 | 
				
			||||||
 | 
					        "400":
 | 
				
			||||||
 | 
					          description: Bad Request
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "401":
 | 
				
			||||||
 | 
					          description: Unauthorized
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "403":
 | 
				
			||||||
 | 
					          description: Forbidden
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "404":
 | 
				
			||||||
 | 
					          description: Resource not found
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "422":
 | 
				
			||||||
 | 
					          description: 'Unprocessable Entity: finding job failed: sql: no rows in
 | 
				
			||||||
 | 
					            result set'
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					        "500":
 | 
				
			||||||
 | 
					          description: Internal Server Error
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: '#/definitions/api.ErrorResponse'
 | 
				
			||||||
 | 
					      security:
 | 
				
			||||||
 | 
					      - ApiKeyAuth: []
 | 
				
			||||||
 | 
					      summary: Remove a job from the sql database
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					      - remove
 | 
				
			||||||
  /jobs/start_job/:
 | 
					  /jobs/start_job/:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      consumes:
 | 
					      consumes:
 | 
				
			||||||
@@ -466,6 +626,8 @@ paths:
 | 
				
			|||||||
      security:
 | 
					      security:
 | 
				
			||||||
      - ApiKeyAuth: []
 | 
					      - ApiKeyAuth: []
 | 
				
			||||||
      summary: Adds a new job as "running"
 | 
					      summary: Adds a new job as "running"
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					      - add and modify
 | 
				
			||||||
  /jobs/stop_job/:
 | 
					  /jobs/stop_job/:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      description: |-
 | 
					      description: |-
 | 
				
			||||||
@@ -482,7 +644,7 @@ paths:
 | 
				
			|||||||
      - application/json
 | 
					      - application/json
 | 
				
			||||||
      responses:
 | 
					      responses:
 | 
				
			||||||
        "200":
 | 
					        "200":
 | 
				
			||||||
          description: Job resource
 | 
					          description: Success message
 | 
				
			||||||
          schema:
 | 
					          schema:
 | 
				
			||||||
            $ref: '#/definitions/schema.JobMeta'
 | 
					            $ref: '#/definitions/schema.JobMeta'
 | 
				
			||||||
        "400":
 | 
					        "400":
 | 
				
			||||||
@@ -513,6 +675,8 @@ paths:
 | 
				
			|||||||
      security:
 | 
					      security:
 | 
				
			||||||
      - ApiKeyAuth: []
 | 
					      - ApiKeyAuth: []
 | 
				
			||||||
      summary: Marks job as completed and triggers archiving
 | 
					      summary: Marks job as completed and triggers archiving
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					      - add and modify
 | 
				
			||||||
  /jobs/stop_job/{id}:
 | 
					  /jobs/stop_job/{id}:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      consumes:
 | 
					      consumes:
 | 
				
			||||||
@@ -567,6 +731,8 @@ paths:
 | 
				
			|||||||
      security:
 | 
					      security:
 | 
				
			||||||
      - ApiKeyAuth: []
 | 
					      - ApiKeyAuth: []
 | 
				
			||||||
      summary: Marks job as completed and triggers archiving
 | 
					      summary: Marks job as completed and triggers archiving
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					      - add and modify
 | 
				
			||||||
  /jobs/tag_job/{id}:
 | 
					  /jobs/tag_job/{id}:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      consumes:
 | 
					      consumes:
 | 
				
			||||||
@@ -586,7 +752,7 @@ paths:
 | 
				
			|||||||
        required: true
 | 
					        required: true
 | 
				
			||||||
        schema:
 | 
					        schema:
 | 
				
			||||||
          items:
 | 
					          items:
 | 
				
			||||||
            $ref: '#/definitions/api.Tag'
 | 
					            $ref: '#/definitions/api.ApiTag'
 | 
				
			||||||
          type: array
 | 
					          type: array
 | 
				
			||||||
      produces:
 | 
					      produces:
 | 
				
			||||||
      - application/json
 | 
					      - application/json
 | 
				
			||||||
@@ -614,10 +780,13 @@ paths:
 | 
				
			|||||||
      security:
 | 
					      security:
 | 
				
			||||||
      - ApiKeyAuth: []
 | 
					      - ApiKeyAuth: []
 | 
				
			||||||
      summary: Adds one or more tags to a job
 | 
					      summary: Adds one or more tags to a job
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					      - add and modify
 | 
				
			||||||
securityDefinitions:
 | 
					securityDefinitions:
 | 
				
			||||||
  ApiKeyAuth:
 | 
					  ApiKeyAuth:
 | 
				
			||||||
    description: JWT based authentification for general API endpoint use.
 | 
					 | 
				
			||||||
    in: header
 | 
					    in: header
 | 
				
			||||||
    name: X-Auth-Token
 | 
					    name: X-Auth-Token
 | 
				
			||||||
    type: apiKey
 | 
					    type: apiKey
 | 
				
			||||||
swagger: "2.0"
 | 
					swagger: "2.0"
 | 
				
			||||||
 | 
					tags:
 | 
				
			||||||
 | 
					- name: Job API
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
// Package api GENERATED BY SWAG; DO NOT EDIT
 | 
					// Package api GENERATED BY SWAG; DO NOT EDIT
 | 
				
			||||||
// This file was generated by swaggo/swag at
 | 
					// This file was generated by swaggo/swag
 | 
				
			||||||
// 2022-09-22 13:31:53.353204065 +0200 CEST m=+0.139444562
 | 
					 | 
				
			||||||
package api
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "github.com/swaggo/swag"
 | 
					import "github.com/swaggo/swag"
 | 
				
			||||||
@@ -11,7 +10,6 @@ const docTemplate = `{
 | 
				
			|||||||
    "info": {
 | 
					    "info": {
 | 
				
			||||||
        "description": "{{escape .Description}}",
 | 
					        "description": "{{escape .Description}}",
 | 
				
			||||||
        "title": "{{.Title}}",
 | 
					        "title": "{{.Title}}",
 | 
				
			||||||
        "termsOfService": "https://monitoring.nhr.fau.de/imprint",
 | 
					 | 
				
			||||||
        "contact": {
 | 
					        "contact": {
 | 
				
			||||||
            "name": "ClusterCockpit Project",
 | 
					            "name": "ClusterCockpit Project",
 | 
				
			||||||
            "url": "https://github.com/ClusterCockpit",
 | 
					            "url": "https://github.com/ClusterCockpit",
 | 
				
			||||||
@@ -34,12 +32,12 @@ const docTemplate = `{
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                "description": "Get a list of all jobs. Filters can be applied using query parameters.\nNumber of results can be limited by page. Results are sorted by descending startTime.",
 | 
					                "description": "Get a list of all jobs. Filters can be applied using query parameters.\nNumber of results can be limited by page. Results are sorted by descending startTime.",
 | 
				
			||||||
                "consumes": [
 | 
					 | 
				
			||||||
                    "application/json"
 | 
					 | 
				
			||||||
                ],
 | 
					 | 
				
			||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "query"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Lists all jobs",
 | 
					                "summary": "Lists all jobs",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -70,13 +68,13 @@ const docTemplate = `{
 | 
				
			|||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        "type": "integer",
 | 
					                        "type": "integer",
 | 
				
			||||||
                        "description": "Items per page (If empty: No Limit)",
 | 
					                        "description": "Items per page (Default: 25)",
 | 
				
			||||||
                        "name": "items-per-page",
 | 
					                        "name": "items-per-page",
 | 
				
			||||||
                        "in": "query"
 | 
					                        "in": "query"
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        "type": "integer",
 | 
					                        "type": "integer",
 | 
				
			||||||
                        "description": "Page Number (If empty: No Paging)",
 | 
					                        "description": "Page Number (Default: 1)",
 | 
				
			||||||
                        "name": "page",
 | 
					                        "name": "page",
 | 
				
			||||||
                        "in": "query"
 | 
					                        "in": "query"
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
@@ -118,6 +116,221 @@ const docTemplate = `{
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        "/jobs/delete_job/": {
 | 
				
			||||||
 | 
					            "delete": {
 | 
				
			||||||
 | 
					                "security": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "ApiKeyAuth": []
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "description": "Job to delete is specified by request body. All fields are required in this case.",
 | 
				
			||||||
 | 
					                "consumes": [
 | 
				
			||||||
 | 
					                    "application/json"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "produces": [
 | 
				
			||||||
 | 
					                    "application/json"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "remove"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "summary": "Remove a job from the sql database",
 | 
				
			||||||
 | 
					                "parameters": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "description": "All fields required",
 | 
				
			||||||
 | 
					                        "name": "request",
 | 
				
			||||||
 | 
					                        "in": "body",
 | 
				
			||||||
 | 
					                        "required": true,
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.DeleteJobApiRequest"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "responses": {
 | 
				
			||||||
 | 
					                    "200": {
 | 
				
			||||||
 | 
					                        "description": "Success message",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.DeleteJobApiResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "400": {
 | 
				
			||||||
 | 
					                        "description": "Bad Request",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "401": {
 | 
				
			||||||
 | 
					                        "description": "Unauthorized",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "403": {
 | 
				
			||||||
 | 
					                        "description": "Forbidden",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "404": {
 | 
				
			||||||
 | 
					                        "description": "Resource not found",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "422": {
 | 
				
			||||||
 | 
					                        "description": "Unprocessable Entity: finding job failed: sql: no rows in result set",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "500": {
 | 
				
			||||||
 | 
					                        "description": "Internal Server Error",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "/jobs/delete_job/{id}": {
 | 
				
			||||||
 | 
					            "delete": {
 | 
				
			||||||
 | 
					                "security": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "ApiKeyAuth": []
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "description": "Job to remove is specified by database ID. This will not remove the job from the job archive.",
 | 
				
			||||||
 | 
					                "produces": [
 | 
				
			||||||
 | 
					                    "application/json"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "remove"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "summary": "Remove a job from the sql database",
 | 
				
			||||||
 | 
					                "parameters": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "type": "integer",
 | 
				
			||||||
 | 
					                        "description": "Database ID of Job",
 | 
				
			||||||
 | 
					                        "name": "id",
 | 
				
			||||||
 | 
					                        "in": "path",
 | 
				
			||||||
 | 
					                        "required": true
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "responses": {
 | 
				
			||||||
 | 
					                    "200": {
 | 
				
			||||||
 | 
					                        "description": "Success message",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.DeleteJobApiResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "400": {
 | 
				
			||||||
 | 
					                        "description": "Bad Request",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "401": {
 | 
				
			||||||
 | 
					                        "description": "Unauthorized",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "403": {
 | 
				
			||||||
 | 
					                        "description": "Forbidden",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "404": {
 | 
				
			||||||
 | 
					                        "description": "Resource not found",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "422": {
 | 
				
			||||||
 | 
					                        "description": "Unprocessable Entity: finding job failed: sql: no rows in result set",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "500": {
 | 
				
			||||||
 | 
					                        "description": "Internal Server Error",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "/jobs/delete_job_before/{ts}": {
 | 
				
			||||||
 | 
					            "delete": {
 | 
				
			||||||
 | 
					                "security": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "ApiKeyAuth": []
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "description": "Remove all jobs with start time before timestamp. The jobs will not be removed from the job archive.",
 | 
				
			||||||
 | 
					                "produces": [
 | 
				
			||||||
 | 
					                    "application/json"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "remove"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "summary": "Remove a job from the sql database",
 | 
				
			||||||
 | 
					                "parameters": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "type": "integer",
 | 
				
			||||||
 | 
					                        "description": "Unix epoch timestamp",
 | 
				
			||||||
 | 
					                        "name": "ts",
 | 
				
			||||||
 | 
					                        "in": "path",
 | 
				
			||||||
 | 
					                        "required": true
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "responses": {
 | 
				
			||||||
 | 
					                    "200": {
 | 
				
			||||||
 | 
					                        "description": "Success message",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.DeleteJobApiResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "400": {
 | 
				
			||||||
 | 
					                        "description": "Bad Request",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "401": {
 | 
				
			||||||
 | 
					                        "description": "Unauthorized",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "403": {
 | 
				
			||||||
 | 
					                        "description": "Forbidden",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "404": {
 | 
				
			||||||
 | 
					                        "description": "Resource not found",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "422": {
 | 
				
			||||||
 | 
					                        "description": "Unprocessable Entity: finding job failed: sql: no rows in result set",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "500": {
 | 
				
			||||||
 | 
					                        "description": "Internal Server Error",
 | 
				
			||||||
 | 
					                        "schema": {
 | 
				
			||||||
 | 
					                            "$ref": "#/definitions/api.ErrorResponse"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "/jobs/start_job/": {
 | 
					        "/jobs/start_job/": {
 | 
				
			||||||
            "post": {
 | 
					            "post": {
 | 
				
			||||||
                "security": [
 | 
					                "security": [
 | 
				
			||||||
@@ -132,6 +345,9 @@ const docTemplate = `{
 | 
				
			|||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "add and modify"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Adds a new job as \"running\"",
 | 
					                "summary": "Adds a new job as \"running\"",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -195,6 +411,9 @@ const docTemplate = `{
 | 
				
			|||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "add and modify"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Marks job as completed and triggers archiving",
 | 
					                "summary": "Marks job as completed and triggers archiving",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -209,7 +428,7 @@ const docTemplate = `{
 | 
				
			|||||||
                ],
 | 
					                ],
 | 
				
			||||||
                "responses": {
 | 
					                "responses": {
 | 
				
			||||||
                    "200": {
 | 
					                    "200": {
 | 
				
			||||||
                        "description": "Job resource",
 | 
					                        "description": "Success message",
 | 
				
			||||||
                        "schema": {
 | 
					                        "schema": {
 | 
				
			||||||
                            "$ref": "#/definitions/schema.JobMeta"
 | 
					                            "$ref": "#/definitions/schema.JobMeta"
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@@ -267,6 +486,9 @@ const docTemplate = `{
 | 
				
			|||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "add and modify"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Marks job as completed and triggers archiving",
 | 
					                "summary": "Marks job as completed and triggers archiving",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -346,6 +568,9 @@ const docTemplate = `{
 | 
				
			|||||||
                "produces": [
 | 
					                "produces": [
 | 
				
			||||||
                    "application/json"
 | 
					                    "application/json"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 | 
					                "tags": [
 | 
				
			||||||
 | 
					                    "add and modify"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                "summary": "Adds one or more tags to a job",
 | 
					                "summary": "Adds one or more tags to a job",
 | 
				
			||||||
                "parameters": [
 | 
					                "parameters": [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -363,7 +588,7 @@ const docTemplate = `{
 | 
				
			|||||||
                        "schema": {
 | 
					                        "schema": {
 | 
				
			||||||
                            "type": "array",
 | 
					                            "type": "array",
 | 
				
			||||||
                            "items": {
 | 
					                            "items": {
 | 
				
			||||||
                                "$ref": "#/definitions/api.Tag"
 | 
					                                "$ref": "#/definitions/api.ApiTag"
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@@ -404,8 +629,53 @@ const docTemplate = `{
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "definitions": {
 | 
					    "definitions": {
 | 
				
			||||||
 | 
					        "api.ApiTag": {
 | 
				
			||||||
 | 
					            "type": "object",
 | 
				
			||||||
 | 
					            "properties": {
 | 
				
			||||||
 | 
					                "name": {
 | 
				
			||||||
 | 
					                    "description": "Tag Name",
 | 
				
			||||||
 | 
					                    "type": "string",
 | 
				
			||||||
 | 
					                    "example": "Testjob"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "type": {
 | 
				
			||||||
 | 
					                    "description": "Tag Type",
 | 
				
			||||||
 | 
					                    "type": "string",
 | 
				
			||||||
 | 
					                    "example": "Debug"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "api.DeleteJobApiRequest": {
 | 
				
			||||||
 | 
					            "type": "object",
 | 
				
			||||||
 | 
					            "required": [
 | 
				
			||||||
 | 
					                "jobId"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "properties": {
 | 
				
			||||||
 | 
					                "cluster": {
 | 
				
			||||||
 | 
					                    "description": "Cluster of job",
 | 
				
			||||||
 | 
					                    "type": "string",
 | 
				
			||||||
 | 
					                    "example": "fritz"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "jobId": {
 | 
				
			||||||
 | 
					                    "description": "Cluster Job ID of job",
 | 
				
			||||||
 | 
					                    "type": "integer",
 | 
				
			||||||
 | 
					                    "example": 123000
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "startTime": {
 | 
				
			||||||
 | 
					                    "description": "Start Time of job as epoch",
 | 
				
			||||||
 | 
					                    "type": "integer",
 | 
				
			||||||
 | 
					                    "example": 1649723812
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "api.DeleteJobApiResponse": {
 | 
				
			||||||
 | 
					            "type": "object",
 | 
				
			||||||
 | 
					            "properties": {
 | 
				
			||||||
 | 
					                "msg": {
 | 
				
			||||||
 | 
					                    "type": "string"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "api.ErrorResponse": {
 | 
					        "api.ErrorResponse": {
 | 
				
			||||||
            "description": "Error message as returned from backend.",
 | 
					 | 
				
			||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
            "properties": {
 | 
					            "properties": {
 | 
				
			||||||
                "error": {
 | 
					                "error": {
 | 
				
			||||||
@@ -419,7 +689,6 @@ const docTemplate = `{
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "api.StartJobApiResponse": {
 | 
					        "api.StartJobApiResponse": {
 | 
				
			||||||
            "description": "Successful job start response with database id of new job.",
 | 
					 | 
				
			||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
            "properties": {
 | 
					            "properties": {
 | 
				
			||||||
                "id": {
 | 
					                "id": {
 | 
				
			||||||
@@ -429,7 +698,6 @@ const docTemplate = `{
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "api.StopJobApiRequest": {
 | 
					        "api.StopJobApiRequest": {
 | 
				
			||||||
            "description": "Request to stop running job using stoptime and final state. They are only required if no database id was provided with endpoint.",
 | 
					 | 
				
			||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
            "required": [
 | 
					            "required": [
 | 
				
			||||||
                "jobState",
 | 
					                "jobState",
 | 
				
			||||||
@@ -470,22 +738,6 @@ const docTemplate = `{
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "api.Tag": {
 | 
					 | 
				
			||||||
            "description": "Defines a tag using name and type.",
 | 
					 | 
				
			||||||
            "type": "object",
 | 
					 | 
				
			||||||
            "properties": {
 | 
					 | 
				
			||||||
                "name": {
 | 
					 | 
				
			||||||
                    "description": "Tag Name",
 | 
					 | 
				
			||||||
                    "type": "string",
 | 
					 | 
				
			||||||
                    "example": "Testjob"
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                "type": {
 | 
					 | 
				
			||||||
                    "description": "Tag Type",
 | 
					 | 
				
			||||||
                    "type": "string",
 | 
					 | 
				
			||||||
                    "example": "Debug"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "schema.Job": {
 | 
					        "schema.Job": {
 | 
				
			||||||
            "description": "Information of a HPC job.",
 | 
					            "description": "Information of a HPC job.",
 | 
				
			||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
@@ -839,22 +1091,26 @@ const docTemplate = `{
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "securityDefinitions": {
 | 
					    "securityDefinitions": {
 | 
				
			||||||
        "ApiKeyAuth": {
 | 
					        "ApiKeyAuth": {
 | 
				
			||||||
            "description": "JWT based authentification for general API endpoint use.",
 | 
					 | 
				
			||||||
            "type": "apiKey",
 | 
					            "type": "apiKey",
 | 
				
			||||||
            "name": "X-Auth-Token",
 | 
					            "name": "X-Auth-Token",
 | 
				
			||||||
            "in": "header"
 | 
					            "in": "header"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    },
 | 
				
			||||||
 | 
					    "tags": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "Job API"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
}`
 | 
					}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
 | 
					// SwaggerInfo holds exported Swagger Info so clients can modify it
 | 
				
			||||||
var SwaggerInfo = &swag.Spec{
 | 
					var SwaggerInfo = &swag.Spec{
 | 
				
			||||||
	Version:          "0.1.0",
 | 
						Version:          "0.2.0",
 | 
				
			||||||
	Host:             "clustercockpit.localhost:8082",
 | 
						Host:             "localhost:8080",
 | 
				
			||||||
	BasePath:         "/api",
 | 
						BasePath:         "/api",
 | 
				
			||||||
	Schemes:          []string{},
 | 
						Schemes:          []string{},
 | 
				
			||||||
	Title:            "ClusterCockpit REST API",
 | 
						Title:            "ClusterCockpit REST API",
 | 
				
			||||||
	Description:      "Defines a tag using name and type.",
 | 
						Description:      "API for batch job control.",
 | 
				
			||||||
	InfoInstanceName: "swagger",
 | 
						InfoInstanceName: "swagger",
 | 
				
			||||||
	SwaggerTemplate:  docTemplate,
 | 
						SwaggerTemplate:  docTemplate,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,9 +32,10 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @title                      ClusterCockpit REST API
 | 
					// @title                      ClusterCockpit REST API
 | 
				
			||||||
// @version                    0.1.0
 | 
					// @version                    0.2.0
 | 
				
			||||||
// @description                API for batch job control.
 | 
					// @description                API for batch job control.
 | 
				
			||||||
// @termsOfService             https://monitoring.nhr.fau.de/imprint
 | 
					
 | 
				
			||||||
 | 
					// @tag.name Job API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @contact.name               ClusterCockpit Project
 | 
					// @contact.name               ClusterCockpit Project
 | 
				
			||||||
// @contact.url                https://github.com/ClusterCockpit
 | 
					// @contact.url                https://github.com/ClusterCockpit
 | 
				
			||||||
@@ -43,13 +44,12 @@ import (
 | 
				
			|||||||
// @license.name               MIT License
 | 
					// @license.name               MIT License
 | 
				
			||||||
// @license.url                https://opensource.org/licenses/MIT
 | 
					// @license.url                https://opensource.org/licenses/MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @host                       clustercockpit.localhost:8082
 | 
					// @host                       localhost:8080
 | 
				
			||||||
// @BasePath                   /api
 | 
					// @basePath                   /api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @securityDefinitions.apikey ApiKeyAuth
 | 
					// @securityDefinitions.apikey ApiKeyAuth
 | 
				
			||||||
// @in                         header
 | 
					// @in                         header
 | 
				
			||||||
// @name                       X-Auth-Token
 | 
					// @name                       X-Auth-Token
 | 
				
			||||||
// @description                JWT based authentification for general API endpoint use.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RestApi struct {
 | 
					type RestApi struct {
 | 
				
			||||||
	JobRepository     *repository.JobRepository
 | 
						JobRepository     *repository.JobRepository
 | 
				
			||||||
@@ -73,6 +73,9 @@ func (api *RestApi) MountRoutes(r *mux.Router) {
 | 
				
			|||||||
	// r.HandleFunc("/jobs/{id}", api.getJob).Methods(http.MethodGet)
 | 
						// r.HandleFunc("/jobs/{id}", api.getJob).Methods(http.MethodGet)
 | 
				
			||||||
	r.HandleFunc("/jobs/tag_job/{id}", api.tagJob).Methods(http.MethodPost, http.MethodPatch)
 | 
						r.HandleFunc("/jobs/tag_job/{id}", api.tagJob).Methods(http.MethodPost, http.MethodPatch)
 | 
				
			||||||
	r.HandleFunc("/jobs/metrics/{id}", api.getJobMetrics).Methods(http.MethodGet)
 | 
						r.HandleFunc("/jobs/metrics/{id}", api.getJobMetrics).Methods(http.MethodGet)
 | 
				
			||||||
 | 
						r.HandleFunc("/jobs/delete_job/", api.deleteJobByRequest).Methods(http.MethodDelete)
 | 
				
			||||||
 | 
						r.HandleFunc("/jobs/delete_job/{id}", api.deleteJobById).Methods(http.MethodDelete)
 | 
				
			||||||
 | 
						r.HandleFunc("/jobs/delete_job_before/{ts}", api.deleteJobBefore).Methods(http.MethodDelete)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if api.Authentication != nil {
 | 
						if api.Authentication != nil {
 | 
				
			||||||
		r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet)
 | 
							r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet)
 | 
				
			||||||
@@ -90,15 +93,17 @@ func (api *RestApi) MountRoutes(r *mux.Router) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// StartJobApiResponse model
 | 
					// StartJobApiResponse model
 | 
				
			||||||
// @Description Successful job start response with database id of new job.
 | 
					 | 
				
			||||||
type StartJobApiResponse struct {
 | 
					type StartJobApiResponse struct {
 | 
				
			||||||
	// Database ID of new job
 | 
						// Database ID of new job
 | 
				
			||||||
	DBID int64 `json:"id"`
 | 
						DBID int64 `json:"id"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeleteJobApiResponse model
 | 
				
			||||||
 | 
					type DeleteJobApiResponse struct {
 | 
				
			||||||
 | 
						Message string `json:"msg"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// StopJobApiRequest model
 | 
					// StopJobApiRequest model
 | 
				
			||||||
// @Description Request to stop running job using stoptime and final state.
 | 
					 | 
				
			||||||
// @Description They are only required if no database id was provided with endpoint.
 | 
					 | 
				
			||||||
type StopJobApiRequest struct {
 | 
					type StopJobApiRequest struct {
 | 
				
			||||||
	// Stop Time of job as epoch
 | 
						// Stop Time of job as epoch
 | 
				
			||||||
	StopTime  int64           `json:"stopTime" validate:"required" example:"1649763839"`
 | 
						StopTime  int64           `json:"stopTime" validate:"required" example:"1649763839"`
 | 
				
			||||||
@@ -108,23 +113,28 @@ type StopJobApiRequest struct {
 | 
				
			|||||||
	StartTime *int64          `json:"startTime" example:"1649723812"`                                                                      // Start Time of job as epoch
 | 
						StartTime *int64          `json:"startTime" example:"1649723812"`                                                                      // Start Time of job as epoch
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeleteJobApiRequest model
 | 
				
			||||||
 | 
					type DeleteJobApiRequest struct {
 | 
				
			||||||
 | 
						JobId     *int64  `json:"jobId" validate:"required" example:"123000"` // Cluster Job ID of job
 | 
				
			||||||
 | 
						Cluster   *string `json:"cluster" example:"fritz"`                    // Cluster of job
 | 
				
			||||||
 | 
						StartTime *int64  `json:"startTime" example:"1649723812"`             // Start Time of job as epoch
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrorResponse model
 | 
					// ErrorResponse model
 | 
				
			||||||
// @Description Error message as returned from backend.
 | 
					 | 
				
			||||||
type ErrorResponse struct {
 | 
					type ErrorResponse struct {
 | 
				
			||||||
	// Statustext of Errorcode
 | 
						// Statustext of Errorcode
 | 
				
			||||||
	Status string `json:"status"`
 | 
						Status string `json:"status"`
 | 
				
			||||||
	Error  string `json:"error"` // Error Message
 | 
						Error  string `json:"error"` // Error Message
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Tag model
 | 
					// ApiTag model
 | 
				
			||||||
// @Description Defines a tag using name and type.
 | 
					type ApiTag struct {
 | 
				
			||||||
type Tag struct {
 | 
					 | 
				
			||||||
	// Tag Type
 | 
						// Tag Type
 | 
				
			||||||
	Type string `json:"type" example:"Debug"`
 | 
						Type string `json:"type" example:"Debug"`
 | 
				
			||||||
	Name string `json:"name" example:"Testjob"` // Tag Name
 | 
						Name string `json:"name" example:"Testjob"` // Tag Name
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type TagJobApiRequest []*Tag
 | 
					type TagJobApiRequest []*ApiTag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func handleError(err error, statusCode int, rw http.ResponseWriter) {
 | 
					func handleError(err error, statusCode int, rw http.ResponseWriter) {
 | 
				
			||||||
	log.Warnf("REST API: %s", err.Error())
 | 
						log.Warnf("REST API: %s", err.Error())
 | 
				
			||||||
@@ -143,28 +153,34 @@ func decode(r io.Reader, val interface{}) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getJobs godoc
 | 
					// getJobs godoc
 | 
				
			||||||
// @Summary     Lists all jobs
 | 
					// @summary     Lists all jobs
 | 
				
			||||||
// @Description Get a list of all jobs. Filters can be applied using query parameters.
 | 
					// @tags query
 | 
				
			||||||
// @Description Number of results can be limited by page. Results are sorted by descending startTime.
 | 
					// @description Get a list of all jobs. Filters can be applied using query parameters.
 | 
				
			||||||
// @Accept      json
 | 
					// @description Number of results can be limited by page. Results are sorted by descending startTime.
 | 
				
			||||||
// @Produce     json
 | 
					// @produce     json
 | 
				
			||||||
// @Param       state          query    string            false "Job State" Enums(running, completed, failed, cancelled, stopped, timeout)
 | 
					// @param       state          query    string            false "Job State" Enums(running, completed, failed, cancelled, stopped, timeout)
 | 
				
			||||||
// @Param       cluster        query    string            false "Job Cluster"
 | 
					// @param       cluster        query    string            false "Job Cluster"
 | 
				
			||||||
// @Param       start-time     query    string            false "Syntax: '$from-$to', as unix epoch timestamps in seconds"
 | 
					// @param       start-time     query    string            false "Syntax: '$from-$to', as unix epoch timestamps in seconds"
 | 
				
			||||||
// @Param       items-per-page query    int               false "Items per page (If empty: No Limit)"
 | 
					// @param       items-per-page query    int               false "Items per page (Default: 25)"
 | 
				
			||||||
// @Param       page           query    int               false "Page Number (If empty: No Paging)"
 | 
					// @param       page           query    int               false "Page Number (Default: 1)"
 | 
				
			||||||
// @Param       with-metadata  query    bool              false "Include metadata (e.g. jobScript) in response"
 | 
					// @param       with-metadata  query    bool              false "Include metadata (e.g. jobScript) in response"
 | 
				
			||||||
// @Success     200            {array}  schema.Job              "Array of matching jobs"
 | 
					// @success     200            {array}  schema.Job              "Array of matching jobs"
 | 
				
			||||||
// @Failure     400            {object} api.ErrorResponse       "Bad Request"
 | 
					// @failure     400            {object} api.ErrorResponse       "Bad Request"
 | 
				
			||||||
// @Failure     401   			   {object} api.ErrorResponse       "Unauthorized"
 | 
					// @failure     401   		   {object} api.ErrorResponse       "Unauthorized"
 | 
				
			||||||
// @Failure     500            {object} api.ErrorResponse       "Internal Server Error"
 | 
					// @failure     500            {object} api.ErrorResponse       "Internal Server Error"
 | 
				
			||||||
// @Security    ApiKeyAuth
 | 
					// @security    ApiKeyAuth
 | 
				
			||||||
// @Router      /jobs/ [get]
 | 
					// @router      /jobs/ [get]
 | 
				
			||||||
func (api *RestApi) getJobs(rw http.ResponseWriter, r *http.Request) {
 | 
					func (api *RestApi) getJobs(rw http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
						if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	withMetadata := false
 | 
						withMetadata := false
 | 
				
			||||||
	filter := &model.JobFilter{}
 | 
						filter := &model.JobFilter{}
 | 
				
			||||||
	page := &model.PageRequest{ItemsPerPage: -1, Page: 1}
 | 
						page := &model.PageRequest{ItemsPerPage: 25, Page: 1}
 | 
				
			||||||
	order := &model.OrderByInput{Field: "startTime", Order: model.SortDirectionEnumDesc}
 | 
						order := &model.OrderByInput{Field: "startTime", Order: model.SortDirectionEnumDesc}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for key, vals := range r.URL.Query() {
 | 
						for key, vals := range r.URL.Query() {
 | 
				
			||||||
		switch key {
 | 
							switch key {
 | 
				
			||||||
		case "state":
 | 
							case "state":
 | 
				
			||||||
@@ -270,21 +286,27 @@ func (api *RestApi) getJobs(rw http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// tagJob godoc
 | 
					// tagJob godoc
 | 
				
			||||||
// @Summary     Adds one or more tags to a job
 | 
					// @summary     Adds one or more tags to a job
 | 
				
			||||||
// @Description Adds tag(s) to a job specified by DB ID. Name and Type of Tag(s) can be chosen freely.
 | 
					// @tags add and modify
 | 
				
			||||||
// @Description If tagged job is already finished: Tag will be written directly to respective archive files.
 | 
					// @description Adds tag(s) to a job specified by DB ID. Name and Type of Tag(s) can be chosen freely.
 | 
				
			||||||
// @Accept      json
 | 
					// @description If tagged job is already finished: Tag will be written directly to respective archive files.
 | 
				
			||||||
// @Produce     json
 | 
					// @accept      json
 | 
				
			||||||
// @Param       id      path     int                  true "Job Database ID"
 | 
					// @produce     json
 | 
				
			||||||
// @Param       request body     api.TagJobApiRequest true "Array of tag-objects to add"
 | 
					// @param       id      path     int                  true "Job Database ID"
 | 
				
			||||||
// @Success     200     {object} schema.Job                "Updated job resource"
 | 
					// @param       request body     api.TagJobApiRequest true "Array of tag-objects to add"
 | 
				
			||||||
// @Failure     400     {object} api.ErrorResponse         "Bad Request"
 | 
					// @success     200     {object} schema.Job                "Updated job resource"
 | 
				
			||||||
// @Failure     401     {object} api.ErrorResponse         "Unauthorized"
 | 
					// @failure     400     {object} api.ErrorResponse         "Bad Request"
 | 
				
			||||||
// @Failure     404     {object} api.ErrorResponse         "Job or tag does not exist"
 | 
					// @failure     401     {object} api.ErrorResponse         "Unauthorized"
 | 
				
			||||||
// @Failure     500     {object} api.ErrorResponse         "Internal Server Error"
 | 
					// @failure     404     {object} api.ErrorResponse         "Job or tag does not exist"
 | 
				
			||||||
// @Security    ApiKeyAuth
 | 
					// @failure     500     {object} api.ErrorResponse         "Internal Server Error"
 | 
				
			||||||
// @Router      /jobs/tag_job/{id} [post]
 | 
					// @security    ApiKeyAuth
 | 
				
			||||||
 | 
					// @router      /jobs/tag_job/{id} [post]
 | 
				
			||||||
func (api *RestApi) tagJob(rw http.ResponseWriter, r *http.Request) {
 | 
					func (api *RestApi) tagJob(rw http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
						if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iid, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)
 | 
						iid, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		http.Error(rw, err.Error(), http.StatusBadRequest)
 | 
							http.Error(rw, err.Error(), http.StatusBadRequest)
 | 
				
			||||||
@@ -329,20 +351,21 @@ func (api *RestApi) tagJob(rw http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// startJob godoc
 | 
					// startJob godoc
 | 
				
			||||||
// @Summary     Adds a new job as "running"
 | 
					// @summary     Adds a new job as "running"
 | 
				
			||||||
// @Description Job specified in request body will be saved to database as "running" with new DB ID.
 | 
					// @tags add and modify
 | 
				
			||||||
// @Description Job specifications follow the 'JobMeta' scheme, API will fail to execute if requirements are not met.
 | 
					// @description Job specified in request body will be saved to database as "running" with new DB ID.
 | 
				
			||||||
// @Accept      json
 | 
					// @description Job specifications follow the 'JobMeta' scheme, API will fail to execute if requirements are not met.
 | 
				
			||||||
// @Produce     json
 | 
					// @accept      json
 | 
				
			||||||
// @Param       request body     schema.JobMeta          true "Job to add"
 | 
					// @produce     json
 | 
				
			||||||
// @Success     201     {object} api.StartJobApiResponse      "Job added successfully"
 | 
					// @param       request body     schema.JobMeta          true "Job to add"
 | 
				
			||||||
// @Failure     400     {object} api.ErrorResponse            "Bad Request"
 | 
					// @success     201     {object} api.StartJobApiResponse      "Job added successfully"
 | 
				
			||||||
// @Failure     401     {object} api.ErrorResponse            "Unauthorized"
 | 
					// @failure     400     {object} api.ErrorResponse            "Bad Request"
 | 
				
			||||||
// @Failure     403     {object} api.ErrorResponse            "Forbidden"
 | 
					// @failure     401     {object} api.ErrorResponse            "Unauthorized"
 | 
				
			||||||
// @Failure     422     {object} api.ErrorResponse            "Unprocessable Entity: The combination of jobId, clusterId and startTime does already exist"
 | 
					// @failure     403     {object} api.ErrorResponse            "Forbidden"
 | 
				
			||||||
// @Failure     500     {object} api.ErrorResponse            "Internal Server Error"
 | 
					// @failure     422     {object} api.ErrorResponse            "Unprocessable Entity: The combination of jobId, clusterId and startTime does already exist"
 | 
				
			||||||
// @Security    ApiKeyAuth
 | 
					// @failure     500     {object} api.ErrorResponse            "Internal Server Error"
 | 
				
			||||||
// @Router      /jobs/start_job/ [post]
 | 
					// @security    ApiKeyAuth
 | 
				
			||||||
 | 
					// @router      /jobs/start_job/ [post]
 | 
				
			||||||
func (api *RestApi) startJob(rw http.ResponseWriter, r *http.Request) {
 | 
					func (api *RestApi) startJob(rw http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
						if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
				
			||||||
		handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
							handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
				
			||||||
@@ -407,22 +430,23 @@ func (api *RestApi) startJob(rw http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// stopJobById godoc
 | 
					// stopJobById godoc
 | 
				
			||||||
// @Summary     Marks job as completed and triggers archiving
 | 
					// @summary     Marks job as completed and triggers archiving
 | 
				
			||||||
// @Description Job to stop is specified by database ID. Only stopTime and final state are required in request body.
 | 
					// @tags add and modify
 | 
				
			||||||
// @Description Returns full job resource information according to 'JobMeta' scheme.
 | 
					// @description Job to stop is specified by database ID. Only stopTime and final state are required in request body.
 | 
				
			||||||
// @Accept      json
 | 
					// @description Returns full job resource information according to 'JobMeta' scheme.
 | 
				
			||||||
// @Produce     json
 | 
					// @accept      json
 | 
				
			||||||
// @Param       id      path     int                   true "Database ID of Job"
 | 
					// @produce     json
 | 
				
			||||||
// @Param       request body     api.StopJobApiRequest true "stopTime and final state in request body"
 | 
					// @param       id      path     int                   true "Database ID of Job"
 | 
				
			||||||
// @Success     200     {object} schema.JobMeta             "Job resource"
 | 
					// @param       request body     api.StopJobApiRequest true "stopTime and final state in request body"
 | 
				
			||||||
// @Failure     400     {object} api.ErrorResponse          "Bad Request"
 | 
					// @success     200     {object} schema.JobMeta             "Job resource"
 | 
				
			||||||
// @Failure     401     {object} api.ErrorResponse          "Unauthorized"
 | 
					// @failure     400     {object} api.ErrorResponse          "Bad Request"
 | 
				
			||||||
// @Failure     403     {object} api.ErrorResponse          "Forbidden"
 | 
					// @failure     401     {object} api.ErrorResponse          "Unauthorized"
 | 
				
			||||||
// @Failure     404     {object} api.ErrorResponse          "Resource not found"
 | 
					// @failure     403     {object} api.ErrorResponse          "Forbidden"
 | 
				
			||||||
// @Failure     422     {object} api.ErrorResponse          "Unprocessable Entity: finding job failed: sql: no rows in result set"
 | 
					// @failure     404     {object} api.ErrorResponse          "Resource not found"
 | 
				
			||||||
// @Failure     500     {object} api.ErrorResponse          "Internal Server Error"
 | 
					// @failure     422     {object} api.ErrorResponse          "Unprocessable Entity: finding job failed: sql: no rows in result set"
 | 
				
			||||||
// @Security    ApiKeyAuth
 | 
					// @failure     500     {object} api.ErrorResponse          "Internal Server Error"
 | 
				
			||||||
// @Router      /jobs/stop_job/{id} [post]
 | 
					// @security    ApiKeyAuth
 | 
				
			||||||
 | 
					// @router      /jobs/stop_job/{id} [post]
 | 
				
			||||||
func (api *RestApi) stopJobById(rw http.ResponseWriter, r *http.Request) {
 | 
					func (api *RestApi) stopJobById(rw http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
						if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
				
			||||||
		handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
							handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
				
			||||||
@@ -461,20 +485,21 @@ func (api *RestApi) stopJobById(rw http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// stopJobByRequest godoc
 | 
					// stopJobByRequest godoc
 | 
				
			||||||
// @Summary     Marks job as completed and triggers archiving
 | 
					// @summary     Marks job as completed and triggers archiving
 | 
				
			||||||
// @Description Job to stop is specified by request body. All fields are required in this case.
 | 
					// @tags add and modify
 | 
				
			||||||
// @Description Returns full job resource information according to 'JobMeta' scheme.
 | 
					// @description Job to stop is specified by request body. All fields are required in this case.
 | 
				
			||||||
// @Produce     json
 | 
					// @description Returns full job resource information according to 'JobMeta' scheme.
 | 
				
			||||||
// @Param       request body     api.StopJobApiRequest true "All fields required"
 | 
					// @produce     json
 | 
				
			||||||
// @Success     200     {object} schema.JobMeta             "Job resource"
 | 
					// @param       request body     api.StopJobApiRequest true "All fields required"
 | 
				
			||||||
// @Failure     400     {object} api.ErrorResponse          "Bad Request"
 | 
					// @success     200     {object} schema.JobMeta             "Success message"
 | 
				
			||||||
// @Failure     401     {object} api.ErrorResponse          "Unauthorized"
 | 
					// @failure     400     {object} api.ErrorResponse          "Bad Request"
 | 
				
			||||||
// @Failure     403     {object} api.ErrorResponse          "Forbidden"
 | 
					// @failure     401     {object} api.ErrorResponse          "Unauthorized"
 | 
				
			||||||
// @Failure     404     {object} api.ErrorResponse          "Resource not found"
 | 
					// @failure     403     {object} api.ErrorResponse          "Forbidden"
 | 
				
			||||||
// @Failure     422     {object} api.ErrorResponse          "Unprocessable Entity: finding job failed: sql: no rows in result set"
 | 
					// @failure     404     {object} api.ErrorResponse          "Resource not found"
 | 
				
			||||||
// @Failure     500     {object} api.ErrorResponse          "Internal Server Error"
 | 
					// @failure     422     {object} api.ErrorResponse          "Unprocessable Entity: finding job failed: sql: no rows in result set"
 | 
				
			||||||
// @Security    ApiKeyAuth
 | 
					// @failure     500     {object} api.ErrorResponse          "Internal Server Error"
 | 
				
			||||||
// @Router      /jobs/stop_job/ [post]
 | 
					// @security    ApiKeyAuth
 | 
				
			||||||
 | 
					// @router      /jobs/stop_job/ [post]
 | 
				
			||||||
func (api *RestApi) stopJobByRequest(rw http.ResponseWriter, r *http.Request) {
 | 
					func (api *RestApi) stopJobByRequest(rw http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
						if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
				
			||||||
		handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
							handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
				
			||||||
@@ -506,6 +531,159 @@ func (api *RestApi) stopJobByRequest(rw http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
	api.checkAndHandleStopJob(rw, job, req)
 | 
						api.checkAndHandleStopJob(rw, job, req)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// deleteJobById godoc
 | 
				
			||||||
 | 
					// @summary     Remove a job from the sql database
 | 
				
			||||||
 | 
					// @tags remove
 | 
				
			||||||
 | 
					// @description Job to remove is specified by database ID. This will not remove the job from the job archive.
 | 
				
			||||||
 | 
					// @produce     json
 | 
				
			||||||
 | 
					// @param       id      path     int                   true "Database ID of Job"
 | 
				
			||||||
 | 
					// @success     200     {object} api.DeleteJobApiResponse     "Success message"
 | 
				
			||||||
 | 
					// @failure     400     {object} api.ErrorResponse          "Bad Request"
 | 
				
			||||||
 | 
					// @failure     401     {object} api.ErrorResponse          "Unauthorized"
 | 
				
			||||||
 | 
					// @failure     403     {object} api.ErrorResponse          "Forbidden"
 | 
				
			||||||
 | 
					// @failure     404     {object} api.ErrorResponse          "Resource not found"
 | 
				
			||||||
 | 
					// @failure     422     {object} api.ErrorResponse          "Unprocessable Entity: finding job failed: sql: no rows in result set"
 | 
				
			||||||
 | 
					// @failure     500     {object} api.ErrorResponse          "Internal Server Error"
 | 
				
			||||||
 | 
					// @security    ApiKeyAuth
 | 
				
			||||||
 | 
					// @router      /jobs/delete_job/{id} [delete]
 | 
				
			||||||
 | 
					func (api *RestApi) deleteJobById(rw http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
						if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Fetch job (that will be stopped) from db
 | 
				
			||||||
 | 
						id, ok := mux.Vars(r)["id"]
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						if ok {
 | 
				
			||||||
 | 
							id, e := strconv.ParseInt(id, 10, 64)
 | 
				
			||||||
 | 
							if e != nil {
 | 
				
			||||||
 | 
								handleError(fmt.Errorf("integer expected in path for id: %w", e), http.StatusBadRequest, rw)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = api.JobRepository.DeleteJobById(id)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							handleError(errors.New("the parameter 'id' is required"), http.StatusBadRequest, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("deleting job failed: %w", err), http.StatusUnprocessableEntity, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rw.Header().Add("Content-Type", "application/json")
 | 
				
			||||||
 | 
						rw.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
						json.NewEncoder(rw).Encode(DeleteJobApiResponse{
 | 
				
			||||||
 | 
							Message: fmt.Sprintf("Successfully deleted job %s", id),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// deleteJobByRequest godoc
 | 
				
			||||||
 | 
					// @summary     Remove a job from the sql database
 | 
				
			||||||
 | 
					// @tags remove
 | 
				
			||||||
 | 
					// @description Job to delete is specified by request body. All fields are required in this case.
 | 
				
			||||||
 | 
					// @accept      json
 | 
				
			||||||
 | 
					// @produce     json
 | 
				
			||||||
 | 
					// @param       request body     api.DeleteJobApiRequest true "All fields required"
 | 
				
			||||||
 | 
					// @success     200     {object} api.DeleteJobApiResponse     "Success message"
 | 
				
			||||||
 | 
					// @failure     400     {object} api.ErrorResponse          "Bad Request"
 | 
				
			||||||
 | 
					// @failure     401     {object} api.ErrorResponse          "Unauthorized"
 | 
				
			||||||
 | 
					// @failure     403     {object} api.ErrorResponse          "Forbidden"
 | 
				
			||||||
 | 
					// @failure     404     {object} api.ErrorResponse          "Resource not found"
 | 
				
			||||||
 | 
					// @failure     422     {object} api.ErrorResponse          "Unprocessable Entity: finding job failed: sql: no rows in result set"
 | 
				
			||||||
 | 
					// @failure     500     {object} api.ErrorResponse          "Internal Server Error"
 | 
				
			||||||
 | 
					// @security    ApiKeyAuth
 | 
				
			||||||
 | 
					// @router      /jobs/delete_job/ [delete]
 | 
				
			||||||
 | 
					func (api *RestApi) deleteJobByRequest(rw http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
						if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Parse request body
 | 
				
			||||||
 | 
						req := DeleteJobApiRequest{}
 | 
				
			||||||
 | 
						if err := decode(r.Body, &req); err != nil {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("parsing request body failed: %w", err), http.StatusBadRequest, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Fetch job (that will be deleted) from db
 | 
				
			||||||
 | 
						var job *schema.Job
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						if req.JobId == nil {
 | 
				
			||||||
 | 
							handleError(errors.New("the field 'jobId' is required"), http.StatusBadRequest, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						job, err = api.JobRepository.Find(req.JobId, req.Cluster, req.StartTime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("finding job failed: %w", err), http.StatusUnprocessableEntity, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = api.JobRepository.DeleteJobById(job.ID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("deleting job failed: %w", err), http.StatusUnprocessableEntity, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rw.Header().Add("Content-Type", "application/json")
 | 
				
			||||||
 | 
						rw.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
						json.NewEncoder(rw).Encode(DeleteJobApiResponse{
 | 
				
			||||||
 | 
							Message: fmt.Sprintf("Successfully deleted job %d", job.ID),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// deleteJobBefore godoc
 | 
				
			||||||
 | 
					// @summary     Remove a job from the sql database
 | 
				
			||||||
 | 
					// @tags remove
 | 
				
			||||||
 | 
					// @description Remove all jobs with start time before timestamp. The jobs will not be removed from the job archive.
 | 
				
			||||||
 | 
					// @produce     json
 | 
				
			||||||
 | 
					// @param       ts      path     int                   true "Unix epoch timestamp"
 | 
				
			||||||
 | 
					// @success     200     {object} api.DeleteJobApiResponse     "Success message"
 | 
				
			||||||
 | 
					// @failure     400     {object} api.ErrorResponse          "Bad Request"
 | 
				
			||||||
 | 
					// @failure     401     {object} api.ErrorResponse          "Unauthorized"
 | 
				
			||||||
 | 
					// @failure     403     {object} api.ErrorResponse          "Forbidden"
 | 
				
			||||||
 | 
					// @failure     404     {object} api.ErrorResponse          "Resource not found"
 | 
				
			||||||
 | 
					// @failure     422     {object} api.ErrorResponse          "Unprocessable Entity: finding job failed: sql: no rows in result set"
 | 
				
			||||||
 | 
					// @failure     500     {object} api.ErrorResponse          "Internal Server Error"
 | 
				
			||||||
 | 
					// @security    ApiKeyAuth
 | 
				
			||||||
 | 
					// @router      /jobs/delete_job_before/{ts} [delete]
 | 
				
			||||||
 | 
					func (api *RestApi) deleteJobBefore(rw http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
						if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("missing role: %#v", auth.RoleApi), http.StatusForbidden, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var cnt int
 | 
				
			||||||
 | 
						// Fetch job (that will be stopped) from db
 | 
				
			||||||
 | 
						id, ok := mux.Vars(r)["ts"]
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						if ok {
 | 
				
			||||||
 | 
							ts, e := strconv.ParseInt(id, 10, 64)
 | 
				
			||||||
 | 
							if e != nil {
 | 
				
			||||||
 | 
								handleError(fmt.Errorf("integer expected in path for ts: %w", e), http.StatusBadRequest, rw)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cnt, err = api.JobRepository.DeleteJobsBefore(ts)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							handleError(errors.New("the parameter 'ts' is required"), http.StatusBadRequest, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							handleError(fmt.Errorf("deleting jobs failed: %w", err), http.StatusUnprocessableEntity, rw)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rw.Header().Add("Content-Type", "application/json")
 | 
				
			||||||
 | 
						rw.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
						json.NewEncoder(rw).Encode(DeleteJobApiResponse{
 | 
				
			||||||
 | 
							Message: fmt.Sprintf("Successfully deleted %d jobs", cnt),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (api *RestApi) checkAndHandleStopJob(rw http.ResponseWriter, job *schema.Job, req StopJobApiRequest) {
 | 
					func (api *RestApi) checkAndHandleStopJob(rw http.ResponseWriter, job *schema.Job, req StopJobApiRequest) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Sanity checks
 | 
						// Sanity checks
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -246,6 +246,29 @@ func (r *JobRepository) Stop(
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *JobRepository) DeleteJobsBefore(startTime int64) (int, error) {
 | 
				
			||||||
 | 
						var cnt int
 | 
				
			||||||
 | 
						qs := fmt.Sprintf("SELECT count(*) FROM job WHERE job.start_time < %d", startTime)
 | 
				
			||||||
 | 
						err := r.DB.Get(&cnt, qs) //ignore error as it will also occur in delete statement
 | 
				
			||||||
 | 
						_, err = r.DB.Exec(`DELETE FROM job WHERE job.start_time < ?`, startTime)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Warnf(" DeleteJobsBefore(%d): error %v", startTime, err)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							log.Infof("DeleteJobsBefore(%d): Deleted %d jobs", startTime, cnt)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return cnt, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *JobRepository) DeleteJobById(id int64) error {
 | 
				
			||||||
 | 
						_, err := r.DB.Exec(`DELETE FROM job WHERE job.id = ?`, id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Warnf("DeleteJobById(%d): error %v", id, err)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							log.Infof("DeleteJobById(%d): Success", id)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: Use node hours instead: SELECT job.user, sum(job.num_nodes * (CASE WHEN job.job_state = "running" THEN CAST(strftime('%s', 'now') AS INTEGER) - job.start_time ELSE job.duration END)) as x FROM job GROUP BY user ORDER BY x DESC;
 | 
					// TODO: Use node hours instead: SELECT job.user, sum(job.num_nodes * (CASE WHEN job.job_state = "running" THEN CAST(strftime('%s', 'now') AS INTEGER) - job.start_time ELSE job.duration END)) as x FROM job GROUP BY user ORDER BY x DESC;
 | 
				
			||||||
func (r *JobRepository) CountGroupedJobs(ctx context.Context, aggreg model.Aggregate, filters []*model.JobFilter, weight *model.Weights, limit *int) (map[string]int, error) {
 | 
					func (r *JobRepository) CountGroupedJobs(ctx context.Context, aggreg model.Aggregate, filters []*model.JobFilter, weight *model.Weights, limit *int) (map[string]int, error) {
 | 
				
			||||||
	if !aggreg.IsValid() {
 | 
						if !aggreg.IsValid() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,26 +17,26 @@ import (
 | 
				
			|||||||
type BaseJob struct {
 | 
					type BaseJob struct {
 | 
				
			||||||
	// The unique identifier of a job
 | 
						// The unique identifier of a job
 | 
				
			||||||
	JobID            int64             `json:"jobId" db:"job_id" example:"123000"`
 | 
						JobID            int64             `json:"jobId" db:"job_id" example:"123000"`
 | 
				
			||||||
	User             string            `json:"user" db:"user" example:"abcd100h"` // The unique identifier of a user
 | 
						User             string            `json:"user" db:"user" example:"abcd100h"`                                                                            // The unique identifier of a user
 | 
				
			||||||
	Project          string            `json:"project" db:"project" example:"abcd200"` // The unique identifier of a project
 | 
						Project          string            `json:"project" db:"project" example:"abcd200"`                                                                       // The unique identifier of a project
 | 
				
			||||||
	Cluster          string            `json:"cluster" db:"cluster" example:"fritz"` // The unique identifier of a cluster
 | 
						Cluster          string            `json:"cluster" db:"cluster" example:"fritz"`                                                                         // The unique identifier of a cluster
 | 
				
			||||||
	SubCluster       string            `json:"subCluster" db:"subcluster" example:"main"` // The unique identifier of a sub cluster
 | 
						SubCluster       string            `json:"subCluster" db:"subcluster" example:"main"`                                                                    // The unique identifier of a sub cluster
 | 
				
			||||||
	Partition        string            `json:"partition" db:"partition" example:"main"` // The Slurm partition to which the job was submitted
 | 
						Partition        string            `json:"partition" db:"partition" example:"main"`                                                                      // The Slurm partition to which the job was submitted
 | 
				
			||||||
	ArrayJobId       int64             `json:"arrayJobId" db:"array_job_id" example:"123000"` // The unique identifier of an array job
 | 
						ArrayJobId       int64             `json:"arrayJobId" db:"array_job_id" example:"123000"`                                                                // The unique identifier of an array job
 | 
				
			||||||
	NumNodes         int32             `json:"numNodes" db:"num_nodes" example:"2" minimum:"1"` // Number of nodes used (Min > 0)
 | 
						NumNodes         int32             `json:"numNodes" db:"num_nodes" example:"2" minimum:"1"`                                                              // Number of nodes used (Min > 0)
 | 
				
			||||||
	NumHWThreads     int32             `json:"numHwthreads" db:"num_hwthreads" example:"20" minimum:"1"` // Number of HWThreads used (Min > 0)
 | 
						NumHWThreads     int32             `json:"numHwthreads" db:"num_hwthreads" example:"20" minimum:"1"`                                                     // Number of HWThreads used (Min > 0)
 | 
				
			||||||
	NumAcc           int32             `json:"numAcc" db:"num_acc" example:"2" minimum:"1"` // Number of accelerators used (Min > 0)
 | 
						NumAcc           int32             `json:"numAcc" db:"num_acc" example:"2" minimum:"1"`                                                                  // Number of accelerators used (Min > 0)
 | 
				
			||||||
	Exclusive        int32             `json:"exclusive" db:"exclusive" example:"1" minimum:"0" maximum:"2"` // Specifies how nodes are shared: 0 - Shared among multiple jobs of multiple users, 1 - Job exclusive (Default), 2 - Shared among multiple jobs of same user
 | 
						Exclusive        int32             `json:"exclusive" db:"exclusive" example:"1" minimum:"0" maximum:"2"`                                                 // Specifies how nodes are shared: 0 - Shared among multiple jobs of multiple users, 1 - Job exclusive (Default), 2 - Shared among multiple jobs of same user
 | 
				
			||||||
	MonitoringStatus int32             `json:"monitoringStatus" db:"monitoring_status" example:"1" minimum:"0" maximum:"3"` // State of monitoring system during job run: 0 - Disabled, 1 - Running or Archiving (Default), 2 - Archiving Failed, 3 - Archiving Successfull
 | 
						MonitoringStatus int32             `json:"monitoringStatus" db:"monitoring_status" example:"1" minimum:"0" maximum:"3"`                                  // State of monitoring system during job run: 0 - Disabled, 1 - Running or Archiving (Default), 2 - Archiving Failed, 3 - Archiving Successfull
 | 
				
			||||||
	SMT              int32             `json:"smt" db:"smt" example:"4"` // SMT threads used by job
 | 
						SMT              int32             `json:"smt" db:"smt" example:"4"`                                                                                     // SMT threads used by job
 | 
				
			||||||
	State            JobState          `json:"jobState" db:"job_state" example:"completed" enums:"completed,failed,cancelled,stopped,timeout,out_of_memory"` // Final state of job
 | 
						State            JobState          `json:"jobState" db:"job_state" example:"completed" enums:"completed,failed,cancelled,stopped,timeout,out_of_memory"` // Final state of job
 | 
				
			||||||
	Duration         int32             `json:"duration" db:"duration" example:"43200" minimum:"1"` // Duration of job in seconds (Min > 0)
 | 
						Duration         int32             `json:"duration" db:"duration" example:"43200" minimum:"1"`                                                           // Duration of job in seconds (Min > 0)
 | 
				
			||||||
	Walltime         int64             `json:"walltime" db:"walltime" example:"86400" minimum:"1"` // Requested walltime of job in seconds (Min > 0)
 | 
						Walltime         int64             `json:"walltime" db:"walltime" example:"86400" minimum:"1"`                                                           // Requested walltime of job in seconds (Min > 0)
 | 
				
			||||||
	Tags             []*Tag            `json:"tags"` // List of tags
 | 
						Tags             []*Tag            `json:"tags"`                                                                                                         // List of tags
 | 
				
			||||||
	RawResources     []byte            `json:"-" db:"resources"` // Resources used by job [As Bytes]
 | 
						RawResources     []byte            `json:"-" db:"resources"`                                                                                             // Resources used by job [As Bytes]
 | 
				
			||||||
	Resources        []*Resource       `json:"resources"` // Resources used by job
 | 
						Resources        []*Resource       `json:"resources"`                                                                                                    // Resources used by job
 | 
				
			||||||
	RawMetaData      []byte            `json:"-" db:"meta_data"` // Additional information about the job [As Bytes]
 | 
						RawMetaData      []byte            `json:"-" db:"meta_data"`                                                                                             // Additional information about the job [As Bytes]
 | 
				
			||||||
	MetaData         map[string]string `json:"metaData"` // Additional information about the job
 | 
						MetaData         map[string]string `json:"metaData"`                                                                                                     // Additional information about the job
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Non-Swaggered Comment: Job
 | 
					// Non-Swaggered Comment: Job
 | 
				
			||||||
@@ -49,15 +49,15 @@ type Job struct {
 | 
				
			|||||||
	ID int64 `json:"id" db:"id"`
 | 
						ID int64 `json:"id" db:"id"`
 | 
				
			||||||
	BaseJob
 | 
						BaseJob
 | 
				
			||||||
	StartTimeUnix    int64     `json:"-" db:"start_time" example:"1649723812"` // Start epoch time stamp in seconds
 | 
						StartTimeUnix    int64     `json:"-" db:"start_time" example:"1649723812"` // Start epoch time stamp in seconds
 | 
				
			||||||
	StartTime        time.Time `json:"startTime"` // Start time as 'time.Time' data type
 | 
						StartTime        time.Time `json:"startTime"`                              // Start time as 'time.Time' data type
 | 
				
			||||||
	MemUsedMax       float64   `json:"-" db:"mem_used_max"` // MemUsedMax as Float64
 | 
						MemUsedMax       float64   `json:"-" db:"mem_used_max"`                    // MemUsedMax as Float64
 | 
				
			||||||
	FlopsAnyAvg      float64   `json:"-" db:"flops_any_avg"` // FlopsAnyAvg as Float64
 | 
						FlopsAnyAvg      float64   `json:"-" db:"flops_any_avg"`                   // FlopsAnyAvg as Float64
 | 
				
			||||||
	MemBwAvg         float64   `json:"-" db:"mem_bw_avg"` // MemBwAvg as Float64
 | 
						MemBwAvg         float64   `json:"-" db:"mem_bw_avg"`                      // MemBwAvg as Float64
 | 
				
			||||||
	LoadAvg          float64   `json:"-" db:"load_avg"` // LoadAvg as Float64
 | 
						LoadAvg          float64   `json:"-" db:"load_avg"`                        // LoadAvg as Float64
 | 
				
			||||||
	NetBwAvg         float64   `json:"-" db:"net_bw_avg"` // NetBwAvg as Float64
 | 
						NetBwAvg         float64   `json:"-" db:"net_bw_avg"`                      // NetBwAvg as Float64
 | 
				
			||||||
	NetDataVolTotal  float64   `json:"-" db:"net_data_vol_total"` // NetDataVolTotal as Float64
 | 
						NetDataVolTotal  float64   `json:"-" db:"net_data_vol_total"`              // NetDataVolTotal as Float64
 | 
				
			||||||
	FileBwAvg        float64   `json:"-" db:"file_bw_avg"` // FileBwAvg as Float64
 | 
						FileBwAvg        float64   `json:"-" db:"file_bw_avg"`                     // FileBwAvg as Float64
 | 
				
			||||||
	FileDataVolTotal float64   `json:"-" db:"file_data_vol_total"` // FileDataVolTotal as Float64
 | 
						FileDataVolTotal float64   `json:"-" db:"file_data_vol_total"`             // FileDataVolTotal as Float64
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Non-Swaggered Comment: JobMeta
 | 
					// Non-Swaggered Comment: JobMeta
 | 
				
			||||||
@@ -70,11 +70,11 @@ type Job struct {
 | 
				
			|||||||
// JobMeta model
 | 
					// JobMeta model
 | 
				
			||||||
// @Description Meta data information of a HPC job.
 | 
					// @Description Meta data information of a HPC job.
 | 
				
			||||||
type JobMeta struct {
 | 
					type JobMeta struct {
 | 
				
			||||||
  // The unique identifier of a job in the database
 | 
						// The unique identifier of a job in the database
 | 
				
			||||||
	ID *int64 `json:"id,omitempty"`
 | 
						ID *int64 `json:"id,omitempty"`
 | 
				
			||||||
	BaseJob
 | 
						BaseJob
 | 
				
			||||||
	StartTime  int64                    `json:"startTime" db:"start_time" example:"1649723812" minimum:"1"` // Start epoch time stamp in seconds (Min > 0)
 | 
						StartTime  int64                    `json:"startTime" db:"start_time" example:"1649723812" minimum:"1"` // Start epoch time stamp in seconds (Min > 0)
 | 
				
			||||||
	Statistics map[string]JobStatistics `json:"statistics,omitempty"` // Metric statistics of job
 | 
						Statistics map[string]JobStatistics `json:"statistics,omitempty"`                                       // Metric statistics of job
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -102,18 +102,18 @@ type JobStatistics struct {
 | 
				
			|||||||
// Tag model
 | 
					// Tag model
 | 
				
			||||||
// @Description Defines a tag using name and type.
 | 
					// @Description Defines a tag using name and type.
 | 
				
			||||||
type Tag struct {
 | 
					type Tag struct {
 | 
				
			||||||
  // The unique DB identifier of a tag
 | 
						// The unique DB identifier of a tag
 | 
				
			||||||
	ID   int64  `json:"id" db:"id"`
 | 
						ID   int64  `json:"id" db:"id"`
 | 
				
			||||||
	Type string `json:"type" db:"tag_type" example:"Debug"` // Tag Type
 | 
						Type string `json:"type" db:"tag_type" example:"Debug"`   // Tag Type
 | 
				
			||||||
	Name string `json:"name" db:"tag_name" example:"Testjob"` // Tag Name
 | 
						Name string `json:"name" db:"tag_name" example:"Testjob"` // Tag Name
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Resource model
 | 
					// Resource model
 | 
				
			||||||
// @Description A resource used by a job
 | 
					// @Description A resource used by a job
 | 
				
			||||||
type Resource struct {
 | 
					type Resource struct {
 | 
				
			||||||
	Hostname      string   `json:"hostname"` // Name of the host (= node)
 | 
						Hostname      string   `json:"hostname"`                // Name of the host (= node)
 | 
				
			||||||
	HWThreads     []int    `json:"hwthreads,omitempty"` // List of OS processor ids
 | 
						HWThreads     []int    `json:"hwthreads,omitempty"`     // List of OS processor ids
 | 
				
			||||||
	Accelerators  []string `json:"accelerators,omitempty"` // List of of accelerator device ids
 | 
						Accelerators  []string `json:"accelerators,omitempty"`  // List of of accelerator device ids
 | 
				
			||||||
	Configuration string   `json:"configuration,omitempty"` // The configuration options of the node
 | 
						Configuration string   `json:"configuration,omitempty"` // The configuration options of the node
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -343,7 +343,7 @@ func TestRestApi(t *testing.T) {
 | 
				
			|||||||
	restapi.MountRoutes(r)
 | 
						restapi.MountRoutes(r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const startJobBody string = `{
 | 
						const startJobBody string = `{
 | 
				
			||||||
"jobId":            123,
 | 
					    	"jobId":            123,
 | 
				
			||||||
		"user":             "testuser",
 | 
							"user":             "testuser",
 | 
				
			||||||
		"project":          "testproj",
 | 
							"project":          "testproj",
 | 
				
			||||||
		"cluster":          "testcluster",
 | 
							"cluster":          "testcluster",
 | 
				
			||||||
@@ -542,7 +542,7 @@ func subtestLetJobFail(t *testing.T, restapi *api.RestApi, r *mux.Router) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const stopJobBody string = `{
 | 
						const stopJobBody string = `{
 | 
				
			||||||
"jobId":     12345,
 | 
						"jobId":     12345,
 | 
				
			||||||
		"cluster":   "testcluster",
 | 
							"cluster":   "testcluster",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		"jobState": "failed",
 | 
							"jobState": "failed",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user