diff --git a/Makefile b/Makefile index 8cc2a49b0..006bb834b 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ DOC_FILES := \ bundle.md \ runtime.md \ runtime-linux.md \ + command-line-interface.md \ config.md \ config-linux.md \ config-solaris.md \ diff --git a/README.md b/README.md index ad9fa7050..75d7eeab0 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Table of Contents - Runtime and Lifecycle - [General Runtime and Lifecycle](runtime.md) - [Linux-specific Runtime and Lifecycle](runtime-linux.md) + - [Runtime Command Line Interface](command-line-interface.md) - Configuration - [General Configuration](config.md) - [Linux-specific Configuration](config-linux.md) @@ -31,9 +32,14 @@ An implementation is not compliant for a given CPU architecture if it fails to s An implementation is compliant for a given CPU architecture if it satisfies all the MUST, REQUIRED, and SHALL requirements for the protocols it implements. Protocols defined by this specification are: -* Linux containers: [runtime.md](runtime.md), [config.md](config.md), [config-linux.md](config-linux.md), and [runtime-linux.md](runtime-linux.md). -* Solaris containers: [runtime.md](runtime.md), [config.md](config.md), and [config-solaris.md](config-solaris.md). -* Windows containers: [runtime.md](runtime.md), [config.md](config.md), and [config-windows.md](config-windows.md). + +* Linux containers: [runtime.md](runtime.md), [config.md](config.md), [config-linux.md](config-linux.md), [runtime-linux.md](runtime-linux.md), and at least one API. +* Solaris containers: [runtime.md](runtime.md), [config.md](config.md), [config-solaris.md](config-solaris.md), and at least one API. +* Windows containers: [runtime.md](runtime.md), [config.md](config.md), [config-windows.md](config-windows.md), and at least one API. + +APIs defined by this specification are: + +* The [command line API](command-line-interface.md). # Use Cases diff --git a/command-line-interface.md b/command-line-interface.md new file mode 100644 index 000000000..3601ae3ef --- /dev/null +++ b/command-line-interface.md @@ -0,0 +1,248 @@ +# Runtime Command Line Interface + +The [runtime][] MUST provide an executable (called `funC` in the following examples). +That executable MUST support commands with the following template: + +``` +$ funC [global-options] [command-specific-options] +``` + +## Global options + +None are required, but the runtime MAY support options that start with at least one hyphen. +Global options MAY take positional arguments (e.g. `--log-level debug`). +Command names MUST NOT start with hyphens. +The option parsing MUST be such that `funC ` is unambiguously an invocation of `` (even for commands not specified in this document). +If the runtime is invoked with an unrecognized command, it MUST exit with a nonzero exit code and MAY log a warning to stderr. +Beyond the above rules, the behavior of the runtime in the presence of commands and options not specified in this document is unspecified. + +## Character encodings + +This API specification does not cover character encodings, but runtimes SHOULD conform to their native operating system. +For example, POSIX systems define [`LANG` and related environment variables][posix-lang] for [declaring][posix-locale-encoding] [locale-specific character encodings][posix-encoding], so a runtime in an `en_US.UTF-8` locale SHOULD write its [state](#state) to stdout in [UTF-8][]. + +## Commands + +### create + +[Create][create] a container from a [bundle directory][bundle]. + +* *Arguments* + * *``* Set the container ID to create. +* *Options* + * *`--bundle `* Override the path to the [bundle directory][bundle] (defaults to the current working directory). + * *`--pid-file `* The runtime MUST write the container PID to this path. +* *Standard streams:* + * If [`process.terminal`][process] is true: + * *stdin:* The runtime MUST NOT attempt to read from its stdin. + * *stdout:* The handling of stdout is unspecified. + * *stderr:* The runtime MAY print diagnostic messages to stderr, and the format for those lines is not specified in this document. + * If [`process.terminal`][process] is not true: + * *stdin:* The runtime MUST pass its stdin file descriptor through to the container process without manipulation or modification. + "Without manipulation or modification" means that the runtime MUST not seek on the file descriptor, or close it, or read or write to it, or [`ioctl`][ioctl.3] it, or perform any other action on it besides bassing it through to the container process. + + When using a container to drop privileges, note that providing a privileged terminal's file descriptor may allow the container to [execute privileged operations via `TIOCSTI`][TIOCSTI-security] or other [TTY ioctls][tty_ioctl.4]. + On Linux, [`TIOCSTI` requires `CAP_SYS_ADMIN`][capabilities.7] unless the target terminal is the caller's [controlling terminal][contolling-terminal]. + * *stdout:* The runtime MUST pass its stdout file descriptor through to the container process without manipulation or modification. + * *stderr:* When `create` exists with a zero code, the runtime MUST pass its stderr file descriptor through to the container process without manipulation or modification. + When `create` exits with a non-zero code, the runtime MAY print diagnostic messages to stderr, and the format for those lines is not specified in this document. +* *Environment variables* + * *`LISTEN_FDS`:* The number of file descriptors passed. + For example, `LISTEN_FDS=2` would mean that the runtime MUST pass file descriptors 3 and 4 to the container process (in addition to the standard streams) to support [socket activation][systemd-listen-fds]. +* *Additional file descriptors* + * If [`process.terminal`][process] is true, the caller MUST provide an open [`AF_UNIX` socket][unix-socket] on file descriptor `$LISTEN_FDS + 3`. + The runtime MUST pass the [pseudoterminal master][posix_openpt.3] through the socket; the protocol is [described below](#console-socket). +* *Exit code:* Zero if the container was successfully created and non-zero on errors. + +Callers MAY block on this command's successful exit to trigger post-create activity. + +#### Console socket + +The [`AF_UNIX`][unix-socket] used by [`--console-socket`](#create) handles request and response messages between a runtime and server. +The socket type MUST be [`SOCK_SEQPACKET`][socket-types] or [`SOCK_STREAM`][socket-types]. +The server MUST send a single response for each runtime request. +The [normal data][socket-queue] ([`msghdr.msg_iov*`][socket.h]) of all messages MUST be [UTF-8][] [JSON](glossary.md#json). + +There are [JSON Schemas](schema/README.md) and [Go bindings](specs-go/socket/socket.go) for the messages specified in this section. + +##### Requests + +All requests MUST contain a **`type`** property whose value MUST one of the following strings: + +* `terminal`, if the request is passing a [pseudoterminal master][posix_openpt.3]. + When `type` is `terminal`, the request MUST also contain the following properties: + + * **`container`** (string, REQUIRED) The container ID, as set by [create](#create). + + The message's [ancillary data][socket-queue] (`msg_control*`) MUST contain at least one [`cmsghdr`][socket.h]). + The first `cmsghdr` MUST have: + + * `cmsg_type` set to [`SOL_SOCKET`][socket.h], + * `cmsg_level` set to [`SCM_RIGHTS`][socket.h], + * `cmsg_len` greater than or equal to `CMSG_LEN(sizeof(int))`, and + * `((int*)CMSG_DATA(cmsg))[0]` set to the pseudoterminal master file descriptor. + +##### Responses + +All responses MUST contain a **`type`** property whose value MUST one of the following strings: + +* `success`, if the request was successfully processed. +* `error`, if the request was not successfully processed. + +In addition, responses MAY contain any of the following properties: + +* **`message`** (string, OPTIONAL) A phrase describing the response. + +#### Example + +``` +# in a bundle directory with a process that echos "hello" and exits 42 +$ test -t 1 && echo 'stdout is a terminal' +stdout is a terminal +$ funC create hello-1 <&- >stdout 2>stderr +$ echo $? +0 +$ wc stdout +0 0 0 stdout +$ funC start hello-1 +$ echo $? +0 +$ cat stdout +hello +$ block-on-exit-and-collect-exit-code hello-1 +$ echo $? +42 +$ funC delete hello-1 +$ echo $? +0 +``` + +#### Container process exit + +The [example's](#example) `block-on-exit-and-collect-exit-code` is platform-specific magic that is not specified in this document. +On Linux, it might involve an ancestor process which had set [`PR_SET_CHILD_SUBREAPER`][prctl.2] and collected the container PID [from the state][state], or a process that was [ptracing][ptrace.2] the container process for [`exit_group`][exit_group.2], although both of those race against the container process exiting before the watcher is monitoring. + +### start + +[Start][start] the user-specified code from [`process`][process]. + +* *Arguments* + * *``* Set the container ID to start. +* *Standard streams:* + * *stdin:* The runtime MUST NOT attempt to read from its stdin. + * *stdout:* The handling of stdout is unspecified. + * *stderr:* The runtime MAY print diagnostic messages to stderr, and the format for those lines is not specified in this document. +* *Exit code:* Zero if the container was successfully started and non-zero on errors. + +Callers MAY block on this command's successful exit to trigger post-start activity. + +See [create](#example) for an example. + +### state + +[Request][state-request] the container [state][state]. + +* *Arguments* + * *``* The container whose state is being requested. +* *Standard streams:* + * *stdin:* The runtime MUST NOT attempt to read from its stdin. + * *stdout:* The runtime MUST print the [state JSON][state] to its stdout. + * *stderr:* The runtime MAY print diagnostic messages to stderr, and the format for those lines is not specified in this document. +* *Exit code:* Zero if the state was successfully written to stdout and non-zero on errors. + +#### Example + +``` +# in a bundle directory with a process that sleeps for several seconds +$ funC start --id sleeper-1 & +$ funC state sleeper-1 +{ + "ociVersion": "1.0.0-rc1", + "id": "sleeper-1", + "status": "running", + "pid": 4422, + "bundlePath": "/containers/sleeper", + "annotations" { + "myKey": "myValue" + } +} +$ echo $? +0 +``` + +### kill + +[Send a signal][kill] to the container process. + +* *Arguments* + * *``* The container being signaled. +* *Options* + * *`--signal `* The signal to send (defaults to `TERM`). + The runtime MUST support `TERM` and `KILL` signals with [the POSIX semantics][posix-signals]. + The runtime MAY support additional signal names. + On platforms that support [POSIX signals][posix-signals], the runtime MUST implement this command using POSIX signals. + On platforms that do not support POSIX signals, the runtime MAY implement this command with alternative technology as long as `TERM` and `KILL` retain their POSIX semantics. + Runtime authors on non-POSIX platforms SHOULD submit documentation for their TERM implementation to this specificiation, so runtime callers can configure the container process to gracefully handle the signals. +* *Standard streams:* + * *stdin:* The runtime MUST NOT attempt to read from its stdin. + * *stdout:* The handling of stdout is unspecified. + * *stderr:* The runtime MAY print diagnostic messages to stderr, and the format for those lines is not specified in this document. +* *Exit code:* Zero if the signal was successfully sent to the container process and non-zero on errors. + Successfully sent does not mean that the signal was successfully received or handled by the container process. + +#### Example + +``` +# in a bundle directory with a process ignores TERM +$ funC start --id sleeper-1 & +$ funC kill sleeper-1 +$ echo $? +0 +$ funC kill --signal KILL sleeper-1 +$ echo $? +0 +``` + +### delete + +[Release](#delete) container resources after the container process has exited. + +* *Arguments* + * *``* Set the container ID to delete. +* *Standard streams:* + * *stdin:* The runtime MUST NOT attempt to read from its stdin. + * *stdout:* The handling of stdout is unspecified. + * *stderr:* The runtime MAY print diagnostic messages to stderr, and the format for those lines is not specified in this document. +* *Exit code:* Zero if the container was successfully deleted and non-zero on errors. + +See [create](#example) for an example. + +[bundle]: bundle.md +[controlling-terminal]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html#tag_11_01_03 +[create]: runtime.md#create +[delete]: runtime.md#delete +[exit_group.2]: http://man7.org/linux/man-pages/man2/exit_group.2.html +[ioctl.3]: http://pubs.opengroup.org/onlinepubs/9699919799/ +[kill]: runtime.md#kill +[kill.2]: http://man7.org/linux/man-pages/man2/kill.2.html +[process]: config.md#process-configuration +[posix-encoding]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html#tag_06_02 +[posix-lang]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_02 +[posix-locale-encoding]: http://www.unicode.org/reports/tr35/#Bundle_vs_Item_Lookup +[posix_openpt.3]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html +[posix-signals]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html#tag_13_42_03 +[prctl.2]: http://man7.org/linux/man-pages/man2/prctl.2.html +[ptrace.2]: http://man7.org/linux/man-pages/man2/ptrace.2.html +[runtime]: glossary.md#runtime +[socket-queue]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_10_11 +[socket-types]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_10_06 +[socket.h]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +[standard-streams]: https://github.com/opencontainers/specs/blob/v0.1.1/runtime-linux.md#file-descriptors +[start]: runtime.md#start +[state]: runtime.md#state +[state-request]: runtime.md#query-state +[systemd-listen-fds]: http://www.freedesktop.org/software/systemd/man/sd_listen_fds.html +[TIOCSTI-security]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=628843 +[tty_ioctl.4]: http://man7.org/linux/man-pages/man4/tty_ioctl.4.html +[unix-socket]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_10_17 +[UTF-8]: http://www.unicode.org/versions/Unicode8.0.0/ch03.pdf diff --git a/runtime-linux.md b/runtime-linux.md index 388df30a7..e4ba33e35 100644 --- a/runtime-linux.md +++ b/runtime-linux.md @@ -1,11 +1,5 @@ # Linux Runtime -## File descriptors - -By default, only the `stdin`, `stdout` and `stderr` file descriptors are kept open for the application by the runtime. -The runtime MAY pass additional file descriptors to the application to support features such as [socket activation](http://0pointer.de/blog/projects/socket-activated-containers.html). -Some of the file descriptors MAY be redirected to `/dev/null` even though they are open. - ## Dev symbolic links After the container has `/proc` mounted, the following standard symlinks MUST be setup within `/dev/` for the io. diff --git a/runtime.md b/runtime.md index 6b5deb3db..827b565f7 100644 --- a/runtime.md +++ b/runtime.md @@ -129,3 +129,14 @@ Once a container is deleted its ID MAY be used by a subsequent container. ## Hooks Many of the operations specified in this specification have "hooks" that allow for additional actions to be taken before or after each operation. See [runtime configuration for hooks](./config.md#hooks) for more information. + +## Container environment + +The following sections discuss portions of the container environment which are not configurable via the [configuration JSON](config.md). +Beyond the sections below, there are additional platform-specific requirements for [Linux](runtime-linux.md). + +### Standard streams + +All OCI-specified runtime APIs MUST allow runtime-callers to specify the file descriptors which will be inherited by the container process, with the [POSIX *exec* caveat][exec] that if file descriptor 0, 1, or 2 would otherwise be closed, the container process may have unspecified files opened for those file descriptors. + +[exec]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html diff --git a/schema/README.md b/schema/README.md index 0362da137..11e9f14cd 100644 --- a/schema/README.md +++ b/schema/README.md @@ -10,6 +10,8 @@ The layout of the files is as follows: * [config-linux.json](config-linux.json) - the [Linux-specific configuration sub-structure](../config-linux.md) * [config-solaris.json](config-solaris.json) - the [Solaris-specific configuration sub-structure](../config-solaris.md) * [config-windows.json](config-windows.json) - the [Windows-specific configuration sub-structure](../config-windows.md) +* [socket-terminal-request-schema.json](socket-terminal-request-schema.json) - the primary entrypoint for the [`terminal` request](../command-line-interface.md#requests) +* [socket-response-schema.json](socket-response-schema.json) - the primary entrypoint for the [`success` and `error` responses](../command-line-interface.md#responses) * [state-schema.json](state-schema.json) - the primary entrypoint for the [state JSON](../runtime.md#state) schema * [defs.json](defs.json) - definitions for general types * [defs-linux.json](defs-linux.json) - definitions for Linux-specific types diff --git a/schema/socket-response-schema.json b/schema/socket-response-schema.json new file mode 100644 index 000000000..d97e82eff --- /dev/null +++ b/schema/socket-response-schema.json @@ -0,0 +1,24 @@ +{ + "description": "Open Container Runtime Socket Response Schema", + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://opencontainers.org/schema/runtime/socket/response", + "type": "object", + "properties": { + "type": { + "id": "https://opencontainers.org/schema/runtime/socket/response/type", + "type": "string", + "enum": [ + "success", + "error" + ] + }, + "message": { + "id": "https://opencontainers.org/schema/runtime/socket/response/message", + "description": "A phrase describing the response.", + "type": "string" + } + }, + "required": [ + "type" + ] +} diff --git a/schema/socket-terminal-request-schema.json b/schema/socket-terminal-request-schema.json new file mode 100644 index 000000000..14844180c --- /dev/null +++ b/schema/socket-terminal-request-schema.json @@ -0,0 +1,24 @@ +{ + "description": "Open Container Runtime Socket Terminal Request Schema", + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://opencontainers.org/schema/runtime/socket/terminal-request", + "type": "object", + "properties": { + "type": { + "id": "https://opencontainers.org/schema/runtime/socket/terminal-request/type", + "type": "string", + "enum": [ + "terminal" + ] + }, + "container": { + "id": "https://opencontainers.org/schema/runtime/state/id", + "description": "the container's ID", + "type": "string" + } + }, + "required": [ + "type", + "container" + ] +} diff --git a/specs-go/socket/socket.go b/specs-go/socket/socket.go new file mode 100644 index 000000000..7bb23dc94 --- /dev/null +++ b/specs-go/socket/socket.go @@ -0,0 +1,23 @@ +package socket + +// Message is the normal data for messages passed on the console socket. +type Message struct { + // Type of message being passed + Type string `json:"type"` +} + +// TerminalRequest is the normal data for messages passing a pseudoterminal master. +type TerminalRequest struct { + Message + + // Container ID for the container whose pseudoterminal master is being set. + Container string `json:"container"` +} + +// Response is the normal data for response messages. +type Response struct { + Message + + // Message is a phrase describing the response. + Message string `json:"message,omitempty"` +}