Go-ansible is a Go package that allows executing Ansible commands, such as ansible-playbook
, ansible-inventory
, or ansible
, directly from Golang applications. It offers a variety of options for each command, facilitating seamless integration of Ansible functionality into your projects. It is important to highlight that go-ansible is not an alternative implementation of Ansible, but rather a wrapper around the Ansible commands.
Let's dive in and explore the capabilities of go-ansible together.
Important: The master branch may contain unreleased or pre-released features. Be cautious when using that branch in your projects. It is recommended to use the stable releases available in the releases.
Note The latest major version of go-ansible, version 2.x, introduced significant and breaking changes. The first change is that the package name has been changed from
github.com/apenella/go-ansible
togithub.com/apenella/go-ansible/v2
. So, you need to update your import paths to use the new module name. To migrate your code from prior version to 2.x, please refer to the upgrade guide for detailed information on how to migrate to version 2.x. The most relevant change is that command structs no longer execute commands. So, AnsiblePlaybookCmd, AnsibleInventoryCmd and AnsibleAdhocCmd do not require an executor anymore. Instead, the executor is responsible for receiving the command to execute and executing it.
- go-ansible
- Install
- Concepts
- Considerations
- Getting Started
- Usage Reference
- Adhoc package
- Execute package
- Galaxy package
- Inventory package
- Playbook package
- Vault package
- Examples
- Development Reference
- License
Use this command to fetch and install the go-ansible module. You can install the release candidate version by executing the following command:
go get github.com/apenella/go-ansible/[email protected]
You can also install the previous stable version by executing the following command:
go get github.com/apenella/go-ansible
If you are currently using a go-ansible version before 1.x, note that there have been significant breaking changes introduced in version 1.0.0 and beyond. Before proceeding with the upgrade, we highly recommend reading the changelog and the upgrade guide carefully. These resources provide detailed information on the changes and steps required for a smooth transition to the new version.
Version 2.0.0 introduced notable changes since the major version 1, including several breaking changes. The upgrade guide conveys the necessary information to migrate to version 2.x. Thoroughly read that document and the changelog before upgrading from version 1.x to 2.x.
There are a few concepts that you need to understand before using the go-ansible library. These concepts are essential to effectively use the library and to understand the examples and usage references provided in this document.
An executor is a component that executes commands and handles the results from the execution output. The library includes the DefaultExecute executor, which is a ready-to-go implementation of an executor. If the DefaultExecute
does not meet your requirements, you can also create a custom executor.
To know more about the DefaultExecute
, refer to that section.
A command generator or a commander is responsible for generating the command to be executed. The AnsiblePlaybookCmd and AnsibleAdhocCmd structs are examples of command generators. That concept has been introduced in the major version 2.0.0.
A results handler or a results outputer is responsible for managing the output of the command execution. The library includes two output mechanisms: the DefaultResults and the JSONStdoutCallbackResults structs.
Before you proceed further, please take note of the following considerations to ensure optimal usage of the go-ansible library.
When executing Ansible commands using the go-ansible library inside a container, ensure that the container has configured an init system. The init system is necessary to manage the child processes created by the Ansible commands. If the container does not have an init system, the child processes may not be correctly managed, leading to unexpected behavior such as zombie processes.
You can read more about that in the issue 139 and here.
Ansible commands forces the pseudo-terminal allocation when executed in a terminal. That configuration can cause that the SSH connection leaves zombie processes when the command finished. If you are experiencing this issue, you can disable the pseudo-terminal allocation by setting the -T
to the SSH extra arguments, that will disable the pseudo-terminal allocation.
You can read more about that in the issue 139 and here.
This section will guide you through the step-by-step process of using the go-ansible library. Follow these instructions to create an application that utilizes the ansible-playbook
utility. The same guidelines can be applied to other Ansible commands, such as the ansible
or ansible-inventory
command.
Note The following example will guide you through a complete process of creating all the components necessary to execute an
ansible-playbook
command. For a simpler example utilizing the AnsiblePlaybookExecute struct, please refer to the ansibleplaybook-simple example in the repository.
Before proceeding, ensure you have installed the latest version of the go-ansible library. If not, please refer to the Installation section for instructions.
To create an application that launches the ansible-playbook
command you need to create an AnsiblePlaybookCmd struct. This struct generates the Ansible command to be run. Then, you need to execute the command using an executor](#executor). In that guided example, you will use the DefaultExecute executor, an executor provided by the go-ansible library.
To execute ansible-playbook
commands, first, define the necessary connection, playbook, and privilege escalation options.
Start by creating the AnsiblePlaybookOptions struct:
ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{
Become: true,
Connection: "local",
Inventory: "127.0.0.1,",
}
Finally, create the AnsiblePlaybookCmd struct that generates the command to execute the playbook site.yml
using the ansible-playbook
command:
playbookCmd := playbook.NewAnsiblePlaybookCmd(
playbook.WithPlaybooks("site.yml", "site2.yml"),
playbook.WithPlaybookOptions(ansiblePlaybookOptions),
)
Once the AnsiblePlaybookCmd
is defined, provide the command to an executor to run the command.
We will use the DefaultExecute struct, provided by the go-ansible library, to execute the ansible-playbook
command. It requires a Commander responsible for generating the command to be executed. In that example, you will use the AnsiblePlaybookCmd previously defined.
// PlaybookCmd is the Commander responsible for generating the command to execute
exec := execute.NewDefaultExecute(
execute.WithCmd(playbookCmd),
)
Once you have defined the DefaultExecute, execute the Ansible command using the following code:
err := exec.Execute(context.Background())
if err != nil {
// Manage the error
}
By default, the DefaultExecute uses the DefaultResults struct to manage the output of the command execution. The DefaultResults
struct handles the output as plain text.
──
── PLAY [all] *********************************************************************
──
── TASK [Gathering Facts] *********************************************************
── ok: [127.0.0.1]
──
── TASK [simple-ansibleplaybook] **************************************************
── ok: [127.0.0.1] => {
── "msg": "Your are running 'simple-ansibleplaybook' example"
── }
──
── PLAY RECAP *********************************************************************
── 127.0.0.1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
──
── Playbook run took 0 days, 0 hours, 0 minutes, 0 seconds
The Usage Reference section provides an overview of the different packages and their main resources available in the go-ansible library. Here you will find the details to effectively use the library to execute Ansible commands, such as ansible-playbook
and ansible
.
For detailed information on the library's packages, structs, methods, and functions, please refer to the complete reference available here.
This section provides an overview of the adhoc
package in the go-ansible library, outlining its key components and functionalities.
The github.com/apenella/go-ansible/v2/pkg/adhoc
package facilitates the generation of Ansible ad-hoc commands. It does not execute the commands directly, but instead provides the necessary structs to generate the command to be executed by an executor. The adhoc
package includes the following essential structs for executing ad-hoc commands:
The AnsibleAdhocCmd
struct enables the generation of Ansible ad-hoc commands. It implements the Commander interface, so its method Command
returns an array of strings that represents the command to be executed. An executor can use it to create the command to be executed.
The package provides the NewAnsibleAdhocCmd
function to create a new instance of the AnsibleAdhocCmd
struct. The function accepts a list of options to customize the ad-hoc command. The following functions are available:
WithAdhocOptions(options *AnsibleAdhocOptions) AdhocOptionsFunc
: Set the ad-hoc options for the command.WithBinary(binary string) AdhocOptionsFunc
: Set the binary for the ad-hoc command.WithPattern(pattern string) AdhocOptionsFunc
: Set the pattern for the ad-hoc command.
The following code snippet demonstrates how to use the AnsibleAdhocCmd
struct to generate an ad-hoc command:
ansibleAdhocOptions := &adhoc.AnsibleAdhocOptions{
Inventory: "127.0.0.1,",
ModuleName: "debug",
Args: "msg={{ arg }}",
ExtraVars: map[string]interface{}{
"arg": "value",
}
}
adhocCmd := adhoc.NewAnsibleAdhocCmd(
adhoc.WithPattern("all"),
adhoc.WithAdhocOptions(ansibleAdhocOptions),
)
// Generate the command to be executed
cmd, err := adhocCmd.Command()
if err != nil {
// Manage the error
}
The AnsibleAdhocExecute
struct serves as a streamlined executor for running ansible
command. It encapsulates the setup process for both the command generator and executor. This executor is particularly useful when no additional configuration or customization is required.
The following methods are available to set attributes for the AnsibleAdhocCmd struct:
WithBinary(binary string) *AnsibleAdhocExecute
: The method sets theBinary
attribute.WithAdhocOptions(options *AnsibleAdhocOptions) *AnsibleAdhocExecute
: The method sets theAdhocOptions
attribute.
Here is an example of launching an ansible
command using AnsibleAdhocExecute
:
err := adhoc.NewAnsibleAdhocExecute("all").
WithAdhocOptions(ansibleAdhocOptions).
Execute(context.TODO())
if err != nil {
// Manage the error
}
With AnsibleAdhocOptions
struct, you can define parameters described in Ansible's manual page's Options
section. On the same struct, you can define the connection options and privilage escalation options.
The execute package, available at github.com/apenella/go-ansible/v2/pkg/execute
, provides the DefaultExecute, a ready-to-use executor. Additionally, the package defines some interfaces for managing the command execution and customizing the behavior of the executor.
Find below the main resources available in the execute package:
The Executor
interface defines components responsible for executing external commands. The DefaultExecute struct implements this interface. Below is the definition of the Executor
interface:
type Executor interface {
Execute(ctx context.Context) error
}
The Commander
interface defines components responsible for generating the command to be executed. The AnsiblePlaybookCmd and AnsibleAdhocCmd structs implement this interface. Below is the definition of the Commander
interface:
type Commander interface {
Command() ([]string, error)
String() string
}
The ErrorEnricher
interface defines components responsible for enriching the error message. The AnsiblePlaybookErrorEnrich struct implements this interface.
The DefaultExecute struct uses this interface to enrich the error message. Below is the definition of the ErrorEnricher
interface:
type ErrorEnricher interface {
Enrich(err error) error
}
The Executabler
interface defines a component required by DefaultExecute to execute commands. Through the Executabler
interface, you can customize the execution of commands according to your requirements.
Below is the definition of the Executabler
interface:
type Executabler interface {
Command(name string, arg ...string) exec.Cmder
CommandContext(ctx context.Context, name string, arg ...string) exec.Cmder
}
The DefaultExecute
executor is a component provided by the go-ansible library for managing the commands execution. It offers flexibility and customization options to suit various use cases.
Think of the DefaultExecute
executor as a pipeline that handles command execution. It consists of three main stages, each managed by a different component:
- Commander: Generates the command to be executed.
- Executabler: Executes the command.
- ResultsOutputer: Manages the output of the command execution.
By default, the DefaultExecute
executor uses the OsExec
struct as the Executabler
for executing commands, a wrapper around the os/exec
package. It also uses the DefaultResults struct as the ResultsOutputer for managing the output of the command execution. However, you can customize these components to tailor the execution process to your needs.
The following functions can be provided when creating a new instance of the DefaultExecute
to customize its behavior. All of them are available in the github.com/apenella/go-ansible/v2/pkg/execute
package:
WithCmd(cmd Commander) ExecuteOptions
: Set the component responsible for generating the command.WithCmdRunDir(cmdRunDir string) ExecuteOptions
: Define the directory where the command will be executed.WithEnvVars(vars map[string]string) ExecuteOptions
: Set environment variables for command execution.WithErrorEnricher(errEnricher ErrorEnricher) ExecuteOptions
: Define the component responsible for enriching the error message.WithExecutable(executable Executabler) ExecuteOptions
: Define the component responsible for executing the command.WithOutput(output result.ResultsOutputer) ExecuteOptions
: Specify the component responsible for managing command output.WithTransformers(trans ...transformer.TransformerFunc) ExecuteOptions
: Add transformers to modify command output.WithWrite(w io.Writer) ExecuteOptions
: Set the writer for command output.WithWriteError(w io.Writer) ExecuteOptions
: Set the writer for command error output.
The snippet below shows how to customize the DefaultExecute
executor using the ExecuteOptions
functions:
// PlaybookCmd is the Commander responsible for generating the command to execute
playbookCmd := playbook.NewAnsiblePlaybookCmd(
playbook.WithPlaybooks("site.yml"),
playbook.WithPlaybookOptions(ansiblePlaybookOptions),
)
// MyExecutabler is an hypothetical implementation of the Executabler interface
executabler := &myExecutabler{}
// MyOutputer is an hypothetical implementation of the ResultsOutputer interface
output := &myOutputer{}
// Exec is an instance of the DefaultExecute executor
exec := execute.NewDefaultExecute(
execute.WithCmd(playbookCmd),
execute.WithExecutable(executabler),
execute.WithOutput(output),
)
// Execute the ansible-playbook command
err := exec.Execute(context.Background())
if err != nil {
// Manage the error
}
For more examples and practical use cases, refer to the examples directory in the go-ansible repository.
If DefaultExecute does not meet your requirements or expectations, you have the option to implement a custom executor. Below is an example of a custom executor that demonstrates how to integrate it with the AnsiblePlaybookCmd or AnsibleAdhocCmd structs to execute the playbook with your desired behavior:
type MyExecutor struct {
Prefix string
Cmd Commander
}
func (e *MyExecutor) Execute(ctx context.Context) error {
// That's a dummy work
fmt.Println(fmt.Sprintf("[%s] %s\n", e.Prefix, "I am a lazy executor and I am doing nothing"))
return nil
}
The next code snippet demonstrates how to execute the ansible-playbook
command using the custom executor:
// Define the command to execute
playbookCmd := playbook.NewAnsiblePlaybookCmd(
playbook.WithPlaybooks("site.yml"),
playbook.WithPlaybookOptions(ansiblePlaybookOptions),
)
// Define an instance for the new executor and set the options
exec := &MyExecutor{
Prefix: "go-ansible example",
Cmd: playbookCmd,
}
err := exec.Execute(context.Background())
if err != nil {
// Manage the error
}
When you run the playbook using the custom executor, the output will be:
[go-ansible example] I am a lazy executor and I am doing nothing
The go-ansible library offers a range of options to configure and customize the execution of the Ansible commands. These customization capabilities were introduced in version 2.0.0, when the executor became the central component in the execution process.
In the following sections, we will explore the components available for customizing the execution process:
The github.com/apenella/go-ansible/v2/pkg/execute/configuration
package provides components for configuring the Ansible settings during command execution. In the following sections, we will explore the available elements for customizing the execution process.
The ExecutorEnvVarSetter
interface extends the Executor interface with the capability of setting environment variables for the command execution. The DefaultExecute struct implements this interface. Below is the definition of the ExecutorEnvVarSetter
interface:
type ExecutorEnvVarSetter interface {
execute.Executor
AddEnvVar(key, value string)
}
The github.com/apenella/go-ansible/v2/pkg/execute/configuration
package provides a set of functions for configuring Ansible settings during command execution. Each function corresponds to a configuration setting available in Ansible's reference guide. The functions follow a consistent naming convention: With<setting name>
or Without<setting name>
, where <setting name>
is the name of the Ansible setting to be configured.
The AnsibleWithConfigurationSettingsExecute
struct serves as a decorator over an ExecutorEnvVarSetter, enabling configuration of Ansible settings for execution. When instantiating a new AnsibleWithConfigurationSettingsExecute
, you must provide an ExecutorEnvVarSetter
and a list of functions for configuring Ansible settings.
Here you can see an example of how to use the AnsibleWithConfigurationSettingsExecute
struct to configure Ansible settings for execution:
ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{
Connection: "local",
Inventory: "127.0.0.1,",
}
playbookCmd := playbook.NewAnsiblePlaybookCmd(
playbook.WithPlaybooks("site.yml"),
playbook.WithPlaybookOptions(ansiblePlaybookOptions),
)
exec := configuration.NewAnsibleWithConfigurationSettingsExecute(
execute.NewDefaultExecute(
execute.WithCmd(playbookCmd),
),
configuration.WithAnsibleForceColor(),
configuration.WithAnsibleForks(10),
configuration.WithAnsibleHome("/path/to/ansible/home"),
configuration.WithAnsibleHostKeyChecking(),
configuration.WithoutAnsibleActionWarnings(),
)
err := exec.Execute(context.Background())
if err != nil {
// Manage the error
}
The go-ansible library offers a convenient mechanism for measuring the execution time of Ansible commands through the github.com/apenella/go-ansible/v2/pkg/execute/measure
package. This package includes the ExecutorTimeMeasurement
struct, which acts as a decorator over an Executor to track the time taken for command execution.
To illustrate, consider the following code snippet, which demonstrates how to use the ExecutorTimeMeasurement
struct to measure the time it takes to execute the ansible-playbook
command:
ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{
Connection: "local",
Inventory: "127.0.0.1,",
}
playbookCmd := playbook.NewAnsiblePlaybookCmd(
playbook.WithPlaybooks("site.yml"),
playbook.WithPlaybookOptions(ansiblePlaybookOptions),
)
executorTimeMeasurement := measure.NewExecutorTimeMeasurement(
execute.NewDefaultExecute(
execute.WithCmd(playbookCmd),
),
)
err := executorTimeMeasurement.Execute(context.Background())
if err != nil {
// Manage the error
}
fmt.Println("Duration: ", exec.Duration().String())
For a complete example showcasing how to use measurement, refer to the ansibleplaybook-time-measurement example in the go-ansible repository.
The github.com/apenella/go-ansible/v2/pkg/execute/result
package provides a set of components and subpackages to manage the output of Ansible commands. The following sections describe the available elements.
The ResultsOutputer
interface in the github.com/apenella/go-ansible/v2/pkg/execute/result
package defines a component responsible for managing the output of command execution within the go-ansible library. Both the DefaultResults and JSONStdoutCallbackResults structs implement this interface. Below is the definition of the ResultsOutputer interface:
type ResultsOutputer interface {
Print(ctx context.Context, reader io.Reader, writer io.Writer, options ...OptionsFunc) error
}
The DefaultResults
struct, located in the github.com/apenella/go-ansible/v2/pkg/execute/result/default
package, serves as the default output manager for command execution within the go-ansible library. It implements the ResultsOutputer interface, providing functionality to handle command output as plain text.
The DefaultResults
struct reads the execution output line by line and applies a set of transformers to each line. A transformer allows you to enrich or modify of the output according to your specific requirements. You can specify the transformers during the instantiation of a new DefaultResults
instance or when configuring the DefaultExecute executor. Here you have an example of how to specify them when creating a new instance of DefaultExecute:
exec := execute.NewDefaultExecute(
execute.WithCmd(playbook),
execute.WithTransformers(
transformer.Prepend("Go-ansible example"),
transformer.LogFormat(transformer.DefaultLogFormatLayout, transformer.Now),
),
)
The JSONStdoutCallbackResults
struct, located in the github.com/apenella/go-ansible/v2/pkg/execute/result/json
package, is designed to handle the output of command execution when using the JSON
stdout callback method. It implements the ResultsOutputer interface, providing functionality to parse and manipulate JSON-formatted output from Ansible commands.
The package also includes the ParseJSONResultsStream
function, which decodes the JSON
output into an AnsiblePlaybookJSONResults
data structure. This structure can be further manipulated to format the JSON
output according to specific requirements. The expected JSON
schema from Ansible output is defined in the json.py file within the Ansible repository.
When creating a new instance of JSONStdoutCallbackResults
, you can specify a list of transformers to be applied to the output. These transformers enrich or update the output as needed. By default, the JSONStdoutCallbackResults
struct applies the IgnoreMessage
transformer to ignore any non-JSON
lines defined in the skipPatterns
array.
Here you have the skipPatterns
definition within the JSONStdoutCallbackResults
code:
skipPatterns := []string{
// This pattern skips timer's callback whitelist output
"^[\\s\\t]*Playbook run took [0-9]+ days, [0-9]+ hours, [0-9]+ minutes, [0-9]+ seconds$",
}
The following code snippet demonstrates how to use the JSONStdoutCallbackResults
struct to manage the output of command execution:
executorTimeMeasurement := stdoutcallback.NewJSONStdoutCallbackExecute(
execute.NewDefaultExecute(
execute.WithCmd(playbookCmd),
// The default executor writes the output to the buffer to be parsed by the JSONStdoutCallbackResults
execute.WithWrite(io.Writer(buff)),
),
)
err = exec.Execute(context.TODO())
if err != nil {
// Manage the error
}
// Parse the JSON output from the buffer
res, err = results.ParseJSONResultsStream(io.Reader(buff))
if err != nil {
// Manage the error
}
fmt.Println(res.String())
For a detailed example showcasing how to use measurement, refer to the ansibleplaybook-json-stdout example in the go-ansible repository.
In go-ansible, transformer functions are essential components that enrich or update the output received from the executor, allowing users to customize the output according to their specific requirements. Each transformer function follows the signature defined by the TransformerFunc
type:
// TransformerFunc is used to enrich or update messages before to be printed out
type TransformerFunc func(string) string
When the output is received from the executor, it undergoes processing line by line, with each line being passed through the available transformers. The github.com/apenella/go-ansible/v2/pkg/execute/result/transformer
package provides a set of ready-to-use transformers, and users can also create custom transformers as needed.
Here you have the transformer functions available in the github.com/apenella/go-ansible/v2/pkg/execute/result/transformer
package:
- Prepend: Adds a specified prefix string to each output line.
transformer.Prepend("Prefix: ")
- Append: Adds a specified suffix string to each output line.
transformer.Append(" [suffix]")
- LogFormat: Prepends each output line with a date-time prefix.
transformer.LogFormat(transformer.DefaultLogFormatLayout, transformer.Now)
- IgnoreMessage: Filters out output lines based on specified patterns. It uses the regexp.MatchString function to match the output lines with the specified patterns.
skipPatterns := []string{"regexp-pattern1", "regexp-pattern2"}
transformer.IgnoreMessage(skipPatterns...)
The github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback
package in the go-ansible library facilitates the management of Ansible's stdout callback method. Configuring the stdout callback method typically involves two steps:
- Setting the
ANSIBLE_STDOUT_CALLBACK
environment variable to specify the desired stdout callback plugin name. - Defining the method responsible for handling the results output from the command execution.
To streamline the configuration process, the go-ansible library provides a collection of structs dedicated to setting each stdout callback method, along with the ExecutorStdoutCallbackSetter interface.
The following sections detail the available components for configuring the stdout callback method:
The ExecutorStdoutCallbackSetter
interface extends the capabilities of the Executor interface by enabling the setting of environment variables and specifying the results output mechanism for command execution. The DefaultExecute struct implements this interface, providing flexibility in configuring the stdout callback method.
Below is the definition of the ExecutorStdoutCallbackSetter
interface:
type ExecutorStdoutCallbackSetter interface {
execute.Executor
AddEnvVar(key, value string)
WithOutput(output result.ResultsOutputer)
}
The ExecutorQuietStdoutCallbackSetter
interface in the github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback
package extends the ExecutorStdoutCallbackSetter interface with the capability to remove the verbosity of the command execution output. The DefaultExecute struct implements this interface, allowing you to silence the output of the command execution.
That interface is required by the JSONStdoutCallbackExecute struct to remove the verbosity of the command execution output.
The next code snippet shows the definition of the ExecutorQuietStdoutCallbackSetter
interface:
type ExecutorQuietStdoutCallbackSetter interface {
ExecutorStdoutCallbackSetter
Quiet()
}
The github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback
package provides a collection of structs designed to simplify the configuration of stdout callback methods for Ansible command execution. These structs act as decorators over an ExecutorStdoutCallbackSetter, allowing seamless integration of different stdout callback plugins with command execution.
Each stdout callback method in Ansible corresponds to a specific struct in go-ansible, making it easy to select and configure the desired method. Here are the available structs:
- DebugStdoutCallbackExecute
- DefaultStdoutCallbackExecute
- DenseStdoutCallbackExecute
- JSONStdoutCallbackExecute
- MinimalStdoutCallbackExecute
- NullStdoutCallbackExecute
- OnelineStdoutCallbackExecute
- StderrStdoutCallbackExecute
- TimerStdoutCallbackExecute
- YamlStdoutCallbackExecute
For example, to configure the JSON
stdout callback method for command execution, you can use the JSONStdoutCallbackExecute
struct as shown in the following code snippet:
execJson := stdoutcallback.NewJSONStdoutCallbackExecute(
execute.NewDefaultExecute(
execute.WithCmd(playbookCmd),
)
)
err := execJson.Execute(context.Background())
if err != nil {
// Manage the error
}
The github.com/apenella/go-ansible/v2/pkg/execute/workflow
package provides an executor that allows you to run a sequence of executors.
The WorkflowExecute
struct is responsible for managing the execution of a sequence of executors. It allows you to define a workflow for running Ansible commands. Additionally, the WorkflowExecute
implements the Executor interface, enabling you to apply some decorators such as the ExecutorTimeMeasurement to the workflow.
By default, when an executor execution in the sequence fails, the WorkflowExecute
stops the execution of the remaining executors. However, you can customize this behaviour by setting the ContinueOnError
attribute to true
. In that case, if one executor fails, the WorkflowExecute
continues with the remaining executors and raises an error at the end of the execution.
The WorkflowExecute
struct provides the following methods to setup the execution process:
AppendExecutor(exec Executor) *WorkflowExecute
: Appends an executor to the sequence.Execute(ctx context.Context) error
: Executes the sequence of executors.WithContinueOnError() *WorkflowExecute
: Sets theContinueOnError
attribute totrue
.
Here is an example of how to use the WorkflowExecute
struct to run a sequence of executors:
exec1 := playbook.NewAnsiblePlaybookExecute("first.yml").
WithPlaybookOptions(ansiblePlaybookOptions)
exec2 := playbook.NewAnsiblePlaybookExecute("second.yml").
WithPlaybookOptions(ansiblePlaybookOptions)
err := workflow.NewWorkflowExecute(exec1, exec2).
WithContinueOnError().
Execute(context.TODO())
if err != nil {
// Manage the error
}
The go-ansible
library provides you with the ability to interact with the Ansible Galaxy command-line tool. To do that it includes the following package:
- github.com/apenella/go-ansible/v2/pkg/galaxy/collection/install: Provides the functionality to install collections from the Ansible Galaxy.
- github.com/apenella/go-ansible/v2/pkg/galaxy/role/install: Provides the functionality to install roles from the Ansible Galaxy.
The github.com/apenella/go-ansible/v2/pkg/galaxy/collection/install
package allows you to install collections from the Ansible Galaxy using the ansible-galaxy
command. The package provides the following structs and functions:
The AnsibleGalaxyCollectionInstallCmd
struct enables the generation of ansible-galaxy
commands to install collections. It implements the Commander interface, so its method Command
returns an array of strings that represents the command to be executed. An executor can use it to create the command to be executed.
The package provides the NewAnsibleGalaxyCollectionInstallCmd
function to create a new instance of the AnsibleGalaxyCollectionInstallCmd
struct. The function accepts a list of options to customize the ansible-galaxy
command. The following functions are available:
WithBinary(binary string) AnsibleGalaxyCollectionInstallOptionsFunc
: Set the binary for theansible-galaxy
command.WithCollectionInstallOptions(options *AnsibleGalaxyCollectionInstallOptions) AnsibleGalaxyCollectionInstallOptionsFunc
: Set the collection install options for the command.WithCollectionNames(collectionNames ...string) AnsibleGalaxyCollectionInstallOptionsFunc
: Set the collection names for theansible-galaxy
command.
The AnsibleGalaxyCollectionInstallOptions
struct includes parameters described in the Options
section of the Ansible Galaxy manual page. It defines the behavior of the Ansible Galaxy collection installation operations and specifies where to find the configuration settings.
The github.com/apenella/go-ansible/v2/pkg/galaxy/role/install
package allows you to install roles from the Ansible Galaxy using the ansible-galaxy
command. The package provides the following structs and functions:
The AnsibleGalaxyRoleInstallCmd
struct enables the generation of ansible-galaxy
commands to install roles. It implements the Commander interface, so its method Command
returns an array of strings that represents the command to be executed. An executor can use it to create the command to be executed.
The package provides the NewAnsibleGalaxyRoleInstallCmd
function to create a new instance of the AnsibleGalaxyRoleInstallCmd
struct. The function accepts a list of options to customize the ansible-galaxy
command. The following functions are available:
WithBinary(binary string) AnsibleGalaxyRoleInstallOptionsFunc
: Set the binary for theansible-galaxy
command.WithGalaxyRoleInstallOptions(options *AnsibleGalaxyRoleInstallOptions) AnsibleGalaxyRoleInstallOptionsFunc
: Set the role install options for the command.WithRoleNames(roleNames ...string) AnsibleGalaxyRoleInstallOptionsFunc
: Set the role names for theansible-galaxy
command.
The AnsibleGalaxyRoleInstallOptions
struct includes parameters described in the Options
section of the Ansible Galaxy manual page. It defines the behavior of the Ansible Galaxy role installation operations and specifies where to find the configuration settings.
The information provided in this section gives an overview of the Inventory
package in go-ansible
.
The github.com/apenella/go-ansible/v2/pkg/inventory
package provides the functionality to execute ansible-inventory
. To perform these tasks, you can use the following inventory structs:
The AnsibleInventoryCmd
struct enables the generation of ansible-inventory
commands. It implements the Commander interface, so its method Command
returns an array of strings that represents the command to be executed. An executor can use it to create the command to be executed.
The package provides the NewAnsibleInventoryCmd
function to create a new instance of the AnsibleInventoryCmd
struct. The function accepts a list of options to customize the ansible-inventory
command. The following functions are available:
WithBinary(binary string) InventoryOptionsFunc
: Set the binary for theansible-inventory
command.WithInventoryOptions(options *AnsibleInventoryOptions) InventoryOptionsFunc
: Set the inventory options for the command.WithPattern(pattern string) InventoryOptionsFunc
: Set the pattern for theansible-inventory
command.
Note Unlike other Ansible commands, the
ansible-inventory
command does not provide privilege escalation or connection options, aligning with the functionality of the command itself.
The AnsibleInventoryExecute
struct serves as a streamlined executor for running ansible-inventory
commands. It encapsulates the setup process for both the command generator and executor. This executor is particularly useful when no additional configuration or customization is required.
The following methods are available to set attributes for the AnsibleInventoryCmd struct:
WithBinary(binary string) *AnsibleInventoryExecute
: The method sets theBinary
attribute.WithInventoryOptions(options *AnsibleAdhocOptions) *AnsibleInventoryExecute
: The method sets theInventoryOptions
attribute.WithPattern(pattern string) *AnsibleInventoryExecute
: The method sets thePattern
attribute.
Here is an example of launching an ansible-inventory
command using AnsibleInventoryExecute
:
err := inventory.NewAnsibleInventoryExecute().
WithInventoryOptions(&ansibleInventoryOptions).
WithPattern("all").
Execute(context.TODO())
if err != nil {
// Manage the error
}
The AnsibleInventoryOptions
struct includes parameters described in the Options
section of the Ansible manual page. It defines the behavior of the Ansible inventory operations and specifies where to find the configuration settings.
This section provides an overview of the playbook
package in the go-ansible library. Here are described its main components and functionalities.
The github.com/apenella/go-ansible/v2/pkg/playbook
package facilitates the generation of ansible-playbook commands. It does not execute the commands directly, but instead provides the necessary structs to generate the command to be executed by an executor. The playbook
package includes the following essential structs for executing ad-hoc commands:
The AnsiblePlaybookCmd
struct enables the generation of ansible-playbook commands. It implements the Commander interface, so its method Command
returns an array of strings that represents the command to be executed. An executor can use it to create the command to be executed.
The package provides the NewAnsiblePlaybookCmd
function to create a new instance of the AnsiblePlaybookCmd
struct. The function accepts a list of options to customize the ansible-playbook command. The following functions are available:
WithBinary(binary string) PlaybookOptionsFunc
: Set the binary for the ansible-playbook command.WithPlaybookOptions(options *AnsiblePlaybookOptions) PlaybookOptionsFunc
: Set the playbook options for the command.WithPlaybooks(playbooks ...string) PlaybookOptionsFunc
: Set the playbooks for the ansible-playbook command.
Next is an example of how to use the AnsiblePlaybookCmd
struct to generate an ansible-playbook command:
ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{
Connection: "local",
Become: true,
Inventory: "127.0.0.1,",
}
playbookCmd := playbook.NewAnsiblePlaybookCmd(
playbook.WithPlaybooks("site.yml"),
playbook.WithPlaybookOptions(ansiblePlaybookOptions),
)
// Generate the command to be executed
cmd, err := playbookCmd.Command()
if err != nil {
// Manage the error
}
The AnsiblePlaybookErrorEnrich
struct, that implements the ErrorEnricher interface, is responsible for enriching the error message when executing an ansible-playbook command. Based on the exit code of the command execution, the AnsiblePlaybookErrorEnrich
struct appends additional information to the error message. This additional information includes the exit code, the command that was executed, and the error message.
The AnsiblePlaybookExecute
struct serves as a streamlined executor for running ansible-playbook
command. It encapsulates the setup process for both the command generator and executor. Additionally, it provides the ability to enrich the error message when an error occurs during command execution.
This executor is particularly useful when no additional configuration or customization is required.
The following methods are available to set attributes for the AnsiblePlaybookCmd struct:
WithBinary(binary string) *AnsiblePlaybookExecute
: The method sets theBinary
attribute.WithPlaybookOptions(options *AnsiblePlaybookOptions) *AnsiblePlaybookExecute
: The method sets thePlaybookOptions
attribute.
Here is an example of launching an ansible-playbook
command using AnsiblePlaybookExecute
:
err := playbook.NewAnsiblePlaybookExecute("site.yml", "site2.yml").
WithPlaybookOptions(ansiblePlaybookOptions).
Execute(context.TODO())
if err != nil {
// Manage the error
}
With AnsiblePlaybookOptions
struct, you can define parameters described in Ansible's manual page's Options
section. It also allows you to define the connection options and privilege escalation options.
The github.com/apenella/go-ansible/v2/pkg/vault
package provides functionality to encrypt variables. It introduces the VariableVaulter
struct, which is responsible for creating a VaultVariableValue
from the value that you need to encrypt.
The VaultVariableValue
can return the instantiated variable in JSON format.
To perform the encryption, the vault
package relies on an Encrypter
interface implementation.
type Encrypter interface {
Encrypt(plainText string) (string, error)
}
The encryption functionality is implemented in the encrypt
package, which is described in the following section.
The github.com/apenella/go-ansible/v2/pkg/vault/encrypt
package is responsible for encrypting variables. It implements the Encrypter
interface defined in the github.com/apenella/go-ansible/v2/pkg/vault
package.
Currently, the package provides the EncryptString
struct, which supports the encryption of string variables. It utilizes the github.com/sosedoff/ansible-vault-go
library for encryption.
To use the EncryptString
struct, you need to instantiate it with a password reader. The password reader is responsible for providing the password used for encryption and it should implement the PasswordReader
interface:
type PasswordReader interface {
Read() (string, error)
}
Here's an example of how to instantiate the EncryptString
struct:
encrypt := NewEncryptString(
WithReader(
text.NewReadPasswordFromText(
text.WithText("secret"),
),
),
)
In this example, the text.NewReadPasswordFromText
function is used to create a password reader that reads the password from a text source. The WithText
option is used to specify the actual password value.
The go-ansible library provides a set of packages that can be used as PasswordReader
to read the password for encryption. The following sections describe these packages and how they can be used.
The github.com/apenella/go-ansible/v2/pkg/vault/password/envvars
package allows you to read the password from an environment variable. To use this package, you need to use the NewReadPasswordFromEnvVar
function and provide the name of the environment variable where the password is stored using the WithEnvVar
option:
reader := NewReadPasswordFromEnvVar(
WithEnvVar("VAULT_PASSWORD"),
)
In this example, the VAULT_PASSWORD
environment variable is specified as the source of the password. The NewReadPasswordFromEnvVar
function creates a password reader that reads the password from the specified environment variable.
Using the envvars
package, you can conveniently read the password from an environment variable and use it for encryption.
The github.com/apenella/go-ansible/v2/pkg/vault/password/file
package allows you to read the password from a file, using the afero file system abstraction.
To use this package, you need to instantiate the NewReadPasswordFromFile
function and provide the necessary options. The WithFs
option is used to specify the file system, and the WithFile
option is used to specify the path to the password file.
If you don't explicitly define a file system, the package uses the default file system, which is the OsFs from the github.com/spf13/afero
package. The OsFs represents the file system of your host machine.
Therefore, if you don't provide a specific file system using the WithFs
option when instantiating the password reader, the file package will automatically use the OsFs as the file system to read the password from a file.
Here's an example without specifying the file system:
reader := NewReadPasswordFromFile(
WithFile("/password"),
)
In this case, the OsFs will be used to access the /password
file on your host file system.
The github.com/apenella/go-ansible/v2/pkg/vault/password/resolve
package provides a mechanism to resolve the password by exploring multiple PasswordReader
implementations. It returns the first password obtained from any of the PasswordReader
instances.
To use this package, you need to create a NewReadPasswordResolve
instance and provide a list of PasswordReader
implementations as arguments to the WithReader
option:
reader := NewReadPasswordResolve(
WithReader(
envvars.NewReadPasswordFromEnvVar(
envvars.WithEnvVar("VAULT_PASSWORD"),
),
file.NewReadPasswordFromFile(
file.WithFs(testFs),
file.WithFile("/password"),
),
),
)
In this example, the ReadPasswordResolve
instance is created with two PasswordReader
implementations: one that reads the password from an environment variable (envvars.NewReadPasswordFromEnvVar
), and another that reads the password from a file (file.NewReadPasswordFromFile
).
The ReadPasswordResolve
will attempt to obtain the password from each PasswordReader
in the provided order. The first successful password read will be returned. It returns an error when no password is achieved.
Using the resolve
package, you can explore multiple PasswordReader
implementations to resolve the password for encryption.
The github.com/apenella/go-ansible/v2/pkg/vault/password/text
package provides functionality to read the password from a text source.
To use this package, you need to instantiate the NewReadPasswordFromText
function and provide the password as a text value using the WithText
option:
reader := NewReadPasswordFromText(
WithText("ThatIsAPassword"),
)
In this example, the password is directly specified as the text value "ThatIsAPassword" using the WithText
option.
The go-ansible library includes a variety of examples that demonstrate how to use the library in different scenarios. These examples can be found in the examples directory of the go-ansible repository.
The examples cover various use cases and provide practical demonstrations of utilizing different features and functionalities offered by go-ansible. They serve as a valuable resource to understand and learn how to integrate go-ansible into your applications.
Feel free to explore the examples directory to gain insights and ideas on how to leverage the go-ansible library in your projects.
Here you have a list of examples:
- ansibleadhoc-command-module
- ansibleadhoc-simple
- ansibleinventory-graph
- ansibleinventory-simple
- ansibleinventory-vaulted-vars
- ansibleplaybook-become
- ansibleplaybook-cobra-cmd
- ansibleplaybook-custom-transformer
- ansibleplaybook-extravars-file
- ansibleplaybook-extravars
- ansibleplaybook-json-stdout
- ansibleplaybook-myexecutor
- ansibleplaybook-signals-and-cancellation
- ansibleplaybook-simple-embedfs
- ansibleplaybook-simple-with-prompt
- ansibleplaybook-simple
- ansibleplaybook-skipping-failing
- ansibleplaybook-ssh
- ansibleplaybook-time-measurement
- ansibleplaybook-walk-through-json-output
- ansibleplaybook-with-executor-time-measurament
- ansibleplaybook-with-timeout
- ansibleplaybook-with-vaulted-extravar
- workflowexecute-simple
- workflowexecute-time-measurament
This section provides a reference guide for developing and contributing to the go-ansible library.
To set up a development environment for the go-ansible library, you need to have the following tools installed on your system:
- Docker Compose. The version used for development is
docker-compose version v2.26.1
. - Docker. The version used for development is
Docker version 26.0.1
. - Go. The version used for development is
1.22
. - make utility. The version used for development is
GNU Make 4.3
. It is used to wrap the continuous integration and development processes, such us testing or linting.
To run the tests, you can use the following command:
make test
To run the static analysis tools, you can use the following command:
make static-analysis
Thank you for your interest in contributing to go-ansible! All contributions are welcome, whether they are bug reports, feature requests, or code contributions. Please read the contributor's guide here to learn more about how to contribute.
The go-ansible project is committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, disability, ethnicity, religion, or similar personal characteristics.
We expect all contributors, users, and community members to follow this code of conduct. This includes all interactions within the go-ansible community, whether online, in person, or otherwise.
Please to know more about the code of conduct refer here.
The go-ansible library is available under MIT license.