Things often run on other things or need other things to run. In Escape we can express this idea using providers and consumers. A provider provides a certain service or platform and a consumer makes use of it.
In practical terms Providers and Consumers are regular Escape packages. A provider defines what kind of interface it implements and usually has a few outputs:
name: quickstart/my-provider
version: 0.0.@
provides:
- introduction
outputs:
- id: credentials
default: "My platform specific configuration output"
A consumer defines what kind of provider it consumes, and will usually use the outputs to configure itself:
name: quickstart/my-consumer
version: 0.0.@
consumes:
- introduction
inputs:
- id: credentials
default: $introduction.outputs.credentials
When we try to escape run build
or escape run deploy
this package that
requires a provider we get an error:
$ escape run build --plan escape-consumer.yml
Build: Starting build.
Build: Error: Missing provider of type 'introduction'. This can be configured using the -p / --extra-provider flag.
Which is Escape complaining that it can’t find a provider of type ‘introduction’, because we haven’t deployed one. We can fix this by releasing and deploying the provider:
$ escape run release --plan escape-provider.yml
Release: Releasing quickstart/my-provider-v0.0.0
Build: ✔️ Completed build
Test: ✔️ Tests passed.
Destroy: ✔️ Destruction complete
Deploy: ✔️ Successfully deployed my-provider-v0.0.0 with deployment name quickstart/my-provider in the dev environment.
Smoke tests: ✔️ Smoke tests passed.
Destroy: ✔️ Destruction complete
Package: ✔️ Packaged quickstart/my-provider-v0.0.0 at /home/user/workspace/.escape/target/my-provider-v0.0.0.tgz
Push: ✔️ Push successful.
Release: ✔️ Successfully released quickstart/my-provider-v0.0.0
$ escape run deploy quickstart/my-provider-latest
Deploy: ✔️ Successfully deployed my-provider-v0.0.0 with deployment name quickstart/my-provider in the dev environment.
$ escape run build --plan escape-consumer.yml
Build: ✔️ Completed build
In a previous section we have seen dependencies. Dependencies are resolved at build time and provide a tight coupling between parents and their children. Providers and consumers provide a much looser coupling due to interface typing. This makes it possible to implement multiple implementations for a provider without having to change consumers; for example: we can provide a different provider for testing or local development purposes.
We can configure dependency inputs from the parent package and/or use their outputs. Consumers, on the other hand, are unable to configure the providers and solely have access to their outputs.
Another difference is that a provider can be consumed by multiple deployments in the same environment, whereas a dependency only works as part of a parent release. In practical terms this means that a platform or shared service (e.g. a Kubernetes cluster, a message queue, etc.) is usually much more appropriate to implement as a provider than a dependency.