Skip to content

Creating a generator plugin

In this guide you will learn how to build a generator plugin.

Introduction

In this guide, you’ll learn about the basic components needed to create and use a packaged generator plugin. To focus this guide on the components needed to package the plugin, the functionality of the plugin’s code is minimal. The plugin prints “Hello World” in the logs or “Hello {who-to-greet}” if you provide a custom name.

This guide uses the OpenTestFactory Orchestrator Toolkit module to speed up development. For more information, see the opentf/toolkit repository.

Once you complete this project, you should understand how to build your own generator plugin and test it in a workflow.

To ensure your plugins are compatible with all OpenTestFactory Orchestrator deployments (linux, windows, …), the packaged code you write should be pure and not rely on other non-portable binaries.

Prerequisites

You may find it helpful to have a basic understanding of OpenTestFactory Orchestrator environment variables:

Before you begin, you will need to create a repository.

  1. Create a new repository on GitHub/Gitlab/BitBucket/.... You can choose any repository name or use “hello-world-generator-plugin” like this example.
  2. Clone your repository to your computer.
  3. From your terminal, change directories into your new repository.
cd hello-world-generator-plugin

Create a web service

Generator plugins are simple web services. They subscribe to specific events on startup, and publish events in response.

The opentf/toolkit module streamlines the process if you want to write your plugin in Python. For more information on doing things in a less assisted way, see “Writing plugins the hard way.”

In your new hello-world-generator-plugin directory, create a new main.py file.

main.py

# main.py
from opentf.toolkit import make_plugin, run_plugin

from .implementation import generate

plugin = make_plugin(
    name='helloworld',
    description='A helloworld generator.',
    generator=generate
)

if __name__ == '__main__':
    run_plugin(plugin)

Create a plugin metadata file

Create a new plugin.yaml file in the hello-world-generator-plugin directory you created above. For more information, see “Metadata syntax for OpenTestFactory Orchestrator plugins.”

plugin.yaml

# plugin.yaml
apiVersion: 'opentestfactory.org/v1alpha1'
kind: 'GeneratorPlugin'
metadata:
  name: 'HelloWorld'
  description: 'Greet someone'
events:
- category: helloworld
  categoryVersion: v1
cmd: 'python3 -m main'
inputs:
  who-to-greet:
    description: 'Who to greet'
    required: false
    default: 'World'
outputs:
  random-number:
    description: 'Random number'
    value: ${{ steps.random-number-generator.outputs.random-id }}

Writing the plugin code

Generator plugins must return a possibly empty collection of jobs. Each job has a name and a definition. For more information about the jobs syntax, see “Workflow syntax for OpenTestFactory Orchestrator.”

Job names and step ids are local to the returned collection of jobs. They do not conflict with names and ids used in the referring workflow.

The following Python script example uses the who-to-greet input variable to print “Hello {who-to-greet}” in the log file and maps the random generated number to the random-number output variable.

implementation.py

# implementation.py

def generate(inputs):
  jobs = {
    'jobs': {
      'job1': {
        'runs-on': 'linux',
        'steps': [
          {'run': 'echo Hello ' + inputs['who-to-greet'] + '.',
           'shell': 'bash'},
          {'id': 'random-number-generator',
           'run': 'echo "::set-output name=random-id::$(echo $RANDOM)"',
           'shell': 'bash'}
        ]
      }
    }
  }
  return jobs

Create a README

To let people know how to use your plugin, you can create a README file. A README is most helpful when you plan to share your plugin publicly, but is also a great way to remind you or your team how to use the plugin.

In your hello-world-generator-plugin directory, create a README.md file that specifies the following information:

  • A detailed description of what the plugin does.
  • Required input and outputs arguments.
  • Optional input and outputs arguments.
  • Environment variables the plugin uses.
  • An example of how to use your plugin in a workflow.

README.md

# Hello world generator plugin

This function prints "Hello World" or "Hello" + the name of a person to greet to
the log.

## Inputs

### `who-to-greets`

**Required** The name of the person to greet.  Default `"World"`.

## Outputs

###  `random-id`

A random number.

## Example usage

generator: helloworld@v1
with:
  who-to-greets: 'Mona the Octocat'

Commit, tag, push, and deploy your plugin

From your terminal, commit your plugin.yaml, implementation.py, helloworld.py, and README.md files.

It is best practice to also add a version tag for releases of your plugin. For more information on versioning your plugin, see “About plugins.”

git add plugin.yaml implementation.py helloworld.py README.md
git commit -m "My first plugin is ready"
git tag -a -m "My first plugin release" v1
git push --follow-tags

TODO (Deploy)

Testing out your plugin in a workflow

Now you are ready to test your plugin out in a workflow.

Example

jobs:
  hello_world_job:
    runs-on: linux
    name: A job to say hello
    generator: helloworld@v1
    with:
      who-to-greets: "Mona the Octocat"