blob: 3e3eb4b0dd1f2f4035f22e369c7a351b36c2a2ec [file] [log] [blame] [view]
# Nebraska
[TOC]
## Introduction
Nebraska is a mock Omaha server built to facilitate testing of Auto Updates as
well as DLC (DownLoadable Content) update and install mechanisms in Chrome
OS. It is designed to be a lightweight, simple, and dependency-free standalone
server that can run on a host machine or DUT. Its single purpose is to respond
to update and install requests with Omaha-like responses based on some provided
metadata. All other related functions (i.e. generating payloads, transferring
files to a DUT, and serving the payloads themselves) must be handled elsewhere.
## System Requirements
The entire server is implemented in `nebraska.py` and it does not depend on
anything outside of the Python standard libraries (WARNING: and it would be
better to be kept that way), so this file on its own should be sufficient to run
the server on any device with Python 3.6 or newer.
WARNING: External dependencies should never be added to Nebraska!
## Payload Metadata
Nebraska handles requests based on the contents of install and update payload
directories. These directories should be populated with JSON files describing
the payloads you wish to make available. On receiving a request, Nebraska
searches the install or update payload directory as appropriate and formulates
a response based on metadata describing a matching payload if it can find one.
Nebraska expects at least one of these directories to be specified on startup.
### Metadata Format
The information in these files should be output by [paygen] when generating a
payload, and should have the following key-value pairs:
* `appid` - The appid of the app provided by the payload.
* `target_version` - App target version.
* `is_delta` - True iff the payload is a delta update.
* `source_version` - The source version if the payload is a delta update.
* `size` - Total size of the payload.
* `metadata_signature` - Metadata signature.
* `metadata_size` - Metadata size.
* `sha256_hex` - SHA256 of the payload.
* `version` - The version of this file format.
An example `sample.json`:
```json
{
"appid": "{F67500C1-C6D8-5287-E4EC-F9BBB4AEE5C5}",
"target_version": "10895.78.0",
"is_delta": true,
"source_version": "10000.0.0",
"size": 1069749941,
"metadata_signature": "Dr4RFXYgcfvFHV/0VRQs+SCQmz15Sk04LLEDswtvng8BqNbBXA7VvPUhpCgX5T/t7cwPxTUHJVtxIREuBZpyIQxJQFZATspaClelpKBwadQzj7dpfShLpcbdlfM8qbLjIbXfC2Vymw03Mwf38lm0Fm75SANSTW9S4arPDf3sy9YGuqesnEJXyT3ZSGyK+Xto79zlURUXCgmia6t7MaJE3ZbCdeF4EiEMPDsipqj9ggmKwiCdUl2+RxTznX/015XFiBhogLrx9RCPHTR8nLz0H9RcRhIvMd+8g4kHUZTDvjCvG5EZHpIKk8FK8z0zY/LWVr738evwuNNwyKIazkQBTA==",
"metadata_size": 50377,
"sha256_hex": "886fd274745b4fa8d1f253cff11242fac07a29522b1bb9e028ab1480353d3160",
"version": 2
}
```
## Payload URLs
Nebraska does not serve the payload itself. It only provides payload metadata
formatted in an Omaha-like response along with a URL where the payload can be
found. The base of this URL can be given at startup.
The URL can be the URL of some other server that serves payloads, or can be a
file URL that points to a directory on the DUT containing update and install
payloads. The complete URL for a payload is constructed by concatenating the
URL given in by Nebraska with the name of the payload, which is also given in
the response from Nebraska. Giving a file URL in place of server URL is possible
due to the fact that update engine relies on `libcurl` to handle the payload
transfer, which is able to handle local files in the same way it handles remote
URLs.
## Configure Nebraska at Runtime
Almost all our Auto Update tests require the nebraska be configured with
specific parameters/behaviors either at runtime or during start up. There are a
few ways to do this but most of them are going to be deprecated except one. So,
when adding a new behavior flag to nebraska, make sure the correct mechanism is
used. The current best supported method is through the `update_config` API. You
can send an HTTP `POST` request which has a JSON body. Look at [`Config`] class
for the list of available flags that can be used to change the Nebraska's
behavior. For example `config.json`:
```json
{
"critical_update": true,
"no_update": false,
"eol_date": 1234
}
```
To update the config do:
```bash
$ curl -X POST -d @config.json http://localhost:{port}/update_config
```
If using the nebraska.py directly as a library, you can call the `UpdateConfig`
function directly at anytime to configure its behavior.
Other methods of configuring the Nebraska's behavior is using either
program/startup flags like (not preferred):
```bash
$ nebraska.py --foo-flag
```
Or you can pass the configs as query string (not preferred either and being
deprecated):
```bash
$ curl http://localhost:{port}/update/?critical_update=True&no_update=False
```
## Running Nebraska on test images
`nebraska.py` is enabled as a system service that is started before UpdateEngine
is up. However, it only starts on test images and only if the config file (a
JSON file) for nebraska is created in `/usr/local/nebraska/config.json`. This
file is the same JSON data that is passed in an HTTP POST request discussed in
[this](#configure-nebraska-at-runtime) section.
It can also be manually started with `$ start nebraska` or stopped with `$ stop
nebraska` commands.
## Testing with Nebraska
In order to run local tests with nebraska (either on DUT or workstation), one
can first run nebraska first:
```bash
# <payloads dir> and <metadata dir> can be the same.
$ nebraska.py --update-metadata=/tmp/<metadata dir> --log-file=stdout --update-payloads-address file:///tmp/<payloads dir>
```
Then, configure nebraska with behaviors you want:
```bash
$ curl -X POST -d '{"critical_update": true}' http://localhost:$(cat /run/nebraska/port)/update_config
```
At this point the nebraska.py instance is ready for interaction. You can start
an update check with UpdateEngine such as:
```bash
$ update_engine_client --omaha_url="http://localhost:$(cat /run/nebraska/port)/update" --update
```
And look at the UpdateEngine logs at `/var/log/update_engine.log`.
## Known Issues
### Detecting Update/Install
In order to signal that a DLC should be installed rather than updated, update
engine includes a request for the platform app without a request for an update.
This allows Omaha to differentiate between an update operation where Chrome OS
and all DLCs will be updated to a strictly greater version, and an install
operation where one or more DLCs of the same version as the platform app will be
installed. We currently decide whether a request is for an update or install
based on whether exactly one other app (which we assume to be the platform app)
the request list does not have an associated update request.
[paygen]: https://chromium.googlesource.com/chromiumos/chromite/+/HEAD/lib/paygen/
[`Config`]: nebraska.py#842