Skip to content

Latest commit

 

History

History
 
 

apiserver

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

apiserver

Current version: 0.1.0

Background

This library provides an API server intended for use in an OS that is primarily accessible through the API. It's intended to be the primary way to read and modify OS settings, to update services based on those settings, and more generally to learn about and change the state of the system.

The server listens to HTTP requests on a Unix-domain socket. There is no built-in authentication - local access to the socket should be limited to processes and containers that should be able to configure the system. Remote access should only be allowed through an authenticated control channel such as SSH or SSM.

Design

API

We present an HTTP interface to configurable settings and other state. The interface is documented in OpenAPI format in openapi.yaml.

The Settings APIs are particularly important. You can GET settings from the /settings endpoint. You can also PATCH changes to the /settings endpoint. Settings are stored as a pending transaction until a commit API is called. Pending settings can be retrieved from /tx to see what will change.

Upon making a /tx/commit POST call, the pending transaction is made live. Upon making an /tx/apply POST call, an external settings applier tool is called to apply the changes to the system and restart services as necessary. There's also /tx/commit_and_apply to do both, which is the most common case.

If you don't specify a transaction, the "default" transaction is used, so you usually don't have to think about it. If you want to group changes into transactions yourself, you can add a tx parameter to the APIs mentioned above. For example, if you want the name "FOO", you can PATCH to /settings?tx=FOO and POST to /tx/commit_and_apply?tx=FOO.

Requests are directed by server::router. server::controller maps requests into our data model.

Model

The API is driven by a data model (similar to a schema) defined in Rust. (See the models directory for model definitions and more documentation.) All input is deserialized into model types, and all output is serialized from model types, so we can be more confident that data is in the format we expect.

The data model describes system settings, services using those settings, and configuration files used by those services. It also has a more general structure for metadata. Metadata entries can be stored for any data field in the model.

Data store

Data from the model is stored in a key/value data store. Keys are dotted strings like "settings.service.abc". This naturally implies some grouping and hierarchy of the data, corresponding to the model.

The current data store implementation maps keys to filesystem paths and stores the value in a file. Metadata about a data key is stored in a file at the data key path + "." + the metadata key. The default data store location is /var/lib/bottlerocket/datastore/current, and the filesystem format makes it fairly easy to inspect.

For more detail, see datastore.

Current limitations

  • Data store locking is coarse; read requests can happen in parallel, but a write request will block everything else.
  • There's no support for rolling back commits.
  • There are no metrics.

Example usage

You can start the API server from the apiserver directory with a command like:

cargo run -- --datastore-path /tmp/bottlerocket/data --socket-path /tmp/bottlerocket/api.sock --log-level debug

Then, from another shell, you can query or modify data. See ../../apiclient/README.md for client examples.

Colophon

This text was generated using cargo-readme, and includes the rustdoc from src/lib.rs.