openapi: 3.0.0 info: title: Poseidon API description: | This API is used by CodeOcean to run code in runners. version: '0.2.2' servers: - url: '/api/v1' components: schemas: ExecutionEnvironment: type: object properties: id: description: The id of the execution environment type: integer example: 6 image: description: The name of the OCI image used for this execution environment type: string example: openhpi/co_execenv_python:latest prewarmingPoolSize: description: Number of runners with this configuration to prewarm type: integer example: 50 cpuLimit: description: CPU limit for one runner in MHz type: number example: 100 memoryLimit: description: Memory limit for one runner in MB. Exceeding the limit may result in termination of the runner. type: integer example: 256 networkAccess: description: Whether the runner is allowed to access the network or not type: boolean example: true exposedPorts: description: A list of ports inside the runner to expose to the outside type: array items: type: integer minimum: 1 maximum: 65535 example: [80, 443] required: - id - image - prewarmingPoolSize - cpuLimit - memoryLimit - networkAccess - exposedPorts additionalProperties: false FileHeader: type: object properties: name: description: The path of the file. type: string example: ./logs/last.log entryType: description: The type of the object (file). See the man page `info ls` for all the meanings. type: string minLength: 1 maxLength: 1 enum: ["-", "a", "A", "b", "c", "C", "d", "D", "l", "M", "n", "p", "P", "s", "w", "?"] default: "-" size: description: The size of the file in bytes. type: integer example: 42 modificationTime: description: The Unix Time Stamp of the last modification. type: integer example: 1654201799 required: - name - size - modificationTime additionalProperties: false ClientError: type: object properties: message: description: Explanation on why the request could not be handled type: string example: Nomad server unreachable required: - message additionalProperties: false securitySchemes: poseidonAuthToken: type: apiKey in: header name: Poseidon-Token description: A security token that might be required depending on the Poseidon configuration. responses: BadRequest: description: Request is invalid. E.g. request body does not follow the json schema required by the given route or url parameters are invalid. content: application/json: schema: type: object properties: message: description: Explanation on why the request is invalid type: string Unauthorized: description: Client could not be authenticated NotFound: description: The entity with the given identifier does not exist. RunnerGone: description: The runner is not available any longer. content: application/json: schema: $ref: "#/components/schemas/ClientError" FailedFileDependency: description: The file is not available. content: application/json: schema: $ref: "#/components/schemas/ClientError" InternalServerError: description: Request could not be handled content: application/json: schema: allOf: - $ref: "#/components/schemas/ClientError" - type: object properties: errorCode: description: Machine readable error description type: string enum: - NOMAD_UNREACHABLE - NOMAD_OVERLOAD - NOMAD_INTERNAL_SERVER_ERROR - PREWARMING_POOL_DEPLETING - UNKNOWN example: NOMAD_UNREACHABLE tags: - name: runner description: A unit of execution - name: execution environment description: A template for runners - name: miscellaneous paths: /health: get: summary: Check if the API is available description: If this route does not return, the API is not available. tags: - miscellaneous responses: "204": description: Everything okay "503": $ref: "#/components/responses/InternalServerError" /version: get: summary: Retrieve the version of Poseidon description: Return hash-like release information. tags: - miscellaneous responses: "200": description: The release information could be returned. "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" /statistics/execution-environments: get: summary: Retrieve the statistics about the execution environments of Poseidon description: Return Return the current availability and usage of runners. tags: - miscellaneous security: - poseidonAuthToken: [ ] responses: "200": description: Success. Returns all execution environments content: application/json: schema: type: object additionalProperties: type: object properties: id: description: The id of the execution environment. type: integer prewarmingPoolSize: description: Number of runners with this configuration to prewarm. type: integer example: 50 idleRunners: description: Number of runners currently prewarmed. type: number example: 45 usedRunners: description: Number of runners currently in use. type: number example: 20 example: 21: id: 21 prewarmingPoolSize: 50 idleRunners: 45 usedRunners: 20 42: id: 42 prewarmingPoolSize: 50 idleRunners: 45 usedRunners: 20 "500": $ref: "#/components/responses/InternalServerError" /runners: post: summary: Provide a runner description: Provide a runner with the requested execution environment to the client (CodeOcean). tags: - runner security: - poseidonAuthToken: [ ] requestBody: description: Runner attributes required: true content: application/json: schema: type: object properties: inactivityTimeout: description: Specify how long the runner should be available when there is no activity (execution or file copy). Activity resets this timer. 0 means no timeout type: integer default: 0 example: 60 executionEnvironmentId: description: Specifies the execution environment of the runner type: integer example: 6 required: - executionEnvironmentId additionalProperties: false responses: "200": description: A runner was successfully reserved content: application/json: schema: type: object properties: runnerId: description: The UUID of the provided runner type: string example: 123e4567-e89b-12d3-a456-426614174000 mappedPorts: description: Array containing the addresses of the mapped ports specified in the execution environment. type: array items: description: The exposedPort inside the container is reachable on the returned hostAddress. type: object properties: exposedPort: description: The port inside the container. type: integer minimum: 0 maximum: 65535 example: 80 hostAddress: description: The address which can be contacted to reach the mapped port. type: string example: 10.224.6.18:23832 "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" /runners/{runnerId}: delete: summary: Destroy the runner description: The runner is no longer in use and should be destroyed. tags: - runner security: - poseidonAuthToken: [ ] parameters: - name: runnerId in: path schema: description: The UUID of the runner that should be destroyed type: string example: 123e4567-e89b-12d3-a456-426614174000 required: true responses: "204": description: Success "401": $ref: "#/components/responses/Unauthorized" "410": $ref: "#/components/responses/RunnerGone" "500": $ref: "#/components/responses/InternalServerError" /runners/{runnerId}/files: parameters: - name: runnerId in: path schema: description: Runner on which the files should be placed type: string example: 123e4567-e89b-12d3-a456-426614174000 required: true get: summary: List filesystem. description: List all files available in the runner. tags: - runner security: - poseidonAuthToken: [ ] parameters: - name: recursive in: query description: Specify if the filesystem should be listed recursively. schema: type: boolean default: true required: false - name: path in: query description: Specify the directory from where the filesystem is listed. schema: type: string format: pct-encoded # rfc 3986 default: "./" required: false - name: privilegedExecution in: query description: Specifies if the command should be executed as an privileged user. schema: type: boolean default: false responses: "200": description: Success. Returns the listing of the runner's filesystem. content: application/json: schema: type: object properties: files: description: A list of all Files type: array items: $ref: "#/components/schemas/FileHeader" "401": $ref: "#/components/responses/Unauthorized" "410": $ref: "#/components/responses/RunnerGone" "424": $ref: "#/components/responses/FailedFileDependency" "500": $ref: "#/components/responses/InternalServerError" patch: summary: Manipulate runner file system description: Delete the files with the given paths from the file system of the specified runner. Afterwards, copy the enclosed files to the runner. Existing files get overwritten and results of previous file copy operations on the same runner are present when executing multiple requests. tags: - runner security: - poseidonAuthToken: [ ] requestBody: description: Files to copy or delete required: true content: application/json: schema: type: object properties: delete: description: Array of filepaths that should be deleted. Each of the given files or directories should be deleted recursively. type: array items: description: Location of the file or directory that should be deleted. Can be absolute (starting with /) or relative to the workspace directory. type: string example: /workspace copy: description: Array of files that should be placed in the runner. type: array items: type: object properties: path: description: Location where the file should be placed. Can be absolute (starting with /) or relative to the workspace directory. Missing parent directories are created. If this ends with a /, the path is interpreted as a directory and content is ignored. Currently, every file/directory is owned by root but the directories have the sticky bit set to allow unprivileged file creation. type: string example: /etc/passwd content: description: The content of the file. MUST be base64 encoded. If this is not given, the file is created with no content. type: string example: cm9vdDp4OjA6MDo6L3Jvb3Q6L2Jpbi9iYXNo # root:x:0:0::/root:/bin/bash required: - path additionalProperties: false additionalProperties: false responses: "204": description: All files were saved "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "410": $ref: "#/components/responses/RunnerGone" "500": $ref: "#/components/responses/InternalServerError" /runners/{runnerId}/files/raw: get: summary: Download the file. description: Download the specified file from the selected runner. tags: - runner security: - poseidonAuthToken: [ ] parameters: - name: runnerId description: Runner on which the command should be executed in: path schema: type: string example: 123e4567-e89b-12d3-a456-426614174000 required: true - name: path in: query description: Specify the file that should be returned by its filename including its path and extension. schema: type: string format: pct-encoded # rfc 3986 example: "./flag.txt" required: true - name: privilegedExecution in: query description: Specifies if the command should be executed as an privileged user. schema: type: boolean default: false responses: "200": description: Success. Returns the file. content: application/octet-stream: schema: type: string format: binary "401": $ref: "#/components/responses/Unauthorized" "410": $ref: "#/components/responses/RunnerGone" "424": $ref: "#/components/responses/FailedFileDependency" /runners/{runnerId}/execute: post: summary: Execute a command description: Execute a command in the runner. Whether this starts the actual execution or only prepares a Websocket URL to start it depends on the implementation. tags: - runner security: - poseidonAuthToken: [ ] parameters: - name: runnerId description: Runner on which the command should be executed in: path schema: type: string example: 123e4567-e89b-12d3-a456-426614174000 required: true requestBody: description: Description what and how to execute required: true content: application/json: schema: type: object properties: command: description: The command to be executed. The working directory for this execution is the working directory of the image of the execution environment. Single quotation ' can not be used. type: string example: python exercise.py privilegedExecution: description: Specifies if the command should be executed as an privileged user. type: boolean default: false environment: description: Environment variables for this execution. The keys of this object are the variable names and the value of each key is the value of the variable with the same name. The environment variables of the system remain accessible. type: object additionalProperties: type: string pattern: "[a-zA-Z_][a-zA-Z0-9_]+" default: {} example: PATH: /bin timeLimit: description: Specifies the time in seconds until this execution should be killed. 0 means do not kill type: integer default: 0 example: 5 required: - command additionalProperties: false responses: "200": description: Success. Returns a Websocket URL to connect to content: application/json: schema: type: object properties: websocketUrl: description: A Websocket endpoint to connect to communicate with the process running in the runner type: string example: "ws://ws.example.com/path/to/websocket" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "410": $ref: "#/components/responses/RunnerGone" "500": $ref: "#/components/responses/InternalServerError" /runners/{runnerId}/websocket: get: summary: Connect to an execution. description: The url including all parameters will be generated and returned by the `execute` route. This is a WebSocket endpoint. The schema for the WS communication is described in `websocket.schema.json`. tags: - runner security: - poseidonAuthToken: [ ] parameters: - name: runnerId description: Runner on which the execution is created. in: path schema: type: string example: 123e4567-e89b-12d3-a456-426614174000 required: true - name: executionID description: The execution of the runner that you want to connect to. in: query schema: type: string example: 123e4567-e89b-12d3-a456-426614174000 required: true responses: "101": description: Success. Switching protocols to WebSocket. "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "410": $ref: "#/components/responses/RunnerGone" "500": $ref: "#/components/responses/InternalServerError" /execution-environments: get: summary: List execution environments description: List all execution environments the API is aware of. tags: - execution environment security: - poseidonAuthToken: [ ] parameters: - name: fetch in: query description: Specify whether environments should be fetched again from the executor before returning. Otherwise, the data currently in cache is returned. schema: type: boolean default: false required: false responses: "200": description: Success. Returns all execution environments content: application/json: schema: type: object properties: executionEnvironments: description: A list of all execution environments type: array items: $ref: "#/components/schemas/ExecutionEnvironment" "401": $ref: "#/components/responses/Unauthorized" /execution-environments/{executionEnvironmentId}: parameters: - name: executionEnvironmentId in: path description: Id of the execution environment required: true schema: type: integer get: summary: Show an execution environment description: Get a representation of the execution environment specified by the id. tags: - execution environment security: - poseidonAuthToken: [ ] parameters: - name: fetch in: query description: Specify whether the environment should be fetched again from the executor before returning. Otherwise, the data currently in cache is returned. schema: type: boolean default: false required: false responses: "200": description: Success. Returns the execution environment content: application/json: schema: $ref: "#/components/schemas/ExecutionEnvironment" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" put: summary: Create or replace the execution environment description: This is used for keeping execution environments in sync between the client and the provider of this API. By sending a request with an id, the execution environment is created if it does not exist and updated otherwise. tags: - execution environment security: - poseidonAuthToken: [ ] requestBody: description: The new execution environment required: true content: application/json: schema: $ref: "#/components/schemas/ExecutionEnvironment" responses: "201": description: The executions environment did not exist and was created "204": description: The execution environment was replaced "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" delete: summary: Delete the execution environment description: Remove the specified execution environment from the API. tags: - execution environment security: - poseidonAuthToken: [ ] responses: "204": description: The execution environment was deleted. "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound"