diff --git a/.env b/.env new file mode 100644 index 0000000..acec581 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +GOLANG_VERSION=1.22 +GOLANGCI_LINT_VERSION=v1.57.2 \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8adc9e1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: testing + +on: + push: + branches: + - master + - fix/* + - feat/* + pull_request: + branches: + - master + +jobs: + static-analysis: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Execute go vet + run: | + make vet + + - name: Execute golangci-lint + run: | + make golangci-lint + + testing: + runs-on: ubuntu-latest + needs: static-analysis + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: git fetch --force --tags + + - name: Execute unit tests + run: | + make unit-test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b781d8..7b113b1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,20 +9,21 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - run: git fetch --force --tags + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: git fetch --force --tags - - uses: actions/setup-go@v3 - with: - go-version: ^1.19 - cache: true + - uses: actions/setup-go@v4 + with: + go-version: ^1.22 + cache: true - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v2 - with: - version: latest - args: release --rm-dist --release-notes RELEASE_NOTES.md - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v5 + with: + version: latest + args: release --rm-dist --release-notes RELEASE_NOTES.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml deleted file mode 100644 index cd93744..0000000 --- a/.github/workflows/testing.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: testing - -on: - push: - branches: - - master - - fix/* - - feat/* - pull_request: - branches: - - master - -jobs: - testing: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - run: git fetch --force --tags - - - uses: actions/setup-go@v3 - with: - go-version: ^1.19 - cache: true - - - name: Test - run: go test ./pkg/... -cover -count=1 - diff --git a/CHANGELOG.md b/CHANGELOG.md index a4c0313..9369279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,99 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v2.0.0 (2024-04-20) + +Version 2.0.0 of *go-ansible* introduces several disruptive changes. Read the upgrade guide carefully before proceeding with the upgrade. + +### BREAKING CHANGES + +> **Note** +> The latest major version of _go-ansible_, version _2.x_, introduced significant and breaking changes. If you are currently using a version prior to _2.x_, please refer to the [upgrade guide](https://github.com/apenella/go-ansible/blob/master/docs/upgrade_guide_to_2.x.md) for detailed information on how to migrate to version _2.x_. + +- The Go module name has been changed from `github.com/apenella/go-ansible` to `github.com/apenella/go-ansible/v2`. So, you need to update your import paths to use the new module name. +- The relationship between the executor and `AnsiblePlaybookCmd` / `AnsibleAdhocCmd` / `AnsibleInvetoryCmd` has undergone important changes. + - **Inversion of responsibilities**: The executor is now responsible for executing external commands, while `AnsiblePlaybookCmd`, `AnsibleInventoryCmd` and `AnsibleAdhocCmd` have cut down their responsibilities, primarily focusing on generating the command to be executed. + - **Method and Attribute Removal**: The following methods and attributes have been removed on `AnsiblePlaybookCmd`, `AnsibleInventoryCmd` and `AnsibleAdhocCmd`: + - The `Run` method. + - The `Exec` and `StdoutCallback` attributes. + - **Attributes Renaming**: The `Options` attribute has been renamed to `PlaybookOptions` in `AnsiblePlaybookCmd`, `AdhocOptions` in `AnsibleAdhocCmd` and `InventoryOptions` in `AnsibleInventoryCmd`. +- The `Executor` interface has undergone a significant signature change. This change entails the removal of the following arguments `resultsFunc` and `options`. The current signature is: `Execute(ctx context.Context) error`. +- The `github.com/apenella/go-ansible/pkg/options` package has been removed. After that deletion, the attributes from `AnsibleConnectionOptions` and `AnsiblePrivilegeEscalationOptions` attributes have been moved to the `PlaybookOptions`, `AdhocOptions` and `InventoryOptions` structs. +- The `github.com/apenella/go-ansible/pkg/stdoutcallback` package has been removed. Its responsibilities have been absorbed by two distinc packages `github.com/apenella/go-ansible/v2/pkg/execute/result`, which manages the output of the commands, and `github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback` that enables the setting of the stdout callback. +- The constants `AnsibleForceColorEnv` and `AnsibleHostKeyCheckingEnv` have been removed from the `github.com/apenella/go-ansible/pkg/options` package. +- The functions `AnsibleForceColor`, `AnsibleAvoidHostKeyChecking` and `AnsibleSetEnv` have been removed from the `github.com/apenella/go-ansible/pkg/options` package. Use the `ExecutorWithAnsibleConfigurationSettings` decorator instead defined in the `github.com/apenella/go-ansible/v2/pkg/execute/configuration` package. +- The methods `WithWrite` and `WithShowduration` have been removed from the `ExecutorTimeMeasurement` decorator. Instead, a new method named `Duration` has been introduced for obtaining the duration of the execution. +- In the `AnsiblePlaybookJSONResultsPlayTaskHostsItem` struct, the attributes `StdoutLines` and `StderrLines` have chnage their type from `[]string` to `[]interface{}`. + +### Fixed + +- Quote properly the attributes `SCPExtraArgs`, `SFTPExtraArgs`, `SSHCommonArgs`, `SSHExtraArgs` in `AnsibleAdhocOptions` and `AnsiblePlaybookOptions` structs when generating the command to be executed. #140 +- When using the JSON Stdout Callback method combined with enabled verbosity in the command, it causes an error during JSON parsing. To resolve this issue, the `DefaultExecute` struct includes the `Quiet` method, which removes verbosity from the executed command. #110 + +### Added + +- `AnsibleAdhocExecute` _executor_ has been introduced. That _executor_ allows you to create an executor to run `ansible` commands using the default settings of `DefaultExecute`. This _executor_ is located in the `github.com/apenella/go-ansible/v2/pkg/execute/adhoc` package. +- `AnsibleInventoryExecute` _executor_ has been introduced. That _executor_ allows you to create an executor to run `ansible-inventory` commands using the default settings of `DefaultExecute`. This _executor_ is located in the `github.com/apenella/go-ansible/v2/pkg/execute/inventory` package. +- `ansibleplaybook-embed-python` example to demonstrate how to use `go-ansible` library along with the `go-embed-python` package. +- `ansibleplaybook-extravars` example to show how to configure extra vars when running an Ansible playbook command. +- `ansibleplaybook-ssh` example to show how to execute an Ansible playbook using SSH as the connection method. +- `AnsiblePlaybookExecute` _executor_ has been introduced. That _executor_ allows you to create an executor to run `ansible-playbook` commands using the default settings of `DefaultExecute`. This _executor_ is located in the `github.com/apenella/go-ansible/v2/pkg/execute/playbook` package. +- `Commander` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute` package. This interface defines the criteria for a struct to be compliant in generating execution commands. +- `ErrorEnricher` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute` package. This interface defines the criteria for a struct to be compliant in enriching the error message of the command execution. +- `Executabler` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute` package. This interface defines the criteria for a struct to be compliant in executing external commands. +- `ExecutorEnvVarSetter` interface in `github.com/apenella/go-ansible/v2/pkg/execute/configuration` defines the criteria for a struct to be compliant in setting Ansible configuration. +- `ExecutorQuietStdoutCallbackSetter` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback` package. This interface defines the criteria for a struct to be compliant in setting an executor that accepts the stdout callback configuration and that enables the `Quiet` method for Ansible executions. +- `ExecutorStdoutCallbackSetter` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback` package. This interface defines the criteria for a struct to be compliant in setting an executor that accepts the stdout callback configuration for Ansible executions. +- `github.com/apenella/go-ansible/v2/internal/executable/os/exec` package has been introduced. This package serves as a wrapper for `os.exec`. +- `github.com/apenella/go-ansible/v2/pkg/execute/configuration` package includes the `ExecutorWithAnsibleConfigurationSettings` struct, which acts as a decorator that facilitates the configuration of Ansible settings within the executor. +- `github.com/apenella/go-ansible/v2/pkg/execute/result/default` package has been introduced. This package offers the default component for printing execution results. It supersedes the `DefaultStdoutCallbackResults` function that was previously defined in the `github.com/apenella/go-ansible/v2/pkg/stdoutcallback` package. +- `github.com/apenella/go-ansible/v2/pkg/execute/result/json` package has been introduced. This package offers the component for printing execution results from the JSON stdout callback. It supersedes the `JSONStdoutCallbackResults` function that was previously defined in the `github.com/apenella/go-ansible/v2/pkg/stdoutcallback` package. +- `github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback`. package has been introduced and offers multiple decorators designed to set the stdout callback for Ansible executions. +- `github.com/apenella/go-ansible/v2/pkg/execute/workflow` package has been introduced and allows you to define a workflow for executing multiple commands in a sequence. +- `github.com/apenella/go-ansible/v2/pkg/galaxy/collection/install` package has been introduced. This package allows you to install Ansible collections from the Ansible Galaxy. Along with this package, the example `workflowexecute-ansibleplaybook-with-galaxy-install-collection` has been added to demonstrate how to install an Ansible collection and execute an Ansible playbook in a sequence. +- `github.com/apenella/go-ansible/v2/pkg/galaxy/role/install` package has been introduced. This package allows you to install Ansible roles from the Ansible Galaxy. Along with this package, the example `workflowexecute-ansibleplaybook-with-galaxy-install-role` has been added to demonstrate how to install an Ansible role and execute an Ansible playbook in a sequence. +- `golangci-lint` has been added to the CI/CD pipeline to ensure the code quality. +- `NewAnsibleAdhocCmd`, `NewAnsibleInventoryCmd` and `NewAnsiblePlaybookCmd` functions have been introduced. These functions are responsible for creating the `AnsibleAdhocCmd`, `AnsibleInventoryCmd` and `AnsiblePlaybookCmd` structs, respectively. +- `Path` attribute has been added to the `AnsiblePlaybookJSONResultsPlayTaskHostsItem` struct. +- `ResultsOutputer` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute/result` package. This interface defines the criteria for a struct to be compliant in printing execution results. +- A utility to generate the code for the configuration package has been introduced. This utility is located in the `utils/cmd/configGenerator.go`. +- The `Quiet` method has been added to the `DefaultExecute` struct. This method forces to remove verbosity from the executed command. + +### Changed + +- `DefaultExecute` used the `String` method from the `Commander` to include the command in the error message when the execution fails, instead of using the the `String` method from the `os/exec.Cmd` struct. +- In the `AnsiblePlaybookJSONResultsPlayTaskHostsItem` struct, the attributes `StdoutLines` and `StderrLines` have chnage their type from `[]string` to `[]interface{}`. +- The `AnsibleAdhocCmd` struct has been updated to implement the `Commander` interface. +- The `AnsibleInventoryCmd` struct has been updated to implement the `Commander` interface. +- The `AnsiblePlaybookCmd` struct has been updated to implement the `Commander` interface. +- The `AnsiblePlaybookOptions` and `AnsibleAdhocOptions` structs have been updated to include the attributes from `AnsibleConnectionOptions` and `AnsiblePrivilegeEscalationOptions`. +- The `DefaultExecute` struct has been updated to have a new attribute named `Exec` of type `Executabler` that is responsible for executing external commands. +- The `DefaultExecute` struct has been updated to have a new attribute named `Output` of type `ResultsOutputer` that is responsible for printing the execution's output. +- The `DefaultExecute` struct has been updated to implement the `Executor` interface. +- The `DefaultExecute` struct has been updated to implement the `ExecutorEnvVarSetter` interface. +- The `DefaultExecute` struct has been updated to implement the `ExecutorStdoutCallbackSetter` interface. +- The `Execute` method in the `DefaultExecute` struct has been updated to return an error on the deferred function when the command execution fails. +- The `Options` attribute in `AnsibleAdhocCmd` struct has been renamed to `AdhocOptions`. +- The `Options` attribute in `AnsibleInventoryCmd` struct has been renamed to `InventoryOptions`. +- The `Options` attribute in `AnsiblePlaybookCmd` struct has been renamed to `PlaybookOptions`. +- The `Read` method in the `ReadPasswordFromEnvVar` struct from the `github.com/apenella/go-ansible/v2/vault/password/envvars` package has been updated to log a warning message when the environment variable is not set. +- The examples has been adapted to use executor as the component to execute Ansible commands. +- The package `github.com/apenella/go-ansible/pkg/stdoutcallback/result/transformer` has been moved to `github.com/apenella/go-ansible/v2/pkg/execute/result/transformer`. +- Upgrade the Go version from `1.19` to `1.22`. + +### Removed + +- Remove from `DefaultExecute` ansible-playbook error enrichment. +- The `Exec` attribute has been removed from `AnsiblePlaybookCmd` and `AdhocPlaybookCmd`. +- The `github.com/apenella/go-ansible/pkg/options` package has been removed. After the `AnsibleConnectionOptions` and `AnsiblePrivilegeEscalationOptions` structs are not available anymore. +- The `github.com/apenella/go-ansible/pkg/stdoutcallback` package has been removed. +- The `Run` method has been removed from the `AnsiblePlaybookCmd` and `AdhocPlaybookCmd` structs. +- The `ShowDuration` attribute in the `DefaultExecute` struct has been removed. +- The `StdoutCallback` attribute has been removed from `AnsiblePlaybookCmd` and `AdhocPlaybookCmd`. +- The constants `AnsibleForceColorEnv` and `AnsibleHostKeyCheckingEnv` have been removed from the `github.com/apenella/go-ansible/pkg/options` package. +- The functions `AnsibleForceColor`, `AnsibleAvoidHostKeyChecking` and `AnsibleSetEnv` have been removed from the `github.com/apenella/go-ansible/pkg/options` package. Use the `ExecutorWithAnsibleConfigurationSettings` decorator instead defined in the `github.com/apenella/go-ansible/v2/pkg/execute/configuration` package. +- The methods `WithWrite` and `withshowduration` have been removed from the `ExecutorTimeMeasurement` decorator. + ## v2.0.0-rc.3 Version 2.0.0 of *go-ansible* introduces several disruptive changes. Read the upgrade guide carefully before proceeding with the upgrade. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5cc47b6 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +# dafault target +.DEFAULT_GOAL: help + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +GOLANG_BINARY := $(DOCKER_COMPOSE_BINARY) run --rm golang-ci go +GOLANGCI_LINT_BINARY := $(DOCKER_COMPOSE_BINARY) run --rm golangci-lint + +## Colors +COLOR_GREEN=\033[0;32m +COLOR_RED=\033[0;31m +COLOR_BLUE=\033[0;34m +COLOR_END=\033[0m + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +static-analysis: vet golangci-lint ## Executes all static analysis tools +test: unit-test + +vet: ## Executes the go vet + @echo + @echo "$(COLOR_GREEN) Executing go vet $(COLOR_END)" + @echo + @$(GOLANG_BINARY) vet ./pkg/... + @$(GOLANG_BINARY) vet ./internal/... + +golangci-lint: ## Executes golangci-lint + @echo + @echo "$(COLOR_GREEN) Executing golangci-lint $(COLOR_END)" + @echo + @$(GOLANGCI_LINT_BINARY) run + +unit-test: ## Run unit tests + @echo + @echo "$(COLOR_GREEN) Running unit tests...$(COLOR_END)" + @echo + @$(GOLANG_BINARY) test ./pkg/... -cover -count=1 + @$(GOLANG_BINARY) test ./internal/... -cover -count=1 + +list-examples: ## List all examples + @echo + @echo "$(COLOR_GREEN) Listing all examples...$(COLOR_END)" + @echo + @ls -1 examples + +attach-golang-ci: ## Attach to golang-ci Docker compose service + @echo + @echo "$(COLOR_GREEN) Attaching to golangci-lint Docker compose service...$(COLOR_END)" + @echo + @$(DOCKER_COMPOSE_BINARY) run --rm golang-ci /bin/sh diff --git a/README.md b/README.md index eaf31ff..200d50d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # go-ansible -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![Test](https://github.com/apenella/go-ansible/actions/workflows/testing.yml/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/apenella/go-ansible)](https://goreportcard.com/report/github.com/apenella/go-ansible) [![Go Reference](https://pkg.go.dev/badge/github.com/apenella/go-ansible.svg)](https://pkg.go.dev/github.com/apenella/go-ansible) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![Test](https://github.com/apenella/go-ansible/actions/workflows/ci.yml/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/apenella/go-ansible/v2)](https://goreportcard.com/report/github.com/apenella/go-ansible/v2) [![Go Reference](https://pkg.go.dev/badge/github.com/apenella/go-ansible/v2.svg)](https://pkg.go.dev/github.com/apenella/go-ansible/v2) ![go-ansible-logo](docs/logo/go-ansible_logo.png "Go-ansible Logo" ) @@ -38,6 +38,7 @@ _**Important:** The master branch may contain unreleased or pre-released feature - [Execute package](#execute-package) - [Executor interface](#executor-interface) - [Commander interface](#commander-interface) + - [ErrorEnricher interface](#errorenricher-interface) - [Executabler interface](#executabler-interface) - [DefaultExecute struct](#defaultexecute-struct) - [Defining a Custom Executor](#defining-a-custom-executor) @@ -54,6 +55,7 @@ _**Important:** The master branch may contain unreleased or pre-released feature - [Transformer functions](#transformer-functions) - [Stdoutcallback package](#stdoutcallback-package) - [ExecutorStdoutCallbackSetter interface](#executorstdoutcallbacksetter-interface) + - [ExecutorQuietStdoutCallbackSetter interface](#executorquietstdoutcallbacksetter-interface) - [Stdout Callback Execute structs](#stdout-callback-execute-structs) - [Workflow package](#workflow-package) - [WorkflowExecute struct](#workflowexecute-struct) @@ -70,6 +72,7 @@ _**Important:** The master branch may contain unreleased or pre-released feature - [AnsibleInventoryOptions struct](#ansibleinventoryoptions-struct) - [Playbook package](#playbook-package) - [AnsiblePlaybookCmd struct](#ansibleplaybookcmd-struct) + - [AnsiblePlaybookErrorEnrich struct](#ansibleplaybookerrorenrich-struct) - [AnsiblePlaybookExecute struct](#ansibleplaybookexecute-struct) - [AnsiblePlaybookOptions struct](#ansibleplaybookoptions-struct) - [Vault package](#vault-package) @@ -80,7 +83,11 @@ _**Important:** The master branch may contain unreleased or pre-released feature - [Resolve](#resolve) - [Text](#text) - [Examples](#examples) - - [Contributing](#contributing) + - [Development Reference](#development-reference) + - [Development Environment](#development-environment) + - [Testing](#testing) + - [Static Analysis](#static-analysis) + - [Contributing](#contributing) - [Code Of Conduct](#code-of-conduct) - [License](#license) @@ -89,10 +96,10 @@ _**Important:** The master branch may contain unreleased or pre-released feature Use this command to fetch and install the _go-ansible_ module. You can install the release candidate version by executing the following command: ```sh -go get github.com/apenella/go-ansible/v2@v2.0.0-rc.3 +go get github.com/apenella/go-ansible/v2@v2.0.0 ``` -You can also install the latest stable version by executing the following command: +You can also install the previous stable version by executing the following command: ```sh go get github.com/apenella/go-ansible @@ -311,6 +318,18 @@ The `Commander` interface defines components responsible for generating the comm ```go type Commander interface { Command() ([]string, error) + String() string +} +``` + +#### ErrorEnricher interface + +The `ErrorEnricher` interface defines components responsible for enriching the error message. The [AnsiblePlaybookErrorEnrich](#ansibleplaybookerrorenrich-struct) struct implements this interface. +The [DefaultExecute](#defaultexecute-struct) struct uses this interface to enrich the error message. Below is the definition of the `ErrorEnricher` interface: + +```go +type ErrorEnricher interface { + Enrich(err error) error } ``` @@ -343,6 +362,7 @@ The following functions can be provided when creating a new instance of the `Def - `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. @@ -652,6 +672,21 @@ type ExecutorStdoutCallbackSetter interface { } ``` +###### ExecutorQuietStdoutCallbackSetter interface + +The `ExecutorQuietStdoutCallbackSetter` interface in the `github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback` package extends the [ExecutorStdoutCallbackSetter](#executorstdoutcallbacksetter-interface) interface with the capability to remove the verbosity of the command execution output. The [DefaultExecute](#defaultexecute-struct) struct implements this interface, allowing you to silence the output of the command execution. + +That interface is required by the [JSONStdoutCallbackExecute](#stdout-callback-execute-structs) struct to remove the verbosity of the command execution output. + +The next code snippet shows the definition of the `ExecutorQuietStdoutCallbackSetter` interface: + +```go +type ExecutorQuietStdoutCallbackSetter interface { + ExecutorStdoutCallbackSetter + Quiet() +} +``` + ###### Stdout Callback Execute structs 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](#executorstdoutcallbacksetter-interface), allowing seamless integration of different stdout callback plugins with command execution. @@ -844,9 +879,14 @@ if err != nil { } ``` +#### AnsiblePlaybookErrorEnrich struct + +The `AnsiblePlaybookErrorEnrich` struct, that implements the [ErrorEnricher](#errorenricher-interface) 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. + #### AnsiblePlaybookExecute struct -The `AnsiblePlaybookExecute` struct serves as a streamlined [executor](#executor) for running `ansible-playbook` command. It encapsulates the setup process for both the [command generator](#command-generator) and _executor_. This _executor_ is particularly useful when no additional configuration or customization is required. +The `AnsiblePlaybookExecute` struct serves as a streamlined [executor](#executor) for running `ansible-playbook` command. It encapsulates the setup process for both the [command generator](#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](#ansibleplaybookcmd-struct) struct: @@ -1027,7 +1067,36 @@ Here you have a list of examples: - [workflowexecute-simple](https://github.com/apenella/go-ansible/tree/master/examples/workflowexecute-simple) - [workflowexecute-time-measurament](https://github.com/apenella/go-ansible/tree/master/examples/workflowexecute-time-measurament) -## Contributing +## Development Reference + +This section provides a reference guide for developing and contributing to the _go-ansible_ library. + +### Development Environment + +To set up a development environment for the _go-ansible_ library, you need to have the following tools installed on your system: + +- [Docker Compose](https://docs.docker.com/compose/). The version used for development is `docker-compose version v2.26.1`. +- [Docker](https://docs.docker.com/engine/reference/commandline/cli/). The version used for development is `Docker version 26.0.1`. +- [Go](https://golang.org/). The version used for development is `1.22`. +- [make](https://www.gnu.org/software/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. + +#### Testing + +To run the tests, you can use the following command: + +```bash +make test +``` + +#### Static Analysis + +To run the static analysis tools, you can use the following command: + +```bash +make static-analysis +``` + +### Contributing 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](https://github.com/apenella/go-ansible/blob/master/CONTRIBUTING.md) to learn more about how to contribute. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f33345b..0440887 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,6 @@ # Release notes -## v2.0.0-rc.3 +## v2.0.0 (2024-04-20) Version 2.0.0 of *go-ansible* introduces several disruptive changes. Read the upgrade guide carefully before proceeding with the upgrade. @@ -22,21 +22,26 @@ Version 2.0.0 of *go-ansible* introduces several disruptive changes. Read the up - The constants `AnsibleForceColorEnv` and `AnsibleHostKeyCheckingEnv` have been removed from the `github.com/apenella/go-ansible/pkg/options` package. - The functions `AnsibleForceColor`, `AnsibleAvoidHostKeyChecking` and `AnsibleSetEnv` have been removed from the `github.com/apenella/go-ansible/pkg/options` package. Use the `ExecutorWithAnsibleConfigurationSettings` decorator instead defined in the `github.com/apenella/go-ansible/v2/pkg/execute/configuration` package. - The methods `WithWrite` and `WithShowduration` have been removed from the `ExecutorTimeMeasurement` decorator. Instead, a new method named `Duration` has been introduced for obtaining the duration of the execution. +- In the `AnsiblePlaybookJSONResultsPlayTaskHostsItem` struct, the attributes `StdoutLines` and `StderrLines` have chnage their type from `[]string` to `[]interface{}`. ### Fixed - Quote properly the attributes `SCPExtraArgs`, `SFTPExtraArgs`, `SSHCommonArgs`, `SSHExtraArgs` in `AnsibleAdhocOptions` and `AnsiblePlaybookOptions` structs when generating the command to be executed. #140 +- When using the JSON Stdout Callback method combined with enabled verbosity in the command, it causes an error during JSON parsing. To resolve this issue, the `DefaultExecute` struct includes the `Quiet` method, which removes verbosity from the executed command. #110 ### Added - `AnsibleAdhocExecute` _executor_ has been introduced. That _executor_ allows you to create an executor to run `ansible` commands using the default settings of `DefaultExecute`. This _executor_ is located in the `github.com/apenella/go-ansible/v2/pkg/execute/adhoc` package. - `AnsibleInventoryExecute` _executor_ has been introduced. That _executor_ allows you to create an executor to run `ansible-inventory` commands using the default settings of `DefaultExecute`. This _executor_ is located in the `github.com/apenella/go-ansible/v2/pkg/execute/inventory` package. +- `ansibleplaybook-embed-python` example to demonstrate how to use `go-ansible` library along with the `go-embed-python` package. - `ansibleplaybook-extravars` example to show how to configure extra vars when running an Ansible playbook command. - `ansibleplaybook-ssh` example to show how to execute an Ansible playbook using SSH as the connection method. - `AnsiblePlaybookExecute` _executor_ has been introduced. That _executor_ allows you to create an executor to run `ansible-playbook` commands using the default settings of `DefaultExecute`. This _executor_ is located in the `github.com/apenella/go-ansible/v2/pkg/execute/playbook` package. - `Commander` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute` package. This interface defines the criteria for a struct to be compliant in generating execution commands. +- `ErrorEnricher` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute` package. This interface defines the criteria for a struct to be compliant in enriching the error message of the command execution. - `Executabler` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute` package. This interface defines the criteria for a struct to be compliant in executing external commands. - `ExecutorEnvVarSetter` interface in `github.com/apenella/go-ansible/v2/pkg/execute/configuration` defines the criteria for a struct to be compliant in setting Ansible configuration. +- `ExecutorQuietStdoutCallbackSetter` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback` package. This interface defines the criteria for a struct to be compliant in setting an executor that accepts the stdout callback configuration and that enables the `Quiet` method for Ansible executions. - `ExecutorStdoutCallbackSetter` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback` package. This interface defines the criteria for a struct to be compliant in setting an executor that accepts the stdout callback configuration for Ansible executions. - `github.com/apenella/go-ansible/v2/internal/executable/os/exec` package has been introduced. This package serves as a wrapper for `os.exec`. - `github.com/apenella/go-ansible/v2/pkg/execute/configuration` package includes the `ExecutorWithAnsibleConfigurationSettings` struct, which acts as a decorator that facilitates the configuration of Ansible settings within the executor. @@ -46,12 +51,17 @@ Version 2.0.0 of *go-ansible* introduces several disruptive changes. Read the up - `github.com/apenella/go-ansible/v2/pkg/execute/workflow` package has been introduced and allows you to define a workflow for executing multiple commands in a sequence. - `github.com/apenella/go-ansible/v2/pkg/galaxy/collection/install` package has been introduced. This package allows you to install Ansible collections from the Ansible Galaxy. Along with this package, the example `workflowexecute-ansibleplaybook-with-galaxy-install-collection` has been added to demonstrate how to install an Ansible collection and execute an Ansible playbook in a sequence. - `github.com/apenella/go-ansible/v2/pkg/galaxy/role/install` package has been introduced. This package allows you to install Ansible roles from the Ansible Galaxy. Along with this package, the example `workflowexecute-ansibleplaybook-with-galaxy-install-role` has been added to demonstrate how to install an Ansible role and execute an Ansible playbook in a sequence. +- `golangci-lint` has been added to the CI/CD pipeline to ensure the code quality. - `NewAnsibleAdhocCmd`, `NewAnsibleInventoryCmd` and `NewAnsiblePlaybookCmd` functions have been introduced. These functions are responsible for creating the `AnsibleAdhocCmd`, `AnsibleInventoryCmd` and `AnsiblePlaybookCmd` structs, respectively. +- `Path` attribute has been added to the `AnsiblePlaybookJSONResultsPlayTaskHostsItem` struct. - `ResultsOutputer` interface has been introduced in the `github.com/apenella/go-ansible/v2/pkg/execute/result` package. This interface defines the criteria for a struct to be compliant in printing execution results. - A utility to generate the code for the configuration package has been introduced. This utility is located in the `utils/cmd/configGenerator.go`. +- The `Quiet` method has been added to the `DefaultExecute` struct. This method forces to remove verbosity from the executed command. ### Changed +- `DefaultExecute` used the `String` method from the `Commander` to include the command in the error message when the execution fails, instead of using the the `String` method from the `os/exec.Cmd` struct. +- In the `AnsiblePlaybookJSONResultsPlayTaskHostsItem` struct, the attributes `StdoutLines` and `StderrLines` have chnage their type from `[]string` to `[]interface{}`. - The `AnsibleAdhocCmd` struct has been updated to implement the `Commander` interface. - The `AnsibleInventoryCmd` struct has been updated to implement the `Commander` interface. - The `AnsiblePlaybookCmd` struct has been updated to implement the `Commander` interface. @@ -61,14 +71,18 @@ Version 2.0.0 of *go-ansible* introduces several disruptive changes. Read the up - The `DefaultExecute` struct has been updated to implement the `Executor` interface. - The `DefaultExecute` struct has been updated to implement the `ExecutorEnvVarSetter` interface. - The `DefaultExecute` struct has been updated to implement the `ExecutorStdoutCallbackSetter` interface. +- The `Execute` method in the `DefaultExecute` struct has been updated to return an error on the deferred function when the command execution fails. - The `Options` attribute in `AnsibleAdhocCmd` struct has been renamed to `AdhocOptions`. - The `Options` attribute in `AnsibleInventoryCmd` struct has been renamed to `InventoryOptions`. - The `Options` attribute in `AnsiblePlaybookCmd` struct has been renamed to `PlaybookOptions`. +- The `Read` method in the `ReadPasswordFromEnvVar` struct from the `github.com/apenella/go-ansible/v2/vault/password/envvars` package has been updated to log a warning message when the environment variable is not set. - The examples has been adapted to use executor as the component to execute Ansible commands. - The package `github.com/apenella/go-ansible/pkg/stdoutcallback/result/transformer` has been moved to `github.com/apenella/go-ansible/v2/pkg/execute/result/transformer`. +- Upgrade the Go version from `1.19` to `1.22`. ### Removed +- Remove from `DefaultExecute` ansible-playbook error enrichment. - The `Exec` attribute has been removed from `AnsiblePlaybookCmd` and `AdhocPlaybookCmd`. - The `github.com/apenella/go-ansible/pkg/options` package has been removed. After the `AnsibleConnectionOptions` and `AnsiblePrivilegeEscalationOptions` structs are not available anymore. - The `github.com/apenella/go-ansible/pkg/stdoutcallback` package has been removed. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..54bd350 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +services: + golang-ci: + image: golang:${GOLANG_VERSION:-1.19}-alpine + volumes: + - .:/app + working_dir: /app + command: ["go", "version"] + + golangci-lint: + image: golangci/golangci-lint:${GOLANGCI_LINT_VERSION:-v1.57.2}-alpine + volumes: + - .:/app + working_dir: /app + entrypoint: ["golangci-lint"] + command: ["--version"] diff --git a/docs/upgrade_guide_to_2.x.md b/docs/upgrade_guide_to_2.x.md index e2ceb4f..7a3c4eb 100644 --- a/docs/upgrade_guide_to_2.x.md +++ b/docs/upgrade_guide_to_2.x.md @@ -5,6 +5,7 @@ This document offers guidance for upgrading from _go-ansible_ _v1.x_ to _v2.x_. It also presents the changes introduced in _go-ansible v2.0.0_ since the major version _1.x_. Some of these are breaking changes. The most relevant change is that the package name has been changed from `github.com/apenella/go-ansible` to `github.com/apenella/go-ansible/v2`. So, you need to update your import paths to use the new module name. + Another important change to highlight is that command structs no longer execute commands. So, `AnsiblePlaybookCmd` and `AnsibleAdhocCmd` do not require an `Executor` anymore. Instead, the `Executor` is responsible for the command execution. To achieve that, the `Executor` depends on the command structs to generate the commands to execute. That change is motivated by the need to segregate the command generation from the command execution. Having the `Executor` as the central component of the command execution process allows the `Executor` to be more flexible and customizable. The _go-ansible_ library provides a set of decorator structs to configure the `Executor` with different features, such as stdout callback management, and Ansible configuration settings. @@ -15,8 +16,10 @@ Proceed through the following sections to understand the changes in version _2.x - [Changes on the interfaces](#changes-on-the-interfaces) - [Added _Cmder_ interface](#added-cmder-interface) - [Added _Commander_ interface](#added-commander-interface) + - [Added _ErrorEnricher_ interface](#added-errorenricher-interface) - [Added _Executabler_ interface](#added-executabler-interface) - [Added _ExecutorEnvVarSetter_ interface](#added-executorenvvarsetter-interface) + - [Added _ExecutorQuietStdoutCallbackSetter_ interface](#added-executorquietstdoutcallbacksetter-interface) - [Added _ExecutorStdoutCallbackSetter_ interface](#added-executorstdoutcallbacksetter-interface) - [Added _ResultsOutputer_ interface](#added-resultsoutputer-interface) - [Updated _Executor_ interface](#updated-executor-interface) @@ -28,9 +31,11 @@ Proceed through the following sections to understand the changes in version _2.x - [Replacing the _options_ argument](#replacing-the-options-argument) - [Changes on the _DefaultExecute_ struct](#changes-on-the-defaultexecute-struct) - [Adding _Cmd_ attribute to generate commands](#adding-cmd-attribute-to-generate-commands) + - [Adding _ErrorEnrich_ attribute to enrich error messages](#adding-errorenrich-attribute-to-enrich-error-messages) - [Adding _Exec_ attribute for running external commands](#adding-exec-attribute-for-running-external-commands) - [Adding _Output_ attribute for printing execution results](#adding-output-attribute-for-printing-execution-results) - [Removing the _ShowDuration_ attribute](#removing-the-showduration-attribute) + - [Removing the error enrichment for ansible-playbook commands](#removing-the-error-enrichment-for-ansible-playbook-commands) - [Changing the _Transformer_ location](#changing-the-transformer-location) - [Changes on the _AnsiblePlaybookCmd_ struct](#changes-on-the-ansibleplaybookcmd-struct) - [Renaming the _Options_ attribute](#renaming-the-options-attribute) @@ -82,6 +87,18 @@ The `AnsiblePlaybookCmd` and `AnsibleAdhocCmd` structs implement the `Commander` // Commander generates commands to be executed type Commander interface { Command() ([]string, error) + String() string +} +``` + +### Added _ErrorEnricher_ interface + +The `ErrorEnricher` interface defined in _github.com/apenella/go-ansible/v2/pkg/execute_ is used to enrich the error message. The `DefaultExecute` struct uses that enable you to append additional information to the error message when an error occurs. + +```go +// ErrorEnricher interface to enrich and customize errors +type ErrorEnricher interface { + Enrich(err error) error } ``` @@ -113,6 +130,20 @@ type ExecutorEnvVarSetter interface { } ``` +### Added _ExecutorQuietStdoutCallbackSetter_ interface + +The `ExecutorQuietStdoutCallbackSetter` interface defined in _github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback_ extends the [ExecutorStdoutCallbackSetter](#added-executorstdoutcallbacksetter-interface) interface by adding the `Quiet` method to remove the verbosity of the command execution. + +```go +// ExecutorQuietStdoutCallbackSetter extends the ExecutorStdoutCallbackSetter interface by adding a method to force the non-verbose mode in the Stdout Callback configuration +type ExecutorQuietStdoutCallbackSetter interface { + // ExecutorStdoutCallbackSetter interface defined in github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback + ExecutorStdoutCallbackSetter + // Quiet removes the verbosity of the command execution + Quiet() +} +``` + ### Added _ExecutorStdoutCallbackSetter_ interface The `ExecutorStdoutCallbackSetter` interface defined in _github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback_ is used to set the stdout callback method to the executor. It is required by the stdout callback decorator structs defined in the same package. @@ -260,6 +291,21 @@ exec := execute.NewDefaultExecute( In the above example, `playbookCmd` is of type `Commander`. The `Cmd` value is set to `playbookCmd` using the `WithCmd` function when instantiating a new `DefaultExecute`. The `DefaultExecute` will then use `playbookCmd` to generate the command for execution. +### Adding _ErrorEnrich_ attribute to enrich error messages + +The `ErrorEnrich` attribute provides the component responsible for enriching error messages. The `DefaultExecute` struct uses the `ErrorEnricher` interface to append additional information to the error message when an error occurs. + +You can set that attribute when you instantiate the `DefaultExecute` struct. The following code snippet demonstrates how to instantiate a `DefaultExecute` struct with a custom `ErrorEnricher`: + +```go +exec := execute.NewDefaultExecute( + execute.WithCmd(cmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), +) +``` + +That is related to the [Removing the error enrichment for ansible-playbook commands](#removing-the-error-enrichment-for-ansible-playbook-commands). + ### Adding _Exec_ attribute for running external commands The `DefaultExecute` now includes the `Exec` attribute of type `Executabler`. The `Exec` component is responsible for executing external commands. If you do not define the `Exec` attribute, it defaults to using the `OsExec` struct, which wraps the `os/exec` package. @@ -345,6 +391,12 @@ if err != nil { fmt.Println("Duration: ", exec.Duration().String()) ``` +### Removing the error enrichment for ansible-playbook commands + +The `DefaultExecute` struct used to enrich the error message based on the exit code. Those enrichments are no longer available by default. The main reason is because those enrichments were based on the _ansible-playbook_ command exit code. However, the `DefaultExecute` is provided by the attribute `ErrorEnrich` to allow you to enrich the error messages. + +That is related to [Adding _ErrorEnrich_ attribute to enrich error messages](#adding-errorenrich-attribute-to-enrich-error-messages). + ### Changing the _Transformer_ location If you configure transformers to modify the output of the execution's results, note that the _transformer_ package in the _go-ansible_ library has been relocated. It was moved from _github.com/apenella/go-ansible/pkg/stdoutcallback/results_ to _github.com/apenella/go-ansible/v2/pkg/execute/result/transformer_. Therefore, ensure that your code is adapted to this updated location. diff --git a/examples/ansibleadhoc-command-module/.env b/examples/ansibleadhoc-command-module/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleadhoc-command-module/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleadhoc-command-module/Makefile b/examples/ansibleadhoc-command-module/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleadhoc-command-module/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleadhoc-command-module/docker-compose.yaml b/examples/ansibleadhoc-command-module/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleadhoc-command-module/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleadhoc-command-module/docker/ansible/Dockerfile b/examples/ansibleadhoc-command-module/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleadhoc-command-module/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleadhoc-simple/.env b/examples/ansibleadhoc-simple/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleadhoc-simple/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleadhoc-simple/Makefile b/examples/ansibleadhoc-simple/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleadhoc-simple/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleadhoc-simple/docker-compose.yaml b/examples/ansibleadhoc-simple/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleadhoc-simple/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleadhoc-simple/docker/ansible/Dockerfile b/examples/ansibleadhoc-simple/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleadhoc-simple/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleinventory-graph/.env b/examples/ansibleinventory-graph/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleinventory-graph/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleinventory-graph/Makefile b/examples/ansibleinventory-graph/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleinventory-graph/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleinventory-graph/docker-compose.yaml b/examples/ansibleinventory-graph/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleinventory-graph/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleinventory-graph/docker/ansible/Dockerfile b/examples/ansibleinventory-graph/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleinventory-graph/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleinventory-simple/.env b/examples/ansibleinventory-simple/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleinventory-simple/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleinventory-simple/Makefile b/examples/ansibleinventory-simple/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleinventory-simple/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleinventory-simple/docker-compose.yaml b/examples/ansibleinventory-simple/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleinventory-simple/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleinventory-simple/docker/ansible/Dockerfile b/examples/ansibleinventory-simple/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleinventory-simple/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleinventory-vaulted-vars/.env b/examples/ansibleinventory-vaulted-vars/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleinventory-vaulted-vars/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleinventory-vaulted-vars/Makefile b/examples/ansibleinventory-vaulted-vars/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleinventory-vaulted-vars/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleinventory-vaulted-vars/ansible-inventory-vaulted-vars.go b/examples/ansibleinventory-vaulted-vars/ansibleinventory-vaulted-vars.go similarity index 100% rename from examples/ansibleinventory-vaulted-vars/ansible-inventory-vaulted-vars.go rename to examples/ansibleinventory-vaulted-vars/ansibleinventory-vaulted-vars.go diff --git a/examples/ansibleinventory-vaulted-vars/docker-compose.yaml b/examples/ansibleinventory-vaulted-vars/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleinventory-vaulted-vars/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleinventory-vaulted-vars/docker/ansible/Dockerfile b/examples/ansibleinventory-vaulted-vars/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleinventory-vaulted-vars/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-become/.env b/examples/ansibleplaybook-become/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-become/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-become/Makefile b/examples/ansibleplaybook-become/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-become/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-become/ansibleplaybook-become.go b/examples/ansibleplaybook-become/ansibleplaybook-become.go index efb146e..4ead627 100644 --- a/examples/ansibleplaybook-become/ansibleplaybook-become.go +++ b/examples/ansibleplaybook-become/ansibleplaybook-become.go @@ -24,14 +24,15 @@ func main() { exec := execute.NewDefaultExecute( execute.WithCmd(playbookCmd), - execute.WithTransformers( - transformer.Prepend("Go-ansible example with become"), - ), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithEnvVars( map[string]string{ "ANSIBLE_FORCE_COLOR": "true", }, ), + execute.WithTransformers( + transformer.Prepend("Go-ansible example with become"), + ), ) err := exec.Execute(context.TODO()) diff --git a/examples/ansibleplaybook-become/docker-compose.yaml b/examples/ansibleplaybook-become/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-become/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-become/docker/ansible/Dockerfile b/examples/ansibleplaybook-become/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-become/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-cobra-cmd/.env b/examples/ansibleplaybook-cobra-cmd/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-cobra-cmd/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-cobra-cmd/Makefile b/examples/ansibleplaybook-cobra-cmd/Makefile new file mode 100644 index 0000000..e475f74 --- /dev/null +++ b/examples/ansibleplaybook-cobra-cmd/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go --inventory 127.0.0.1, --playbook site.yml --connection-local --extra-var example="ansibleplaybook-cobra-cmd!" diff --git a/examples/ansibleplaybook-cobra-cmd/ansibleplaybook-cobra-cmd.go b/examples/ansibleplaybook-cobra-cmd/ansibleplaybook-cobra-cmd.go index 0c52748..fe4c9f4 100644 --- a/examples/ansibleplaybook-cobra-cmd/ansibleplaybook-cobra-cmd.go +++ b/examples/ansibleplaybook-cobra-cmd/ansibleplaybook-cobra-cmd.go @@ -80,6 +80,7 @@ func commandHandler(cmd *cobra.Command, args []string) error { exec := configuration.NewAnsibleWithConfigurationSettingsExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithTransformers( transformer.Prepend("Go-ansible example with become"), ), diff --git a/examples/ansibleplaybook-cobra-cmd/docker-compose.yaml b/examples/ansibleplaybook-cobra-cmd/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-cobra-cmd/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-cobra-cmd/docker/ansible/Dockerfile b/examples/ansibleplaybook-cobra-cmd/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-cobra-cmd/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-custom-transformer/.env b/examples/ansibleplaybook-custom-transformer/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-custom-transformer/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-custom-transformer/Makefile b/examples/ansibleplaybook-custom-transformer/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-custom-transformer/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-custom-transformer/ansibleplaybook-custom-transformer.go b/examples/ansibleplaybook-custom-transformer/ansibleplaybook-custom-transformer.go index 6ad9b7f..a0b3b44 100644 --- a/examples/ansibleplaybook-custom-transformer/ansibleplaybook-custom-transformer.go +++ b/examples/ansibleplaybook-custom-transformer/ansibleplaybook-custom-transformer.go @@ -39,6 +39,7 @@ func main() { exec := configuration.NewAnsibleWithConfigurationSettingsExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithTransformers( outputColored(), transformer.Prepend("Go-ansible example"), diff --git a/examples/ansibleplaybook-custom-transformer/docker-compose.yaml b/examples/ansibleplaybook-custom-transformer/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-custom-transformer/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-custom-transformer/docker/ansible/Dockerfile b/examples/ansibleplaybook-custom-transformer/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-custom-transformer/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-embed-python/.env b/examples/ansibleplaybook-embed-python/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-embed-python/.gitignore b/examples/ansibleplaybook-embed-python/.gitignore new file mode 100644 index 0000000..1c7d098 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/.gitignore @@ -0,0 +1,3 @@ +# +# The repository does not contains the data directory content, so you need to generate it by running the command: go generate ./... +internal/ansibleplaybook-embed-python/data diff --git a/examples/ansibleplaybook-embed-python/Dockerfile b/examples/ansibleplaybook-embed-python/Dockerfile new file mode 100644 index 0000000..96aaf0c --- /dev/null +++ b/examples/ansibleplaybook-embed-python/Dockerfile @@ -0,0 +1,37 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-bookworm as builder + +RUN apt-get update \ + && apt-get install -y \ + openssh-client \ + git \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +WORKDIR /app + +# Copy the Go module files and download dependencies +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +## go generate is used to install go-embed-python +RUN go generate ./... + +RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /usr/local/bin/app ansibleplaybook-embed-python.go + +FROM debian:bookworm-slim + +COPY --from=builder /usr/local/bin/app /usr/local/bin/app + +CMD ["/usr/local/bin/app"] + diff --git a/examples/ansibleplaybook-embed-python/Makefile b/examples/ansibleplaybook-embed-python/Makefile new file mode 100644 index 0000000..db657e1 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/Makefile @@ -0,0 +1,15 @@ +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +run: ## Run the example + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build app diff --git a/examples/ansibleplaybook-embed-python/README.md b/examples/ansibleplaybook-embed-python/README.md new file mode 100644 index 0000000..495183b --- /dev/null +++ b/examples/ansibleplaybook-embed-python/README.md @@ -0,0 +1,69 @@ +# Ansible Playbook Embed Python + +> **Disclaimer**: This example demonstrates how to use `go-ansible` library along with the `go-embed-python` solution. While this is not a feature of the library itself, its compatibility with various Ansible playbooks could vary depending on the requirements of the playbook. However, it serves as a source of inspiration for creating your solution. + +- [Ansible Playbook Embed Python](#ansible-playbook-embed-python) + - [Considerations](#considerations) + - [Run the example](#run-the-example) + +## Considerations + +This example does not include the `go-embed-python` packages within the `data` folder. You need to install them manually by running the following command: + +```sh +go generate ./... +``` + +As a result, the `data` folder will be created with the embedded Python packages. + +## Run the example + +This example provides a Dockerfile that encapsulates all the necessary steps to generate the embedded Python packages, create a Go binary containing the Ansible playbook, and the embedded Python packages. + +The example installs the `ansible-core` package. That is the minimal package required to run the Ansible playbook embedded in the Go binary. You can include additional packages by adding them to the `internal/ansibleplaybook-embed-python/requirements.txt` file. + +The Ansible playbook used in this example is defined in the `resources/ansible/site.yml` file. When the application is executed, the playbook is unpacked from the Go binary into a temporary directory. The embedded Python packages are also unpacked into another temporary directory. The playbook is then executed using the embedded Python interpreter. + +You can run the example with the following command: + +```sh +$ make run +[+] Creating 1/1 + ✔ Network go-ansible-ansibleplaybook-embed-python_default Created 0.1s +[+] Building 52.2s (19/19) FINISHED docker:default + => [app internal] load build definition from Dockerfile 0.0s + => => transferring dockerfile: 812B 0.0s + => [app internal] load metadata for docker.io/library/debian:bookworm-slim 0.5s + => [app internal] load metadata for docker.io/library/golang:1.19-bookworm 0.5s + => [app internal] load metadata for docker.io/library/python:3.12-bookworm 0.0s + => [app internal] load .dockerignore 0.0s + => => transferring context: 2B 0.0s + => [app builder 1/9] FROM docker.io/library/python:3.12-bookworm 0.0s + => [app internal] load build context 0.2s + => => transferring context: 852.70kB 0.1s + => [app stage-2 1/2] FROM docker.io/library/debian:bookworm-slim@sha256:3d5df92588469a4c503adbead0e4129ef3f88e223954011c2169073897547cac 0.0s + => [app golang 1/1] FROM docker.io/library/golang:1.19-bookworm@sha256:da9da58d86d106a5dda2ce249b00cf3b31cdd626ea41597e476de7b4eebad8c4 0.0s + => CACHED [app builder 2/9] RUN apt-get update && apt-get install -y openssh-client git && rm -rf /var/lib/apt/lists/* 0.0s + => CACHED [app builder 3/9] COPY --from=golang /usr/local/go /usr/local/go 0.0s + => CACHED [app builder 4/9] WORKDIR /app 0.0s + => CACHED [app builder 5/9] COPY go.mod go.sum ./ 0.0s + => CACHED [app builder 6/9] RUN go mod download 0.0s + => [app builder 7/9] COPY . . 0.7s + => [app builder 8/9] RUN go generate ./... 47.0s + => [app builder 9/9] RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /usr/local/bin/app ansibleplaybook-embed-python.go 3.8s + => CACHED [app stage-2 2/2] COPY --from=builder /usr/local/bin/app /usr/local/bin/app 0.0s + => [app] exporting to image 0.0s + => => exporting layers 0.0s + => => writing image sha256:9bac9ee8a88b138b87099e2d14a8b45d0b2313c59bb7f809ec27b529922235dc 0.0s + => => naming to docker.io/library/go-ansible-ansibleplaybook-embed-python-app 0.0s + +PLAY [all] ********************************************************************* + +TASK [ansibleplaybook-simple] ************************************************** +ok: [127.0.0.1] => { + "msg": "Your are running 'ansibleplaybook-embed-python' example" +} + +PLAY RECAP ********************************************************************* +127.0.0.1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +``` diff --git a/examples/ansibleplaybook-embed-python/ansibleplaybook-embed-python.go b/examples/ansibleplaybook-embed-python/ansibleplaybook-embed-python.go new file mode 100644 index 0000000..7eb8120 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/ansibleplaybook-embed-python.go @@ -0,0 +1,106 @@ +package main + +import ( + "context" + "embed" + "os" + "path/filepath" + + "github.com/apenella/go-ansible/v2/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/data" + executable "github.com/apenella/go-ansible/v2/internal/executable/os/exec" + "github.com/apenella/go-ansible/v2/pkg/execute" + "github.com/apenella/go-ansible/v2/pkg/playbook" + "github.com/kluctl/go-embed-python/embed_util" + "github.com/kluctl/go-embed-python/python" +) + +//go:embed resources +var resources embed.FS + +// PythonExec struct implements the executable.Exec interface and is used to execute Python commands using the embedded Python interpreter +type PythonExec struct { + ep *python.EmbeddedPython + pythonLibFsPath string + resourcesFsPath string +} + +func NewPythonExec() *PythonExec { + + tmpDir := filepath.Join(os.TempDir(), "go-ansible") + pythonDir := tmpDir + "-python" + pythonLibDir := tmpDir + "-python-lib" + resourcesDir := tmpDir + "-resources" + + pythonLibFs, _ := embed_util.NewEmbeddedFilesWithTmpDir(data.Data, pythonLibDir, true) + pythonLibFsPath := pythonLibFs.GetExtractedPath() + resourcesFs, _ := embed_util.NewEmbeddedFilesWithTmpDir(resources, resourcesDir, true) + resourcesFsPath := resourcesFs.GetExtractedPath() + + ep, _ := python.NewEmbeddedPythonWithTmpDir(pythonDir, true) + ep.AddPythonPath(pythonLibFs.GetExtractedPath()) + ep.AddPythonPath(resourcesFs.GetExtractedPath()) + + return &PythonExec{ + ep: ep, + pythonLibFsPath: pythonLibFsPath, + resourcesFsPath: resourcesFsPath, + } +} + +// Command is a wrapper of exec.Command +func (e *PythonExec) Command(name string, arg ...string) executable.Cmder { + + cmd := append([]string{name}, arg...) + + return e.ep.PythonCmd2(cmd) +} + +// CommandContext is a wrapper of exec.CommandContext +func (e *PythonExec) CommandContext(ctx context.Context, name string, arg ...string) executable.Cmder { + cmd := append([]string{name}, arg...) + return e.ep.PythonCmd2(cmd) +} + +func main() { + + var err error + + epExec := NewPythonExec() + + // + // You can use the following line to install additional ansible collections or roles + // + // galaxyEP := ep.PythonCmd("-m", "ansible", "galaxy", "collection", "install", "community.general", "--force") + // galaxyEP.Stdout = os.Stdout + // galaxyEP.Stderr = os.Stderr + // err = galaxyEP.Run() + // if err != nil { + // panic(err) + // } + + ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{ + Inventory: "127.0.0.1,", + Connection: "local", + } + + playbookCmd := playbook.NewAnsiblePlaybookCmd( + playbook.WithPlaybooks( + filepath.Join(epExec.resourcesFsPath, "resources", "ansible", "site.yml"), + ), + playbook.WithPlaybookOptions(ansiblePlaybookOptions), + playbook.WithBinary( + filepath.Join(epExec.pythonLibFsPath, "bin", "ansible-playbook"), + ), + ) + + ansiblePlaybookExecutor := execute.NewDefaultExecute( + execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), + execute.WithExecutable(epExec), + ) + + err = ansiblePlaybookExecutor.Execute(context.TODO()) + if err != nil { + panic(err) + } +} diff --git a/examples/ansibleplaybook-embed-python/docker-compose.yml b/examples/ansibleplaybook-embed-python/docker-compose.yml new file mode 100644 index 0000000..2bcc5ce --- /dev/null +++ b/examples/ansibleplaybook-embed-python/docker-compose.yml @@ -0,0 +1,8 @@ + +services: + app: + build: + context: . + dockerfile: Dockerfile + args: + - golang_version=${GOLANG_VERSION} diff --git a/examples/ansibleplaybook-embed-python/go.mod b/examples/ansibleplaybook-embed-python/go.mod new file mode 100644 index 0000000..3cced59 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/go.mod @@ -0,0 +1,30 @@ +module github.com/apenella/go-ansible/v2/examples/ansibleplaybook-embed-python + +go 1.19 + +require ( + github.com/apenella/go-ansible/v2 v2.0.0-rc.3 + github.com/kluctl/go-embed-python v0.0.0-3.12.2-20240224-1 +) + +require ( + github.com/apenella/go-common-utils/data v0.0.0-20220913191136-86daaa87e7df // indirect + github.com/apenella/go-common-utils/error v0.0.0-20220913191136-86daaa87e7df // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.9.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.17.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/examples/ansibleplaybook-embed-python/go.sum b/examples/ansibleplaybook-embed-python/go.sum new file mode 100644 index 0000000..9e49275 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/go.sum @@ -0,0 +1,64 @@ +github.com/apenella/go-ansible/v2 v2.0.0-rc.3 h1:IZLYp9qPmYlDHCBguie67BE9tPmMFsrGrj510cJ1/NY= +github.com/apenella/go-ansible/v2 v2.0.0-rc.3/go.mod h1:CW8BknrWkGIEG+BB6/MNXDYajvH2TwyzZEhwMp0rhBk= +github.com/apenella/go-common-utils/data v0.0.0-20220913191136-86daaa87e7df h1:sEikY2P+NZK/7VZUwIsnXIGElhsuFDSxh1bZYwHxdcI= +github.com/apenella/go-common-utils/data v0.0.0-20220913191136-86daaa87e7df/go.mod h1:cLVL6GjUiKG/WyBzX+KD6h/XRV/HnNZIZbMNNiBgQ9o= +github.com/apenella/go-common-utils/error v0.0.0-20220913191136-86daaa87e7df h1:SvlYbjlsSQDS7hbVT1h012/zdgvcwWJ+Yd9XRiiY/8s= +github.com/apenella/go-common-utils/error v0.0.0-20220913191136-86daaa87e7df/go.mod h1:+3dyIlHX350xJIUIffwMLswZXU+N2FwDE05VuKqxYdw= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/kluctl/go-embed-python v0.0.0-3.12.2-20240224-1 h1:24tIzQxakGNqGCgkyJT55yA7VQzGntUGqMtWkG0Vrtc= +github.com/kluctl/go-embed-python v0.0.0-3.12.2-20240224-1/go.mod h1:FJ7V83X5BIqrkPpy2Lmlu2zoDpUnQfVfGpMeRbI0hQ4= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sosedoff/ansible-vault-go v0.2.0 h1:XqkBdqbXgTuFQ++NdrZvSdUTNozeb6S3V5x7FVs17vg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/dummy.go b/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/dummy.go new file mode 100644 index 0000000..b34ef7a --- /dev/null +++ b/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/dummy.go @@ -0,0 +1,3 @@ +package internal + +//go:generate go run ./generate diff --git a/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/generate/main.go b/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/generate/main.go new file mode 100644 index 0000000..29059b3 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/generate/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "github.com/kluctl/go-embed-python/pip" +) + +func main() { + err := pip.CreateEmbeddedPipPackagesForKnownPlatforms("requirements.txt", "./data/") + if err != nil { + panic(err) + } +} diff --git a/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/requirements.txt b/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/requirements.txt new file mode 100644 index 0000000..c9ca4d0 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/internal/ansibleplaybook-embed-python/requirements.txt @@ -0,0 +1 @@ +ansible-core==2.16.3 diff --git a/examples/ansibleplaybook-embed-python/resources/ansible/requirements.yml b/examples/ansibleplaybook-embed-python/resources/ansible/requirements.yml new file mode 100644 index 0000000..5c7755d --- /dev/null +++ b/examples/ansibleplaybook-embed-python/resources/ansible/requirements.yml @@ -0,0 +1,4 @@ +--- + +collections: +- name: community.general \ No newline at end of file diff --git a/examples/ansibleplaybook-embed-python/resources/ansible/site.yml b/examples/ansibleplaybook-embed-python/resources/ansible/site.yml new file mode 100644 index 0000000..0ade525 --- /dev/null +++ b/examples/ansibleplaybook-embed-python/resources/ansible/site.yml @@ -0,0 +1,10 @@ +--- + +- hosts: all + gather_facts: no + + tasks: + - name: ansibleplaybook-simple + ansible.builtin.debug: + msg: Your are running 'ansibleplaybook-embed-python' example + diff --git a/examples/ansibleplaybook-extravars-file/.env b/examples/ansibleplaybook-extravars-file/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-extravars-file/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-extravars-file/Makefile b/examples/ansibleplaybook-extravars-file/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-extravars-file/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-extravars-file/ansibleplaybook-extravars-file.go b/examples/ansibleplaybook-extravars-file/ansibleplaybook-extravars-file.go index faa13d8..0eb037a 100644 --- a/examples/ansibleplaybook-extravars-file/ansibleplaybook-extravars-file.go +++ b/examples/ansibleplaybook-extravars-file/ansibleplaybook-extravars-file.go @@ -26,6 +26,7 @@ func main() { exec := execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), ) err := exec.Execute(context.TODO()) diff --git a/examples/ansibleplaybook-extravars-file/docker-compose.yaml b/examples/ansibleplaybook-extravars-file/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-extravars-file/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-extravars-file/docker/ansible/Dockerfile b/examples/ansibleplaybook-extravars-file/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-extravars-file/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-extravars/.env b/examples/ansibleplaybook-extravars/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-extravars/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-extravars/Makefile b/examples/ansibleplaybook-extravars/Makefile index 07c979b..21d43c8 100644 --- a/examples/ansibleplaybook-extravars/Makefile +++ b/examples/ansibleplaybook-extravars/Makefile @@ -41,5 +41,7 @@ attach-server: ## Attach to the server container project-name: ## Show the project name @echo $(PROJECT_NAME) -run: ## Run the playbook - @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go \ No newline at end of file +_run: + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go + +run: up _run down ## Run the playbook diff --git a/examples/ansibleplaybook-extravars/ansibleplaybook-extravars.go b/examples/ansibleplaybook-extravars/ansibleplaybook-extravars.go index 67b1a21..3af6275 100644 --- a/examples/ansibleplaybook-extravars/ansibleplaybook-extravars.go +++ b/examples/ansibleplaybook-extravars/ansibleplaybook-extravars.go @@ -31,6 +31,7 @@ func main() { yamlexec := stdoutcallback.NewYAMLStdoutCallbackExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), ), ) diff --git a/examples/ansibleplaybook-extravars/docker-compose.yaml b/examples/ansibleplaybook-extravars/docker-compose.yaml index 2763781..d8ae9c5 100644 --- a/examples/ansibleplaybook-extravars/docker-compose.yaml +++ b/examples/ansibleplaybook-extravars/docker-compose.yaml @@ -1,9 +1,11 @@ -name: ansibleplaybook-ssh +--- services: ansible: build: context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} command: ["tail", "-f", "/dev/null"] # command: ["ansible-playbook", "--help"] volumes: diff --git a/examples/ansibleplaybook-extravars/docker/ansible/Dockerfile b/examples/ansibleplaybook-extravars/docker/ansible/Dockerfile index 41c9850..6eafa18 100644 --- a/examples/ansibleplaybook-extravars/docker/ansible/Dockerfile +++ b/examples/ansibleplaybook-extravars/docker/ansible/Dockerfile @@ -1,3 +1,7 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + FROM python:3.12-alpine3.19 RUN apk add --update --no-cache \ @@ -14,12 +18,10 @@ RUN pip3 install -U pip setuptools \ ansible \ && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook -RUN apk add --update --no-cache \ - go +COPY --from=golang /usr/local/go /usr/local/go # Configure Go -ENV GOROOT /usr/lib/go -ENV GOPATH /go -ENV PATH /go/bin:$PATH +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-json-stdout/.env b/examples/ansibleplaybook-json-stdout/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-json-stdout/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-json-stdout/Makefile b/examples/ansibleplaybook-json-stdout/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-json-stdout/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-json-stdout/ansibleplaybook-json-stdout.go b/examples/ansibleplaybook-json-stdout/ansibleplaybook-json-stdout.go index 9d48d47..882b017 100644 --- a/examples/ansibleplaybook-json-stdout/ansibleplaybook-json-stdout.go +++ b/examples/ansibleplaybook-json-stdout/ansibleplaybook-json-stdout.go @@ -36,6 +36,7 @@ func main() { stdoutcallback.NewJSONStdoutCallbackExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithWrite(io.Writer(buff)), ), ), diff --git a/examples/ansibleplaybook-json-stdout/docker-compose.yaml b/examples/ansibleplaybook-json-stdout/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-json-stdout/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-json-stdout/docker/ansible/Dockerfile b/examples/ansibleplaybook-json-stdout/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-json-stdout/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-myexecutor/.env b/examples/ansibleplaybook-myexecutor/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-myexecutor/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-myexecutor/Makefile b/examples/ansibleplaybook-myexecutor/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-myexecutor/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-myexecutor/docker-compose.yaml b/examples/ansibleplaybook-myexecutor/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-myexecutor/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-myexecutor/docker/ansible/Dockerfile b/examples/ansibleplaybook-myexecutor/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-myexecutor/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-signals-and-cancellation/.env b/examples/ansibleplaybook-signals-and-cancellation/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-signals-and-cancellation/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-signals-and-cancellation/Makefile b/examples/ansibleplaybook-signals-and-cancellation/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-signals-and-cancellation/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-signals-and-cancellation/ansibleplaybook-signals-and-cancellation.go b/examples/ansibleplaybook-signals-and-cancellation/ansibleplaybook-signals-and-cancellation.go index e057772..9364727 100644 --- a/examples/ansibleplaybook-signals-and-cancellation/ansibleplaybook-signals-and-cancellation.go +++ b/examples/ansibleplaybook-signals-and-cancellation/ansibleplaybook-signals-and-cancellation.go @@ -31,6 +31,7 @@ func main() { exec := configuration.NewAnsibleWithConfigurationSettingsExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithTransformers( transformer.Prepend("[ansibleplaybook-signals-and-cancellation]"), ), diff --git a/examples/ansibleplaybook-signals-and-cancellation/docker-compose.yaml b/examples/ansibleplaybook-signals-and-cancellation/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-signals-and-cancellation/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-signals-and-cancellation/docker/ansible/Dockerfile b/examples/ansibleplaybook-signals-and-cancellation/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-signals-and-cancellation/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-simple-embedfs/.env b/examples/ansibleplaybook-simple-embedfs/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-simple-embedfs/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-simple-embedfs/Makefile b/examples/ansibleplaybook-simple-embedfs/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-simple-embedfs/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-simple-embedfs/ansibleplaybook-simple-embedfs.go b/examples/ansibleplaybook-simple-embedfs/ansibleplaybook-simple-embedfs.go index 5f070ca..5282454 100644 --- a/examples/ansibleplaybook-simple-embedfs/ansibleplaybook-simple-embedfs.go +++ b/examples/ansibleplaybook-simple-embedfs/ansibleplaybook-simple-embedfs.go @@ -43,6 +43,7 @@ func main() { exec := execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), ) err = exec.Execute(context.TODO()) diff --git a/examples/ansibleplaybook-simple-embedfs/docker-compose.yaml b/examples/ansibleplaybook-simple-embedfs/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-simple-embedfs/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-simple-embedfs/docker/ansible/Dockerfile b/examples/ansibleplaybook-simple-embedfs/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-simple-embedfs/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-simple-with-prompt/.env b/examples/ansibleplaybook-simple-with-prompt/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-simple-with-prompt/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-simple-with-prompt/Makefile b/examples/ansibleplaybook-simple-with-prompt/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-simple-with-prompt/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-simple-with-prompt/ansibleplaybook-simple-with-prompt.go b/examples/ansibleplaybook-simple-with-prompt/ansibleplaybook-simple-with-prompt.go index f0c9c19..7b9560b 100644 --- a/examples/ansibleplaybook-simple-with-prompt/ansibleplaybook-simple-with-prompt.go +++ b/examples/ansibleplaybook-simple-with-prompt/ansibleplaybook-simple-with-prompt.go @@ -21,6 +21,7 @@ func main() { exec := execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), ) err := exec.Execute(context.TODO()) diff --git a/examples/ansibleplaybook-simple-with-prompt/docker-compose.yaml b/examples/ansibleplaybook-simple-with-prompt/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-simple-with-prompt/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-simple-with-prompt/docker/ansible/Dockerfile b/examples/ansibleplaybook-simple-with-prompt/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-simple-with-prompt/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-simple/.env b/examples/ansibleplaybook-simple/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-simple/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-simple/Makefile b/examples/ansibleplaybook-simple/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-simple/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-simple/docker-compose.yaml b/examples/ansibleplaybook-simple/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-simple/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-simple/docker/ansible/Dockerfile b/examples/ansibleplaybook-simple/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-simple/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-skipping-failing/.env b/examples/ansibleplaybook-skipping-failing/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-skipping-failing/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-skipping-failing/Makefile b/examples/ansibleplaybook-skipping-failing/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-skipping-failing/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-skipping-failing/docker-compose.yaml b/examples/ansibleplaybook-skipping-failing/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-skipping-failing/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-skipping-failing/docker/ansible/Dockerfile b/examples/ansibleplaybook-skipping-failing/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-skipping-failing/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-ssh/.env b/examples/ansibleplaybook-ssh/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-ssh/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-ssh/Makefile b/examples/ansibleplaybook-ssh/Makefile index 5c42d87..9391bae 100644 --- a/examples/ansibleplaybook-ssh/Makefile +++ b/examples/ansibleplaybook-ssh/Makefile @@ -41,5 +41,10 @@ attach-server: ## Attach to the server container project-name: ## Show the project name @echo $(PROJECT_NAME) -run: ## Run the playbook - @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible go run ansibleplaybook-ssh.go \ No newline at end of file +# run: ## Run the playbook +# @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible go run ansibleplaybook-ssh.go + +_run: + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go || true + +run: up _run down ## Run the playbook diff --git a/examples/ansibleplaybook-ssh/ansibleplaybook-ssh.go b/examples/ansibleplaybook-ssh/ansibleplaybook-ssh.go index c0bef72..58582f3 100644 --- a/examples/ansibleplaybook-ssh/ansibleplaybook-ssh.go +++ b/examples/ansibleplaybook-ssh/ansibleplaybook-ssh.go @@ -22,13 +22,14 @@ func main() { exec := execute.NewDefaultExecute( execute.WithCmd(cmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), ) + fmt.Println("Executing command: ", cmd.String()) + err := exec.Execute(context.TODO()) if err != nil { + fmt.Println(err) os.Exit(1) } - - fmt.Println(cmd.String()) - } diff --git a/examples/ansibleplaybook-ssh/docker-compose.yaml b/examples/ansibleplaybook-ssh/docker-compose.yaml index a082f7a..8179ecc 100644 --- a/examples/ansibleplaybook-ssh/docker-compose.yaml +++ b/examples/ansibleplaybook-ssh/docker-compose.yaml @@ -1,9 +1,11 @@ -name: ansibleplaybook-ssh +--- services: ansible: build: context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} command: ["tail", "-f", "/dev/null"] # command: ["ansible-playbook", "--help"] volumes: diff --git a/examples/ansibleplaybook-ssh/docker/ansible/Dockerfile b/examples/ansibleplaybook-ssh/docker/ansible/Dockerfile index 41c9850..6eafa18 100644 --- a/examples/ansibleplaybook-ssh/docker/ansible/Dockerfile +++ b/examples/ansibleplaybook-ssh/docker/ansible/Dockerfile @@ -1,3 +1,7 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + FROM python:3.12-alpine3.19 RUN apk add --update --no-cache \ @@ -14,12 +18,10 @@ RUN pip3 install -U pip setuptools \ ansible \ && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook -RUN apk add --update --no-cache \ - go +COPY --from=golang /usr/local/go /usr/local/go # Configure Go -ENV GOROOT /usr/lib/go -ENV GOPATH /go -ENV PATH /go/bin:$PATH +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-time-measurement/.env b/examples/ansibleplaybook-time-measurement/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-time-measurement/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-time-measurement/Makefile b/examples/ansibleplaybook-time-measurement/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-time-measurement/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-time-measurement/ansibleplaybook-time-measurement.go b/examples/ansibleplaybook-time-measurement/ansibleplaybook-time-measurement.go index 8f9e68f..fc90ed7 100644 --- a/examples/ansibleplaybook-time-measurement/ansibleplaybook-time-measurement.go +++ b/examples/ansibleplaybook-time-measurement/ansibleplaybook-time-measurement.go @@ -26,6 +26,7 @@ func main() { configuration.NewAnsibleWithConfigurationSettingsExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), ), configuration.WithAnsibleForceColor(), ), diff --git a/examples/ansibleplaybook-time-measurement/docker-compose.yaml b/examples/ansibleplaybook-time-measurement/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-time-measurement/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-time-measurement/docker/ansible/Dockerfile b/examples/ansibleplaybook-time-measurement/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-time-measurement/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-walk-through-json-output/.env b/examples/ansibleplaybook-walk-through-json-output/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-walk-through-json-output/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-walk-through-json-output/Makefile b/examples/ansibleplaybook-walk-through-json-output/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-walk-through-json-output/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-walk-through-json-output/ansibleplaybook-walk-through-json-output.go b/examples/ansibleplaybook-walk-through-json-output/ansibleplaybook-walk-through-json-output.go index 7bbc873..01464d8 100644 --- a/examples/ansibleplaybook-walk-through-json-output/ansibleplaybook-walk-through-json-output.go +++ b/examples/ansibleplaybook-walk-through-json-output/ansibleplaybook-walk-through-json-output.go @@ -34,6 +34,7 @@ func main() { exec := stdoutcallback.NewJSONStdoutCallbackExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithWrite(io.Writer(buff)), ), ) diff --git a/examples/ansibleplaybook-walk-through-json-output/docker-compose.yaml b/examples/ansibleplaybook-walk-through-json-output/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-walk-through-json-output/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-walk-through-json-output/docker/ansible/Dockerfile b/examples/ansibleplaybook-walk-through-json-output/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-walk-through-json-output/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-with-executor-time-measurament/.env b/examples/ansibleplaybook-with-executor-time-measurament/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-with-executor-time-measurament/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-with-executor-time-measurament/Makefile b/examples/ansibleplaybook-with-executor-time-measurament/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-with-executor-time-measurament/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-with-executor-time-measurament/ansibleplaybook-with-executor-time-measurament.go b/examples/ansibleplaybook-with-executor-time-measurament/ansibleplaybook-with-executor-time-measurament.go index 45fb4b3..9f533c4 100644 --- a/examples/ansibleplaybook-with-executor-time-measurament/ansibleplaybook-with-executor-time-measurament.go +++ b/examples/ansibleplaybook-with-executor-time-measurament/ansibleplaybook-with-executor-time-measurament.go @@ -27,6 +27,7 @@ func main() { configuration.NewAnsibleWithConfigurationSettingsExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithTransformers( transformer.Prepend("Go-ansible example"), transformer.LogFormat(transformer.DefaultLogFormatLayout, transformer.Now), diff --git a/examples/ansibleplaybook-with-executor-time-measurament/docker-compose.yaml b/examples/ansibleplaybook-with-executor-time-measurament/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-with-executor-time-measurament/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-with-executor-time-measurament/docker/ansible/Dockerfile b/examples/ansibleplaybook-with-executor-time-measurament/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-with-executor-time-measurament/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-with-timeout/.env b/examples/ansibleplaybook-with-timeout/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-with-timeout/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-with-timeout/Makefile b/examples/ansibleplaybook-with-timeout/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-with-timeout/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-with-timeout/ansibleplaybook-with-timeout.go b/examples/ansibleplaybook-with-timeout/ansibleplaybook-with-timeout.go index d0437c8..ebe51f3 100644 --- a/examples/ansibleplaybook-with-timeout/ansibleplaybook-with-timeout.go +++ b/examples/ansibleplaybook-with-timeout/ansibleplaybook-with-timeout.go @@ -35,6 +35,7 @@ func main() { exec := execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithTransformers( transformer.Prepend("Go-ansible example"), ), diff --git a/examples/ansibleplaybook-with-timeout/docker-compose.yaml b/examples/ansibleplaybook-with-timeout/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-with-timeout/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-with-timeout/docker/ansible/Dockerfile b/examples/ansibleplaybook-with-timeout/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-with-timeout/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/ansibleplaybook-with-vaulted-extravar/.env b/examples/ansibleplaybook-with-vaulted-extravar/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/ansibleplaybook-with-vaulted-extravar/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/ansibleplaybook-with-vaulted-extravar/Makefile b/examples/ansibleplaybook-with-vaulted-extravar/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/ansibleplaybook-with-vaulted-extravar/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/ansibleplaybook-with-vaulted-extravar/ansibleplaybook-with-vaulted-extravar.go b/examples/ansibleplaybook-with-vaulted-extravar/ansibleplaybook-with-vaulted-extravar.go index 77c17fb..c9475a9 100644 --- a/examples/ansibleplaybook-with-vaulted-extravar/ansibleplaybook-with-vaulted-extravar.go +++ b/examples/ansibleplaybook-with-vaulted-extravar/ansibleplaybook-with-vaulted-extravar.go @@ -64,6 +64,7 @@ func main() { exec := configuration.NewAnsibleWithConfigurationSettingsExecute( execute.NewDefaultExecute( execute.WithCmd(playbookCmd), + execute.WithErrorEnrich(playbook.NewAnsiblePlaybookErrorEnrich()), execute.WithTransformers( transformer.Prepend("Go-ansible example with become"), ), diff --git a/examples/ansibleplaybook-with-vaulted-extravar/docker-compose.yaml b/examples/ansibleplaybook-with-vaulted-extravar/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/ansibleplaybook-with-vaulted-extravar/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/ansibleplaybook-with-vaulted-extravar/docker/ansible/Dockerfile b/examples/ansibleplaybook-with-vaulted-extravar/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/ansibleplaybook-with-vaulted-extravar/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/.env b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/Makefile b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/Makefile index d06c0b1..a0dbecf 100644 --- a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/Makefile +++ b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/Makefile @@ -44,7 +44,7 @@ attach-server: ## Attach to the server container project-name: ## Show the project name @echo $(PROJECT_NAME) -run: ## Run the example +_run: @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go -start-and-run: up run ## Start the environment and run the example +run: up _run down ## Run the playbook diff --git a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/docker-compose.yaml b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/docker-compose.yaml index 6655a19..9d131d3 100644 --- a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/docker-compose.yaml +++ b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/docker-compose.yaml @@ -1,9 +1,11 @@ -name: ansibleplaybook-ssh +--- services: ansible: build: context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} command: ["tail", "-f", "/dev/null"] # command: ["ansible-playbook", "--help"] volumes: diff --git a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/docker/ansible/Dockerfile b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/docker/ansible/Dockerfile index 41c9850..6eafa18 100644 --- a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/docker/ansible/Dockerfile +++ b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-collection/docker/ansible/Dockerfile @@ -1,3 +1,7 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + FROM python:3.12-alpine3.19 RUN apk add --update --no-cache \ @@ -14,12 +18,10 @@ RUN pip3 install -U pip setuptools \ ansible \ && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook -RUN apk add --update --no-cache \ - go +COPY --from=golang /usr/local/go /usr/local/go # Configure Go -ENV GOROOT /usr/lib/go -ENV GOPATH /go -ENV PATH /go/bin:$PATH +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/.env b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/Makefile b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/Makefile index d06c0b1..a0dbecf 100644 --- a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/Makefile +++ b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/Makefile @@ -44,7 +44,7 @@ attach-server: ## Attach to the server container project-name: ## Show the project name @echo $(PROJECT_NAME) -run: ## Run the example +_run: @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go -start-and-run: up run ## Start the environment and run the example +run: up _run down ## Run the playbook diff --git a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/docker-compose.yaml b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/docker-compose.yaml index 6655a19..9d131d3 100644 --- a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/docker-compose.yaml +++ b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/docker-compose.yaml @@ -1,9 +1,11 @@ -name: ansibleplaybook-ssh +--- services: ansible: build: context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} command: ["tail", "-f", "/dev/null"] # command: ["ansible-playbook", "--help"] volumes: diff --git a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/docker/ansible/Dockerfile b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/docker/ansible/Dockerfile index 41c9850..bf15020 100644 --- a/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/docker/ansible/Dockerfile +++ b/examples/workflowexecute-ansibleplaybook-with-galaxy-install-role/docker/ansible/Dockerfile @@ -1,3 +1,7 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + FROM python:3.12-alpine3.19 RUN apk add --update --no-cache \ @@ -14,12 +18,11 @@ RUN pip3 install -U pip setuptools \ ansible \ && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook -RUN apk add --update --no-cache \ - go -# Configure Go -ENV GOROOT /usr/lib/go -ENV GOPATH /go -ENV PATH /go/bin:$PATH +COPY --from=golang /usr/local/go /usr/local/go +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/workflowexecute-simple/.env b/examples/workflowexecute-simple/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/workflowexecute-simple/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/workflowexecute-simple/Makefile b/examples/workflowexecute-simple/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/workflowexecute-simple/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/workflowexecute-simple/docker-compose.yaml b/examples/workflowexecute-simple/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/workflowexecute-simple/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/workflowexecute-simple/docker/ansible/Dockerfile b/examples/workflowexecute-simple/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/workflowexecute-simple/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/examples/workflowexecute-time-measurament/.env b/examples/workflowexecute-time-measurament/.env new file mode 100644 index 0000000..3c79a50 --- /dev/null +++ b/examples/workflowexecute-time-measurament/.env @@ -0,0 +1 @@ +GOLANG_VERSION=1.22 \ No newline at end of file diff --git a/examples/workflowexecute-time-measurament/Makefile b/examples/workflowexecute-time-measurament/Makefile new file mode 100644 index 0000000..e250ae3 --- /dev/null +++ b/examples/workflowexecute-time-measurament/Makefile @@ -0,0 +1,39 @@ + +DOCKER_COMPOSE_BINARY := $(shell docker compose version > /dev/null 2>&1 && echo "docker compose" || (which docker-compose > /dev/null 2>&1 && echo "docker-compose" || (echo "docker compose not found. Aborting." >&2; exit 1))) + +PROJECT_NAME := go-ansible-$(shell basename ${PWD}) + +# dafault target +.DEFAULT_GOAL: help + +help: ## Lists available targets + @echo + @echo "Makefile usage:" + @grep -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2}' + @echo + +build: ## Build the Docker compose environment + @$(DOCKER_COMPOSE_BINARY) build + +up: ## Create and start containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) up --detach --build + +down: ## Stop and remove containers, networks, and volumes + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) down --volumes --remove-orphans --timeout 3 + +restart: down up ## Restart the containers + +ps: ## List containers + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) ps + +logs: ## Show all logs + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) logs + +attach-ansible: ## Attach to the ansible container + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) exec --workdir /code/examples/$$(basename $$(pwd)) ansible /bin/sh + +project-name: ## Show the project name + @echo $(PROJECT_NAME) + +run: ## Run the playbook + @$(DOCKER_COMPOSE_BINARY) --project-name $(PROJECT_NAME) run --build --rm --workdir /code/examples/$$(basename $$(pwd)) ansible go run $$(basename $$(pwd)).go diff --git a/examples/workflowexecute-time-measurament/docker-compose.yaml b/examples/workflowexecute-time-measurament/docker-compose.yaml new file mode 100644 index 0000000..e0f9dc4 --- /dev/null +++ b/examples/workflowexecute-time-measurament/docker-compose.yaml @@ -0,0 +1,15 @@ +--- + +services: + ansible: + build: + context: docker/ansible + args: + - golang_version=${GOLANG_VERSION} + command: ["tail", "-f", "/dev/null"] + # command: ["ansible-playbook", "--help"] + volumes: + - ../..:/code + working_dir: /code + ## Set the init flag to true lets the process 1 to reap all the zombie processes + init: true diff --git a/examples/workflowexecute-time-measurament/docker/ansible/Dockerfile b/examples/workflowexecute-time-measurament/docker/ansible/Dockerfile new file mode 100644 index 0000000..6eafa18 --- /dev/null +++ b/examples/workflowexecute-time-measurament/docker/ansible/Dockerfile @@ -0,0 +1,27 @@ +ARG golang_version=1.22 + +FROM golang:${golang_version}-bookworm as golang + +FROM python:3.12-alpine3.19 + +RUN apk add --update --no-cache \ + openssh-client \ + git \ + && rm -rf /var/cache/apk/* + +RUN pip3 install -U pip setuptools \ + && pip3 install --no-cache-dir \ + setuptools-rust \ + cryptography \ + # Required library to execute ansible community.general.dig plugin + dnspython \ + ansible \ + && ln /usr/local/bin/ansible-playbook /usr/bin/ansible-playbook + +COPY --from=golang /usr/local/go /usr/local/go + +# Configure Go +ENV GOROOT /usr/local/go +ENV PATH /usr/local/go/bin:/go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin diff --git a/go.mod b/go.mod index 4a83940..9544591 100644 --- a/go.mod +++ b/go.mod @@ -1,36 +1,34 @@ module github.com/apenella/go-ansible/v2 -go 1.19 +go 1.22 require ( - github.com/PuerkitoBio/goquery v1.8.1 + github.com/PuerkitoBio/goquery v1.9.1 github.com/apenella/go-common-utils/data v0.0.0-20220913191136-86daaa87e7df github.com/apenella/go-common-utils/error v0.0.0-20220913191136-86daaa87e7df - github.com/fatih/color v1.13.0 - github.com/go-errors/errors v1.4.2 + github.com/fatih/color v1.16.0 + github.com/go-errors/errors v1.5.1 github.com/iancoleman/strcase v0.3.0 github.com/pkg/errors v0.9.1 github.com/sosedoff/ansible-vault-go v0.2.0 - github.com/spf13/afero v1.9.5 - github.com/spf13/cobra v1.5.0 - github.com/stretchr/testify v1.8.0 + github.com/spf13/afero v1.11.0 + github.com/spf13/cobra v1.8.0 + github.com/stretchr/testify v1.9.0 ) require ( - github.com/andybalholm/cascadia v1.3.1 // indirect + github.com/andybalholm/cascadia v1.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect - github.com/kr/text v0.2.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.4.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 379b197..996cfc1 100644 --- a/go.sum +++ b/go.sum @@ -1,513 +1,91 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= -github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= -github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= -github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= +github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/apenella/go-common-utils/data v0.0.0-20220913191136-86daaa87e7df h1:sEikY2P+NZK/7VZUwIsnXIGElhsuFDSxh1bZYwHxdcI= github.com/apenella/go-common-utils/data v0.0.0-20220913191136-86daaa87e7df/go.mod h1:cLVL6GjUiKG/WyBzX+KD6h/XRV/HnNZIZbMNNiBgQ9o= github.com/apenella/go-common-utils/error v0.0.0-20220913191136-86daaa87e7df h1:SvlYbjlsSQDS7hbVT1h012/zdgvcwWJ+Yd9XRiiY/8s= github.com/apenella/go-common-utils/error v0.0.0-20220913191136-86daaa87e7df/go.mod h1:+3dyIlHX350xJIUIffwMLswZXU+N2FwDE05VuKqxYdw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sosedoff/ansible-vault-go v0.2.0 h1:XqkBdqbXgTuFQ++NdrZvSdUTNozeb6S3V5x7FVs17vg= github.com/sosedoff/ansible-vault-go v0.2.0/go.mod h1:wMU54HNJfY0n0KIgbpA9m15NBfaUDlJrAsaZp0FwzkI= -github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/mocks/mockAnsibleCmd.go b/mocks/mockAnsibleCmd.go index 5f4c185..427bd87 100644 --- a/mocks/mockAnsibleCmd.go +++ b/mocks/mockAnsibleCmd.go @@ -14,3 +14,7 @@ func NewMockAnsibleCmd(cmd []string, err error) *MockAnsibleCmd { func (c *MockAnsibleCmd) Command() ([]string, error) { return c.cmd, c.err } + +func (c *MockAnsibleCmd) String() string { + return "" +} diff --git a/mocks/mockExitCodeErr.go b/mocks/mockExitCodeErr.go new file mode 100644 index 0000000..8020b65 --- /dev/null +++ b/mocks/mockExitCodeErr.go @@ -0,0 +1,15 @@ +package mocks + +type MockExitCodeErr struct { + error //nolint:golint,unused + Code int + Message string +} + +func (e *MockExitCodeErr) Error() string { + return e.Message +} + +func (e *MockExitCodeErr) ExitCode() int { + return e.Code +} diff --git a/pkg/execute/defaultExecute.go b/pkg/execute/defaultExecute.go index 6311258..c1a7967 100644 --- a/pkg/execute/defaultExecute.go +++ b/pkg/execute/defaultExecute.go @@ -8,7 +8,6 @@ import ( osexec "os/exec" "strings" "sync" - "syscall" "github.com/apenella/go-ansible/v2/internal/executable/os/exec" "github.com/apenella/go-ansible/v2/pkg/execute/result" @@ -63,22 +62,26 @@ func (e EnvVars) Environ() []string { // DefaultExecute is a simple definition of an executor type DefaultExecute struct { - // Writer is where is written the command stdout - Write io.Writer - // WriterError is where is written the command stderr - WriterError io.Writer + // Cmd is the command generator + Cmd Commander // CmdRunDir specifies the working directory of the command. CmdRunDir string // EnvVars specifies env vars of the command. EnvVars EnvVars - // Transformers is the list of transformers func for the output - Transformers []transformer.TransformerFunc - // Output manages the output of the command - Output result.ResultsOutputer + // ErrContext is the error context + ErrorEnrich ErrorEnricher // Exec is the executor Exec Executabler - // Cmd is the command generator - Cmd Commander + // Output manages the output of the command + Output result.ResultsOutputer + // quiet is a flag to set the executor in quiet mode + quiet bool + // Transformers is the list of transformers func for the output + Transformers []transformer.TransformerFunc + // Writer is where is written the command stdout + Write io.Writer + // WriterError is where is written the command stderr + WriterError io.Writer } // NewDefaultExecute return a new DefaultExecute instance with all options @@ -126,13 +129,41 @@ func (e *DefaultExecute) AddEnvVarSafe(key, value string) error { return nil } +// Quiet sets the executor in quiet mode +func (e *DefaultExecute) Quiet() { + e.quiet = true +} + +// quietCommand returns the command without the verbose flags -v, -vv, -vvv, -vvvv and --verbose +func (e *DefaultExecute) quietCommand() ([]string, error) { + + errContext := "(execute::DefaultExecute:quietCommand)" + + command, err := e.Cmd.Command() + if err != nil { + return nil, errors.New(errContext, "Error creating command", err) + } + + quietCommand := make([]string, 0) + for _, cmd := range command { + if cmd == "-v" || cmd == "-vv" || cmd == "-vvv" || cmd == "-vvvv" || cmd == "--verbose" { + continue + } + quietCommand = append(quietCommand, cmd) + } + + return quietCommand, nil +} + // Execute takes a command and args and runs it, streaming output to stdout -func (e *DefaultExecute) Execute(ctx context.Context) error { +func (e *DefaultExecute) Execute(ctx context.Context) (err error) { - var err error + var errCmd error var cmdStderr, cmdStdout io.ReadCloser var wg sync.WaitGroup + errContext := "(execute::DefaultExecute::Execute)" + defer e.checkCompatibility() execErrChan := make(chan error) @@ -151,12 +182,19 @@ func (e *DefaultExecute) Execute(ctx context.Context) error { } if e.Cmd == nil { - return errors.New("(DefaultExecute::Execute)", "Command is not defined") + return errors.New(errContext, "Command is not defined") } command, err := e.Cmd.Command() if err != nil { - return errors.New("(DefaultExecute::Execute)", "Error creating command", err) + return errors.New(errContext, "Error creating command", err) + } + + if e.quiet { + command, err = e.quietCommand() + if err != nil { + return errors.New(errContext, "Error creating quiet command", err) + } } cmd := e.Exec.CommandContext(ctx, command[0], command[1:]...) @@ -180,15 +218,19 @@ func (e *DefaultExecute) Execute(ctx context.Context) error { trans = append(trans, e.Transformers...) cmdStdout, err = cmd.StdoutPipe() - defer cmdStdout.Close() + defer func() { + _ = cmdStdout.Close() + }() if err != nil { - return errors.New("(DefaultExecute::Execute)", "Error creating stdout pipe", err) + return errors.New(errContext, "Error creating stdout pipe", err) } cmdStderr, err = cmd.StderrPipe() - defer cmdStderr.Close() + defer func() { + _ = cmdStderr.Close() + }() if err != nil { - return errors.New("(DefaultExecute::Execute)", "Error creating stderr pipe", err) + return errors.New(errContext, "Error creating stderr pipe", err) } if e.Output == nil { @@ -200,7 +242,7 @@ func (e *DefaultExecute) Execute(ctx context.Context) error { err = cmd.Start() if err != nil { - return errors.New("(DefaultExecute::Execute)", "Error starting command", err) + return errors.New(errContext, "Error starting command", err) } // Waig for stdout and stderr @@ -228,7 +270,7 @@ func (e *DefaultExecute) Execute(ctx context.Context) error { wg.Wait() if err := <-execErrChan; err != nil { - return errors.New("(DefaultExecute::Execute)", "Error managing results output", err) + return errors.New(errContext, "Error managing results output", err) } err = cmd.Wait() @@ -237,37 +279,24 @@ func (e *DefaultExecute) Execute(ctx context.Context) error { if ctx.Err() != nil { fmt.Fprintf(e.Write, "%s\n", fmt.Sprintf("\nWhoops! %s\n", ctx.Err())) } else { - errorMessage := fmt.Sprintf("Command executed:\n%s\n", cmd.String()) + + if e.ErrorEnrich != nil { + errCmd = e.ErrorEnrich.Enrich(err) + } else { + errCmd = err + } + + errorMessage := fmt.Sprintf(" Command executed: %s\n", e.Cmd.String()) if len(e.EnvVars) > 0 { - errorMessage = fmt.Sprintf("%s\nEnvironment variables:\n%s\n", errorMessage, strings.Join(e.EnvVars.Environ(), "\n")) + errorMessage = fmt.Sprintf("%s\n Environment variables:\n%s\n", errorMessage, strings.Join(e.EnvVars.Environ(), "\n")) } - errorMessage = fmt.Sprintf("%s\nError:\n%s\n", errorMessage, err.Error()) + stderrErrorMessage := string(err.(*osexec.ExitError).Stderr) if len(stderrErrorMessage) > 0 { errorMessage = fmt.Sprintf("%s\n'%s'\n", errorMessage, stderrErrorMessage) } - exitError, exists := err.(*osexec.ExitError) - if exists { - ws := exitError.Sys().(syscall.WaitStatus) - switch ws.ExitStatus() { - case AnsiblePlaybookErrorCodeGeneralError: - errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageGeneralError, errorMessage) - case AnsiblePlaybookErrorCodeOneOrMoreHostFailed: - errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageOneOrMoreHostFailed, errorMessage) - case AnsiblePlaybookErrorCodeOneOrMoreHostUnreachable: - errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageOneOrMoreHostUnreachable, errorMessage) - case AnsiblePlaybookErrorCodeParserError: - errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageParserError, errorMessage) - case AnsiblePlaybookErrorCodeBadOrIncompleteOptions: - errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageBadOrIncompleteOptions, errorMessage) - case AnsiblePlaybookErrorCodeUserInterruptedExecution: - errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageUserInterruptedExecution, errorMessage) - case AnsiblePlaybookErrorCodeUnexpectedError: - errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageUnexpectedError, errorMessage) - } - } - return errors.New("(DefaultExecute::Execute)", fmt.Sprintf("Error during command execution: %s", errorMessage)) + return errors.New(errContext, fmt.Sprintf("Error during command execution.\n%s", errorMessage), errCmd) } } diff --git a/pkg/execute/defaultExecuteOptions.go b/pkg/execute/defaultExecuteOptions.go index f0a6e1a..eb6fa88 100644 --- a/pkg/execute/defaultExecuteOptions.go +++ b/pkg/execute/defaultExecuteOptions.go @@ -61,9 +61,16 @@ func WithEnvVars(vars map[string]string) ExecuteOptions { } } -// WithOutput add +// WithOutput sets the output mechanism to DefaultExecutor func WithOutput(output result.ResultsOutputer) ExecuteOptions { return func(e *DefaultExecute) { e.WithOutput(output) } } + +// WithErrorEnrich sets the error context mechanism to DefaultExecutor +func WithErrorEnrich(enricher ErrorEnricher) ExecuteOptions { + return func(e *DefaultExecute) { + e.ErrorEnrich = enricher + } +} diff --git a/pkg/execute/defaultExecute_test.go b/pkg/execute/defaultExecute_test.go index bf1df03..f6d2eab 100644 --- a/pkg/execute/defaultExecute_test.go +++ b/pkg/execute/defaultExecute_test.go @@ -43,6 +43,8 @@ func TestExecute(t *testing.T) { var stdout, stderr bytes.Buffer var cmdRead bytes.Buffer + errContext := "(execute::DefaultExecute::Execute)" + tests := []struct { desc string err error @@ -53,7 +55,7 @@ func TestExecute(t *testing.T) { }{ { desc: "Testing error executing a command when Command is not defiend", - err: errors.New("(DefaultExecute::Execute)", "Command is not defined"), + err: errors.New(errContext, "Command is not defined"), execute: NewDefaultExecute( WithWrite(io.Writer(&stdout)), WithWriteError(io.Writer(&stderr)), @@ -92,6 +94,39 @@ func TestExecute(t *testing.T) { e.AssertExpectations(t) }, }, + { + desc: "Testing execute a command in a quiet mode", + err: &errors.Error{}, + exec: exec.NewMockCmd(), + execute: &DefaultExecute{ + Exec: exec.NewMockExec(), + Cmd: mocks.NewMockAnsibleCmd([]string{"ansible-playbook", "--connection", "local", "../../test/test_site.yml"}, nil), + Write: io.Writer(&stdout), + WriterError: io.Writer(&stderr), + quiet: true, + }, + + prepareAssertFunc: func(e *exec.MockExec, cmd *exec.MockCmd) { + if e == nil { + t.Fatal("prepareAssertFunc requires a *exec.MockExec") + } + + if cmd == nil { + t.Fatal("prepareAssertFunc requires a *exec.MockCmd") + } + + cmd.On("StdoutPipe").Return(io.NopCloser(io.Reader(&cmdRead)), nil) + cmd.On("StderrPipe").Return(io.NopCloser(io.Reader(&cmdRead)), nil) + cmd.On("Start").Return(nil) + cmd.On("Wait").Return(nil) + + e.On("CommandContext", context.TODO(), "ansible-playbook", []string{"--connection", "local", "../../test/test_site.yml"}).Return(cmd) + }, + assertFunc: func(e *exec.MockExec, cmd *exec.MockCmd) { + cmd.AssertExpectations(t) + e.AssertExpectations(t) + }, + }, } for _, test := range tests { @@ -192,6 +227,66 @@ func TestExecute(t *testing.T) { // } // } +// TestQuiet tests the function WithQuiet +func TestQuiet(t *testing.T) { + execute := &DefaultExecute{} + execute.Quiet() + + assert.Equal(t, execute.quiet, true) +} + +func TestQuietCommand(t *testing.T) { + tests := []struct { + desc string + execute *DefaultExecute + expected []string + err error + }{ + { + desc: "Testing execute a command with verbose flags", + err: &errors.Error{}, + execute: &DefaultExecute{ + Exec: exec.NewMockExec(), + Cmd: mocks.NewMockAnsibleCmd( + []string{ + "ansible-playbook", + "--connection", + "local", + "site.yml", + "-v", + "-vv", + "-vvv", + "-vvvv", + "--verbose", + }, + nil), + // The test executes the quietCommand method so it is not necessary to set the quiet flag + // quiet: true, + }, + + expected: []string{ + "ansible-playbook", + "--connection", + "local", + "site.yml", + }, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + t.Log(test.desc) + + command, err := test.execute.quietCommand() + if err != nil { + assert.Equal(t, test.err, err) + } else { + assert.Equal(t, test.expected, command) + } + }) + } +} + func TestEnviron(t *testing.T) { tests := []struct { desc string diff --git a/pkg/execute/interface.go b/pkg/execute/interface.go index e9c0293..aa5c9ed 100644 --- a/pkg/execute/interface.go +++ b/pkg/execute/interface.go @@ -20,4 +20,10 @@ type Executabler interface { // Commander generates commands to be executed type Commander interface { Command() ([]string, error) + String() string +} + +// ErrorEnricher interface to enrich and customize errors +type ErrorEnricher interface { + Enrich(err error) error } diff --git a/pkg/execute/mockExecute.go b/pkg/execute/mockExecute.go index 18b6b61..ddd8db0 100644 --- a/pkg/execute/mockExecute.go +++ b/pkg/execute/mockExecute.go @@ -17,6 +17,11 @@ func NewMockExecute() *MockExecute { return &MockExecute{} } +// Quiet is a mock +func (e *MockExecute) Quiet() { + e.Called() +} + // Execute is a mock func (e *MockExecute) Execute(ctx context.Context) error { args := e.Called(ctx) diff --git a/pkg/execute/result/default/defaultResult.go b/pkg/execute/result/default/defaultResult.go index 6d9b414..602b181 100644 --- a/pkg/execute/result/default/defaultResult.go +++ b/pkg/execute/result/default/defaultResult.go @@ -29,7 +29,7 @@ func NewDefaultResults(options ...result.OptionsFunc) *DefaultResults { return results } -// WithTransformers sets a transformes list to DefaultResults +// WithTransformers sets a transformers list to DefaultResults func WithTransformers(trans ...transformer.TransformerFunc) result.OptionsFunc { return func(r result.ResultsOutputer) { r.(*DefaultResults).trans = append(r.(*DefaultResults).trans, trans...) diff --git a/pkg/execute/result/json/JSONResults.go b/pkg/execute/result/json/JSONResults.go index 7dc9e26..8001cde 100644 --- a/pkg/execute/result/json/JSONResults.go +++ b/pkg/execute/result/json/JSONResults.go @@ -27,7 +27,7 @@ func NewJSONStdoutCallbackResults(options ...result.OptionsFunc) *JSONStdoutCall return results } -// WithTransformers sets a transformes list to DefaultResults +// WithTransformers sets a transformers list to DefaultResults func WithTransformers(trans ...transformer.TransformerFunc) result.OptionsFunc { return func(r result.ResultsOutputer) { r.(*JSONStdoutCallbackResults).trans = append(r.(*JSONStdoutCallbackResults).trans, trans...) diff --git a/pkg/execute/result/json/ansiblePlaybookJSONResults.go b/pkg/execute/result/json/ansiblePlaybookJSONResults.go index 2082645..8ef18d5 100644 --- a/pkg/execute/result/json/ansiblePlaybookJSONResults.go +++ b/pkg/execute/result/json/ansiblePlaybookJSONResults.go @@ -58,7 +58,23 @@ func (r *AnsiblePlaybookJSONResults) CheckStats() error { return nil } -// AnsiblePlaybookJSONResultsPlay +/* +https://github.com/ansible-collections/ansible.posix/blob/main/plugins/callback/json.py#L80 + + { + 'play': { + 'name': play.get_name(), + 'id': to_text(play._uuid), + 'path': to_text(play.get_path()), + 'duration': { + 'start': current_time() + } + }, + 'tasks': [] + } + + AnsiblePlaybookJSONResultsPlay +*/ type AnsiblePlaybookJSONResultsPlay struct { Play *AnsiblePlaybookJSONResultsPlaysPlay `json:"play"` Tasks []AnsiblePlaybookJSONResultsPlayTask `json:"tasks"` @@ -66,27 +82,33 @@ type AnsiblePlaybookJSONResultsPlay struct { // AnsiblePlaybookJSONResultsPlaysPlay type AnsiblePlaybookJSONResultsPlaysPlay struct { - Name string `json:"name"` - Id string `json:"id"` Duration *AnsiblePlaybookJSONResultsPlayDuration `json:"duration"` + Id string `json:"id"` + Name string `json:"name"` + Path string `json:"path"` } /* - AnsiblePlaybookJSONResultsPlayTask +https://github.com/ansible-collections/ansible.posix/blob/main/plugins/callback/json.py#L94 + + { + 'task': { + 'name': task.get_name(), + 'id': to_text(task._uuid), + 'path': to_text(task.get_path()), + 'duration': { + 'start': current_time() + } + }, - 'task': { - 'name': task.get_name(), - 'id': to_text(task._uuid), - 'duration': { - 'start': current_time() - } - }, + 'hosts': {} + } -'hosts': {} + AnsiblePlaybookJSONResultsPlayTask */ type AnsiblePlaybookJSONResultsPlayTask struct { - Task *AnsiblePlaybookJSONResultsPlayTaskItem `json:"task"` Hosts map[string]*AnsiblePlaybookJSONResultsPlayTaskHostsItem `json:"hosts"` + Task *AnsiblePlaybookJSONResultsPlayTaskItem `json:"task"` } type AnsiblePlaybookJSONResultsPlayTaskHostsItem struct { @@ -95,9 +117,9 @@ type AnsiblePlaybookJSONResultsPlayTaskHostsItem struct { Msg interface{} `json:"msg"` AnsibleFacts map[string]interface{} `json:"ansible_facts"` Stdout interface{} `json:"stdout"` - StdoutLines []string `json:"stdout_lines"` + StdoutLines []interface{} `json:"stdout_lines"` Stderr interface{} `json:"stderr"` - StderrLines []string `json:"stderr_lines"` + StderrLines []interface{} `json:"stderr_lines"` Cmd interface{} `json:"cmd"` Failed bool `json:"failed"` FailedWhenResult bool `json:"failed_when_result"` @@ -107,9 +129,10 @@ type AnsiblePlaybookJSONResultsPlayTaskHostsItem struct { } type AnsiblePlaybookJSONResultsPlayTaskItem struct { - Name string `json:"name"` - Id string `json:"id"` Duration *AnsiblePlaybookJSONResultsPlayTaskItemDuration `json:"duration"` + Id string `json:"id"` + Name string `json:"name"` + Path string `json:"path"` } type AnsiblePlaybookJSONResultsPlayTaskItemDuration struct { diff --git a/pkg/execute/result/json/ansiblePlaybookJSONResults_test.go b/pkg/execute/result/json/ansiblePlaybookJSONResults_test.go index 0cde3d5..cf5dc48 100644 --- a/pkg/execute/result/json/ansiblePlaybookJSONResults_test.go +++ b/pkg/execute/result/json/ansiblePlaybookJSONResults_test.go @@ -101,7 +101,8 @@ func TestJSONParser(t *testing.T) { "start": "2020-08-07T20:51:30.607525Z" }, "id": "a0a4c5d1-62fd-b6f1-98ea-000000000006", - "name": "local" + "name": "local", + "path": "path" }, "tasks": [ { @@ -120,7 +121,8 @@ func TestJSONParser(t *testing.T) { "start": "2020-08-07T20:51:30.908539Z" }, "id": "a0a4c5d1-62fd-b6f1-98ea-000000000008", - "name": "Print line" + "name": "Print line", + "path": "path" } } ] @@ -150,6 +152,7 @@ func TestJSONParser(t *testing.T) { End: "2020-08-07T20:51:30.942955Z", Start: "2020-08-07T20:51:30.607525Z", }, + Path: "path", }, Tasks: []AnsiblePlaybookJSONResultsPlayTask{ { @@ -160,8 +163,8 @@ func TestJSONParser(t *testing.T) { End: "2020-08-07T20:51:30.942955Z", Start: "2020-08-07T20:51:30.908539Z", }, + Path: "path", }, - // TODOx Hosts: map[string]*AnsiblePlaybookJSONResultsPlayTaskHostsItem{ "127.0.0.1": { //"_ansible_no_log": false, "_ansible_verbose_always": true, @@ -219,7 +222,8 @@ func TestParseJSONResultsStream(t *testing.T) { "start": "2021-12-21T06:55:29.881536Z" }, "id": "3982ba1a-4acb-67e8-84e1-000000000006", - "name": "all" + "name": "all", + "path": "path" }, "tasks": [ { @@ -238,7 +242,8 @@ func TestParseJSONResultsStream(t *testing.T) { "start": "2021-12-21T06:55:29.886253Z" }, "id": "3982ba1a-4acb-67e8-84e1-000000000008", - "name": "json-stdout-ansibleplaybook" + "name": "json-stdout-ansibleplaybook", + "path": "path" } } ] @@ -458,6 +463,7 @@ func TestParseJSONResultsStream(t *testing.T) { End: "2021-12-21T06:55:29.890926Z", Start: "2021-12-21T06:55:29.881536Z", }, + Path: "path", }, Tasks: []AnsiblePlaybookJSONResultsPlayTask{ { @@ -468,6 +474,7 @@ func TestParseJSONResultsStream(t *testing.T) { End: "2021-12-21T06:55:29.890926Z", Start: "2021-12-21T06:55:29.886253Z", }, + Path: "path", }, Hosts: map[string]*AnsiblePlaybookJSONResultsPlayTaskHostsItem{ "127.0.0.1": { @@ -773,9 +780,9 @@ func TestParseJSONResultsStream(t *testing.T) { Action: "command", Changed: true, Stdout: "", - StdoutLines: []string{}, + StdoutLines: []interface{}{}, Stderr: "", - StderrLines: []string{}, + StderrLines: []interface{}{}, Cmd: "/usr/bin/true", Failed: false, FailedWhenResult: false, @@ -821,9 +828,9 @@ func TestParseJSONResultsStream(t *testing.T) { Changed: true, Msg: "non-zero return code", Stdout: "", - StdoutLines: []string{}, + StdoutLines: []interface{}{}, Stderr: "", - StderrLines: []string{}, + StderrLines: []interface{}{}, Cmd: "exit -1", Failed: true, FailedWhenResult: false, @@ -848,9 +855,9 @@ func TestParseJSONResultsStream(t *testing.T) { Changed: true, Msg: "non-zero return code", Stdout: "", - StdoutLines: []string{}, + StdoutLines: []interface{}{}, Stderr: "/usr/bin/ls: cannot access '/tmp/foobar.baz': No such file or directory", - StderrLines: []string{"/usr/bin/ls: cannot access '/tmp/foobar.baz': No such file or directory"}, + StderrLines: []interface{}{"/usr/bin/ls: cannot access '/tmp/foobar.baz': No such file or directory"}, Cmd: []interface{}{"/usr/bin/ls", "/tmp/foobar.baz"}, Failed: true, FailedWhenResult: true, @@ -875,6 +882,140 @@ func TestParseJSONResultsStream(t *testing.T) { }, }, }, + { + desc: "Testing json parse using and slice of slices in the stdout_lines", + inputResult: `{ + "custom_stats": {}, + "global_custom_stats": {}, + "plays": [ + { + "play": { + "duration": { + "end": "2024-04-01T03:08:28.359220Z", + "start": "2024-04-01T03:08:25.115857Z" + }, + "id": "ff523e0a-84a7-e3d6-229a-000000000006", + "name": "Slice of slices test" + }, + "tasks": [ + { + "hosts": { + "192.168.0.1": { + "_ansible_no_log": false, + "action": "ios_command", + "ansible_facts": { + "discovered_interpreter_python": "/usr/bin/python3" + }, + "changed": false, + "invocation": { + "module_args": { + "commands": [ + "show version | incl Version" + ], + "interval": 1, + "match": "all", + "provider": null, + "retries": 10, + "wait_for": null + } + }, + "stdout": [ + "One line\nAnother line\nEven another line\nLast line" + ], + "stdout_lines": [ + [ + "One line", + "Another line", + "Even another line", + "Last line" + ] + ] + } + }, + "task": { + "duration": { + "end": "2024-04-01T03:08:27.896416Z", + "start": "2024-04-01T03:08:25.148062Z" + }, + "id": "ff523e0a-84a7-e3d6-229a-000000000008", + "name": "run show version on the routers" + } + } + ] + } + ], + "stats": { + "192.168.0.1": { + "changed": 0, + "failures": 0, + "ignored": 0, + "ok": 2, + "rescued": 0, + "skipped": 0, + "unreachable": 0 + } + } + }`, + res: &AnsiblePlaybookJSONResults{ + + CustomStats: map[string]interface{}{}, + GlobalCustomStats: map[string]interface{}{}, + Plays: []AnsiblePlaybookJSONResultsPlay{ + { + Play: &AnsiblePlaybookJSONResultsPlaysPlay{ + Name: "Slice of slices test", + Id: "ff523e0a-84a7-e3d6-229a-000000000006", + Duration: &AnsiblePlaybookJSONResultsPlayDuration{ + End: "2024-04-01T03:08:28.359220Z", + Start: "2024-04-01T03:08:25.115857Z", + }, + }, + Tasks: []AnsiblePlaybookJSONResultsPlayTask{ + { + Hosts: map[string]*AnsiblePlaybookJSONResultsPlayTaskHostsItem{ + "192.168.0.1": { + // "_ansible_no_log": false, "_ansible_verbose_always": true, + Action: "ios_command", + AnsibleFacts: map[string]interface{}{ + "discovered_interpreter_python": "/usr/bin/python3", + }, + Changed: false, + Stdout: []interface{}{"One line\nAnother line\nEven another line\nLast line"}, + StdoutLines: []interface{}{ + []interface{}{ + "One line", + "Another line", + "Even another line", + "Last line", + }, + }, + }, + }, + Task: &AnsiblePlaybookJSONResultsPlayTaskItem{ + Id: "ff523e0a-84a7-e3d6-229a-000000000008", + Name: "run show version on the routers", + Duration: &AnsiblePlaybookJSONResultsPlayTaskItemDuration{ + End: "2024-04-01T03:08:27.896416Z", + Start: "2024-04-01T03:08:25.148062Z", + }, + }, + }, + }, + }, + }, + Stats: map[string]*AnsiblePlaybookJSONResultsStats{ + "192.168.0.1": { + Changed: 0, + Failures: 0, + Ignored: 0, + Ok: 2, + Rescued: 0, + Skipped: 0, + Unreachable: 0, + }, + }, + }, + }, } for _, test := range tests { diff --git a/pkg/execute/stdoutcallback/interface.go b/pkg/execute/stdoutcallback/interface.go index 47ce19d..a1b51bc 100644 --- a/pkg/execute/stdoutcallback/interface.go +++ b/pkg/execute/stdoutcallback/interface.go @@ -11,3 +11,9 @@ type ExecutorStdoutCallbackSetter interface { AddEnvVar(key, value string) WithOutput(output result.ResultsOutputer) } + +// ExecutorQuietStdoutCallbackSetter extends the ExecutorStdoutCallbackSetter interface by adding a method to force the non-verbose mode in the Stdout Callback configuration +type ExecutorQuietStdoutCallbackSetter interface { + ExecutorStdoutCallbackSetter + Quiet() +} diff --git a/pkg/execute/stdoutcallback/json.go b/pkg/execute/stdoutcallback/json.go index 602ba2b..e259f4d 100644 --- a/pkg/execute/stdoutcallback/json.go +++ b/pkg/execute/stdoutcallback/json.go @@ -14,14 +14,14 @@ const ( ) type JSONStdoutCallbackExecute struct { - executor ExecutorStdoutCallbackSetter + executor ExecutorQuietStdoutCallbackSetter } -func NewJSONStdoutCallbackExecute(executor ExecutorStdoutCallbackSetter) *JSONStdoutCallbackExecute { +func NewJSONStdoutCallbackExecute(executor ExecutorQuietStdoutCallbackSetter) *JSONStdoutCallbackExecute { return &JSONStdoutCallbackExecute{executor: executor} } -func (e *JSONStdoutCallbackExecute) WithExecutor(exec ExecutorStdoutCallbackSetter) *JSONStdoutCallbackExecute { +func (e *JSONStdoutCallbackExecute) WithExecutor(exec ExecutorQuietStdoutCallbackSetter) *JSONStdoutCallbackExecute { e.executor = exec return e } @@ -33,6 +33,7 @@ func (e *JSONStdoutCallbackExecute) Execute(ctx context.Context) error { return fmt.Errorf("JSONStdoutCallbackExecute executor requires an executor") } + e.executor.Quiet() e.executor.WithOutput(jsonresults.NewJSONStdoutCallbackResults()) return configuration.NewAnsibleWithConfigurationSettingsExecute(e.executor, diff --git a/pkg/execute/stdoutcallback/json_test.go b/pkg/execute/stdoutcallback/json_test.go index cbfa71b..24406ac 100644 --- a/pkg/execute/stdoutcallback/json_test.go +++ b/pkg/execute/stdoutcallback/json_test.go @@ -16,6 +16,7 @@ func TestJSONStdoutCallbackExecute(t *testing.T) { t.Run("Testing JSON stdout callback execution", func(t *testing.T) { exec := execute.NewMockExecute() + exec.On("Quiet") exec.On("WithOutput", mock.Anything).Return(exec) exec.On("AddEnvVar", configuration.AnsibleStdoutCallback, JSONStdoutCallback) exec.On("Execute", mock.Anything).Return(nil) @@ -30,6 +31,7 @@ func TestJSONStdoutCallbackExecute(t *testing.T) { t.Run("Testing error on JSON stdout callback when execute function returns an error", func(t *testing.T) { exec := execute.NewMockExecute() + exec.On("Quiet") exec.On("WithOutput", mock.Anything).Return(exec) exec.On("AddEnvVar", configuration.AnsibleStdoutCallback, JSONStdoutCallback) exec.On("Execute", mock.Anything).Return(errors.New("some error")) diff --git a/pkg/playbook/ansiblePlaybookCmd.go b/pkg/playbook/ansiblePlaybookCmd.go index 2444d24..bfafb46 100644 --- a/pkg/playbook/ansiblePlaybookCmd.go +++ b/pkg/playbook/ansiblePlaybookCmd.go @@ -7,37 +7,6 @@ import ( ) const ( - // TODO: error management - // // AnsiblePlaybookErrorCodeGeneralError is the error code for a general error - // AnsiblePlaybookErrorCodeGeneralError = 1 - // // AnsiblePlaybookErrorCodeOneOrMoreHostFailed is the error code for a one or more host failed - // AnsiblePlaybookErrorCodeOneOrMoreHostFailed = 2 - // // AnsiblePlaybookErrorCodeOneOrMoreHostUnreachable is the error code for a one or more host unreachable - // AnsiblePlaybookErrorCodeOneOrMoreHostUnreachable = 3 - // // AnsiblePlaybookErrorCodeParserError is the error code for a parser error - // AnsiblePlaybookErrorCodeParserError = 4 - // // AnsiblePlaybookErrorCodeBadOrIncompleteOptions is the error code for a bad or incomplete options - // AnsiblePlaybookErrorCodeBadOrIncompleteOptions = 5 - // // AnsiblePlaybookErrorCodeUserInterruptedExecution is the error code for a user interrupted execution - // AnsiblePlaybookErrorCodeUserInterruptedExecution = 99 - // // AnsiblePlaybookErrorCodeUnexpectedError is the error code for a unexpected error - // AnsiblePlaybookErrorCodeUnexpectedError = 250 - - // // AnsiblePlaybookErrorMessageGeneralError is the error message for a general error - // AnsiblePlaybookErrorMessageGeneralError = "ansible-playbook error: general error" - // // AnsiblePlaybookErrorMessageOneOrMoreHostFailed is the error message for a one or more host failed - // AnsiblePlaybookErrorMessageOneOrMoreHostFailed = "ansible-playbook error: one or more host failed" - // // AnsiblePlaybookErrorMessageOneOrMoreHostUnreachable is the error message for a one or more host unreachable - // AnsiblePlaybookErrorMessageOneOrMoreHostUnreachable = "ansible-playbook error: one or more host unreachable" - // // AnsiblePlaybookErrorMessageParserError is the error message for a parser error - // AnsiblePlaybookErrorMessageParserError = "ansible-playbook error: parser error" - // // AnsiblePlaybookErrorMessageBadOrIncompleteOptions is the error message for a bad or incomplete options - // AnsiblePlaybookErrorMessageBadOrIncompleteOptions = "ansible-playbook error: bad or incomplete options" - // // AnsiblePlaybookErrorMessageUserInterruptedExecution is the error message for a user interrupted execution - // AnsiblePlaybookErrorMessageUserInterruptedExecution = "ansible-playbook error: user interrupted execution" - // // AnsiblePlaybookErrorMessageUnexpectedError is the error message for a unexpected error - // AnsiblePlaybookErrorMessageUnexpectedError = "ansible-playbook error: unexpected error" - // DefaultAnsiblePlaybookBinary is the ansible-playbook binary file default value DefaultAnsiblePlaybookBinary = "ansible-playbook" ) @@ -139,47 +108,3 @@ func (p *AnsiblePlaybookCmd) String() string { return str } - -// TODO: error management for Ansible Playbook -// func (p *AnsiblePlaybookCmd) Error(ctx context.Context, err error) error { - -// if err != nil { -// if ctx.Err() != nil { -// goerrors.Wrap(err, fmt.Sprintf("\nWhoops! %s\n", ctx.Err())) - -// fmt.Fprintf(e.Write, "%s\n", fmt.Sprintf("\nWhoops! %s\n", ctx.Err())) -// } else { -// errorMessage := fmt.Sprintf("Command executed:\n%s\n", cmd.String()) -// if len(e.EnvVars) > 0 { -// errorMessage = fmt.Sprintf("%s\nEnvironment variables:\n%s\n", errorMessage, strings.Join(e.EnvVars.Environ(), "\n")) -// } -// errorMessage = fmt.Sprintf("%s\nError:\n%s\n", errorMessage, err.Error()) -// stderrErrorMessage := string(err.(*osexec.ExitError).Stderr) -// if len(stderrErrorMessage) > 0 { -// errorMessage = fmt.Sprintf("%s\n'%s'\n", errorMessage, stderrErrorMessage) -// } - -// exitError, exists := err.(*osexec.ExitError) -// if exists { -// ws := exitError.Sys().(syscall.WaitStatus) -// switch ws.ExitStatus() { -// case AnsiblePlaybookErrorCodeGeneralError: -// errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageGeneralError, errorMessage) -// case AnsiblePlaybookErrorCodeOneOrMoreHostFailed: -// errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageOneOrMoreHostFailed, errorMessage) -// case AnsiblePlaybookErrorCodeOneOrMoreHostUnreachable: -// errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageOneOrMoreHostUnreachable, errorMessage) -// case AnsiblePlaybookErrorCodeParserError: -// errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageParserError, errorMessage) -// case AnsiblePlaybookErrorCodeBadOrIncompleteOptions: -// errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageBadOrIncompleteOptions, errorMessage) -// case AnsiblePlaybookErrorCodeUserInterruptedExecution: -// errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageUserInterruptedExecution, errorMessage) -// case AnsiblePlaybookErrorCodeUnexpectedError: -// errorMessage = fmt.Sprintf("%s\n\n%s", AnsiblePlaybookErrorMessageUnexpectedError, errorMessage) -// } -// } -// return errors.New("(DefaultExecute::Execute)", fmt.Sprintf("Error during command execution: %s", errorMessage)) -// } -// } -// } diff --git a/pkg/playbook/ansiblePlaybookErrorEnrich.go b/pkg/playbook/ansiblePlaybookErrorEnrich.go new file mode 100644 index 0000000..f87ae08 --- /dev/null +++ b/pkg/playbook/ansiblePlaybookErrorEnrich.go @@ -0,0 +1,75 @@ +package playbook + +import ( + "github.com/pkg/errors" +) + +const ( + // TODO: error management + // AnsiblePlaybookErrorCodeGeneralError is the error code for a general error + AnsiblePlaybookErrorCodeGeneralError = 1 + // AnsiblePlaybookErrorCodeOneOrMoreHostFailed is the error code for a one or more host failed + AnsiblePlaybookErrorCodeOneOrMoreHostFailed = 2 + // AnsiblePlaybookErrorCodeOneOrMoreHostUnreachable is the error code for a one or more host unreachable + AnsiblePlaybookErrorCodeOneOrMoreHostUnreachable = 3 + // AnsiblePlaybookErrorCodeParserError is the error code for a parser error + AnsiblePlaybookErrorCodeParserError = 4 + // AnsiblePlaybookErrorCodeBadOrIncompleteOptions is the error code for a bad or incomplete options + AnsiblePlaybookErrorCodeBadOrIncompleteOptions = 5 + // AnsiblePlaybookErrorCodeUserInterruptedExecution is the error code for a user interrupted execution + AnsiblePlaybookErrorCodeUserInterruptedExecution = 99 + // AnsiblePlaybookErrorCodeUnexpectedError is the error code for a unexpected error + AnsiblePlaybookErrorCodeUnexpectedError = 250 + + // AnsiblePlaybookErrorMessageGeneralError is the error message for a general error + AnsiblePlaybookErrorMessageGeneralError = "ansible-playbook error: general error" + // AnsiblePlaybookErrorMessageOneOrMoreHostFailed is the error message for a one or more host failed + AnsiblePlaybookErrorMessageOneOrMoreHostFailed = "ansible-playbook error: one or more host failed" + // AnsiblePlaybookErrorMessageOneOrMoreHostUnreachable is the error message for a one or more host unreachable + AnsiblePlaybookErrorMessageOneOrMoreHostUnreachable = "ansible-playbook error: one or more host unreachable" + // AnsiblePlaybookErrorMessageParserError is the error message for a parser error + AnsiblePlaybookErrorMessageParserError = "ansible-playbook error: parser error" + // AnsiblePlaybookErrorMessageBadOrIncompleteOptions is the error message for a bad or incomplete options + AnsiblePlaybookErrorMessageBadOrIncompleteOptions = "ansible-playbook error: bad or incomplete options" + // AnsiblePlaybookErrorMessageUserInterruptedExecution is the error message for a user interrupted execution + AnsiblePlaybookErrorMessageUserInterruptedExecution = "ansible-playbook error: user interrupted execution" + // AnsiblePlaybookErrorMessageUnexpectedError is the error message for a unexpected error + AnsiblePlaybookErrorMessageUnexpectedError = "ansible-playbook error: unexpected error" +) + +// AnsiblePlaybookErrorEnrich is an error enricher for ansible-playbook errors +type AnsiblePlaybookErrorEnrich struct{} + +// NewAnsiblePlaybookErrorEnrich creates a new AnsiblePlaybookErrorEnrich instance +func NewAnsiblePlaybookErrorEnrich() *AnsiblePlaybookErrorEnrich { + return &AnsiblePlaybookErrorEnrich{} +} + +// Enrich return an error enriched with ansible-playbook error information +func (e *AnsiblePlaybookErrorEnrich) Enrich(err error) error { + + var errorMessage string + + _, hasExitCode := err.(ExitCodeErrorer) + + if hasExitCode { + switch err.(ExitCodeErrorer).ExitCode() { + case AnsiblePlaybookErrorCodeGeneralError: + errorMessage = AnsiblePlaybookErrorMessageGeneralError + case AnsiblePlaybookErrorCodeOneOrMoreHostFailed: + errorMessage = AnsiblePlaybookErrorMessageOneOrMoreHostFailed + case AnsiblePlaybookErrorCodeOneOrMoreHostUnreachable: + errorMessage = AnsiblePlaybookErrorMessageOneOrMoreHostUnreachable + case AnsiblePlaybookErrorCodeParserError: + errorMessage = AnsiblePlaybookErrorMessageParserError + case AnsiblePlaybookErrorCodeBadOrIncompleteOptions: + errorMessage = AnsiblePlaybookErrorMessageBadOrIncompleteOptions + case AnsiblePlaybookErrorCodeUserInterruptedExecution: + errorMessage = AnsiblePlaybookErrorMessageUserInterruptedExecution + case AnsiblePlaybookErrorCodeUnexpectedError: + errorMessage = AnsiblePlaybookErrorMessageUnexpectedError + } + } + + return errors.Wrap(err, errorMessage) +} diff --git a/pkg/playbook/ansiblePlaybookErrorEnrich_test.go b/pkg/playbook/ansiblePlaybookErrorEnrich_test.go new file mode 100644 index 0000000..cc221ae --- /dev/null +++ b/pkg/playbook/ansiblePlaybookErrorEnrich_test.go @@ -0,0 +1,83 @@ +package playbook + +import ( + "fmt" + "testing" + + "github.com/apenella/go-ansible/v2/mocks" + "github.com/stretchr/testify/assert" +) + +func TestEnrich(t *testing.T) { + + tests := []struct { + desc string + err error + expected string + }{ + { + desc: "Testing enrich with a ansible-playbook general error", + err: &mocks.MockExitCodeErr{ + Code: AnsiblePlaybookErrorCodeGeneralError, + Message: "error cause", + }, + expected: fmt.Sprintf("%s: %s", AnsiblePlaybookErrorMessageGeneralError, "error cause"), + }, + { + desc: "Testing enrich with a ansible-playbook hosts failed error", + err: &mocks.MockExitCodeErr{ + Code: AnsiblePlaybookErrorCodeOneOrMoreHostFailed, + Message: "error cause", + }, + expected: fmt.Sprintf("%s: %s", AnsiblePlaybookErrorMessageOneOrMoreHostFailed, "error cause"), + }, + { + desc: "Testing enrich with a ansible-playbook hosts unreachable error", + err: &mocks.MockExitCodeErr{ + Code: AnsiblePlaybookErrorCodeOneOrMoreHostUnreachable, + Message: "error cause", + }, + expected: fmt.Sprintf("%s: %s", AnsiblePlaybookErrorMessageOneOrMoreHostUnreachable, "error cause"), + }, + { + desc: "Testing enrich with a ansible-playbook parser error", + err: &mocks.MockExitCodeErr{ + Code: AnsiblePlaybookErrorCodeParserError, + Message: "error cause", + }, + expected: fmt.Sprintf("%s: %s", AnsiblePlaybookErrorMessageParserError, "error cause"), + }, + { + desc: "Testing enrich with a ansible-playbook bad or incomplete options error", + err: &mocks.MockExitCodeErr{ + Code: AnsiblePlaybookErrorCodeBadOrIncompleteOptions, + Message: "error cause", + }, + expected: fmt.Sprintf("%s: %s", AnsiblePlaybookErrorMessageBadOrIncompleteOptions, "error cause"), + }, + { + desc: "Testing enrich with a ansible-playbook user interrupted execution error", + err: &mocks.MockExitCodeErr{ + Code: AnsiblePlaybookErrorCodeUserInterruptedExecution, + Message: "error cause", + }, + expected: fmt.Sprintf("%s: %s", AnsiblePlaybookErrorMessageUserInterruptedExecution, "error cause"), + }, + { + desc: "Testing enrich with a ansible-playbook unexpected error", + err: &mocks.MockExitCodeErr{ + Code: AnsiblePlaybookErrorCodeUnexpectedError, + Message: "error cause", + }, + expected: fmt.Sprintf("%s: %s", AnsiblePlaybookErrorMessageUnexpectedError, "error cause"), + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + e := NewAnsiblePlaybookErrorEnrich() + err := e.Enrich(test.err) + assert.Equal(t, test.expected, err.Error()) + }) + } +} diff --git a/pkg/playbook/ansiblePlaybookExecute.go b/pkg/playbook/ansiblePlaybookExecute.go index 3cbcca9..8c5ae62 100644 --- a/pkg/playbook/ansiblePlaybookExecute.go +++ b/pkg/playbook/ansiblePlaybookExecute.go @@ -44,6 +44,7 @@ func (e *AnsiblePlaybookExecute) Execute(ctx context.Context) error { exec := execute.NewDefaultExecute( execute.WithCmd(e.cmd), + execute.WithErrorEnrich(NewAnsiblePlaybookErrorEnrich()), ) err := exec.Execute(ctx) diff --git a/pkg/playbook/interface.go b/pkg/playbook/interface.go index 98a7cfe..6f599a6 100644 --- a/pkg/playbook/interface.go +++ b/pkg/playbook/interface.go @@ -5,3 +5,7 @@ import "github.com/apenella/go-ansible/v2/pkg/vault" type Vaulter interface { Vault(value string) (*vault.VaultVariableValue, error) } + +type ExitCodeErrorer interface { + ExitCode() int +} diff --git a/pkg/vault/password/envvars/readPasswordFromEnvVar.go b/pkg/vault/password/envvars/readPasswordFromEnvVar.go index 76bb939..86d5747 100644 --- a/pkg/vault/password/envvars/readPasswordFromEnvVar.go +++ b/pkg/vault/password/envvars/readPasswordFromEnvVar.go @@ -1,7 +1,7 @@ package envvars import ( - "fmt" + "log" "os" "github.com/pkg/errors" @@ -45,7 +45,7 @@ func (s *ReadPasswordFromEnvVar) Read() (string, error) { secret := os.Getenv(s.envvar) if len(secret) <= 0 { - errors.New(fmt.Sprintf("The environment variable '%s' is not set.", s.envvar)) + log.Printf("The environment variable '%s' is not set.", s.envvar) } return secret, nil