Skip to content

Commit 7cc8d17

Browse files
author
Johannes Duesing
committed
Added runCommand, retreiveLogs and streamLogs to docu and implementation
1 parent e82dee1 commit 7cc8d17

File tree

2 files changed

+153
-31
lines changed

2 files changed

+153
-31
lines changed

OpenAPISpecification.yaml

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ paths:
347347
tags:
348348
- Basic Operations
349349
consumes:
350-
- text/plain
350+
- application/json
351351
summary: Add a label to the instance with the specified id
352352
description: >-
353353
This command will add the specified label to the instance with the
@@ -374,6 +374,65 @@ paths:
374374
description: 'Bad request, your label exceeded the character limit'
375375
'404':
376376
description: 'Not found, the id you specified could not be found'
377+
/instances/{Id}/logs:
378+
get:
379+
tags:
380+
- Basic Operations
381+
summary: Retrieve the logging output of the specified instance
382+
description: This command retrieves the docker container logging output for the specified instance, if the instance is in fact running inside a docker container.
383+
operationId: retreiveLogs
384+
parameters:
385+
- name: Id
386+
in: path
387+
description: Id of the instance
388+
required: true
389+
type: integer
390+
format: int64
391+
- name: StdErr
392+
in: query
393+
description: Switch to select the stderr channel
394+
required: false
395+
type: boolean
396+
responses:
397+
'200':
398+
description: Success, log string is being returned
399+
schema:
400+
type: string
401+
example: "I am logging output .."
402+
'400':
403+
description: Selected instance not running inside docker container
404+
'404':
405+
description: Id not found on the server
406+
'500':
407+
description: Internal Server Error
408+
/instances/{Id}/attach:
409+
get:
410+
tags:
411+
- Basic Operations
412+
summary: Stream logging output from instance
413+
description: 'This command streams the docker container logging output for the specified instance. NOTE: This is a websocket endpoint, so only valid websocket requests will be processed. Swagger does not provide sufficient support for websockets, so this documentation might be confusing as it defines a HTTP method, etc. The names of parameters and response-codes are valid though.'
414+
operationId: streamLogs
415+
parameters:
416+
- name: Id
417+
in: path
418+
description: Id of the instance
419+
required: true
420+
type: integer
421+
format: int64
422+
- name: StdErr
423+
in: query
424+
description: Switch to select the stderr channel
425+
required: false
426+
type: boolean
427+
responses:
428+
'200':
429+
description: Success, logs are being streamed via websocket connection.
430+
'400':
431+
description: Selected instance not running inside docker container
432+
'404':
433+
description: Id not found on the server
434+
'500':
435+
description: Internal Server Error
377436
/instances/deploy:
378437
post:
379438
tags:
@@ -688,6 +747,49 @@ paths:
688747
description: One of the ids was not found on the server
689748
'500':
690749
description: Internal server error
750+
/instances/{Id}/command:
751+
post:
752+
tags:
753+
- Docker Operations
754+
summary: Runs a command into a docker container
755+
description: >-
756+
This command runs a specified command inside a docker container.
757+
operationId: command
758+
parameters:
759+
- in: path
760+
name: Id
761+
description: The ID of the instance that is a docker container
762+
required: true
763+
type: integer
764+
format: int64
765+
- in: body
766+
name: CommandData
767+
description: The data needed to run the command
768+
required: true
769+
schema:
770+
type: object
771+
required:
772+
- Command
773+
properties:
774+
Command:
775+
type: string
776+
example: "rm -rf *"
777+
Privileged:
778+
type: boolean
779+
User:
780+
type: string
781+
example: root
782+
responses:
783+
'200':
784+
description: 'OK'
785+
'400':
786+
description: >-
787+
Cannot run command, ID is no docker container.
788+
'404':
789+
description: Cannot run command, ID not found.
790+
'500':
791+
description: Internal server error, unknown operation result DESCRIPTION
792+
691793
definitions:
692794
InstanceLink:
693795
type: object

src/main/scala/de/upb/cs/swt/delphi/instanceregistry/connection/Server.scala

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,21 @@ class Server(handler: RequestHandler) extends HttpApp
116116
} ~
117117
path("label") {
118118
entity(as[JsValue]) { json => addLabel(Id, json.asJsObject) }
119+
} ~
120+
path("logs") {
121+
retrieveLogs(Id)
122+
} ~
123+
path("attach") {
124+
streamLogs(Id)
125+
} ~
126+
path("command") {
127+
entity(as[JsValue]) { json => runCommandInContainer(Id, json.asJsObject) }
119128
}
120129
}
121130
} ~
122-
path("command") {
123-
runCommandInContainer()
124-
} ~
125-
path("events") {
126-
streamEvents()
127-
}
131+
path("events") {
132+
streamEvents()
133+
}
128134

