Parameters, Credentials, Outputs, and Images in Porter

In the Porter manifest, you can declare both parameters and credentials. In addition to providing a mechanism for declaring parameters and credentials at the bundle level, Porter provides a way to declare how each of these are provided to mixins. This mechanism is also applicable to declaring how output from one mixin can be passed to another, as well as how to consume parameters, credentials and outputs from bundle dependencies. Finally, you can also use this technique to reference images defined in the images section of the manifest.

Wiring Installation Metadata

The installation name is available at runtime as {{ installation.name }}. In the example below, we install a helm chart and set the release name to the installation name of the bundle:

install:
  helm3:
    description: Install myapp
    name: "{{ installation.name }}"
    chart: charts/myapp

Parameters

In order to declare a parameter in a Porter bundle, you first declare a parameters block with one or more parameters in the porter.yaml. For example, to declare a parameter named database_name, you might include the following YAML block:

parameters:
- name: database_name
  type: string

This is the minimum required to create a parameter in Porter. Porter will specify an environment variable destination that defaults to the upper-cased name of the parameter.

You can also provide any other attributes, as specified by the CNAB parameters specification. To specify a default value, for example, you could provide the following parameter definition:

- name: database_name
  type: string
  default: "wordpress"

File Parameters

Porter also enables the use of file parameters in a bundle.

For instance, a bundle might declare a parameter mytar of type file, to exist at /root/mytar in the execution environment:

- name: mytar
  type: file
  path: /root/mytar

which can be used in a step like install:

install:
  - exec:
      description: "Install"
      command: bash
      flags:
        c: tar zxvf /root/mytar

The syntax to pass a parameter to porter is the same for both regular and file parameters:

$ porter install --param mytar=./my.tar.gz

See the Parameters section of the Author Bundles doc for additional examples and configuration.

Wiring Parameters

Once a parameter has been declared in the porter.yaml, Porter provides a simple mechanism for specifying how the parameter value should be wired into the mixin. To reference a parameter in the bundle, you use a notation of the form "{{ bundle.parameters.PARAM_NAME }}". This can be used anywhere within step definition. For example, to use the database_name parameter defined above in the set block of the helm mixin:

install:
- helm3:
    description: "Install MySQL"
    name: porter-ci-mysql
    chart: bitnami/mysql
    version: 6.14.2
    replace: true
    set:
      db.name: "{{ bundle.parameters.database-name }}"
      db.user: "root"

Or to provide a parameter to the command attribute of the exec mixin:

parameters:
  - name: command
    type: string
    default: "echo Hello World"

install:
  - description: "Install Hello World"
    exec:
      command: "{{ bundle.parameters.command }}"

This syntax is used in dictionary, as above, or in a list:

parameters:
  - name: command
    type: string
    default: "echo Hello World"

install:
  - description: "Install Hello World"
    exec:
      command: bash
      flags:
        c: "{{ bundle.parameters.command }}"

NOTE: These references must be quoted, as in the examples above.

See Parameters to learn how parameters are passed in to Porter prior to bundle execution.

Credentials

Credentials are defined in the porter.yaml with a YAML block of one more credential definitions. You can declare that a credential should be placed in a path within the invocation image or into an environment variable.

To declare a file injection:

credentials:
- name: kubeconfig
  path: /root/.kube/config

To declare an environment variable injection:

credentials:
- name: SUBSCRIPTION_ID
  env: AZURE_SUBSCRIPTION_ID

Wiring Credentials

The same mechanism for declaring how to use a parameter can be used for credentials. To declare a credential usage, references are defined with the following syntax: "{{ bundle.credentials.CREDENTIAL_NAME}}".

When the bundle is executed, the Porter runtime will locate the parameter definition in the porter.yaml to determine where the parameter value has been stored. The Porter runtime will then rewrite the YAML block before it is passed to the mixin. See Credentials to learn how credentials work.

Outputs

In addition to parameters and credentials, Porter introduces a type called an output. Outputs are values that are generated during the execution of a mixin. These could be things like a hostname for a newly provisioned Azure service or a generated password from something installed with Helm. These often need to be used in subsequent steps so Porter allows you to declare how to reference them after they have been created. The form used to declare these varies by mixin, but might look something like:

install:
  - arm:
      description: "Create Azure MySQL"
      type: arm
      template: "arm/mysql.json"
      name: demo-mysql-azure-porter-demo-wordpress
      resourceGroup: "porter-test"
      parameters:
        administratorLogin: "{{ bundle.parameters.mysql_user}}"
        administratorLoginPassword: "{{ bundle.parameters.mysql_password }}"
        location: "eastus"
        serverName: "mysql-jeremy-porter-test-jan-2018"
        version: "5.7"
        sslEnforcement: "Disabled"
        databaseName: "{{ bundle.parameters.database_name }}"
      outputs:
        - name: "MYSQL_URL"
          key: "MYSQL_HOST"

In this example, a new output will be created named MYSQL_URL. The Azure mixin allows you to specify the key to fetch the output from, in this case it is MYSQL_HOST. Each mixin can provide different ways of addressing outputs, so refer to the schema for each mixin. The Porter runtime will keep a map in memory with each of the outputs declared.

Wiring Outputs

Once an output has been declared, it can be referenced in the same way as parameters and credentials. Outputs are referenced with the syntax "{{ bundle.outputs.OUTPUT_NAME }}"

For example, given the install step above, we can use the MYSQL_URL with the helm mixin in the following way:

  - helm3:
      description: "Helm Install Wordpress"
      name: porter-ci-wordpress
      chart: bitnami/wordpress
      version: "9.9.3"
      set:
        mariadb.enabled: "false"
        externalDatabase.port: 3306
        externalDatabase.host: "{{  bundle.outputs.MYSQL_URL }}"
        externalDatabase.user: "{{ bundle.parameters.mysql_user }}"
        externalDatabase.password: "{{ bundle.parameters.mysql_password }}"
        externalDatabase.database: "{{ bundle.parameters.database_name }}"

