Mixin Commands
These are the commands that a mixin can implement to work with porter. Some must be implemented, or porter will refuse to load the mixin, while others are just recommended so that your mixin has a good user experience.
Our skeleton mixin template demonstrates how to implement each command, providing a working implementation, tests, and a Makefile to manage common tasks. If you are writing a mixin in Go, we strongly recommend starting from the template.
Required Commands
Optional Commands
build
The build command (required) is called on the local machine during the porter build
command. Any mixin configuration and all usages of the mixin are passed
on stdin. The mixin should return lines for the Dockerfile on stdout.
Example:
stdin
config:
extensions:
- iot
actions:
install:
- az:
arguments:
- login
description: Login
uninstall: []
upgrade: []
stdout
RUN apt-get update && apt-get install -y apt-transport-https lsb-release gnupg curl
RUN curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.asc.gpg
RUN echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/azure-cli.list
RUN apt-get update && apt-get install -y azure-cli
RUN az extension add --name azure-cli-iot-ext
schema
The schema command (required) is used in multiple porter commands, such as
porter schema
, porter build
and porter run
. The mixin should return a json
schema for the parts of the Porter manifest it is responsible for. Porter
combines each of the mixin’s schema documents into a single json schema document
and uses that to validate the Porter manifest, and other tools, like VS Code,
use the document to provide autocomplete when editing the manifest.
The output of your schema command must be a json schema document. The schema should describe which fields are supported by your mixin, and their descriptions, type and optionality. Good examples of a mixin schema are the exec mixin schema and helm mixin schema.
Your mixin is responsible for defining the allowed schema for each action because for some mixins the schema is different per action. Porter will handle parsing through your schema and piecing it all together into a coherent schema for porter.yaml. You just need to worry about what your schema should look like for your portion of the manifest related to the mixin:
Below is an example of the potion of the Porter manifest that will be used with the exec mixin schema.
install:
- exec:
description: Some description
command: ./helpers.sh
The mixin skeleton template provides an example implementation, unit tests and an integration test to validate your implementation. After you have customized your schema command, you can test it out with the Porter extension for Visual Studio Code. Install your updated mixin, and then open a porter.yaml file with VS Code. You should get autocomplete and hover documentation for your mixin’s fields.
A great resource for developing and testing your schema is the JSON Schema Validator and YAML to JSON converter.
There are a few rules to follow when authoring your mixin’s json schema as there are known bugs in the libraries used by Porter and VS Code that they workaround:
-
Do not chain together references. A reference should only link to another type, not immediately to another
$ref
. -
Only use relative references, such as
#/definitions/installStep
. -
Do not use
$id
’s. Do not use references to an internal$id
. -
Every supported action must be defined with a root level property named after the action, e.g. “install”, and a definition named
<action>Step
, e.g. “installStep”. Below is an example from the exec mixin for the install action:{ "definitions": { "installStep": { "type": "object", "properties": { "exec": { "type": "object", "properties": { "description": { "type": "string", "minLength": 1 }, "command": { "type": "string" }, "arguments": { "type": "array", "items": { "type": "string", "minItems": 1 } } }, "additionalProperties": false, "required": [ "description", "command" ] } }, "additionalProperties": false, "required": [ "exec" ] } }, "type": "object", "properties": { "install": { "type": "array", "items": { "$ref": "#/definitions/installStep" } } }, "additionalProperties": false }
-
Custom action support is signaled by having a property named “.*” with items of type
invokeStep
.
NOTE: porter handles rewriting the references when it merges the json *schemas. So write your references relative to your mixin’s schema document, and *porter will take care of adjusting it when the schema is merged.
install
The install command (required) is called from inside the invocation image during
the porter run
command. The current step from the manifest is passed on stdin.
The mixin should write any output values to their own files in the
/cnab/app/porter/outputs/
directory.
Example:
stdin
install:
- helm3:
description: "Install MySQL"
name: porter-ci-mysql
chart: bitnami/mysql
outputs:
- name: mysql-root-password
secret: "{{ bundle.parameters.mysql-name }}"
key: mysql-root-password
- name: mysql-password
secret: "{{ bundle.parameters.mysql-name }}"
key: mysql-password
/cnab/app/porter/outputs/mysql-root-password
topsecret
/cnab/app/porter/outputs/mysql-password
alsotopsecret
upgrade
The upgrade command (required) is called from inside the invocation image during
the porter run
command. The current step from the manifest is passed on stdin.
The mixin should write any output values to their own files in the
/cnab/app/porter/outputs/
directory.
Example:
stdin
parameters:
- name: mysql-password
type: string
...
upgrade:
- helm3:
description: "Upgrade MySQL"
name: porter-ci-mysql
replace: true
set:
mysqlPassword: "{{ bundle.parameters.mysql-password }}"
/cnab/app/porter/outputs/mysql-root-password
topsecret
/cnab/app/porter/outputs/mysql-password
updatedtopsecret
uninstall
The uninstall command (required) is called from inside the invocation image during
the porter run
command. The current step from the manifest is passed on stdin.
Example:
stdin
uninstall:
- helm3:
description: "Uninstall MySQL"
purge: true
releases:
- "{{ bundle.parameters.mysql-name }}"
invoke
The invoke command (optional) is called from inside the invocation image during
the porter run
command when a custom action defined in the bundle is executed.
The current step from the manifest is passed on stdin. The mixin should write
any output values to their own files in the /cnab/app/porter/outputs/
directory.
A mixin doesn’t have to support custom actions. If your mixin just maps to CLI commands, and doesn’t take the action into account, then we strongly recommend supporting custom actions so that bundle authors can use your mixin anywhere in their bundle, not just in install/upgrade/uninstall.
Example:
stdin
status:
- exec:
description: "Run a rando command, don't care what action I'm in"
command: bash
flags:
c: echo "Don't mind me, just getting the status of something..."
version
The version command (required) is used by porter during porter build
and when
listing installed mixins via porter mixins list
. It should support an
--output|o
flag that accepts either plaintext
or json
as values,
defaulting to plaintext
.
Example:
$ ~/.porter/mixins/exec/exec version
exec mixin v0.13.1-beta.1 (37f3637)
$ ~/.porter/mixins/exec/exec version --output json
{
"name": "exec",
"version": "v0.13.1-beta.1",
"commit": "37f3637",
"author": "Porter Authors"
}