Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Lifecycle descriptor #20

Merged
merged 5 commits into from
Aug 15, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions text/0000-lifecycle-descriptor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Meta
[meta]: #meta
- Name: Lifecycle Descriptor
- Start Date: 08/05/2019
- CNB Pull Request: (leave blank)
- CNB Issue: (leave blank)
- Supersedes: N/A

# Summary
[summary]: #summary

The CNB specification defines platform/lifecycle and lifecycle/buildpack contracts. When we inevitable introduce a breaking change to either contract, we will need a way to indicate to tools like `pack` which version of each contract a given lifecycle implements. I propose adding a `lifecycle.toml` file to all lifecycles specifying these api versions. Eventually this file could also be used to provide additional metadata or indicate the availability of non-breaking additive features.

# Motivation
[motivation]: #motivation

We should do this so `pack` and other platforms can gracefully handle breaking changes in the platform/lifecycle and lifecycle/buildpack APIs. This file also provides a natural extension point for a lifecycle to provide useful metadata to users/platforms or advertise non-breaking features.

`pack` currently uses the lifecycle version to make inferences about the platform/lifecycle and lifecycle/buildpack API versions. However, this has drawbacks. We want `pack` to work with newer lifecycles when there are no breaking changes. By explicitly noting breaking changes in the lifecycle/platform contract we can make `pack` helpfully fail when it encounters an `api` version it isn't familiar with, but continue to work successfully w/ new lifecycles that don't introduce breaking changes.

# What it is
[what-it-is]: #what-it-is

Lifecycle can include a `lifecycle.toml` at it's root. Initially, the only supported fields will be the `api.platform`, `api.buildpack` and `lifecycle.version`.

```toml
[api]
platform = "1"
buildpack = "1"

[lifecycle]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder if a top-level lifecycle field would be necessary. I guess we do the same for buildpack.toml, so it's probably fine.

version = "v0.4.0"
ekcasey marked this conversation as resolved.
Show resolved Hide resolved
```

When `lifeycle.toml` exists but either of the `api.x` fields is omitted, `pack` will be assume that the lifecycle implements the latest API known to that version of `pack`. When `lifecycle.toml` is omitted, `pack` will initially warn users and assume the lifecycle implements the oldest known api version, for backwards compatibility. Eventually `pack` may require the presence of `lifecycle.toml`.

# How it Works
[how-it-works]: #how-it-works

When `pack create-builder` creates a builder. The lifecycle API versions will be added to the `io.buildpacks.builder.metadata` label.

```json
{
...
"lifecycle": {"version": "v0.4.0", "api": {"platform": "1", "buildpack": "1"}}
}
```

`pack` would ensure that the `api.buildpack` version matches the `api` version provided by all of the buildpacks that are added to the given builder.
ekcasey marked this conversation as resolved.
Show resolved Hide resolved

When `pack build` executes, it will check `lifecycle.api.platform` and it will either execute the correct commands for the given platform API, or fail if the platform API version is not supported. For example, if in the future we combine restorer/analyzer and cacher/exporter, then the platform API version of the next lifecycle release would be incremented. This will allow `pack` to know which binaries to execute with which flags.
ekcasey marked this conversation as resolved.
Show resolved Hide resolved

When `pack build` is run with the `--buildpack` flag, `pack` may use the buildpack api version from the builder metadata to determine whether the buildpack supplied with the `--buildpack` flag is compatible with the builder's lifecycle.

If `lifecycle.toml` specifies a lifecycle version and `builder.toml` also provides a lifecycle version, `pack` will ensure the versions match. If `builder.toml` does not specify a lifecycle version but `lifecycle.toml` does, the version from `lifecycle.toml` will be used.

# Drawbacks
[drawbacks]: #drawbacks

The concept of API version is a new number that could possibly confuse users. It doesn't map cleanly to an existing concept like spec version. We could document `api` version in the spec to mitigate this concern, but it still has the potential to introduce confusion by increasing the number of versions in the ecosystem.

# Alternatives
[alternatives]: #alternatives

- We can continue to use lifecycle version as a standin for lifecycle/platform and lifecycle/buildpack API versions (we can encode `pack` with knowledge of the behavior of specific lifecycle versions). However this will not allow us to decide whether it is safe to run specific commands or execute specific buildpacks when a lifecycle is newer than a given `pack` version.
- Instead of introducing new version numbers we can use spec versions to represent the same concepts