0
0
mirror of https://github.com/thegeeklab/wp-ansible.git synced 2024-06-02 18:29:40 +02:00

Compare commits

...

64 Commits
v0.1.0 ... main

Author SHA1 Message Date
renovate[bot]
37719b63ec chore(deps): update dependency golangci/golangci-lint to v1.59.0 2024-05-27 05:13:15 +00:00
renovate[bot]
28c58de3f3
chore(deps): update dependency ansible to v9.6.0 (#66)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-24 09:42:43 +02:00
renovate[bot]
e247774398
fix(deps): update module github.com/rs/zerolog to v1.33.0 (#67)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-24 09:25:47 +02:00
renovate[bot]
c18776810e chore(docker): update docker.io/python:3.12-alpine docker digest to 5365725 2024-05-24 03:37:12 +00:00
renovate[bot]
e1e01963bf chore(deps): update dependency golangci/golangci-lint to v1.58.2 2024-05-20 10:29:39 +00:00
ed42a97d1c
chore: migrate to wp-plugin-go v3 (#63) 2024-05-17 21:49:52 +02:00
renovate[bot]
7b51a968a2
chore(docker): update docker.io/library/golang:1.22 docker digest to f43c6f0 (#62)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-16 13:41:03 +02:00
renovate[bot]
ebaa5a61a4 chore(deps): update dependency golangci/golangci-lint to v1.58.1 2024-05-13 03:59:19 +00:00
b05c2cfd4a
ci: fix golangci-lint deprecations 2024-05-12 11:08:30 +02:00
renovate[bot]
01ece4ef61 chore(docker): update docker.io/library/golang:1.22 docker digest to b1e05e2 2024-05-08 04:58:02 +00:00
ed3e3e86f5
cleanup mixed versions on wp-plugin-go imports 2024-05-07 21:55:21 +02:00
f1e1e84b4a
fix: check is cmd is nil before execution (#59) 2024-05-07 11:57:21 +02:00
a7a02b3f74
cleanup import 2024-05-06 21:26:27 +02:00
aa769cb2fa
use assert instead of require 2024-05-06 21:03:08 +02:00
3148862ffa
refactor: switch to plugin Cmd and add tests (#58) 2024-05-06 20:29:44 +02:00
renovate[bot]
ca0a484ed7 chore(deps): update dependency golangci/golangci-lint to v1.58.0 2024-05-06 04:46:12 +00:00
renovate[bot]
23d8438dfd
fix(deps): update module github.com/thegeeklab/wp-plugin-go/v2 to v2.0.1 (#55)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-05 13:42:10 +02:00
renovate[bot]
06793e5a12
fix(deps): update module golang.org/x/sys to v0.20.0 (#54)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-05 13:03:38 +02:00
30c17c5e8c
docs: hide system flags and refactor generator (#52) 2024-05-05 13:03:29 +02:00
2f1a89a6cb
fix: fix static bin paths and required flags (#50) 2024-05-04 14:35:41 +02:00
renovate[bot]
93819eb5b2
fix(deps): update module github.com/urfave/cli/v2 to v2.27.2 (#49)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-29 10:26:00 +02:00
renovate[bot]
95fb144d16 chore(docker): update docker.io/library/golang:1.22 docker digest to d5302d4 2024-04-25 03:25:50 +00:00
renovate[bot]
9d3afd9141
chore(deps): update dependency ansible to v9.5.1 (#47)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-24 08:58:06 +02:00
renovate[bot]
2d6d320cab
fix(deps): update module github.com/thegeeklab/wp-plugin-go to v1.7.1 (#46)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-22 12:38:29 +02:00
renovate[bot]
fa06c54fca chore(docker): update docker digests 2024-04-11 06:13:52 +00:00
renovate[bot]
960d7b5a28
fix(deps): update module golang.org/x/sys to v0.19.0 (#44)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-05 08:54:27 +02:00
renovate[bot]
d465320164 chore(docker): update docker.io/library/golang:1.22 docker digest to c4fb952 2024-04-04 03:06:51 +00:00
renovate[bot]
7a6240d6e9 chore(deps): update dependency golangci/golangci-lint to v1.57.2 2024-04-01 03:16:15 +00:00
renovate[bot]
39a41cf6d3
chore(deps): update dependency ansible to v9.4.0 (#41)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-28 12:44:38 +01:00
renovate[bot]
dae0e49a3a
chore(deps): update quay.io/thegeeklab/wp-docker-buildx docker tag to v4 (#40)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-27 08:56:23 +01:00
renovate[bot]
51b7c08c29
fix(deps): update module github.com/thegeeklab/wp-plugin-go to v1.7.0 (#35)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-26 21:32:18 +01:00
renovate[bot]
4db13815bd chore(docker): update docker.io/python:3.12-alpine docker digest to c7eb5c9 2024-03-26 07:37:19 +00:00
renovate[bot]
82e8ab9a3c chore(deps): update dependency golangci/golangci-lint to v1.57.1 2024-03-25 03:18:28 +00:00
renovate[bot]
1d9f323672 chore(docker): update docker.io/python:3.12-alpine docker digest to 25a82f6 2024-03-17 04:16:41 +00:00
renovate[bot]
62caf44650 chore(docker): update docker.io/library/golang:1.22 docker digest to 0b55ab8 2024-03-13 07:09:02 +00:00
a9809bae47
cleanup docs and examples 2024-03-12 20:43:38 +01:00
renovate[bot]
af63f0ede2
fix(deps): update module github.com/thegeeklab/wp-plugin-go to v1.6.1 (#34)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-07 21:26:24 +01:00
renovate[bot]
113f414397
fix(deps): update module golang.org/x/sys to v0.18.0 (#32)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-06 14:42:11 +01:00
renovate[bot]
a0fe1bc6c4 chore(docker): update docker.io/library/golang:1.22 docker digest to 34ce21a 2024-03-06 03:04:58 +00:00
renovate[bot]
7e88678f14
chore(deps): update dependency ansible to v9.3.0 (#31)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-28 09:44:47 +01:00
renovate[bot]
c331ac96b2 chore(deps): update dependency golangci/golangci-lint to v1.56.2 2024-02-19 04:08:27 +00:00
renovate[bot]
bc1a8d4697 chore(docker): update docker digests 2024-02-16 03:18:37 +00:00
fc1c113b5a
[skip ci] revert renovate automerge config 2024-02-15 12:19:31 +01:00
renovate[bot]
ef99c0e84c
fix(deps): update module github.com/thegeeklab/wp-plugin-go to v1.6.0 (#28)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-09 22:11:50 +01:00
renovate[bot]
db53dcbfed
fix(deps): update module golang.org/x/sys to v0.17.0 (#27)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-08 08:32:02 +01:00
renovate[bot]
94b9d11ed8
chore(deps): update docker.io/library/golang docker tag to v1.22 (#26)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Robert Kaussow <mail@thegeeklab.de>
2024-02-07 22:32:22 +01:00
c1d424e25f
harmonize container image refs and use fqin 2024-02-07 09:40:52 +01:00
7f12ab4701
run ci on renovate auto branches 2024-02-07 09:10:13 +01:00
b0b79e312b
ci: enable ci run on renovate branches 2024-02-05 08:58:31 +01:00
renovate[bot]
ac033a6627 chore(docker): update docker.io/golang:1.21 docker digest to 7b575fe 2024-02-03 07:39:42 +00:00
renovate[bot]
4d085d5217
chore(deps): update dependency ansible to v9.2.0 (#23)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-31 09:08:47 +01:00
renovate[bot]
fac5d1087f chore(deps): update dependency mvdan/gofumpt to v0.6.0 2024-01-30 15:23:57 +00:00
renovate[bot]
8e4e1c384b chore(docker): update docker.io/python:3.12-alpine docker digest to 14cfc61 2024-01-29 10:06:23 +00:00
renovate[bot]
26be721449 chore(docker): update docker.io/golang:1.21 docker digest to 76aadd9 2024-01-25 07:29:40 +00:00
renovate[bot]
4458cc5c02
chore(deps): update quay.io/thegeeklab/wp-docker-buildx docker tag to v3 (#19)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-22 11:29:34 +01:00
renovate[bot]
74ebabd571 chore(docker): update docker.io/python:3.12-alpine docker digest to 801b54e 2024-01-20 01:06:27 +00:00
renovate[bot]
6dde39bfd0 chore(docker): update docker.io/python:3.12-alpine docker digest to 4a156f7 2024-01-19 09:41:50 +00:00
renovate[bot]
9c51ec57f4 chore(docker): update docker.io/golang:1.21 docker digest to 5f5d61d 2024-01-17 11:47:51 +00:00
9c0998e68f
fix plugin image in docs example 2024-01-16 14:33:56 +01:00
renovate[bot]
b7b23bf043 chore(docker): update docker.io/golang:1.21 docker digest to 6fbd2d3 2024-01-12 00:18:55 +00:00
renovate[bot]
f95371b431 chore(docker): update docker.io/golang:1.21 docker digest to 21260a4 2024-01-11 15:44:31 +00:00
renovate[bot]
7a21c1aa68 chore(docker): update docker.io/golang:1.21 docker digest to ffbb0b8 2024-01-11 03:50:31 +00:00
renovate[bot]
10c125dbfb chore(docker): update docker.io/golang:1.21 docker digest to 7026fb7 2024-01-10 04:19:20 +00:00
ed73f885b6
fix license desc in docs 2024-01-06 14:46:00 +01:00
24 changed files with 952 additions and 771 deletions

View File

@ -23,7 +23,6 @@ linters:
- errchkjson
- errname
- errorlint
- execinquery
- exhaustive
- exportloopref
- forcetypeassert
@ -37,12 +36,12 @@ linters:
- gocyclo
- godot
- godox
- goerr113
- err113
- gofmt
- gofumpt
- goheader
- goimports
- gomnd
- mnd
- gomoddirectives
- gomodguard
- goprintffuncname

View File

@ -7,7 +7,7 @@ when:
steps:
- name: dryrun
image: quay.io/thegeeklab/wp-docker-buildx:2.0.0
image: quay.io/thegeeklab/wp-docker-buildx:4
settings:
containerfile: Containerfile.multiarch
dry_run: true
@ -20,7 +20,7 @@ steps:
- event: [pull_request]
- name: publish-dockerhub
image: quay.io/thegeeklab/wp-docker-buildx:2.0.0
image: quay.io/thegeeklab/wp-docker-buildx:4
group: container
settings:
auto_tag: true
@ -41,7 +41,7 @@ steps:
- ${CI_REPO_DEFAULT_BRANCH}
- name: publish-quay
image: quay.io/thegeeklab/wp-docker-buildx:2.0.0
image: quay.io/thegeeklab/wp-docker-buildx:4
group: container
settings:
auto_tag: true

View File

@ -7,7 +7,7 @@ when:
steps:
- name: build
image: docker.io/techknowlogick/xgo:go-1.21.x
image: docker.io/techknowlogick/xgo:go-1.22.x
commands:
- ln -s $(pwd) /source
- make release

View File

@ -7,11 +7,11 @@ when:
steps:
- name: lint
image: docker.io/library/golang:1.21
image: docker.io/library/golang:1.22
commands:
- make lint
- name: test
image: docker.io/library/golang:1.21
image: docker.io/library/golang:1.22
commands:
- make test

View File

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM docker.io/golang:1.21@sha256:672a2286da3ee7a854c3e0a56e0838918d0dbb1c18652992930293312de898a6 as build
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.22@sha256:f43c6f049f04cbbaeb28f0aad3eea15274a7d0a7899a617d0037aec48d7ab010 as build
ARG TARGETOS
ARG TARGETARCH
@ -8,7 +8,7 @@ WORKDIR /src
RUN make build
FROM docker.io/python:3.12-alpine@sha256:c793b92fd9e0e2a0b611756788a033d569ca864b733461c8fb30cfd14847dbcf
FROM docker.io/python:3.12-alpine@sha256:5365725a6cd59b72a927628fdda9965103e3dc671676c89ef3ed8b8b0e22e812
LABEL maintainer="Robert Kaussow <mail@thegeeklab.de>"
LABEL org.opencontainers.image.authors="Robert Kaussow <mail@thegeeklab.de>"
@ -22,7 +22,7 @@ ARG TARGETARCH
ARG ANSIBLE_VERSION
# renovate: datasource=pypi depName=ansible
ENV ANSIBLE_VERSION="${ANSIBLE_VERSION:-9.1.0}"
ENV ANSIBLE_VERSION="${ANSIBLE_VERSION:-9.6.0}"
RUN apk --update add --virtual .build-deps python3-dev libffi-dev build-base && \
apk add --no-cache bash git curl rsync openssh-client sshpass && \

View File

@ -1,7 +1,7 @@
# renovate: datasource=github-releases depName=mvdan/gofumpt
GOFUMPT_PACKAGE_VERSION := v0.5.0
GOFUMPT_PACKAGE_VERSION := v0.6.0
# renovate: datasource=github-releases depName=golangci/golangci-lint
GOLANGCI_LINT_PACKAGE_VERSION := v1.55.2
GOLANGCI_LINT_PACKAGE_VERSION := v1.59.0
EXECUTABLE := wp-ansible
@ -19,8 +19,7 @@ GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@$(G
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GOTESTSUM_PACKAGE ?= gotest.tools/gotestsum@latest
GENERATE ?=
XGO_VERSION := go-1.21.x
XGO_VERSION := go-1.22.x
XGO_TARGETS ?= linux/amd64,linux/arm64
TARGETOS ?= linux
@ -65,11 +64,7 @@ lint: golangci-lint
.PHONY: generate
generate:
$(GO) generate $(GENERATE)
.PHONY: generate-docs
generate-docs:
$(GO) generate ./cmd/$(EXECUTABLE)/flags.go
$(GO) generate $(PACKAGES)
.PHONY: test
test:

267
ansible/ansible.go Normal file
View File

@ -0,0 +1,267 @@
package ansible
import (
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/rs/zerolog/log"
plugin_exec "github.com/thegeeklab/wp-plugin-go/v3/exec"
"github.com/urfave/cli/v2"
)
const (
AnsibleForksDefault = 5
ansibleBin = "/usr/local/bin/ansible"
ansibleGalaxyBin = "/usr/local/bin/ansible-galaxy"
ansiblePlaybookBin = "/usr/local/bin/ansible-playbook"
)
var ErrAnsiblePlaybookNotFound = errors.New("no playbook found")
type Ansible struct {
GalaxyRequirements string
Inventories cli.StringSlice
Playbooks cli.StringSlice
Limit string
SkipTags string
StartAtTask string
Tags string
ExtraVars cli.StringSlice
ModulePath cli.StringSlice
Check bool
Diff bool
FlushCache bool
ForceHandlers bool
ListHosts bool
ListTags bool
ListTasks bool
SyntaxCheck bool
Forks int
VaultID string
VaultPasswordFile string
Verbose int
PrivateKeyFile string
User string
Connection string
Timeout int
SSHCommonArgs string
SFTPExtraArgs string
SCPExtraArgs string
SSHExtraArgs string
Become bool
BecomeMethod string
BecomeUser string
}
// Version runs the Ansible binary with the --version flag to retrieve the current version.
func (a *Ansible) Version() *plugin_exec.Cmd {
args := []string{
"--version",
}
cmd := plugin_exec.Command(ansibleBin, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
}
// GetPlaybooks retrieves the list of Ansible playbook files based on the configured playbook patterns.
func (a *Ansible) GetPlaybooks() error {
var playbooks []string
for _, pb := range a.Playbooks.Value() {
files, err := filepath.Glob(pb)
if err != nil {
playbooks = append(playbooks, pb)
continue
}
playbooks = append(playbooks, files...)
}
if len(playbooks) == 0 {
log.Debug().Strs("patterns", a.Playbooks.Value()).Msg("no playbooks found")
return ErrAnsiblePlaybookNotFound
}
a.Playbooks = *cli.NewStringSlice(playbooks...)
return nil
}
// GalaxyInstall runs the ansible-galaxy install command with the configured options.
func (a *Ansible) GalaxyInstall() *plugin_exec.Cmd {
args := []string{
"install",
"--force",
"--role-file",
a.GalaxyRequirements,
}
if a.Verbose > 0 {
args = append(args, fmt.Sprintf("-%s", strings.Repeat("v", a.Verbose)))
}
cmd := plugin_exec.Command(ansibleGalaxyBin, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
}
// Play runs the Ansible playbook with the configured options.
//
//nolint:gocyclo
func (a *Ansible) Play() *plugin_exec.Cmd {
args := make([]string, 0)
for _, inventory := range a.Inventories.Value() {
args = append(args, "--inventory", inventory)
}
if len(a.ModulePath.Value()) > 0 {
args = append(args, "--module-path", strings.Join(a.ModulePath.Value(), ":"))
}
if a.VaultID != "" {
args = append(args, "--vault-id", a.VaultID)
}
if a.VaultPasswordFile != "" {
args = append(args, "--vault-password-file", a.VaultPasswordFile)
}
for _, v := range a.ExtraVars.Value() {
args = append(args, "--extra-vars", v)
}
if a.ListHosts {
args = append(args, "--list-hosts")
args = append(args, a.Playbooks.Value()...)
cmd := plugin_exec.Command(ansiblePlaybookBin, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
}
if a.SyntaxCheck {
args = append(args, "--syntax-check")
args = append(args, a.Playbooks.Value()...)
cmd := plugin_exec.Command(ansiblePlaybookBin, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
}
if a.Check {
args = append(args, "--check")
}
if a.Diff {
args = append(args, "--diff")
}
if a.FlushCache {
args = append(args, "--flush-cache")
}
if a.ForceHandlers {
args = append(args, "--force-handlers")
}
if a.Forks != AnsibleForksDefault {
args = append(args, "--forks", strconv.Itoa(a.Forks))
}
if a.Limit != "" {
args = append(args, "--limit", a.Limit)
}
if a.ListTags {
args = append(args, "--list-tags")
}
if a.ListTasks {
args = append(args, "--list-tasks")
}
if a.SkipTags != "" {
args = append(args, "--skip-tags", a.SkipTags)
}
if a.StartAtTask != "" {
args = append(args, "--start-at-task", a.StartAtTask)
}
if a.Tags != "" {
args = append(args, "--tags", a.Tags)
}
if a.PrivateKeyFile != "" {
args = append(args, "--private-key", a.PrivateKeyFile)
}
if a.User != "" {
args = append(args, "--user", a.User)
}
if a.Connection != "" {
args = append(args, "--connection", a.Connection)
}
if a.Timeout != 0 {
args = append(args, "--timeout", strconv.Itoa(a.Timeout))
}
if a.SSHCommonArgs != "" {
args = append(args, "--ssh-common-args", a.SSHCommonArgs)
}
if a.SFTPExtraArgs != "" {
args = append(args, "--sftp-extra-args", a.SFTPExtraArgs)
}
if a.SCPExtraArgs != "" {
args = append(args, "--scp-extra-args", a.SCPExtraArgs)
}
if a.SSHExtraArgs != "" {
args = append(args, "--ssh-extra-args", a.SSHExtraArgs)
}
if a.Become {
args = append(args, "--become")
}
if a.BecomeMethod != "" {
args = append(args, "--become-method", a.BecomeMethod)
}
if a.BecomeUser != "" {
args = append(args, "--become-user", a.BecomeUser)
}
if a.Verbose > 0 {
args = append(args, fmt.Sprintf("-%s", strings.Repeat("v", a.Verbose)))
}
args = append(args, a.Playbooks.Value()...)
cmd := plugin_exec.Command(ansiblePlaybookBin, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
}

206
ansible/ansible_test.go Normal file
View File

@ -0,0 +1,206 @@
package ansible
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v2"
)
func TestVersion(t *testing.T) {
tests := []struct {
name string
ansible *Ansible
want []string
}{
{
name: "test version command",
ansible: &Ansible{},
want: []string{ansibleBin, "--version"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := tt.ansible.Version()
assert.Equal(t, tt.want, cmd.Cmd.Args)
})
}
}
func TestGalaxyInstall(t *testing.T) {
tests := []struct {
name string
ansible *Ansible
want []string
}{
{
name: "with valid requirements file and no verbosity",
ansible: &Ansible{
GalaxyRequirements: "requirements.yml",
},
want: []string{ansibleGalaxyBin, "install", "--force", "--role-file", "requirements.yml"},
},
{
name: "with valid requirements file and verbosity level 1",
ansible: &Ansible{
GalaxyRequirements: "requirements.yml",
Verbose: 1,
},
want: []string{ansibleGalaxyBin, "install", "--force", "--role-file", "requirements.yml", "-v"},
},
{
name: "with valid requirements file and verbosity level 3",
ansible: &Ansible{
GalaxyRequirements: "requirements.yml",
Verbose: 3,
},
want: []string{ansibleGalaxyBin, "install", "--force", "--role-file", "requirements.yml", "-vvv"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := tt.ansible.GalaxyInstall()
assert.Equal(t, tt.want, cmd.Cmd.Args)
})
}
}
func TestAnsibleCommand(t *testing.T) {
tests := []struct {
name string
ansible *Ansible
want []string
}{
{
name: "with inventory and no other settings",
ansible: &Ansible{
Inventories: *cli.NewStringSlice("inventory.yml"),
},
want: []string{ansiblePlaybookBin, "--inventory", "inventory.yml", "--forks", "0"},
},
{
name: "with inventory and module path",
ansible: &Ansible{
Inventories: *cli.NewStringSlice("inventory.yml"),
ModulePath: *cli.NewStringSlice("/path/to/modules"),
},
want: []string{
ansiblePlaybookBin, "--inventory", "inventory.yml", "--module-path",
"/path/to/modules", "--forks", "0",
},
},
{
name: "with inventory, module path, and vault ID",
ansible: &Ansible{
Inventories: *cli.NewStringSlice("inventory.yml"),
ModulePath: *cli.NewStringSlice("/path/to/modules"),
VaultID: "my_vault_id",
},
want: []string{
ansiblePlaybookBin, "--inventory", "inventory.yml", "--module-path", "/path/to/modules",
"--vault-id", "my_vault_id", "--forks", "0",
},
},
{
name: "with inventory, module path, vault ID, and vault password file",
ansible: &Ansible{
Inventories: *cli.NewStringSlice("inventory.yml"),
ModulePath: *cli.NewStringSlice("/path/to/modules"),
VaultID: "my_vault_id",
VaultPasswordFile: "/path/to/vault/password/file",
},
want: []string{
ansiblePlaybookBin, "--inventory", "inventory.yml", "--module-path", "/path/to/modules",
"--vault-id", "my_vault_id", "--vault-password-file", "/path/to/vault/password/file",
"--forks", "0",
},
},
{
name: "with inventory, module path, vault ID, vault password file, and extra vars",
ansible: &Ansible{
Inventories: *cli.NewStringSlice("inventory.yml"),
ModulePath: *cli.NewStringSlice("/path/to/modules"),
VaultID: "my_vault_id",
VaultPasswordFile: "/path/to/vault/password/file",
ExtraVars: *cli.NewStringSlice("var1=value1", "var2=value2"),
},
want: []string{
ansiblePlaybookBin, "--inventory", "inventory.yml", "--module-path", "/path/to/modules",
"--vault-id", "my_vault_id", "--vault-password-file", "/path/to/vault/password/file",
"--extra-vars", "var1=value1", "--extra-vars", "var2=value2", "--forks", "0",
},
},
{
name: "with inventory and list hosts",
ansible: &Ansible{
ListHosts: true,
Inventories: *cli.NewStringSlice("inventory.yml"),
Playbooks: *cli.NewStringSlice("playbook1.yml", "playbook2.yml"),
},
want: []string{
ansiblePlaybookBin, "--inventory", "inventory.yml", "--list-hosts",
"playbook1.yml", "playbook2.yml",
},
},
{
name: "with inventory and syntax check",
ansible: &Ansible{
SyntaxCheck: true,
Inventories: *cli.NewStringSlice("inventory.yml"),
Playbooks: *cli.NewStringSlice("playbook1.yml", "playbook2.yml"),
},
want: []string{
ansiblePlaybookBin, "--inventory", "inventory.yml", "--syntax-check",
"playbook1.yml", "playbook2.yml",
},
},
{
name: "with all options",
ansible: &Ansible{
Check: true,
Diff: true,
FlushCache: true,
ForceHandlers: true,
Forks: 10,
Limit: "host1,host2",
ListTags: true,
ListTasks: true,
SkipTags: "tag1,tag2",
StartAtTask: "task_name",
Tags: "tag3,tag4",
PrivateKeyFile: "/path/to/private/key",
User: "remote_user",
Connection: "ssh",
Timeout: 60,
SSHCommonArgs: "-o StrictHostKeyChecking=no",
SFTPExtraArgs: "-o IdentitiesOnly=yes",
SCPExtraArgs: "-r",
SSHExtraArgs: "-o ForwardAgent=yes",
Become: true,
BecomeMethod: "sudo",
BecomeUser: "root",
Verbose: 2,
Inventories: *cli.NewStringSlice("inventory.yml"),
Playbooks: *cli.NewStringSlice("playbook1.yml", "playbook2.yml"),
},
want: []string{
ansiblePlaybookBin, "--inventory", "inventory.yml", "--check", "--diff", "--flush-cache",
"--force-handlers", "--forks", "10", "--limit", "host1,host2", "--list-tags", "--list-tasks",
"--skip-tags", "tag1,tag2", "--start-at-task", "task_name", "--tags", "tag3,tag4",
"--private-key", "/path/to/private/key", "--user", "remote_user", "--connection", "ssh",
"--timeout", "60", "--ssh-common-args", "-o StrictHostKeyChecking=no", "--sftp-extra-args",
"-o IdentitiesOnly=yes", "--scp-extra-args", "-r", "--ssh-extra-args", "-o ForwardAgent=yes",
"--become", "--become-method", "sudo", "--become-user", "root", "-vv", "playbook1.yml", "playbook2.yml",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := tt.ansible.Play()
assert.Equal(t, tt.want, cmd.Cmd.Args)
})
}
}

View File

@ -1,58 +0,0 @@
//go:build generate
// +build generate
package main
import (
"bytes"
"embed"
"fmt"
"os"
"text/template"
"github.com/thegeeklab/wp-ansible/plugin"
"github.com/thegeeklab/wp-plugin-go/docs"
wp "github.com/thegeeklab/wp-plugin-go/plugin"
wp_template "github.com/thegeeklab/wp-plugin-go/template"
"github.com/urfave/cli/v2"
)
//go:embed templates/docs-data.yaml.tmpl
var yamlTemplate embed.FS
func main() {
settings := &plugin.Settings{}
app := &cli.App{
Flags: settingsFlags(settings, wp.FlagsPluginCategory),
}
out, err := toYAML(app)
if err != nil {
panic(err)
}
fi, err := os.Create("../../docs/data/data-raw.yaml")
if err != nil {
panic(err)
}
defer fi.Close()
if _, err := fi.WriteString(out); err != nil {
panic(err)
}
}
func toYAML(app *cli.App) (string, error) {
var w bytes.Buffer
yamlTmpl, err := template.New("docs").Funcs(wp_template.LoadFuncMap()).ParseFS(yamlTemplate, "templates/docs-data.yaml.tmpl")
if err != nil {
fmt.Println(yamlTmpl)
return "", err
}
if err := yamlTmpl.ExecuteTemplate(&w, "docs-data.yaml.tmpl", docs.GetTemplateData(app)); err != nil {
return "", err
}
return w.String(), nil
}

View File

@ -1,246 +0,0 @@
package main
import (
"github.com/thegeeklab/wp-ansible/plugin"
"github.com/urfave/cli/v2"
)
// SettingsFlags has the cli.Flags for the plugin.Settings.
//
//go:generate go run docs.go flags.go
func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "python-requirements",
Usage: "path to python requirements file",
EnvVars: []string{"PLUGIN_PYTHON_REQUIREMENTS"},
Destination: &settings.PythonRequirements,
Category: category,
},
&cli.StringFlag{
Name: "galaxy-requirements",
Usage: "path to galaxy requirements file",
EnvVars: []string{"PLUGIN_GALAXY_REQUIREMENTS"},
Destination: &settings.GalaxyRequirements,
Category: category,
},
&cli.StringSliceFlag{
Name: "inventory",
Usage: "path to inventory file",
EnvVars: []string{"PLUGIN_INVENTORY", "PLUGIN_INVENTORIES"},
Destination: &settings.Inventories,
Category: category,
},
&cli.StringSliceFlag{
Name: "playbook",
Usage: "list of playbooks to apply",
EnvVars: []string{"PLUGIN_PLAYBOOK", "PLUGIN_PLAYBOOKS"},
Destination: &settings.Playbooks,
Category: category,
},
&cli.StringFlag{
Name: "limit",
Usage: "limit selected hosts to an additional pattern",
EnvVars: []string{"PLUGIN_LIMIT"},
Destination: &settings.Limit,
Category: category,
},
&cli.StringFlag{
Name: "skip-tags",
Usage: "only run plays and tasks whose tags do not match",
EnvVars: []string{"PLUGIN_SKIP_TAGS"},
Destination: &settings.SkipTags,
Category: category,
},
&cli.StringFlag{
Name: "start-at-task",
Usage: "start the playbook at the task matching this name",
EnvVars: []string{"PLUGIN_START_AT_TASK"},
Destination: &settings.StartAtTask,
Category: category,
},
&cli.StringFlag{
Name: "tags",
Usage: "only run plays and tasks tagged with these values",
EnvVars: []string{"PLUGIN_TAGS"},
Destination: &settings.Tags,
Category: category,
},
&cli.StringSliceFlag{
Name: "extra-vars",
Usage: "set additional variables as `key=value`",
EnvVars: []string{"PLUGIN_EXTRA_VARS", "ANSIBLE_EXTRA_VARS"},
Destination: &settings.ExtraVars,
Category: category,
},
&cli.StringSliceFlag{
Name: "module-path",
Usage: "prepend paths to module library",
EnvVars: []string{"PLUGIN_MODULE_PATH"},
Destination: &settings.ModulePath,
Category: category,
},
&cli.BoolFlag{
Name: "check",
Usage: "run a check, do not apply any changes",
EnvVars: []string{"PLUGIN_CHECK"},
Destination: &settings.Check,
Category: category,
},
&cli.BoolFlag{
Name: "diff",
Usage: "show the differences, may print secrets",
EnvVars: []string{"PLUGIN_DIFF"},
Destination: &settings.Diff,
Category: category,
},
&cli.BoolFlag{
Name: "flush-cache",
Usage: "clear the fact cache for every host in inventory",
EnvVars: []string{"PLUGIN_FLUSH_CACHE"},
Destination: &settings.FlushCache,
Category: category,
},
&cli.BoolFlag{
Name: "force-handlers",
Usage: "run handlers even if a task fails",
EnvVars: []string{"PLUGIN_FORCE_HANDLERS"},
Destination: &settings.ForceHandlers,
Category: category,
},
&cli.BoolFlag{
Name: "list-hosts",
Usage: "outputs a list of matching hosts",
EnvVars: []string{"PLUGIN_LIST_HOSTS"},
Destination: &settings.ListHosts,
Category: category,
},
&cli.BoolFlag{
Name: "list-tags",
Usage: "list all available tags",
EnvVars: []string{"PLUGIN_LIST_TAGS"},
Destination: &settings.ListTags,
Category: category,
},
&cli.BoolFlag{
Name: "list-tasks",
Usage: "list all tasks that would be executed",
EnvVars: []string{"PLUGIN_LIST_TASKS"},
Destination: &settings.ListTasks,
Category: category,
},
&cli.BoolFlag{
Name: "syntax-check",
Usage: "perform a syntax check on the playbook",
EnvVars: []string{"PLUGIN_SYNTAX_CHECK"},
Destination: &settings.SyntaxCheck,
Category: category,
},
&cli.IntFlag{
Name: "forks",
Usage: "specify number of parallel processes to use",
EnvVars: []string{"PLUGIN_FORKS"},
Value: plugin.AnsibleForksDefault,
Destination: &settings.Forks,
Category: category,
},
&cli.StringFlag{
Name: "vault-id",
Usage: "the vault identity to use",
EnvVars: []string{"PLUGIN_VAULT_ID", "ANSIBLE_VAULT_ID"},
Destination: &settings.VaultID,
Category: category,
},
&cli.StringFlag{
Name: "vault-password",
Usage: "the vault password to use",
EnvVars: []string{"PLUGIN_VAULT_PASSWORD", "ANSIBLE_VAULT_PASSWORD"},
Destination: &settings.VaultPassword,
Category: category,
},
&cli.IntFlag{
Name: "verbose",
Usage: "level of verbosity, 0 up to 4",
EnvVars: []string{"PLUGIN_VERBOSE"},
Destination: &settings.Verbose,
Category: category,
},
&cli.StringFlag{
Name: "private-key",
Usage: "SSH private key used to authenticate the connection",
EnvVars: []string{"PLUGIN_PRIVATE_KEY", "ANSIBLE_PRIVATE_KEY"},
Destination: &settings.PrivateKey,
Category: category,
},
&cli.StringFlag{
Name: "user",
Usage: "connect as this user",
EnvVars: []string{"PLUGIN_USER", "ANSIBLE_USER"},
Destination: &settings.User,
Category: category,
},
&cli.StringFlag{
Name: "connection",
Usage: "connection type to use",
EnvVars: []string{"PLUGIN_CONNECTION"},
Destination: &settings.Connection,
Category: category,
},
&cli.IntFlag{
Name: "timeout",
Usage: "override the connection timeout in seconds",
EnvVars: []string{"PLUGIN_TIMEOUT"},
Destination: &settings.Timeout,
Category: category,
},
&cli.StringFlag{
Name: "ssh-common-args",
Usage: "specify common arguments to pass to SFTP, SCP and SSH connections",
EnvVars: []string{"PLUGIN_SSH_COMMON_ARGS"},
Destination: &settings.SSHCommonArgs,
Category: category,
},
&cli.StringFlag{
Name: "sftp-extra-args",
Usage: "specify extra arguments to pass to SFTP connections only",
EnvVars: []string{"PLUGIN_SFTP_EXTRA_ARGS"},
Destination: &settings.SFTPExtraArgs,
Category: category,
},
&cli.StringFlag{
Name: "scp-extra-args",
Usage: "specify extra arguments to pass to SCP connections only",
EnvVars: []string{"PLUGIN_SCP_EXTRA_ARGS"},
Destination: &settings.SCPExtraArgs,
Category: category,
},
&cli.StringFlag{
Name: "ssh-extra-args",
Usage: "specify extra arguments to pass to SSH connections only",
EnvVars: []string{"PLUGIN_SSH_EXTRA_ARGS"},
Destination: &settings.SSHExtraArgs,
Category: category,
},
&cli.BoolFlag{
Name: "become",
Usage: "enable privilege escalation",
EnvVars: []string{"PLUGIN_BECOME"},
Destination: &settings.Become,
Category: category,
},
&cli.StringFlag{
Name: "become-method",
Usage: "privilege escalation method to use",
EnvVars: []string{"PLUGIN_BECOME_METHOD", "ANSIBLE_BECOME_METHOD"},
Destination: &settings.BecomeMethod,
Category: category,
},
&cli.StringFlag{
Name: "become-user",
Usage: "privilege escalation user to use",
EnvVars: []string{"PLUGIN_BECOME_USER", "ANSIBLE_BECOME_USER"},
Destination: &settings.BecomeUser,
Category: category,
},
}
}

View File

@ -1,11 +1,7 @@
package main
import (
"fmt"
"github.com/thegeeklab/wp-ansible/plugin"
wp "github.com/thegeeklab/wp-plugin-go/plugin"
)
//nolint:gochecknoglobals
@ -15,14 +11,5 @@ var (
)
func main() {
settings := &plugin.Settings{}
options := wp.Options{
Name: "wp-ansible",
Description: "Manage infrastructure with Ansible",
Version: BuildVersion,
VersionMetadata: fmt.Sprintf("date=%s", BuildDate),
Flags: settingsFlags(settings, wp.FlagsPluginCategory),
}
plugin.New(options, settings).Run()
plugin.New(nil, BuildVersion, BuildDate).Run()
}

View File

@ -1,18 +0,0 @@
---
{{- if .GlobalArgs }}
properties:
{{- range $v := .GlobalArgs }}
- name: {{ $v.Name }}
{{- with $v.Description }}
description: |
{{ . | ToSentence }}
{{- end }}
{{- with $v.Type }}
type: {{ . }}
{{- end }}
{{- with $v.Default }}
defaultValue: {{ . }}
{{- end }}
required: {{ default false $v.Required }}
{{ end -}}
{{ end -}}

View File

@ -8,7 +8,7 @@ title: wp-ansible
[![Go Report Card](https://goreportcard.com/badge/github.com/thegeeklab/wp-ansible)](https://goreportcard.com/report/github.com/thegeeklab/wp-ansible)
[![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/wp-ansible)](https://github.com/thegeeklab/wp-ansible/graphs/contributors)
[![Source: GitHub](https://img.shields.io/badge/source-github-blue.svg?logo=github&logoColor=white)](https://github.com/thegeeklab/wp-ansible)
[![License: MIT](https://img.shields.io/github/license/thegeeklab/wp-ansible)](https://github.com/thegeeklab/wp-ansible/blob/main/LICENSE)
[![License: Apache-2.0](https://img.shields.io/github/license/thegeeklab/wp-ansible)](https://github.com/thegeeklab/wp-ansible/blob/main/LICENSE)
Woodpecker CI plugin to manage infrastructure with [Ansible](https://github.com/ansible/ansible).
@ -21,17 +21,15 @@ Woodpecker CI plugin to manage infrastructure with [Ansible](https://github.com/
## Usage
```YAML
kind: pipeline
name: default
steps:
- name: ansible
image: quay.io/thegeeklab/drone-ansible
image: quay.io/thegeeklab/wp-ansible
settings:
playbook: deployment/playbook.yml
private_key:
from_secret: ansible_private_key
inventory: deployment/hosts.yml
syntax_check: true
```
### Parameters
@ -59,5 +57,11 @@ docker build --file Containerfile.multiarch --tag thegeeklab/wp-ansible .
## Test
```Shell
docker run --rm \
-e PLUGIN_PLAYBOOK=playbook.yml \
-e PLUGIN_INVENTORY=inventory.yml \
-e PLUGIN_SYNTAX_CHECK=true \
-v $(pwd)/testdata:/build:z \
-w /build \
thegeeklab/wp-ansible
```

View File

@ -72,11 +72,18 @@ properties:
type: string
required: false
- name: insecure_skip_verify
description: |
Skip SSL verification.
type: bool
defaultValue: false
required: false
- name: inventory
description: |
Path to inventory file.
type: list
required: false
required: true
- name: limit
description: |
@ -105,6 +112,13 @@ properties:
defaultValue: false
required: false
- name: log_level
description: |
Plugin log level.
type: string
defaultValue: "info"
required: false
- name: module_path
description: |
Prepend paths to module library.
@ -115,7 +129,7 @@ properties:
description: |
List of playbooks to apply.
type: list
required: false
required: true
- name: private_key
description: |

22
go.mod
View File

@ -1,18 +1,20 @@
module github.com/thegeeklab/wp-ansible
go 1.21
go 1.22
require (
github.com/thegeeklab/wp-plugin-go v1.5.0
github.com/urfave/cli/v2 v2.27.1
golang.org/x/sys v0.16.0
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.9.0
github.com/thegeeklab/wp-plugin-go/v3 v3.0.2
github.com/urfave/cli/v2 v2.27.2
)
require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.1.1 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.11 // indirect
@ -21,11 +23,13 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/rs/zerolog v1.31.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/net v0.19.0 // indirect
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

39
go.sum
View File

@ -6,14 +6,12 @@ github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYr
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
@ -36,8 +34,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
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/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
@ -47,27 +45,27 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/thegeeklab/wp-plugin-go v1.5.0 h1:fA/kQwQrntjxdxePKKGecMRnPbj1xwpy6D2JrrPD2qA=
github.com/thegeeklab/wp-plugin-go v1.5.0/go.mod h1:ULBD5SNC7bkIB/UbLMQpcPWj7iZObCTWg8bqXf1zqsA=
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
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/thegeeklab/wp-plugin-go/v3 v3.0.2 h1:Mv5i8S1WY+BUNjTjX6lOnB3p8S9mvM+XwfY4R98gx0g=
github.com/thegeeklab/wp-plugin-go/v3 v3.0.2/go.mod h1:ij1iJcAVgzerBTqXnmq0bu1VA+hhVVwzXKqiqfoGjjg=
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -79,8 +77,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@ -92,6 +90,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=

42
internal/docs/main.go Normal file
View File

@ -0,0 +1,42 @@
//go:build generate
// +build generate
package main
import (
"context"
"flag"
"net/http"
"os"
"time"
"github.com/thegeeklab/wp-ansible/plugin"
plugin_docs "github.com/thegeeklab/wp-plugin-go/v3/docs"
plugin_template "github.com/thegeeklab/wp-plugin-go/v3/template"
)
func main() {
tmpl := "https://raw.githubusercontent.com/thegeeklab/woodpecker-plugins/main/templates/docs-data.yaml.tmpl"
client := http.Client{
Timeout: 30 * time.Second,
}
p := plugin.New(nil)
out, err := plugin_template.Render(context.Background(), client, tmpl, plugin_docs.GetTemplateData(p.App))
if err != nil {
panic(err)
}
outputFile := flag.String("output", "", "Output file path")
flag.Parse()
if *outputFile == "" {
panic("no output file specified")
}
err = os.WriteFile(*outputFile, []byte(out), 0o644)
if err != nil {
panic(err)
}
}

View File

@ -1,292 +0,0 @@
package plugin
import (
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/urfave/cli/v2"
"golang.org/x/sys/execabs"
)
const (
AnsibleForksDefault = 5
ansibleFolder = "/etc/ansible"
ansibleConfig = "/etc/ansible/ansible.cfg"
pipBin = "/usr/bin/pip"
ansibleBin = "/usr/bin/ansible"
ansibleGalaxyBin = "/usr/bin/ansible-galaxy"
ansiblePlaybookBin = "/usr/bin/ansible-playbook"
strictFilePerm = 0o600
)
const ansibleContent = `
[defaults]
host_key_checking = False
`
var ErrAnsiblePlaybookNotFound = errors.New("playbook not found")
func (p *Plugin) ansibleConfig() error {
if err := os.MkdirAll(ansibleFolder, os.ModePerm); err != nil {
return fmt.Errorf("failed to create ansible directory: %w", err)
}
if err := os.WriteFile(ansibleConfig, []byte(ansibleContent), strictFilePerm); err != nil {
return fmt.Errorf("failed to create ansible config: %w", err)
}
return nil
}
func (p *Plugin) privateKey() error {
tmpfile, err := os.CreateTemp("", "privateKey")
if err != nil {
return fmt.Errorf("failed to create private key file: %w", err)
}
if _, err := tmpfile.Write([]byte(p.Settings.PrivateKey)); err != nil {
return fmt.Errorf("failed to write private key file: %w", err)
}
if err := tmpfile.Close(); err != nil {
return fmt.Errorf("failed to close private key file: %w", err)
}
p.Settings.PrivateKeyFile = tmpfile.Name()
return nil
}
func (p *Plugin) vaultPass() error {
tmpfile, err := os.CreateTemp("", "vaultPass")
if err != nil {
return fmt.Errorf("failed to create vault password file: %w", err)
}
if _, err := tmpfile.Write([]byte(p.Settings.VaultPassword)); err != nil {
return fmt.Errorf("failed to write vault password file: %w", err)
}
if err := tmpfile.Close(); err != nil {
return fmt.Errorf("failed to close vault password file: %w", err)
}
p.Settings.VaultPasswordFile = tmpfile.Name()
return nil
}
func (p *Plugin) playbooks() error {
var playbooks []string
for _, p := range p.Settings.Playbooks.Value() {
files, err := filepath.Glob(p)
if err != nil {
playbooks = append(playbooks, p)
continue
}
playbooks = append(playbooks, files...)
}
if len(playbooks) == 0 {
return ErrAnsiblePlaybookNotFound
}
p.Settings.Playbooks = *cli.NewStringSlice(playbooks...)
return nil
}
func (p *Plugin) versionCommand() *execabs.Cmd {
args := []string{
"--version",
}
return execabs.Command(
ansibleBin,
args...,
)
}
func (p *Plugin) pythonRequirementsCommand() *execabs.Cmd {
args := []string{
"install",
"--upgrade",
"--requirement",
p.Settings.PythonRequirements,
}
return execabs.Command(
pipBin,
args...,
)
}
func (p *Plugin) galaxyRequirementsCommand() *execabs.Cmd {
args := []string{
"install",
"--force",
"--role-file",
p.Settings.GalaxyRequirements,
}
if p.Settings.Verbose > 0 {
args = append(args, fmt.Sprintf("-%s", strings.Repeat("v", p.Settings.Verbose)))
}
return execabs.Command(
ansibleGalaxyBin,
args...,
)
}
func (p *Plugin) ansibleCommand(inventory string) *execabs.Cmd {
args := []string{
"--inventory",
inventory,
}
if len(p.Settings.ModulePath.Value()) > 0 {
args = append(args, "--module-path", strings.Join(p.Settings.ModulePath.Value(), ":"))
}
if p.Settings.VaultID != "" {
args = append(args, "--vault-id", p.Settings.VaultID)
}
if p.Settings.VaultPasswordFile != "" {
args = append(args, "--vault-password-file", p.Settings.VaultPasswordFile)
}
for _, v := range p.Settings.ExtraVars.Value() {
args = append(args, "--extra-vars", v)
}
if p.Settings.ListHosts {
args = append(args, "--list-hosts")
args = append(args, p.Settings.Playbooks.Value()...)
return execabs.Command(
ansiblePlaybookBin,
args...,
)
}
if p.Settings.SyntaxCheck {
args = append(args, "--syntax-check")
args = append(args, p.Settings.Playbooks.Value()...)
return execabs.Command(
ansiblePlaybookBin,
args...,
)
}
if p.Settings.Check {
args = append(args, "--check")
}
if p.Settings.Diff {
args = append(args, "--diff")
}
if p.Settings.FlushCache {
args = append(args, "--flush-cache")
}
if p.Settings.ForceHandlers {
args = append(args, "--force-handlers")
}
if p.Settings.Forks != AnsibleForksDefault {
args = append(args, "--forks", strconv.Itoa(p.Settings.Forks))
}
if p.Settings.Limit != "" {
args = append(args, "--limit", p.Settings.Limit)
}
if p.Settings.ListTags {
args = append(args, "--list-tags")
}
if p.Settings.ListTasks {
args = append(args, "--list-tasks")
}
if p.Settings.SkipTags != "" {
args = append(args, "--skip-tags", p.Settings.SkipTags)
}
if p.Settings.StartAtTask != "" {
args = append(args, "--start-at-task", p.Settings.StartAtTask)
}
if p.Settings.Tags != "" {
args = append(args, "--tags", p.Settings.Tags)
}
if p.Settings.PrivateKeyFile != "" {
args = append(args, "--private-key", p.Settings.PrivateKeyFile)
}
if p.Settings.User != "" {
args = append(args, "--user", p.Settings.User)
}
if p.Settings.Connection != "" {
args = append(args, "--connection", p.Settings.Connection)
}
if p.Settings.Timeout != 0 {
args = append(args, "--timeout", strconv.Itoa(p.Settings.Timeout))
}
if p.Settings.SSHCommonArgs != "" {
args = append(args, "--ssh-common-args", p.Settings.SSHCommonArgs)
}
if p.Settings.SFTPExtraArgs != "" {
args = append(args, "--sftp-extra-args", p.Settings.SFTPExtraArgs)
}
if p.Settings.SCPExtraArgs != "" {
args = append(args, "--scp-extra-args", p.Settings.SCPExtraArgs)
}
if p.Settings.SSHExtraArgs != "" {
args = append(args, "--ssh-extra-args", p.Settings.SSHExtraArgs)
}
if p.Settings.Become {
args = append(args, "--become")
}
if p.Settings.BecomeMethod != "" {
args = append(args, "--become-method", p.Settings.BecomeMethod)
}
if p.Settings.BecomeUser != "" {
args = append(args, "--become-user", p.Settings.BecomeUser)
}
if p.Settings.Verbose > 0 {
args = append(args, fmt.Sprintf("-%s", strings.Repeat("v", p.Settings.Verbose)))
}
args = append(args, p.Settings.Playbooks.Value()...)
return execabs.Command(
ansiblePlaybookBin,
args...,
)
}

View File

@ -2,21 +2,14 @@ package plugin
import (
"context"
"errors"
"fmt"
"os"
"github.com/thegeeklab/wp-plugin-go/trace"
"golang.org/x/sys/execabs"
plugin_exec "github.com/thegeeklab/wp-plugin-go/v3/exec"
plugin_file "github.com/thegeeklab/wp-plugin-go/v3/file"
)
var (
ErrPluginPlaybookNotSet = errors.New("playbook is required")
ErrPluginInventoryNotSet = errors.New("inventory is required")
)
//nolint:revive
func (p *Plugin) run(ctx context.Context) error {
func (p *Plugin) run(_ context.Context) error {
if err := p.Validate(); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
@ -30,12 +23,8 @@ func (p *Plugin) run(ctx context.Context) error {
// Validate handles the settings validation of the plugin.
func (p *Plugin) Validate() error {
if len(p.Settings.Playbooks.Value()) == 0 {
return ErrPluginPlaybookNotSet
}
if len(p.Settings.Inventories.Value()) == 0 {
return ErrPluginInventoryNotSet
if err := p.Settings.Ansible.GetPlaybooks(); err != nil {
return err
}
return nil
@ -43,54 +32,46 @@ func (p *Plugin) Validate() error {
// Execute provides the implementation of the plugin.
func (p *Plugin) Execute() error {
if err := p.playbooks(); err != nil {
return err
}
var err error
if err := p.ansibleConfig(); err != nil {
return err
}
batchCmd := make([]*plugin_exec.Cmd, 0)
batchCmd = append(batchCmd, p.Settings.Ansible.Version())
if p.Settings.PrivateKey != "" {
if err := p.privateKey(); err != nil {
p.Settings.Ansible.PrivateKeyFile, err = plugin_file.WriteTmpFile("privateKey", p.Settings.PrivateKey)
if err != nil {
return err
}
defer os.Remove(p.Settings.PrivateKeyFile)
defer os.Remove(p.Settings.Ansible.PrivateKeyFile)
}
if p.Settings.VaultPassword != "" {
if err := p.vaultPass(); err != nil {
p.Settings.Ansible.VaultPasswordFile, err = plugin_file.WriteTmpFile("vaultPass", p.Settings.VaultPassword)
if err != nil {
return err
}
defer os.Remove(p.Settings.VaultPasswordFile)
}
commands := []*execabs.Cmd{
p.versionCommand(),
defer os.Remove(p.Settings.Ansible.VaultPasswordFile)
}
if p.Settings.PythonRequirements != "" {
commands = append(commands, p.pythonRequirementsCommand())
batchCmd = append(batchCmd, PipInstall(p.Settings.PythonRequirements))
}
if p.Settings.GalaxyRequirements != "" {
commands = append(commands, p.galaxyRequirementsCommand())
if p.Settings.Ansible.GalaxyRequirements != "" {
batchCmd = append(batchCmd, p.Settings.Ansible.GalaxyInstall())
}
for _, inventory := range p.Settings.Inventories.Value() {
commands = append(commands, p.ansibleCommand(inventory))
}
batchCmd = append(batchCmd, p.Settings.Ansible.Play())
for _, cmd := range commands {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
for _, cmd := range batchCmd {
if cmd == nil {
continue
}
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "ANSIBLE_FORCE_COLOR=1")
trace.Cmd(cmd)
cmd.Env = append(os.Environ(), "ANSIBLE_FORCE_COLOR=1")
if err := cmd.Run(); err != nil {
return err

View File

@ -1,64 +1,295 @@
package plugin
import (
wp "github.com/thegeeklab/wp-plugin-go/plugin"
"fmt"
"github.com/thegeeklab/wp-ansible/ansible"
plugin_base "github.com/thegeeklab/wp-plugin-go/v3/plugin"
"github.com/urfave/cli/v2"
)
//go:generate go run ../internal/docs/main.go -output=../docs/data/data-raw.yaml
// Plugin implements provide the plugin.
type Plugin struct {
*wp.Plugin
*plugin_base.Plugin
Settings *Settings
}
// Settings for the Plugin.
type Settings struct {
PythonRequirements string
GalaxyRequirements string
Inventories cli.StringSlice
Playbooks cli.StringSlice
Limit string
SkipTags string
StartAtTask string
Tags string
ExtraVars cli.StringSlice
ModulePath cli.StringSlice
Check bool
Diff bool
FlushCache bool
ForceHandlers bool
ListHosts bool
ListTags bool
ListTasks bool
SyntaxCheck bool
Forks int
VaultID string
VaultPassword string
VaultPasswordFile string
Verbose int
PrivateKey string
PrivateKeyFile string
User string
Connection string
Timeout int
SSHCommonArgs string
SFTPExtraArgs string
SCPExtraArgs string
SSHExtraArgs string
Become bool
BecomeMethod string
BecomeUser string
VaultPassword string
Ansible ansible.Ansible
}
func New(options wp.Options, settings *Settings) *Plugin {
p := &Plugin{}
if options.Execute == nil {
options.Execute = p.run
func New(e plugin_base.ExecuteFunc, build ...string) *Plugin {
p := &Plugin{
Settings: &Settings{},
}
p.Plugin = wp.New(options)
p.Settings = settings
options := plugin_base.Options{
Name: "wp-ansible",
Description: "Manage infrastructure with Ansible",
Flags: Flags(p.Settings, plugin_base.FlagsPluginCategory),
Execute: p.run,
HideWoodpeckerFlags: true,
}
if len(build) > 0 {
options.Version = build[0]
}
if len(build) > 1 {
options.VersionMetadata = fmt.Sprintf("date=%s", build[1])
}
if e != nil {
options.Execute = e
}
p.Plugin = plugin_base.New(options)
return p
}
// Flags returns a slice of CLI flags for the plugin.
func Flags(settings *Settings, category string) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "python-requirements",
Usage: "path to python requirements file",
EnvVars: []string{"PLUGIN_PYTHON_REQUIREMENTS"},
Destination: &settings.PythonRequirements,
Category: category,
},
&cli.StringFlag{
Name: "galaxy-requirements",
Usage: "path to galaxy requirements file",
EnvVars: []string{"PLUGIN_GALAXY_REQUIREMENTS"},
Destination: &settings.Ansible.GalaxyRequirements,
Category: category,
},
&cli.StringSliceFlag{
Name: "inventory",
Usage: "path to inventory file",
EnvVars: []string{"PLUGIN_INVENTORY", "PLUGIN_INVENTORIES"},
Required: true,
Destination: &settings.Ansible.Inventories,
Category: category,
},
&cli.StringSliceFlag{
Name: "playbook",
Usage: "list of playbooks to apply",
EnvVars: []string{"PLUGIN_PLAYBOOK", "PLUGIN_PLAYBOOKS"},
Required: true,
Destination: &settings.Ansible.Playbooks,
Category: category,
},
&cli.StringFlag{
Name: "limit",
Usage: "limit selected hosts to an additional pattern",
EnvVars: []string{"PLUGIN_LIMIT"},
Destination: &settings.Ansible.Limit,
Category: category,
},
&cli.StringFlag{
Name: "skip-tags",
Usage: "only run plays and tasks whose tags do not match",
EnvVars: []string{"PLUGIN_SKIP_TAGS"},
Destination: &settings.Ansible.SkipTags,
Category: category,
},
&cli.StringFlag{
Name: "start-at-task",
Usage: "start the playbook at the task matching this name",
EnvVars: []string{"PLUGIN_START_AT_TASK"},
Destination: &settings.Ansible.StartAtTask,
Category: category,
},
&cli.StringFlag{
Name: "tags",
Usage: "only run plays and tasks tagged with these values",
EnvVars: []string{"PLUGIN_TAGS"},
Destination: &settings.Ansible.Tags,
Category: category,
},
&cli.StringSliceFlag{
Name: "extra-vars",
Usage: "set additional variables as `key=value`",
EnvVars: []string{"PLUGIN_EXTRA_VARS", "ANSIBLE_EXTRA_VARS"},
Destination: &settings.Ansible.ExtraVars,
Category: category,
},
&cli.StringSliceFlag{
Name: "module-path",
Usage: "prepend paths to module library",
EnvVars: []string{"PLUGIN_MODULE_PATH"},
Destination: &settings.Ansible.ModulePath,
Category: category,
},
&cli.BoolFlag{
Name: "check",
Usage: "run a check, do not apply any changes",
EnvVars: []string{"PLUGIN_CHECK"},
Destination: &settings.Ansible.Check,
Category: category,
},
&cli.BoolFlag{
Name: "diff",
Usage: "show the differences, may print secrets",
EnvVars: []string{"PLUGIN_DIFF"},
Destination: &settings.Ansible.Diff,
Category: category,
},
&cli.BoolFlag{
Name: "flush-cache",
Usage: "clear the fact cache for every host in inventory",
EnvVars: []string{"PLUGIN_FLUSH_CACHE"},
Destination: &settings.Ansible.FlushCache,
Category: category,
},
&cli.BoolFlag{
Name: "force-handlers",
Usage: "run handlers even if a task fails",
EnvVars: []string{"PLUGIN_FORCE_HANDLERS"},
Destination: &settings.Ansible.ForceHandlers,
Category: category,
},
&cli.BoolFlag{
Name: "list-hosts",
Usage: "outputs a list of matching hosts",
EnvVars: []string{"PLUGIN_LIST_HOSTS"},
Destination: &settings.Ansible.ListHosts,
Category: category,
},
&cli.BoolFlag{
Name: "list-tags",
Usage: "list all available tags",
EnvVars: []string{"PLUGIN_LIST_TAGS"},
Destination: &settings.Ansible.ListTags,
Category: category,
},
&cli.BoolFlag{
Name: "list-tasks",
Usage: "list all tasks that would be executed",
EnvVars: []string{"PLUGIN_LIST_TASKS"},
Destination: &settings.Ansible.ListTasks,
Category: category,
},
&cli.BoolFlag{
Name: "syntax-check",
Usage: "perform a syntax check on the playbook",
EnvVars: []string{"PLUGIN_SYNTAX_CHECK"},
Destination: &settings.Ansible.SyntaxCheck,
Category: category,
},
&cli.IntFlag{
Name: "forks",
Usage: "specify number of parallel processes to use",
EnvVars: []string{"PLUGIN_FORKS"},
Value: ansible.AnsibleForksDefault,
Destination: &settings.Ansible.Forks,
Category: category,
},
&cli.StringFlag{
Name: "vault-id",
Usage: "the vault identity to use",
EnvVars: []string{"PLUGIN_VAULT_ID", "ANSIBLE_VAULT_ID"},
Destination: &settings.Ansible.VaultID,
Category: category,
},
&cli.StringFlag{
Name: "vault-password",
Usage: "the vault password to use",
EnvVars: []string{"PLUGIN_VAULT_PASSWORD", "ANSIBLE_VAULT_PASSWORD"},
Destination: &settings.VaultPassword,
Category: category,
},
&cli.IntFlag{
Name: "verbose",
Usage: "level of verbosity, 0 up to 4",
EnvVars: []string{"PLUGIN_VERBOSE"},
Destination: &settings.Ansible.Verbose,
Category: category,
},
&cli.StringFlag{
Name: "private-key",
Usage: "SSH private key used to authenticate the connection",
EnvVars: []string{"PLUGIN_PRIVATE_KEY", "ANSIBLE_PRIVATE_KEY"},
Destination: &settings.PrivateKey,
Category: category,
},
&cli.StringFlag{
Name: "user",
Usage: "connect as this user",
EnvVars: []string{"PLUGIN_USER", "ANSIBLE_USER"},
Destination: &settings.Ansible.User,
Category: category,
},
&cli.StringFlag{
Name: "connection",
Usage: "connection type to use",
EnvVars: []string{"PLUGIN_CONNECTION"},
Destination: &settings.Ansible.Connection,
Category: category,
},
&cli.IntFlag{
Name: "timeout",
Usage: "override the connection timeout in seconds",
EnvVars: []string{"PLUGIN_TIMEOUT"},
Destination: &settings.Ansible.Timeout,
Category: category,
},
&cli.StringFlag{
Name: "ssh-common-args",
Usage: "specify common arguments to pass to SFTP, SCP and SSH connections",
EnvVars: []string{"PLUGIN_SSH_COMMON_ARGS"},
Destination: &settings.Ansible.SSHCommonArgs,
Category: category,
},
&cli.StringFlag{
Name: "sftp-extra-args",
Usage: "specify extra arguments to pass to SFTP connections only",
EnvVars: []string{"PLUGIN_SFTP_EXTRA_ARGS"},
Destination: &settings.Ansible.SFTPExtraArgs,
Category: category,
},
&cli.StringFlag{
Name: "scp-extra-args",
Usage: "specify extra arguments to pass to SCP connections only",
EnvVars: []string{"PLUGIN_SCP_EXTRA_ARGS"},
Destination: &settings.Ansible.SCPExtraArgs,
Category: category,
},
&cli.StringFlag{
Name: "ssh-extra-args",
Usage: "specify extra arguments to pass to SSH connections only",
EnvVars: []string{"PLUGIN_SSH_EXTRA_ARGS"},
Destination: &settings.Ansible.SSHExtraArgs,
Category: category,
},
&cli.BoolFlag{
Name: "become",
Usage: "enable privilege escalation",
EnvVars: []string{"PLUGIN_BECOME"},
Destination: &settings.Ansible.Become,
Category: category,
},
&cli.StringFlag{
Name: "become-method",
Usage: "privilege escalation method to use",
EnvVars: []string{"PLUGIN_BECOME_METHOD", "ANSIBLE_BECOME_METHOD"},
Destination: &settings.Ansible.BecomeMethod,
Category: category,
},
&cli.StringFlag{
Name: "become-user",
Usage: "privilege escalation user to use",
EnvVars: []string{"PLUGIN_BECOME_USER", "ANSIBLE_BECOME_USER"},
Destination: &settings.Ansible.BecomeUser,
Category: category,
},
}
}

26
plugin/util.go Normal file
View File

@ -0,0 +1,26 @@
package plugin
import (
"os"
plugin_exec "github.com/thegeeklab/wp-plugin-go/v3/exec"
)
const pipBin = "/usr/local/bin/pip"
// PipInstall returns a command to install Python packages from a requirements file.
// The command will upgrade any existing packages and install the packages specified in the given requirements file.
func PipInstall(req string) *plugin_exec.Cmd {
args := []string{
"install",
"--upgrade",
"--requirement",
req,
}
cmd := plugin_exec.Command(pipBin, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
}

28
plugin/util_test.go Normal file
View File

@ -0,0 +1,28 @@
package plugin
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestPipInstall(t *testing.T) {
tests := []struct {
name string
requirements string
want []string
}{
{
name: "with valid requirements file",
requirements: "requirements.txt",
want: []string{pipBin, "install", "--upgrade", "--requirement", "requirements.txt"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := PipInstall(tt.requirements)
assert.Equal(t, tt.want, cmd.Cmd.Args)
})
}
}

6
testdata/inventory.yml vendored Normal file
View File

@ -0,0 +1,6 @@
---
ungrouped:
hosts:
localhost:
ansible_connection: local
ansible_python_interpreter: auto_silent

6
testdata/playbook.yml vendored Normal file
View File

@ -0,0 +1,6 @@
---
- hosts: all
tasks:
- name: Hello World
debug:
msg: "Say hello"