Ora

How do I run a puppet script?

Published in Puppet Script Execution 7 mins read

To run external scripts (like shell, Python, or PowerShell scripts) using Puppet, you primarily leverage Puppet Bolt tasks. These tasks provide a robust and controlled way to execute arbitrary code on remote systems or locally, going beyond standard Puppet resource management.

How to Run Scripts with Puppet (Using Bolt Tasks)

Puppet Bolt tasks are the go-to method for executing custom scripts through Puppet. They allow you to define and run executable files as part of your automation workflows, making complex operational tasks repeatable and scalable.

Understanding Puppet Bolt Tasks

A Puppet Bolt task is essentially any executable file (e.g., a Bash script, Python script, PowerShell script) that Bolt can run on target nodes. Tasks are designed to perform specific actions that might not be easily managed through declarative Puppet manifests alone, such as restarting services, deploying applications, or gathering dynamic information.

Where to Store Your Scripts (Task Files)

For Bolt to discover and execute your scripts effectively, they should be placed in designated directories within your Puppet modules or Bolt project.

The scripts/ Directory (Preferred for Tasks)

The scripts/ directory within your Puppet module is the preferred location for task executables. When a script is placed here, Bolt automatically recognizes it as a task.

  • Example Structure: my_module/scripts/my_script.sh
  • Referencing for Execution: When running from the command line, you reference these as my_module::my_script.
  • Referencing for Loading/Plans: If you need to explicitly reference the script file's path within a Bolt plan or task metadata, you would use <my_module/scripts/my_script.sh>.

The files/ Directory (Alternative for Supporting Scripts)

You can also store scripts and other supporting files in the files/ directory of a module. Scripts in this directory are not automatically recognized as Bolt tasks but can be used as supporting files for tasks or plans, often uploaded to targets before execution.

  • Example Structure: my_module/files/utility_script.py
  • Referencing for Loading/Plans: To load or reference a file from this directory within Bolt operations (e.g., to upload it to a target), you use the format <my_module/files/utility_script.py>.

Path Formats for Referencing Scripts

When working with Bolt, you can specify script locations using different path types:

  • Module-Relative Paths: The most common way to refer to scripts within a module, such as my_module/scripts/my_script.sh or my_module/files/another_script.py. Bolt interprets these paths relative to the root of your Bolt project or module.
  • Absolute File Paths: You can use an absolute path to a script file on your Bolt controller, like /path/to/my_script.sh. While flexible for ad-hoc use, this is less portable for reusable tasks.

How to Execute a Script with Puppet Bolt

There are several ways to run your scripts using Bolt, depending on your needs.

1. Running Scripts as Bolt Tasks from the Command Line

This is the most direct way to execute a predefined task.

Command Description
bolt task run <TASK_NAME> -t <TARGETS> Runs a task defined in a module's scripts/ directory on specified target nodes. Parameters are passed as key=value.
bolt command run '<COMMAND>' -t <TARGETS> Executes an arbitrary command string on the specified targets. This can include executing a script that has already been uploaded.

Example: Running a Task from the scripts/ directory

Let's say you have a script my_module/scripts/hello.sh:

#!/bin/bash
# my_module/scripts/hello.sh
echo "Hello, $PT_name!"

To run this task, passing a parameter:

bolt task run my_module::hello name=World -t localhost

2. Executing Arbitrary Scripts using Bolt Plans

For scripts that are not formal Bolt tasks (e.g., in files/), or for more complex orchestration, you can use Bolt plans. A plan allows you to combine multiple steps, including uploading files and running commands.

Example: Running a script from the files/ directory via a Plan

Suppose you have my_module/files/my_utility.sh that you want to run:

#!/bin/bash
# my_module/files/my_utility.sh
echo "Running a utility script from files/ directory."
hostname

You could create a Bolt plan my_module/plans/run_utility.pp:

# my_module/plans/run_utility.pp
plan my_module::run_utility(TargetSpec $targets) {
  $script_path_on_target = '/tmp/my_utility.sh'

  # Upload the script from the module's files/ directory
  # Note the syntax: <module/files/script.sh>
  upload(get_targets($targets), '<my_module/files/my_utility.sh>', $script_path_on_target)

  # Make the script executable on the target
  run_command("chmod +x ${script_path_on_target}", $targets)

  # Execute the script on the target
  run_command($script_path_on_target, $targets)
}

Then, run this plan from your command line:

bolt plan run my_module::run_utility -t webserver

3. Running Tasks from Puppet Manifests or Plans

You can integrate Bolt tasks directly into your Puppet code using the run_task function within Puppet plans or even in Puppet manifests (though plans are generally preferred for task orchestration).

Example: Calling a Task from a Puppet Plan

In a plan like my_module/plans/deploy_app.pp, you can trigger another task:

# my_module/plans/deploy_app.pp
plan my_module::deploy_app(TargetSpec $targets) {
  # ... other deployment steps ...

  # Run a task to restart a service after deployment
  run_task('my_module::restart_service', $targets, service_name => 'nginx')
  # Assuming 'my_module::restart_service' is a task defined in my_module/scripts/restart_service.sh
}

Then, execute the plan:

bolt plan run my_module::deploy_app -t production_servers

Essential Script Considerations for Bolt Tasks

When writing scripts to be used with Puppet Bolt, keep the following in mind for optimal performance and reliability:

  • Shebang Line: Always include a shebang line at the top of your script (e.g., #!/bin/bash, #!/usr/bin/env python). This tells the operating system which interpreter to use.
  • Executable Permissions: Ensure your script has executable permissions (chmod +x myscript.sh). Bolt typically handles this automatically for tasks in the scripts/ directory, but you might need to manage it manually if uploading with bolt file upload and then executing with bolt command run.
  • Parameters: For Bolt tasks, parameters passed via key=value are made available to your script as environment variables prefixed with PT_. For instance, a parameter name=World becomes $PT_name in a Bash script.
  • Exit Codes: Scripts should return an exit code of 0 for success and a non-zero exit code (e.g., 1) for failure. Bolt uses these codes to determine the success or failure status of the task.
  • Error Handling: Implement robust error handling and logging within your scripts to make debugging easier.

Best Practices for Scripting with Puppet Bolt

To maximize the benefits of using scripts with Puppet Bolt, follow these best practices:

  • Modularize: Break down complex operations into smaller, focused tasks. This enhances reusability and maintainability.
  • Idempotency: Strive to make your scripts idempotent. This means running a script multiple times should have the same effect as running it once, preventing unintended changes or errors.
  • Version Control: Store all your tasks, plans, and module code in a version control system like Git for tracking changes, collaboration, and easy rollback.
  • Testing: Thoroughly test your scripts and plans in isolated development or staging environments before deploying them to production.

What if it's a Puppet Manifest (.pp) file?

If by "Puppet script" you are referring to a Puppet manifest (a .pp file containing Puppet code to declare resources), you would apply it rather than run it as an executable script. This is typically done using the Puppet agent or bolt apply.

  • Applying a manifest with Bolt:
    bolt apply my_module/manifests/site.pp -t webserver
  • Applying a manifest with Puppet Agent:
    sudo puppet agent -t

    (This requires a configured Puppet agent and master.)