Skip to content

Commit

Permalink
document protobuf in the sozu-command-lib README
Browse files Browse the repository at this point in the history
  • Loading branch information
Keksoj committed May 3, 2023
1 parent cdc8629 commit 78a6363
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 306 deletions.
8 changes: 4 additions & 4 deletions bin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ file.
The proxy receives orders through a unix socket. The path to this unix socket can
be defined by the `command_socket` option in the TOML configuration file.

The messages are sent as JSON messages, separated by the 0 byte.
The messages are sent as binary, using protobuf,
separated by the 0 byte.

Their format is defined in `../command/README.md`. Additionally, the
`sozu_command_lib` crate in `../command` already provides the necessary
structures, serialization and deserialization code to communicate with
Their format is defined in `../command/command.proto`. Additionally, the
provides the necessary channels to communicate with
the command socket.
332 changes: 36 additions & 296 deletions command/README.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,58 @@
# sozu-command-lib, tools to communicate with the sozu proxy
# sozu-command-lib, tools to communicate with the Sōzu proxy

The sozu proxy can receive dynamic configuration changes through a unix socket.
This library defines the communication protocol, the message format, the required
structures, serialization and deserialization code.

## Command socket message format
## Command messages are defined in protobuf

The messages are sent as JSON messages, separated by the 0 byte.
Protobuf is a language-agnostic, binary serialization format
used to efficiently transmit structured data between different systems and languages.

All messages contain an identifier which will be used to match the proxy's
response to the order, and a type, to decide how to parse the message.
The idea is to define the data _once_ in this format, so that various libraries
of various languages can translate it to their own.

You send a `CommandRequest`, defined as follows:
All types are defined in the `command.proto` file.
There are two main types received by, and sent from, Sōzu:

```rust
pub struct CommandRequest {
pub id: String,
pub version: u8,
pub order: CommandRequestOrder,
pub worker_id: Option<String>,
}
```

When serialized to JSON it looks like this:

```json
{
"id": "ID_TEST",
"version": 0,
"worker_id": 0,
"type": "<CommandRequestOrder enum name>",
"data": { <CommandRequestOrder wrapped value> }
}"
```

The type indicates which kind of message it wraps. The id field will be used
for answers. Since the protocol is asynchronous, this is used to identify
answers to a specific message (you can receive multiple answers to one message).
The `worker_id` field is used to target a specific worker.
- `Request`
- `Response`

An answer has the format `CommandResponse`, defined as follows:
They look like this, in protobuf:

