Skip to content

Commit 6661670

Browse files
feat: add SIP for supporting Spin plugins
Signed-off-by: Kate Goldenring <kate.goldenring@fermyon.com>
1 parent 232567f commit 6661670

File tree

1 file changed

+233
-0
lines changed

1 file changed

+233
-0
lines changed

docs/content/sips/006-spin-plugins.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
title = "SIP 006 - Spin Plugins"
2+
template = "main"
3+
date = "2022-08-23T14:53:30Z"
4+
---
5+
6+
Summary: A Spin CLI command that will enable plugging in additional functionality and subcommands to Spin.
7+
8+
Owners: karthik.ganeshram@fermyon.com and kate.goldenring@fermyon.com
9+
10+
Created: August 23, 2022
11+
12+
## Background
13+
14+
The realm of possibilities with Spin continues to grow. However, not every new feature is desired by every user. Instead of needing to modify the Spin codebase, contributors should be able to plug in new functionality or subcommands to Spin via the Spin CLI. This makes Spin easily extensible while keeping it lightweight.
15+
16+
## Proposal
17+
18+
Create a `spin plugin` command, which can be used to install a subcommand that can later be invoked via the Spin CLI.
19+
20+
For the initial proposal, all Spin plugins are expected to be packaged as an executable that will be executed by Spin when the plugin subcommand is invoked.
21+
22+
A [`spin-plugins` repository](#centralized-plugin-manifest-repository) will act as an inventory of available plugins, made by both Spin maintainers and the community. In the repository, a plugin will be defined by a [JSON Spin plugin manifest](#spin-plugin-manifest). Spin will pull down this manifest during installation, which will instruct it on where to find the plugin binary, version, platform compatibility, and more.
23+
24+
### Usage
25+
26+
The `spin plugin` command will have three sub-commands.
27+
28+
```bash
29+
Commands for working with Spin plugins
30+
31+
USAGE:
32+
spin plugin <SUBCOMMAND>
33+
34+
SUBCOMMANDS:
35+
install Install plugin as described by a remote or local plugin manifest
36+
uninstall Uninstall a plugin
37+
update Update one or all plugins to the latest or specified version
38+
```
39+
40+
**`spin plugin install`**
41+
42+
The `spin plugin install` subcommand installs a plugin named `$name`. By default, it will look for a plugin manifest named `$name.json` in the `spin-plugin` repository; however, it can be directed to use a local manifest or one at a different remote location using the `--file` or `--url` flag, respectively.
43+
44+
```bash
45+
Install a Spin plugin using a plugin manifest file.
46+
By default, looks for the plugin manifest named <name>.json
47+
in the Spin plugins repository https://github.com/fermyon/spin-plugins
48+
49+
USAGE:
50+
spin plugin install <name>
51+
52+
OPTIONS:
53+
-f, --file Path to local plugin manifest
54+
-u, --url Address of remote plugin manifest
55+
-v, --version Desired version to update plugin to. Defaults to latest.
56+
-s, --skip-version-compat-check Instructs Spin to install the plugin even
57+
if its manifest specifies that it is
58+
incompatible with the current version of Spin
59+
```
60+
61+
If the manifest is found, Spin will check that the plugin is compatible with the current OS, platform, and version of Spin. If so, before installing the plugin, Spin will prompt the user as to whether to trust the source. For example, the following prompt would be displayed for a plugin named `deploy` with an Apache 2 license and hosted at [`https://github.com/fermyon/spin-plugin-deploy/releases/download/v0.1.0/spin-plugin-deploy-v0.1.0-macos-aarch64.tar.gz`](https://github.com/fermyon/spin-plugin-deploy/releases/download/v0.1.0/spin-plugin-deploy-v0.1.0-macos-aarch64.tar.gz):
62+
63+
```bash
64+
Installing plugin deploy with license Apache 2.0 from https://github.com/fermyon/spin-plugin-deploy/releases/download/v0.1.0/spin-plugin-deploy-v0.1.0-macos-aarch64.tar.gz
65+
For more information, reference the plugin metadata at `https://github.com/fermyon/spin-plugins/plugin-manifests/deploy.json`.
66+
Are you sure you want to proceed? ('yes'/'no') (default: no)
67+
```
68+
69+
The plugin will only be installed if a user enters `yes`. Otherwise, the command exits.
70+
71+
Spin will reference the plugin manifest in order to fetch the plugin binary and install it into the user’s local data directory under a Spin-managed `plugins` subdirectory. The plugin manifest will be stored within a `manifests` subdirectory.
72+
73+
After installing a plugin, it can be executed directly from the Spin CLI. For example, a plugin named `$name` would be executed by running `spin $name <args>`. Any additional arguments supplied will be passed when executing the associated binary.
74+
75+
76+
77+
**`spin plugin uninstall`**
78+
79+
The `spin plugin uninstall` command uninstalls a plugin named `$name`.
80+
81+
```bash
82+
Uninstall a Spin plugin.
83+
84+
USAGE:
85+
spin plugin uninstall <name>
86+
```
87+
88+
**`spin plugin update`**
89+
90+
The `spin plugin update` command updates one or all plugins. If updating a single plugin, the desired version can be specified. By default, plugins are updated to the latest version in the plugins repository. As with `spin plugin install`, the local path or remote addresses to a plugin manifest can be specified.
91+
92+
```bash
93+
Update one or all installed Spin plugins.
94+
95+
USAGE:
96+
spin plugin update [OPTIONS]
97+
98+
OPTIONS:
99+
-a, --all Update all installed plugins (cannot be used with any other option)
100+
-p, --plugin Name of plugin
101+
-v, --version Desired version to update the plugin to. Defaults to latest.
102+
-f, --file Path to local manifest (mutex with `-u`)
103+
-u, --url Address of remote manifest (mutex with `-f`)
104+
-d, --downgrade Enables downgrading a plugin to an older specified version.
105+
-s, --skip-version-compat-check Instructs Spin to install the plugin even
106+
if its manifest specifies that it is
107+
incompatible with the current version of Spin
108+
```
109+
110+
The update will fail if the latest or user-specified version of the plugin is not [compatible with the current version of Spin](#plugin-compatibility). This failure can be overridden with `--skip-version-compat-check`.
111+
112+
### Spin Plugin Manifest
113+
114+
A Spin plugin is defined by a Spin Plugin Manifest which is a JSON file that conforms with the following [JSON Schema](https://json-schema.org/):
115+
116+
```json
117+
{
118+
"$schema": "https://json-schema.org/draft/2019-09/schema",
119+
"$id": "https://github.com/fermyon/spin-plugins/json-schema/spin-plugin-manifest-schema-0.1.json",
120+
"type": "object",
121+
"title": "spin-plugin-manifest-schema-0.1",
122+
"required": [
123+
"name",
124+
"description",
125+
"version",
126+
"spinCompatibility",
127+
"license",
128+
"packages"
129+
],
130+
"properties": {
131+
"name": {
132+
"type": "string"
133+
},
134+
"description": {
135+
"type": "string"
136+
},
137+
"homepage": {
138+
"type": "string"
139+
},
140+
"version": {
141+
"type": "string"
142+
},
143+
"spinCompatibility": {
144+
"type": "string",
145+
"pattern": "^[><~^*]?[=]?v?(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$"
146+
},
147+
"license": {
148+
"type": "string"
149+
},
150+
"packages": {
151+
"type": "array",
152+
"minItems": 1,
153+
"items": {
154+
"type": "object",
155+
"required": [
156+
"os",
157+
"arch",
158+
"url",
159+
"sha256"
160+
],
161+
"properties": {
162+
"os": {
163+
"type": "string",
164+
"enum": [
165+
"linux",
166+
"osx",
167+
"windows"
168+
]
169+
},
170+
"arch": {
171+
"type": "string",
172+
"enum": [
173+
"amd64",
174+
"aarch64"
175+
]
176+
},
177+
"url": {
178+
"type": "string"
179+
},
180+
"sha256": {
181+
"type": "string"
182+
}
183+
},
184+
"additionalProperties": false
185+
}
186+
}
187+
},
188+
"additionalProperties": false
189+
}
190+
```
191+
192+
A plugin manifest defines a plugin’s name, version, license, homepage (i.e. GitHub repo), compatible Spin version, and gives a short description of the plugin. It also points to the plugin source for various operating systems and platforms.
193+
194+
The `name` and `spinCompatibility` fields have specific format conventions.
195+
196+
#### Spin Plugin Naming Conventions
197+
198+
The following naming conventions are to be followed for plugins where `$name` is the name of the plugin.
199+
200+
- The `name` field in the plugin manifest must be `$name`.
201+
- Even if the majority of plugins live within the Spin plugins repository, there is a need to distinguish between plugins that are maintained by Spin vs community plugins. They will be distinguished via the plugin name inside the manifest. The name of community plugins must not have "spin" as a prefix, while plugins maintained by Spin should contain a prefix of `spin-`.
202+
- Manifests for older versions of the plugin can be retained in the Spin Plugins repository named `$name@$version.json` where `$version` is the value of the `version` field of the manifest. These specific versions can be installed using the `--version` flag.
203+
- The binary of the plugin must be named `$name`
204+
- The latest plugin manifest file must be named `$name.json`
205+
- The license for the plugin must be named `$name.license`
206+
207+
#### Plugin Compatibility
208+
209+
Spin plugins must specify compatible versions of Spin in the `spinCompatibility` field of the manifest. The field is expected to be a [comparison operator](https://docs.rs/semver/1.0.13/semver/enum.Op.html) (`=, >, >=, <, <=, ~, ^, *`) along with the compatible version of Spin. The JSON schema validates that the `spinCompatibility` field is a string that matches the following regular expression: `^[><~^*]?[=]?v?(0|[1-9]\d*)(\.(0|[1-9]\d*))?(\.(0|[1-9]\d*))?(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$`.
210+
For example, specifying `=0.4` means that the plugin is compatible with versions equivalent to `>=0.4.0, <0.5.0`.
211+
212+
Spin will use the [`semver`](https://docs.rs/semver/1.0.13/semver/struct.VersionReq.html) crate that inspired this syntax to verify that the plugin works on the current version of Spin. If it does not, it will fail to install the plugin and log a message explaining the version mismatch. An `--skip-version-compat-check` flag can be added to a plugin installation to ignore this error.
213+
214+
#### Centralized Plugin Manifest Repository
215+
216+
- A new GitHub repository https://github.com/fermyon/spin-plugins will act as the index for all the Spin plugin manifests. Having a centralized location for plugin manifests enables future support of a `spin plugin search` subcommand that allows users to search for plugins via the Spin CLI.
217+
- Creators of new plugins can submit PRs to add a plugin manifest to the repository.
218+
- Plugin creators are required to test Spin compatibility with their plugin and update the `spinCompatability` field of the manifest over time accordingly.
219+
- Plugin manifests can be hosted elsewhere and installed via the `--file` or `--url` fields of `spin plugin install`.
220+
221+
## Future design considerations
222+
223+
### Larger scope for Spin Plugins
224+
225+
The concept of Spin plugins is to allow both new subcommands and functionality to be added to Spin. This SIP focuses on the former, enabling users to both install and execute subcommands from the Spin CLI; however, there are cases where it may be useful to install a new Spin feature that is executed by Spin rather than the user. An example of this is Spin triggers. A user may wish to [extend Spin to support a timer trigger](https://spin.fermyon.dev/extending-and-embedding/) that executes components at a configured time interval. Instead of having to understand, modify, and grow the spin codebase, a user could package the trigger as a plugin. After installing the trigger via `spin plugin install`. Spin could invoke it when a Spin manifest references the trigger.
226+
227+
While for now plugins are assumed to be executables, in the future, support for plugging in WebAssembly modules may be desirable.
228+
229+
### Clean versioning and Spin plugin compatibility
230+
231+
The proposed method of using version strings to declare compatibility between a plugin and Spin has several drawbacks. Firstly, this requires plugin creators to stay involved with their contribution, regularly testing and updating the compatibility of their plugin with Spin. One way to make this more hands-off would be to encourage plugin creators to also contribute an integration test. For each new spin release, a workflow in the plugins repository can automatically run these integration tests and bump compatibility versioning on success. This is a strategy taken by [MicroK8s](https://microk8s.io/docs/addons) for its core and community add-ons.
232+
233+
Another issue with using versioning to check for compatibility with Spin is that canary releases of Spin have the same version as the latest release. This means that if a user is using main or canary Spin, when Spin checks its version before installing a plugin, it may incorrectly assume compatibility even though its feature set is beyond that of the latest stable release. Spin templates currently have a workaround for detecting and handling this inconsistency. A more ideal way of assessing compatibility would be via capability checking wherein a plugin could declare what set of features it is compatible with and Spin would assert if those exist. For example, a plugin could be compatible with only a specific version of Spin manifests or only have support for WAGI. While a system like this would be full-proof, it would require deep design. As plugins are developed, a better understanding will come of what capabilities plugins need from Spin. From this, compatibility via compatibilities system could be designed.

0 commit comments

Comments
 (0)