Sharing task code

Multiple tasks can share common files between them. Tasks can additionally pull library code from other modules.

To create a task that includes additional files pulled from modules, include the files property in your metadata as an array of paths. A path consists of:

  • the module name
  • one of the following directories within the module:
    • files — Most helper files. This prevents the file from being treated as a task or added to the PuppetRuby loadpath.

    • tasks — Helper files that can be called as tasks on their own.

    • libRuby code that might be reused by types, providers, or Puppet functions.

  • the remaining path to a file or directory; directories must include a trailing slash /

All path separators must be forward slashes. An example would be stdlib/lib/puppet/.

The files property can be included both as a top-level metadata property, and as a property of an implementation, for example:

{
  "implementations": [
    {"name": "sql_linux.sh", "requirements": ["shell"], "files": ["mymodule/files/lib.sh"]},
    {"name": "sql_windows.ps1", "requirements": ["powershell"], "files": ["mymodule/files/lib.ps1"]}
  ],
  "files": ["emoji/files/emojis/"]
}

When a task includes the files property, all files listed in the top-level property and in the specific implementation chosen for a target are copied to a temporary directory on that target. The directory structure of the specified files is preserved such that paths specified with the files metadata option are available to tasks prefixed with _installdir. The task executable itself is located in its module location under the _installdir as well, so other files can be found at ../../mymodule/files/ relative to the task executable's location.

For example, you can create a task and metadata in a module at ~/.puppetlabs/bolt/site-modules/mymodule/tasks/task.{json,rb}.

Metadata

{
  "files": ["multi_task/files/rb_helper.rb"]
}

File resource

multi_task/files/rb_helper.rb

def useful_ruby
  { helper: "ruby" }
end

Task

#!/usr/bin/env ruby
require 'json'

params = JSON.parse(STDIN.read)
require_relative File.join(params['_installdir'], 'multi_task', 'files', 'rb_helper.rb')
# Alternatively use relative path
# require_relative File.join(__dir__, '..', '..', 'multi_task', 'files', 'rb_helper.rb')
 puts useful_ruby.to_json

Output

Started on localhost...
Finished on localhost:
  {
    "helper": "ruby"
  }
Successful on 1 node: localhost
Ran on 1 node in 0.12 seconds

Task helpers

To help with writing tasks, Bolt includes python_task_helper and ruby_task_helper. It also makes a useful demonstration of including code from another module.

Python example

Create task and metadata in a module at ~/.puppetlabs/bolt/site-modules/mymodule/tasks/task.{json,py}.

Metadata

{
  "files": ["python_task_helper/files/task_helper.py"],
  "input_method": "stdin"
}

Task

#!/usr/bin/env python
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python_task_helper', 'files'))
from task_helper import TaskHelper

class MyTask(TaskHelper):
  def task(self, args):
    return {'greeting': 'Hi, my name is '+args['name']}

if __name__ == '__main__':
    MyTask().run()

Output

$ bolt task run mymodule::task -n localhost name='Julia'
Started on localhost...
Finished on localhost:
  {
    "greeting": "Hi, my name is Julia"
  }
Successful on 1 node: localhost
Ran on 1 node in 0.12 seconds

Ruby example

Create task and metadata in a new module at ~/.puppetlabs/bolt/site-modules/mymodule/tasks/mytask.{json,rb}.

Metadata

{
  "files": ["ruby_task_helper/files/task_helper.rb"],
  "input_method": "stdin"
}

Task

#!/usr/bin/env ruby
require_relative '../../ruby_task_helper/files/task_helper.rb'

class MyTask < TaskHelper 
  def task(name: nil, **kwargs)
    { greeting: "Hi, my name is #{name}" }
  end
end


MyTask.run if __FILE__ == $0

Output

$ bolt task run mymodule::mytask -n localhost name="Robert'); DROP TABLE Students;--"
Started on localhost...
Finished on localhost:
  {
    "greeting": "Hi, my name is Robert'); DROP TABLE Students;--"
  }
Successful on 1 node: localhost
Ran on 1 node in 0.12 seconds