```rust
pub struct CommandResponse {
pub id: String,
pub version: u8,
pub status: CommandStatus,
pub message: String
```protobuf
// A message received by Sōzu to change its state or query information
message Request {
oneof request_type {
// save Sōzu's parseable state as a file, with a path
string save_state = 1;
// load a state file, given its path
string load_state = 2;
/*
40 more requests
*/
}
}
```

When serialized to JSON it looks like this:

```json
{
"id": "ID_TEST",
"version": 0,
"status": "Ok",
"message": "done"
```protobuf
// Response to a request
message Response {
// wether the request was a success, a failure, or is processing
required ResponseStatus status = 1 [default = FAILURE];
// a success or error message
required string message = 2;
// response data, if any
optional ResponseContent content = 3;
}
```

An answer can have 3 possible status:
These are serialized in binary, NOT in plain text formats like JSON.

A response can have 3 possible status:

- `Ok`: the task was done
- `Error`: there was an unrecoverable error
- `Failure`: there was an unrecoverable error
- `Processing`: the task was started but may not finish right away

As an example, in a soft shutdown, the shutdown message is sent to all
Expand All @@ -74,251 +62,3 @@ new connections but keeps the active ones and exits when they are no longer
active. Once all connections are done, a worker will send an answer
with the same id and the `Ok` status.

## Message types

### Main process messages

#### Save state message

This message tells the proxy to dump the current proxy state (backends,
front domains, certificates, etc) as json, to a file. This file can be used later
to bootstrap the proxy. This message is not forwarded to workers.

The save state message is defined as follows:

```json
{
"id": "ID_TEST",
"version": 0,
"type": "SAVE_STATE",
"data": {
"path": "./config_dump.json"
}
}
```

If the specified path is relative, it will be calculated relative to the current
working directory of the proxy.

#### Load state message

```json
{
"id": "ID_TEST",
"version": 0,
"type": "LOAD_STATE",
"data": {
"path": "./config_dump.json"
}
}
```

#### Dump state message

This message will gather the same information as the save state message, but
will write it back to the unix socket.

The dump state message is defined like this:

```json
{
"id": "ID_TEST",
"version": 0,
"type": "DUMP_STATE"
}
```

#### Soft shutdown

```json
{
"id": "ID_TEST",
"version": 0,
"data": {
"type": "SOFT_STOP",
}
}
```

#### Hard shutdown

```json
{
"id": "ID_TEST",
"version": 0,
"data": {
"type": "HARD_STOP",
}
}
```

#### Status

```json
{
"id": "ID_TEST",
"version": 0,
"data": {
"type": "STATUS",
}
}
```

#### Binary upgrade

```json
{
"id": "ID_TEST",
"version": 0,
"data": {
"type": "UPGRADE_MAIN",
}
}
```

### Worker configuration messages

The proxy's configuration can be altered at runtime, without restarts,
by communication configuration changes through the socket.

The proxy attribute indicates the proxy's name, as defined in the
configuration file, in the section name (ie, `[proxies.HELLO]` creates
the `HELLO` proxy).

The data attribute will contain one of the proxy orders.

#### Adding a new HTTP front

```json
{
"id": "ID_TEST",
"version": 0,
"data": {
"type": "ADD_HTTP_FRONT",
"data": {
"cluster_id": "xxx",
"hostname": "example.com",
"path_begin": "/hello"
}
}
}
```

#### Adding a new HTTPS front

```json
{
"id": "ID_TEST",
"version": 0,
"data": {
"type": "ADD_HTTPS_FRONT",
"data": {
"cluster_id": "xxx",
"hostname": "example.com",
"path_begin": "/hello",
"fingerprint": "ab2618b674e15243fd02a5618c66509e4840ba60e7d64cebec84cdbfeceee0c5"
}
}
}
```

The fingerprint is the hexadecimal representation of the SHA256 hash of the certificate.

#### Adding a new backend server

```json
{
"id": "ID_ABCD",
"version": 0,
"data":{
"type": "ADD_BACKEND",
"data": {
"cluster_id": "xxx",
"ip_address": "127.0.0.1",
"port": 8080
}
}
}
```

#### Removing a HTTP frontend

```json
{
"id": "ID_ABCD",
"version": 0,
"data": {
"type": "REMOVE_HTTP_FRONT",
"cluster_id": "xxx",
"hostname": "yyy",
"path_begin": "xxx",
"port": 4242
}
}
```

#### Removing a HTTPS frontend

```json
{
"id": "ID_TEST",
"version": 0,
"data": {
"type": "REMOVE_HTTPS_FRONT",
"data": {
"cluster_id": "xxx",
"hostname": "yyy",
"path_begin": "xxx",
"fingerprint": "ab2618b674e15243fd02a5618c66509e4840ba60e7d64cebec84cdbfeceee0c5"
}
}
}
```

#### Removing a backend server

```json
{
"id": "ID_789",
"version": 0,
"data": {
"type": "REMOVE_BACKEND",
"data": {
"cluster_id": "xxx",
"ip_address": "127.0.0.1",
"port": 8080
}
}
}
```

#### Adding a new certificate

```json
{
"id": "ID_789",
"version": 0,
"data": {
"type": "ADD_CERTIFICATE",
"data": {
"certificate": "<PEM certificate>",
"certificate_chain": ["<PEM certificate>", "<PEM certificate>"],
"key": "<PEM private key>"
}
}
}
```

#### Removing a certificate

```json
{
"id": "ID_789",
"version": 0,
"data": {
"type": "REMOVE_CERTIFICATE",
"data": "ab2618b674e15243fd02a5618c66509e4840ba60e7d64cebec84cdbfeceee0c5"
}
}
```

2 changes: 2 additions & 0 deletions command/src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ use serde_json;

use crate::{buffer::growable::Buffer, ready::Ready};

/// A wrapper around unix socket using the mio crate.
/// Used in pairs to communicate, in a blocking or non-blocking way.
pub struct Channel<Tx, Rx> {
pub sock: MioUnixStream,
front_buf: Buffer,
Expand Down

0 comments on commit 78a6363

Please sign in to comment.