docs/api-change-runbook.md
This runbook will cover triaging API changes and ways to implement them appropriately.
For the purposes of this document, there are 2 main categories for API changes, namely breaking and non-breaking.
A breaking change in the API is a change that makes the API incompatible with the previous version (backwards incompatible). In an effort to avoid a breaking change, we may take the route of deprecation and incrementing the minor version in an effort to preserve backwards compatibility, but breaking changes will always ultimately result in incrementing the major version. Here is a non-exhaustive list of such changes:
A change in the API is not a breaking change if the version resulting from it is compatible with the previous one (backwards compatible). The outcome of a non-breaking change should always include incrementing the minor version but must not lead to incrementing the major version by itself. Here is a non-exhaustive list of such changes:
API changes result in version increases. As Firecracker’s support policy is based on semantic versioning 2.0.0, we will look at API changes from this point of view.
Given a version number MAJOR.MINOR.PATCH, increment the: MAJOR version when you make incompatible API changes; MINOR version when you add functionality in a backwards compatible manner; PATCH version when you make backwards compatible bug fixes.
All deprecated endpoints are supported until at least the next major version release, where they may be removed.
We will go through multiple types of API changes and provide ways to ensure we don’t break our backwards compatibility promise to our customers. The list is split into categories of components changed.
In case the outlined solution for your case is not feasible (e.g. because of security concerns), break the glass and increment the major version.
As outlined in the diagram above, sometimes we have to deprecate endpoints partially or entirely. In this section we will go through different situations where we have to deprecate something and ways of avoiding common pitfalls when doing so.
Some paths in the flowchart above lead to deprecation. Based on the initial conditions, there are 2 major cases where we need to deprecate an endpoint:
/v2 to it.Make sure that any changes you make in the code are also reflected in the swagger specification.
Some tips:
required: true in the swagger definition. All other fields are optional.When marking:
warn! message stating that the user accessed a deprecated endpoint.deprecatedHttpApi metric.Deprecated header in the response.warn! message stating that the user used a
deprecated field.deprecatedHttpApi metric.warn_deprecated_parameters function where we log it and
increment the deprecatedCmdLineApi metric.When doing a major release, the API can have breaking changes. This is the only time where we can safely remove deprecated elements of the API. To remove a deprecated element of the API:
vmm or
mmds);api_server;In this guide we set out to remove the vsock_id field in PUTs on /vsock.
This was implemented in PR #2763 and we will go step by step through the
changes in order to understand the process of changing something in the
Firecracker API.
api_server/src/requests which is responsible for
parsing this request, which is parse_put_vsock in this case, and do the
following.
vmm_config struct which serde_json uses for
deserialization, in this case VsockDeviceConfig.Option with #[serde(default)] and
#[serde(skip_serializing_if = "Option::is_none")] so that we don’t break
existing implementations, but we follow the new, desired usage of the
endpoint.vsock_cfg.vsock_id.is_some()."PUT /vsock: vsock_id field is deprecated.")
and increment the deprecated HTTP API metric
(METRICS.deprecated_api.deprecated_http_api_calls.inc()).ParsedRequest where, if we marked the request as
deprecated, we append the deprecation message into its parsing_info
structure, in this case by calling
parsed_req.parsing_info().append_deprecation_message(msg).vsock_id field from the required parameter list in the Vsock definition
and adding a description to it stating that it is deprecated since the
current version.tests/integration_tests/functional/test_api.py
test to use the artifact model instead of the fixture one. If the test
already uses the artifact model, you can skip this step.min_version parameter of artifacts.firecrackers(). We do this in order
to ensure that, when we create patch releases on older branches, we test the
API with future binaries to enforce backwards compatibility. Disclaimer:
This test will fail when running with the binary artifact fetched from S3
until you update the binary there with your current build. You should only
do this once your PR has all necessary approves and this test is the last
thing keeping it from getting merged.Deprecation header is also present in the response by asserting
response.headers['deprecation']. We do not also check that the header is
not present when the field is not present because, in a future version, some
other field may be deprecated in the same request and would return the
header anyway, resulting in a fail in our test when it shouldn’t.