129135

130136
/**
@@ -916,38 +922,52 @@ class Server(handler: RequestHandler) extends HttpApp
916922
*
917923
* @return Server route that either maps to 200 Ok or the respective error codes.
918924
*/
919-
def runCommandInContainer(): server.Route = parameters('Id.as[Long], 'Command.as[String],
920-
'AttachStdin.as[Boolean].?, 'AttachStdout.as[Boolean].?,
921-
'AttachStderr.as[Boolean].?, 'DetachKeys.as[String].?, 'Privileged.as[Boolean].?, 'Tty.as[Boolean].?, 'User.as[String].?
922-
) { (id, command, attachStdin, attachStdout, attachStderr, detachKeys, privileged, tty, user) =>
925+
def runCommandInContainer(id:Long, json: JsObject): server.Route = {
923926
authenticateOAuth2[AccessToken]("Secure Site", AuthProvider.authenticateOAuthRequire(_, userType = UserType.Admin)) { token =>
924927
post {
925928
log.debug(s"POST /command has been called")
926-
handler.handleCommand(id, command, attachStdin, attachStdout, attachStderr, detachKeys, privileged, tty, user) match {
927-
case handler.OperationResult.IdUnknown =>
928-
log.warning(s"Cannot run command $command to $id, id not found.")
929-
complete {
930-
HttpResponse(StatusCodes.NotFound, entity = s"Cannot run command, id $id not found.")
931-
}
932-
case handler.OperationResult.NoDockerContainer =>
933-
log.warning(s"Cannot run command $command to $id, $id is no docker container.")
934-
complete {
935-
HttpResponse(StatusCodes.BadRequest, entity = s"Cannot run command, $id is no docker container.")
936-
}
937-
case handler.OperationResult.Ok =>
938-
complete {
939-
HttpResponse(StatusCodes.OK)
940-
}
941-
case r =>
942-
complete {
943-
HttpResponse(StatusCodes.InternalServerError, entity = s"Internal server error, unknown operation result $r")
929+
930+
val privileged = Try(json.fields("Privileged").toString.toBoolean) match {
931+
case Success(res) => Some(res)
932+
case Failure(_) => None
933+
}
934+
935+
val user = Try(json.fields("User").toString) match {
936+
case Success(res) => Some(res)
937+
case Failure(_) => None
938+
}
939+
940+
Try(json.fields("Command").toString) match {
941+
case Success(command) =>
942+
handler.handleCommand(id, command, None, None, None, None, privileged, None, user) match {
943+
case handler.OperationResult.IdUnknown =>
944+
log.warning(s"Cannot run command $command to $id, id not found.")
945+
complete {
946+
HttpResponse(StatusCodes.NotFound, entity = s"Cannot run command, id $id not found.")
947+
}
948+
case handler.OperationResult.NoDockerContainer =>
949+
log.warning(s"Cannot run command $command to $id, $id is no docker container.")
950+
complete {
951+
HttpResponse(StatusCodes.BadRequest, entity = s"Cannot run command, $id is no docker container.")
952+
}
953+
case handler.OperationResult.Ok =>
954+
complete {
955+
HttpResponse(StatusCodes.OK)
956+
}
957+
case r =>
958+
complete {
959+
HttpResponse(StatusCodes.InternalServerError, entity = s"Internal server error, unknown operation result $r")
960+
}
944961
}
962+
case Failure(ex) =>
963+
log.warning(s"Failed to unmarshal parameters with message ${ex.getMessage}. Data: $json")
964+
complete{HttpResponse(StatusCodes.BadRequest, entity = "Wrong data format supplied.")}
945965
}
946966
}
947967
}
948968
}
949969

950-
def retrieveLogs(): server.Route = parameters('Id.as[Long], 'StdErr.as[Boolean].?) { (id, stdErrOption) =>
970+
def retrieveLogs(id: Long): server.Route = parameters('StdErr.as[Boolean].?) { stdErrOption =>
951971
authenticateOAuth2[AccessToken]("Secure Site", AuthProvider.authenticateOAuthRequire(_, userType = UserType.Admin)) { token =>
952972
get {
953973
log.debug(s"GET /logs?Id=$id has been called")
@@ -982,7 +1002,7 @@ class Server(handler: RequestHandler) extends HttpApp
9821002
}
9831003
}
9841004

985-
def streamLogs(): server.Route = parameters('Id.as[Long], 'StdErr.as[Boolean].?) { (id, stdErrOption) =>
1005+
def streamLogs(id: Long): server.Route = parameters('StdErr.as[Boolean].?) { stdErrOption =>
9861006

9871007

9881008
val stdErrSelected = stdErrOption.isDefined && stdErrOption.get

0 commit comments

Comments
 (0)