Just like in the case of credentials and parameters, the value of the bundle.outputs.MYSQL_URL reference will be rewritten in the YAML before the helm mixin is invoked.

Parameters can also use the value from an output from the current bundle or one of its dependencies as its default value using the source field when defining the parameter.

Source an output from the current bundle

parameters:
- name: tfstate
  type: file
  path: /cnab/app/tfstate
  source:
    output: tfstate

Source an output from a dependency

parameters:
- name: connection-string
  type: string
  source:
    dependency: mysql
    source: connstr

Wiring Custom Metadata

In the porter.yaml, you can define custom metadata and use it in your bundle. These custom values are hard-coded into the bundle and cannot be modified at runtime. If you need that, then you should use a parameter.

custom:
  myApp:
    featureFlags:
      featureA: true

Now you can use the custom values in your actions like so:

install:
  helm3:
    description: Install myapp
    chart: charts/myapp
    set:
      featureA: "{{ bundle.custom.myApp.featureFlags.featureA }}"

Wiring Images

In the porter.yaml, you can define what images will be used within the bundle with the images section:

images:
  ALIAS:
    description: A very useful image
    imageType: docker
    repository: gcr.io/mcguffin-co/mcguffin
    digest: sha256:85b1a9
    tag: v1.1.0

These images will be used to build the bundle.json images section, but can also be referenced using the same syntax you would use for referencing parameters, credentials, and outputs.

  - helm3:
      description: "Helm Install Wordpress"
      name: porter-ci-wordpress
      chart: bitnami/wordpress
      version: "9.9.3"
      set:
        image.repository: "{{ bundle.images.ALIAS.repository }}"
        image.tag: "{{ bundle.images.ALIAS.tag }}"

Wiring Dependency Outputs

You can reference outputs from a dependency defined in your bundle using the syntax {{ bundle.dependencies.DEPENDENCY.outputs.OUTPUT }}.

For example, consider a bundle that creates a mysql defined with the following porter.yaml:

name: mysql
version: 0.1.3
registry: getporter

mixins:
- helm3:
    repositories:
      bitnami:
        url: "https://charts.bitnami.com/bitnami"

credentials:
- name: kubeconfig
  path: /root/.kube/config

parameters:
- name: database-name
  type: string
  default: mydb
  env: DATABASE_NAME
- name: mysql-user
  type: string
  env: MYSQL_USER

install:
- helm3:
    description: "Install MySQL"
    name: porter-ci-mysql
    chart: bitnami/mysql
    version: 6.14.2
    replace: true
    set:
      db.name: "{{ bundle.parameters.database-name }}"
      db.user: "{{ bundle.parameters.mysql-user }}"
    outputs:
    - name: mysql-root-password
      secret: porter-ci-mysql
      key: mysql-root-password
    - name: mysql-password
      secret: porter-ci-mysql
      key: mysql-password

With this bundle definition, we can build a second bundle to install wordpress and declare a dependency on this bundle. The porter.yaml for this might look something like:

name: wordpress
version: 0.1.0
registry: getporter

mixins:
- helm3:
    repositories:
      bitnami:
        url: "https://charts.bitnami.com/bitnami"

dependencies:
  requires:
    - name: mysql
      reference: getporter/mysql:v0.1.3
      parameters:
        database_name: wordpress
        mysql_user: wordpress

credentials:
- name: kubeconfig
  path: /root/.kube/config

parameters:
- name: wordpress-name
  type: string
  default: porter-ci-wordpress
  env: WORDPRESS_NAME
- name: wordpress-password
  type: string
  sensitive: true
  applyTo:
    - install
    - upgrade
- name: namespace
  type: string
  default: ''

install:
- helm3:
  description: "Install Wordpress"
  name: "{{ bundle.parameters.wordpress-name }}"
  chart: bitnami/wordpress
  version: "9.9.3"  
  namespace: "{{ bundle.parameters.namespace }}"
  replace: true
  set:
    wordpressPassword: "{{ bundle.parameters.wordpress-password }}"
    externalDatabase.password: "{{ bundle.dependencies.mysql.outputs.mysql-password }}"
    externalDatabase.port: 3306
    mariadb.enabled: false
  outputs:
    - name: wordpress-password
      secret: "{{ bundle.parameters.wordpress-name }}"
      key: wordpress-password

The wordpress bundle declares a dependency on the mysql bundle, which we saw above. Now, we are able to refer to the parameters and the outputs from that bundle!

install:
- helm3:
  description: "Install Wordpress"
  name: "{{ bundle.parameters.wordpress-name }}"
  chart: bitnami/wordpress
  version: "9.9.3"      
  namespace: "{{ bundle.parameters.namespace }}"
  replace: true
  set:
    wordpressPassword: "{{ bundle.parameters.wordpress-password }}"
    externalDatabase.password: "{{ bundle.dependencies.mysql.outputs.mysql-password }}"
    externalDatabase.port: 3306
    mariadb.enabled: false

For more information on how dependencies are handled, refer to the dependencies documentation.

Combining References

It is possible to reference multiple parameters, credentials and/or outputs in a single place. You can combine the expressions as follows:

install:
- helm3:
    description: "Install Java App"
    name: "{{ bundle.parameters.cool-app}}"
    chart: bitnami/wordpress
    version: "9.9.3"
    replace: true
    set:
      jdbc_url: "jdbc:mysql://{{ bundle.outputs.mysql_host }}:{{ bundle.outputs.mysql_port }}/{{ bundle.parameters.database_name }}"