syntax = "proto2";
package command;
// A message received by Sōzu to change its state or query information
message Request {
oneof request_type {
// This message tells Sōzu to dump the current proxy state (backends,
// front domains, certificates, etc) as a list of JSON-serialized Requests,
// separated by a 0 byte, to a file. This file can be used later
// to bootstrap the proxy. This message is not forwarded to workers.
// If the specified path is relative, it will be calculated relative to the current
// working directory of the proxy.
string save_state = 1;
// load a state file, given its path
string load_state = 2;
// list the workers and their status
ListWorkers list_workers = 4;
// list the frontends, filtered by protocol and/or domain
FrontendFilters list_frontends = 5;
// list all listeners
ListListeners list_listeners = 6;
// launch a new worker
// never implemented, the tag is unused and probably not needed
// we may still implement it later with no paramater
// the main process will automatically assign a new id to a new worker
string launch_worker = 7;
// upgrade the main process
UpgradeMain upgrade_main = 8;
// upgrade an existing worker, giving its id
uint32 upgrade_worker = 9;
// subscribe to proxy events
SubscribeEvents subscribe_events = 10;
// reload the configuration from the config file, or a new file
// CHECK: this used to be an option. None => use the config file, Some(string) => path_to_file
// make sure it works using "" and "path_to_file"
string reload_configuration = 11;
// give status of main process and all workers
Status status = 12;
// add a cluster
Cluster add_cluster = 13;
// remove a cluster giving its id
string remove_cluster = 14;
// add an HTTP frontend
RequestHttpFrontend add_http_frontend = 15;
// remove an HTTP frontend
RequestHttpFrontend remove_http_frontend = 16;
// add an HTTPS frontend
RequestHttpFrontend add_https_frontend = 17;
// remove an HTTPS frontend
RequestHttpFrontend remove_https_frontend = 18;
// add a certificate
AddCertificate add_certificate = 19;
// replace a certificate
ReplaceCertificate replace_certificate = 20;
// remove a certificate
RemoveCertificate remove_certificate = 21;
// add a TCP frontend
RequestTcpFrontend add_tcp_frontend = 22;
// remove a TCP frontend
RequestTcpFrontend remove_tcp_frontend = 23;
// add a backend
AddBackend add_backend = 24;
// remove a backend
RemoveBackend remove_backend = 25;
// add an HTTP listener
HttpListenerConfig add_http_listener = 26;
// add an HTTPS listener
HttpsListenerConfig add_https_listener = 27;
// add a TCP listener
TcpListenerConfig add_tcp_listener = 28;
// remove a listener
RemoveListener remove_listener = 29;
// activate a listener
ActivateListener activate_listener = 30;
// deactivate a listener
DeactivateListener deactivate_listener = 31;
// query a cluster by id
string query_cluster_by_id = 35;
// query clusters with a hostname and optional path
QueryClusterByDomain query_clusters_by_domain = 36;
// query clusters hashes
QueryClustersHashes query_clusters_hashes = 37;
// query metrics
QueryMetricsOptions query_metrics = 38;
// soft stop
SoftStop soft_stop = 39;
// hard stop
HardStop hard_stop = 40;
// enable, disable or clear the metrics
MetricsConfiguration configure_metrics = 41;
// Change the logging level
string Logging = 42;
// Return the listen sockets
ReturnListenSockets return_listen_sockets = 43;
// Get certificates from the state (rather than from the workers)
QueryCertificatesFilters query_certificates_from_the_state = 44;
// Get certificates from the workers (rather than from the state)
QueryCertificatesFilters query_certificates_from_workers = 45;
// query the state about how many requests of each type has been received
// since startup
CountRequests count_requests = 46;
}
}
message ListWorkers {}
message ListListeners {}
message UpgradeMain {}
message SubscribeEvents {}
message Status {}
message QueryClustersHashes {}
message SoftStop {}
message HardStop {}
message ReturnListenSockets {}
message CountRequests {}
// details of an HTTP listener
message HttpListenerConfig {
required SocketAddress address = 1;
optional SocketAddress public_address = 2;
required bool expect_proxy = 5 [default = false];
required string sticky_name = 6;
// client inactive time, in seconds
required uint32 front_timeout = 7 [default = 60];
// backend server inactive time, in seconds
required uint32 back_timeout = 8 [default = 30];
// time to connect to the backend, in seconds
required uint32 connect_timeout = 9 [default = 3];
// max time to send a complete request, in seconds
required uint32 request_timeout = 10 [default = 10];
// wether the listener is actively listening on its socket
required bool active = 11 [default = false];
optional CustomHttpAnswers http_answers = 12;
}
// details of an HTTPS listener
message HttpsListenerConfig {
required SocketAddress address = 1;
optional SocketAddress public_address = 2;
required bool expect_proxy = 5 [default = false];
required string sticky_name = 6;
// client inactive time, in seconds
required uint32 front_timeout = 7 [default = 60];
// backend server inactive time, in seconds
required uint32 back_timeout = 8 [default = 30];
// time to connect to the backend, in seconds
required uint32 connect_timeout = 9 [default = 3];
// max time to send a complete request, in seconds
required uint32 request_timeout = 10 [default = 10];
// wether the listener is actively listening on its socket
required bool active = 11 [default = false];
// TLS versions
repeated TlsVersion versions = 12;
repeated string cipher_list = 13;
repeated string cipher_suites = 14;
repeated string signature_algorithms = 15;
repeated string groups_list = 16;
optional string certificate = 17;
repeated string certificate_chain = 18;
optional string key = 19;
// Number of TLS 1.3 tickets to send to a client when establishing a connection.
// The tickets allow the client to resume a session. This protects the client
// agains session tracking. Defaults to 4.
required uint64 send_tls13_tickets = 20;
optional CustomHttpAnswers http_answers = 21;
}
// details of an TCP listener
message TcpListenerConfig {
required SocketAddress address = 1;
optional SocketAddress public_address = 2;
required bool expect_proxy = 3 [default = false];
// client inactive time, in seconds
required uint32 front_timeout = 4 [default = 60];
// backend server inactive time, in seconds
required uint32 back_timeout = 5 [default = 30];
// time to connect to the backend, in seconds
required uint32 connect_timeout = 6 [default = 3];
// wether the listener is actively listening on its socket
required bool active = 7 [default = false];
}
// custom HTTP answers, useful for 404, 503 pages
message CustomHttpAnswers {
// MovedPermanently
optional string answer_301 = 1;
// BadRequest
optional string answer_400 = 2;
// Unauthorized
optional string answer_401 = 3;
// NotFound
optional string answer_404 = 4;
// RequestTimeout
optional string answer_408 = 5;
// PayloadTooLarge
optional string answer_413 = 6;
// BadGateway
optional string answer_502 = 7;
// ServiceUnavailable
optional string answer_503 = 8;
// GatewayTimeout
optional string answer_504 = 9;
// InsufficientStorage
optional string answer_507 = 10;
}
message ActivateListener {
required SocketAddress address = 1;
required ListenerType proxy = 2;
required bool from_scm = 3;
}
message DeactivateListener {
required SocketAddress address = 1;
required ListenerType proxy = 2;
required bool to_scm = 3;
}
message RemoveListener {
required SocketAddress address = 1;
required ListenerType proxy = 2;
}
enum ListenerType {
HTTP = 0;
HTTPS = 1;
TCP = 2;
}
// All listeners, listed
message ListenersList {
// address -> http listener config
map<string, HttpListenerConfig> http_listeners = 1;
// address -> https listener config
map<string, HttpsListenerConfig> https_listeners = 2;
// address -> tcp listener config
map<string, TcpListenerConfig> tcp_listeners = 3;
}
// An HTTP or HTTPS frontend, as order to, or received from, Sōzu
message RequestHttpFrontend {
optional string cluster_id = 1;
required SocketAddress address = 2;
required string hostname = 3;
required PathRule path = 4;
optional string method = 5;
required RulePosition position = 6 [default = TREE];
// custom tags to identify the frontend in the access logs
map<string, string> tags = 7;
}
message RequestTcpFrontend {
required string cluster_id = 1;
// the socket address on which to listen for incoming traffic
required SocketAddress address = 2;
// custom tags to identify the frontend in the access logs
map<string, string> tags = 3;
}
// list the frontends, filtered by protocol and/or domain
message FrontendFilters {
required bool http = 1;
required bool https = 2;
required bool tcp = 3;
optional string domain = 4;
}
// A filter for the path of incoming requests
message PathRule {
// The kind of filter used for path rules
required PathRuleKind kind = 1;
// the value of the given prefix, regex or equal pathrule
required string value = 2;
}
// The kind of filter used for path rules
enum PathRuleKind {
// filters paths that start with a pattern, typically "/api"
PREFIX = 0;
// filters paths that match a regex pattern
REGEX = 1;
// filters paths that exactly match a pattern, no more, no less
EQUALS = 2;
}
// TODO: find a proper definition for this
enum RulePosition {
PRE = 0;
POST = 1;
TREE = 2;
}
// Add a new TLS certificate to an HTTPs listener
message AddCertificate {
required SocketAddress address = 1;
required CertificateAndKey certificate = 2;
// A unix timestamp. Overrides certificate expiration.
optional int64 expired_at = 3;
}
message RemoveCertificate {
required SocketAddress address = 1;
// a hex-encoded TLS fingerprint to identify the certificate to remove
required string fingerprint = 2;
}
message ReplaceCertificate {
required SocketAddress address = 1;
required CertificateAndKey new_certificate = 2;
// a hex-encoded TLS fingerprint to identify the old certificate
required string old_fingerprint = 3;
// A unix timestamp. Overrides certificate expiration.
optional int64 new_expired_at = 4;
}
message CertificateAndKey {
required string certificate = 1;
repeated string certificate_chain = 2;
required string key = 3;
repeated TlsVersion versions = 4;
// a list of domain names. Override certificate names
// if empty, the names of the certificate will be used
repeated string names = 5;
}
// Should be either a domain name or a fingerprint.
// These filter do not compound, use either one but not both.
// If none of them is specified, all certificates will be returned.
message QueryCertificatesFilters {
// a domain name to filter certificate results
optional string domain = 1;
// a hex-encoded fingerprint of the TLS certificate to find
optional string fingerprint = 2;
}
// domain name and fingerprint of a certificate
message CertificateSummary {
required string domain = 1;
// a hex-encoded TLS fingerprint
required string fingerprint = 2;
}
// Used by workers to reply to some certificate queries
message ListOfCertificatesByAddress {
repeated CertificatesByAddress certificates = 1;
}
// Summaries of certificates for a given address
message CertificatesByAddress {
required SocketAddress address = 1;
repeated CertificateSummary certificate_summaries = 2;
}
// to reply to several certificate queries
message CertificatesWithFingerprints {
// a map of fingerprint -> certificate_and_key
map<string, CertificateAndKey> certs = 1;
}
enum TlsVersion {
SSL_V2 = 0;
SSL_V3 = 1;
TLS_V1_0 = 2;
TLS_V1_1 = 3;
TLS_V1_2 = 4;
TLS_V1_3 = 5;
}
// A cluster is what binds a frontend to backends with routing rules
message Cluster {
required string cluster_id = 1;
// wether a connection from a client shall be always redirected to the same backend
required bool sticky_session = 2;
required bool https_redirect = 3;
optional ProxyProtocolConfig proxy_protocol = 4;
required LoadBalancingAlgorithms load_balancing = 5 [default = ROUND_ROBIN];
optional string answer_503 = 6;
optional LoadMetric load_metric = 7;
}
enum LoadBalancingAlgorithms {
ROUND_ROBIN = 0;
RANDOM = 1;
LEAST_LOADED = 2;
POWER_OF_TWO = 3;
}
enum ProxyProtocolConfig {
EXPECT_HEADER = 0;
SEND_HEADER = 1;
RELAY_HEADER = 2;
}
// how sozu measures which backend is less loaded
enum LoadMetric {
// number of TCP connections
CONNECTIONS = 0;
// number of active HTTP requests
REQUESTS = 1;
// time to connect to the backend, weighted by the number of active connections (peak EWMA)
CONNECTION_TIME = 2;
}
// add a backend
message AddBackend {
required string cluster_id = 1;
required string backend_id = 2;
// the socket address of the backend
required SocketAddress address = 3;
optional string sticky_id = 4;
optional LoadBalancingParams load_balancing_parameters = 5;
optional bool backup = 6;
}
// remove an existing backend
message RemoveBackend {
required string cluster_id = 1;
required string backend_id = 2;
// the socket address of the backend
required SocketAddress address = 3 ;
}
message LoadBalancingParams {
required int32 weight = 1;
}
message QueryClusterByDomain {
required string hostname = 1;
optional string path = 2;
}
// Options when querying metrics
message QueryMetricsOptions {
// query a list of available metrics
required bool list = 1;
// query metrics for these clusters
repeated string cluster_ids = 2;
// query metrics for these backends
repeated string backend_ids = 3;
// query only these metrics
repeated string metric_names = 4;
// query only worker and main process metrics (no cluster metrics)
required bool no_clusters = 5;
// display metrics of each worker, without flattening (takes more space)
required bool workers = 6;
}
// options to configure metrics collection
enum MetricsConfiguration {
// enable metrics collection
ENABLED = 0;
// disable metrics collection
DISABLED = 1;
// wipe the metrics memory
CLEAR = 2;
}
// 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;
}
// content of a response
message ResponseContent {
oneof content_type {
// a list of workers, with ids, pids, statuses
WorkerInfos workers = 1;
// aggregated metrics of main process and workers
AggregatedMetrics metrics = 2;
// a collection of worker responses to the same request
WorkerResponses worker_responses = 3;
// a proxy event
Event event = 4;
// a filtered list of frontend
ListedFrontends frontend_list = 5;
// all listeners
ListenersList listeners_list = 6;
// contains proxy & cluster metrics
WorkerMetrics worker_metrics = 7;
// Lists of metrics that are available
AvailableMetrics available_metrics = 8;
// a list of cluster informations
ClusterInformations clusters = 9;
// collection of hashes of cluster information,
ClusterHashes cluster_hashes = 10;
// a list of certificates summaries, grouped by socket address
ListOfCertificatesByAddress certificates_by_address = 11;
// a map of complete certificates using fingerprints as key
CertificatesWithFingerprints certificates_with_fingerprints = 12;
// a census of the types of requests received since startup,
RequestCounts request_counts = 13;
}
}
// a map of worker_id -> ResponseContent
message WorkerResponses {
map<string, ResponseContent> map = 1;
}
// lists of frontends present in the state
message ListedFrontends {
repeated RequestHttpFrontend http_frontends = 1;
repeated RequestHttpFrontend https_frontends = 2;
repeated RequestTcpFrontend tcp_frontends = 3;
}
message ClusterInformations {
repeated ClusterInformation vec = 1;
}
// Information about a given cluster
// Contains types usually used in requests, because they are readily available in protobuf
message ClusterInformation {
optional Cluster configuration = 1;
repeated RequestHttpFrontend http_frontends = 2;
repeated RequestHttpFrontend https_frontends = 3;
repeated RequestTcpFrontend tcp_frontends = 4;
repeated AddBackend backends = 5;
}
// an event produced by a worker to notify about backends status
message Event {
required EventKind kind = 1;
optional string cluster_id = 2;
optional string backend_id = 3;
optional SocketAddress address = 4;
}
enum EventKind {
BACKEND_DOWN = 0;
BACKEND_UP = 1;
NO_AVAILABLE_BACKENDS = 2;
REMOVED_BACKEND_HAS_NO_CONNECTIONS = 3;
}
message ClusterHashes {
// cluster id -> hash of cluster information
map<string, uint64> map = 1;
}
enum ResponseStatus {
OK = 0;
PROCESSING = 1;
FAILURE = 2;
}
// A list of worker infos
message WorkerInfos {
repeated WorkerInfo vec = 1;
}
// Information about a worker with id, pid, runstate
message WorkerInfo {
required uint32 id = 1;
required int32 pid = 2;
required RunState run_state = 3;
}
// Runstate of a worker
enum RunState {
RUNNING = 0;
STOPPING = 1;
STOPPED = 2;
NOT_ANSWERING = 3;
}
// lists of available metrics in a worker, or in the main process (in which case there are no cluster metrics)
message AvailableMetrics {
repeated string proxy_metrics = 1;
repeated string cluster_metrics = 2;
}
// Aggregated metrics of main process & workers
message AggregatedMetrics {
// metrics about the main process.
// metric_name -> metric_value
map<string, FilteredMetrics> main = 1;
// details of worker metrics, with clusters and backends.
// worker_id -> worker_metrics
map<string, WorkerMetrics> workers = 2;
// if present, contains metrics of clusters and their backends, merged across all workers.
// cluster_id -> cluster_metrics
map<string, ClusterMetrics> clusters = 3;
// if present, proxying metrics, merged accross all workers.
// metric_name -> metric_value
map<string, FilteredMetrics> proxying = 4;
}
// All metrics of a worker: proxy and clusters
// Populated by Options so partial results can be sent
message WorkerMetrics {
// Metrics of the worker process, key -> value
map<string, FilteredMetrics> proxy = 1;
// cluster_id -> cluster_metrics
map<string, ClusterMetrics> clusters = 2;
}
// the metrics of a given cluster, with several backends
message ClusterMetrics {
// metric name -> metric value
map<string, FilteredMetrics> cluster = 1;
// list of backends with their metrics
repeated BackendMetrics backends = 2;
}
message BackendMetrics {
required string backend_id = 1;
map<string, FilteredMetrics> metrics = 2;
}
// A metric, in a "filtered" format, which means: sendable to outside programs.
message FilteredMetrics {
oneof inner {
// increases or decrease depending on the state
uint64 gauge = 1;
// increases only
int64 count = 2;
// milliseconds
uint64 time = 3;
Percentiles percentiles = 4;
FilteredTimeSerie time_serie = 5;
FilteredHistogram histogram = 6;
}
}
message FilteredTimeSerie {
required uint32 last_second = 1;
repeated uint32 last_minute = 2;
repeated uint32 last_hour = 3;
}
message Percentiles {
required uint64 samples = 1;
required uint64 p_50 = 2;
required uint64 p_90 = 3;
required uint64 p_99 = 4;
required uint64 p_99_9 = 5;
required uint64 p_99_99 = 6;
required uint64 p_99_999 = 7;
required uint64 p_100 = 8;
required uint64 sum = 9;
}
// a histogram meant to be translated to prometheus
message FilteredHistogram {
required uint64 sum = 1;
required uint64 count = 2;
repeated Bucket buckets = 3;
}
// a prometheus histogram bucket
message Bucket {
required uint64 count = 1;
// upper range of the bucket (le = less or equal)
required uint64 le = 2;
}
message RequestCounts {
map<string, int32> map = 1;
}
// matches std::net::SocketAddr in the Rust library
// beware that the ports are expressed with uint32 here,
// but they should NOT exceed uint16 value
message SocketAddress {
required IpAddress ip = 1;
required uint32 port = 2;
}
message IpAddress {
oneof inner {
fixed32 v4 = 1;
Uint128 v6 = 2;
}
}
// used to represent the 128 bits of an IPv6 address
message Uint128 {
// higher value, first 8 bytes of the ip
required uint64 low = 1;
// lower value, last 8 bytes of the ip
required uint64 high = 2;
}
// This is sent only from Sōzu to Sōzu
message WorkerRequest {
required string id = 1;
required Request content = 2;
}
// A response as sent by a worker
message WorkerResponse {
required string id = 1;
required ResponseStatus status = 2;
// an associated message to detail failure, success or processing
required string message = 3;
optional ResponseContent content = 4;
}
// intended to workers
message ServerMetricsConfig {
required string address = 1;
required bool tagged_metrics = 2;
optional string prefix = 3;
}
// Used by a worker to start its server loop.
// The defaults should match those of the config module
message ServerConfig {
required uint64 max_connections = 1 [default = 10000];
required uint32 front_timeout = 2 [default = 60];
required uint32 back_timeout = 3 [default = 30];
required uint32 connect_timeout = 4 [default = 3];
required uint32 zombie_check_interval = 5 [default = 1800];
required uint32 accept_queue_timeout = 6 [default = 60];
required uint64 min_buffers = 7 [default = 1];
required uint64 max_buffers = 8 [default = 1000];
required uint64 buffer_size = 9 [default = 16393];
required string log_level = 10 [default = "info"];
required string log_target = 11 [default = "stdout"];
optional string access_logs_target = 12;
required uint64 command_buffer_size = 13 [default = 1000000];
required uint64 max_command_buffer_size = 14 [default = 2000000];
optional ServerMetricsConfig metrics = 15;
required ProtobufAccessLogFormat access_log_format = 16;
required bool log_colored = 17;
}
enum ProtobufAccessLogFormat {
Ascii = 1;
Protobuf = 2;
}
// Addresses of listeners, passed to new workers
message ListenersCount {
// socket addresses of HTTP listeners
repeated string http = 1;
// socket addresses of HTTPS listeners
repeated string tls = 2;
// socket addresses of TCP listeners
repeated string tcp = 3;
}
// the Sōzu state, passed to a new worker.
// Consists in a collection of worker requests
message InitialState {
repeated WorkerRequest requests = 1;
}
message OpenTelemetry {
required string trace_id = 1;
required string span_id = 2;
optional string parent_span_id = 3;
}
// An access log, meant to be passed to another agent
message ProtobufAccessLog {
// error message if any
optional string message = 1;
// LogContext = request_id + cluster_id + backend_id
required Uint128 request_id = 2;
// id of the cluster (set of frontend, backend, routing rules)
optional string cluster_id = 3;
// id of the backend (the server to which the traffic is redirected)
optional string backend_id = 4;
// ip and port of the client
optional SocketAddress session_address = 5;
// socket address of the backend server
optional SocketAddress backend_address = 6;
// the protocol, with SSL/TLS version, for instance "HTTPS-TLS1.1"
required string protocol = 7;
// TCP or HTTP endpoint (method, path, context...)
required ProtobufEndpoint endpoint = 8;
// round trip time for the client (microseconds)
optional uint64 client_rtt = 9;
// round trip time for the backend (microseconds)
optional uint64 server_rtt = 10;
// time spent on a session (microseconds)
required uint64 service_time = 13;
// number of bytes received from the client
required uint64 bytes_in = 14;
// number of bytes written to the client
required uint64 bytes_out = 15;
// value of the User-Agent header, if any
optional string user_agent = 16;
// custom tags as key-values, for instance owner_id: MyOrganisation
map<string, string> tags = 17;
// short description of which process sends the log, for instance: "WRK-02"
required string tag = 18;
// POSIX timestamp, nanoseconds
required Uint128 time = 19;
// Entire time between first byte received and last byte of the response.
// If a request ends abruptly before the last byte is transmitted,
// the `request_time` produced is the time elapsed since the first byte received.
optional uint64 request_time = 20;
// time for the backend to respond (microseconds)
optional uint64 response_time = 21;
// OpenTelemetry tracing information
optional OpenTelemetry otel = 22;
}
message ProtobufEndpoint {
oneof inner {
HttpEndpoint http = 1;
TcpEndpoint tcp = 2;
}
}
message HttpEndpoint {
optional string method = 1;
optional string authority = 2;
optional string path = 3;
// warning: this should be a u16 but protobuf only has uint32.
// Make sure the value never exceeds u16 bounds.
optional uint32 status = 4;
optional string reason = 5;
}
message TcpEndpoint {}