This commit is contained in:
parent
fd7d6f3ba5
commit
cab88875b1
20
Dockerfile
20
Dockerfile
@ -1,12 +1,24 @@
|
||||
FROM python:3.11.4-slim
|
||||
FROM golang:1.20.5-alpine AS build-stage
|
||||
|
||||
RUN apt-get update && apt-get install -y git toilet \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY *.go ./
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /entrypoint
|
||||
|
||||
|
||||
FROM python:3.11.4-slim AS runtime-stage
|
||||
|
||||
# RUN apt-get update && apt-get install -y git toilet \
|
||||
# && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# renovate: datasource=pypi depName=ansible
|
||||
ENV ANSIBLE_VERSION=8.1.0
|
||||
RUN pip3 install --no-cache-dir ansible==${ANSIBLE_VERSION} dnspython passlib netaddr
|
||||
|
||||
COPY entrypoint /bin/entrypoint
|
||||
COPY --from=build-stage /entrypoint /bin/entrypoint
|
||||
|
||||
ENTRYPOINT [ "/bin/entrypoint" ]
|
44
README.md
44
README.md
@ -6,39 +6,43 @@ kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: Check ansible syntax
|
||||
image: harbor.sebclem.fr/sebclem/drone-ansible-runner
|
||||
check-ansible-syntax:
|
||||
image: git.sebclem.fr/sebclem/woodpecker-ansible-runner
|
||||
pull: true
|
||||
settings:
|
||||
playbook: sites.yml
|
||||
playbook: playbooks/install.yml
|
||||
galaxy_file: roles/requirements.yml
|
||||
check_syntax: true
|
||||
vault_token:
|
||||
from_secret: ansible_vault_password
|
||||
private_key:
|
||||
from_secret: ansible_private_key
|
||||
from_secret: ansible_vault_token
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- custom
|
||||
- event: "push"
|
||||
branch: [main, master]
|
||||
- event: [pull_request, manual, deployment]
|
||||
|
||||
- name: Run ansible playbook
|
||||
image: harbor.sebclem.fr/sebclem/drone-ansible-runner
|
||||
run-ansible-playbook:
|
||||
image: git.sebclem.fr/sebclem/woodpecker-ansible-runner
|
||||
pull: true
|
||||
settings:
|
||||
verbosity: ${verbosity=1}
|
||||
verbosity: ${verbosity=0}
|
||||
diff: ${diff=false}
|
||||
check: ${check=false}
|
||||
limit: ${limit}
|
||||
tags: ${tags}
|
||||
playbook: sites.yml
|
||||
playbook: playbooks/install.yml
|
||||
galaxy_file: roles/requirements.yml
|
||||
check_syntax: true
|
||||
vault_token:
|
||||
from_secret: ansible_vault_password
|
||||
from_secret: ansible_vault_token
|
||||
private_key:
|
||||
from_secret: ansible_private_key
|
||||
limit: harbor.home
|
||||
when:
|
||||
event:
|
||||
- promote
|
||||
- rollback
|
||||
- custom
|
||||
environment: production
|
||||
event: deployment
|
||||
|
||||
when:
|
||||
- event: "push"
|
||||
branch: [main, master]
|
||||
- event: [pull_request, manual, deployment]
|
||||
|
||||
|
||||
```
|
82
entrypoint
82
entrypoint
@ -1,82 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
check=${PLUGIN_CHECK_SYNTAX:-false}
|
||||
verbosity=${PLUGIN_VERBOSITY:-0}
|
||||
|
||||
C_RESET="\e[39m"
|
||||
C_RED="\e[31m"
|
||||
C_YELLOW="\e[33m"
|
||||
C_BLUE="\e[34m"
|
||||
|
||||
run_command(){
|
||||
echo "➡️ $@"
|
||||
$@
|
||||
}
|
||||
echo -e "${C_BLUE}"
|
||||
toilet -f smblock Woodpecker Ansible
|
||||
toilet -f smblock " Runner"
|
||||
echo -e "${C_RESET}"
|
||||
|
||||
if [ -z "$PLUGIN_PLAYBOOK" ]; then
|
||||
echo -e "⚠️ ${C_RED}'playbook' setting not defined, ABORT!${C_RESET}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$PLUGIN_PRIVATE_KEY" ]; then
|
||||
echo -e "⚠️ ${C_YELLOW}[WARN] 'private_key' setting not defined !${C_RESET}"
|
||||
else
|
||||
|
||||
run_command "mkdir /root/.ssh"
|
||||
echo "$PLUGIN_PRIVATE_KEY" > /root/.ssh/id_ed25519
|
||||
run_command chmod 400 /root/.ssh/id_ed25519
|
||||
fi
|
||||
|
||||
args=("$PLUGIN_PLAYBOOK")
|
||||
|
||||
if [ -n "$PLUGIN_VAULT_TOKEN" ]; then
|
||||
echo "💼 Adding vault token to 'credentials/ci_vault_token'"
|
||||
run_command "mkdir credentials"
|
||||
echo "$PLUGIN_VAULT_TOKEN" > credentials/ci_vault_token
|
||||
args+=("--vault-password-file=credentials/ci_vault_token")
|
||||
echo "⚙️ Clean ansible.cfg"
|
||||
echo "➡️ sed -i '/vault_password_file.*/d' ./ansible.cfg"
|
||||
sed -i '/vault_password_file.*/d' ./ansible.cfg
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ -f "ansible-ci.cfg" ]; then
|
||||
echo "⚙️ ansible-ci.cfg is present, using it."
|
||||
rm ansible.cfg
|
||||
mv ansible-ci.cfg ansible.cfg
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ -n "$PLUGIN_GALAXY_FILE" ]; then
|
||||
echo "🚀 Installing Galaxy dependencies ($PLUGIN_GALAXY_FILE)"
|
||||
run_command "ansible-galaxy install -r $PLUGIN_GALAXY_FILE --force"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [[ $check = true ]]; then
|
||||
args+=("--syntax-check")
|
||||
fi
|
||||
|
||||
if [[ $verbosity != "0" ]]; then
|
||||
verb="-"
|
||||
for i in `seq 1 $verbosity`; do
|
||||
verb+="v"
|
||||
done
|
||||
args+=("$verb")
|
||||
fi
|
||||
|
||||
if [[ -n "$PLUGIN_LIMIT" ]]; then
|
||||
args+=("--limit" "$PLUGIN_LIMIT")
|
||||
fi
|
||||
|
||||
if [[ -n "$PLUGIN_TAGS" ]]; then
|
||||
args+=("--tags" "$PLUGIN_TAGS")
|
||||
fi
|
||||
|
||||
run_command "export ANSIBLE_HOST_KEY_CHECKING=False"
|
||||
echo "➡️ ansible-playbook ${args[@]}"
|
||||
ansible-playbook "${args[@]}"
|
219
entrypoint.go
Normal file
219
entrypoint.go
Normal file
@ -0,0 +1,219 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
type pluginConfig struct {
|
||||
check_syntax bool
|
||||
check bool
|
||||
diff bool
|
||||
verbosity int64
|
||||
limit *string
|
||||
tags *string
|
||||
privateKey *string
|
||||
vaultToken *string
|
||||
galaxyFile *string
|
||||
playbook *string
|
||||
}
|
||||
|
||||
func runCommand(sugar *zap.SugaredLogger, args ...string) {
|
||||
sugar.Infof("➡️ %s", args)
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func getPluginConfig(sugar *zap.SugaredLogger) pluginConfig {
|
||||
config := pluginConfig{}
|
||||
|
||||
check_syntax, present := os.LookupEnv("PLUGIN_CHECK_SYNTAX")
|
||||
if !present {
|
||||
config.check_syntax = false
|
||||
} else {
|
||||
converted, err := strconv.ParseBool(check_syntax)
|
||||
if err != nil {
|
||||
sugar.Fatal(err)
|
||||
}
|
||||
config.check_syntax = converted
|
||||
}
|
||||
|
||||
check, present := os.LookupEnv("PLUGIN_CHECK")
|
||||
if !present {
|
||||
config.check = false
|
||||
} else {
|
||||
converted, err := strconv.ParseBool(check)
|
||||
if err != nil {
|
||||
sugar.Fatal(err)
|
||||
}
|
||||
config.check = converted
|
||||
}
|
||||
|
||||
diff, present := os.LookupEnv("PLUGIN_DIFF")
|
||||
if !present {
|
||||
config.diff = false
|
||||
} else {
|
||||
converted, err := strconv.ParseBool(diff)
|
||||
if err != nil {
|
||||
sugar.Fatal(err)
|
||||
}
|
||||
config.diff = converted
|
||||
}
|
||||
|
||||
verbosity, present := os.LookupEnv("PLUGIN_VERBOSITY")
|
||||
if !present {
|
||||
config.verbosity = 0
|
||||
} else {
|
||||
converted, err := strconv.ParseInt(verbosity, 10, 0)
|
||||
if err != nil {
|
||||
sugar.Fatal(err)
|
||||
}
|
||||
config.verbosity = converted
|
||||
}
|
||||
|
||||
limit, present := os.LookupEnv("PLUGIN_LIMIT")
|
||||
if !present {
|
||||
config.limit = nil
|
||||
} else {
|
||||
config.limit = &limit
|
||||
}
|
||||
|
||||
tags, present := os.LookupEnv("PLUGIN_TAGS")
|
||||
if !present {
|
||||
config.tags = nil
|
||||
} else {
|
||||
config.tags = &tags
|
||||
}
|
||||
|
||||
privateKey, present := os.LookupEnv("PLUGIN_PRIVATE_KEY")
|
||||
if !present {
|
||||
sugar.Warn("⚠️ 'private_key' setting not defined !")
|
||||
config.privateKey = nil
|
||||
} else {
|
||||
config.privateKey = &privateKey
|
||||
}
|
||||
|
||||
vaultToken, present := os.LookupEnv("PLUGIN_VAULT_TOKEN")
|
||||
if !present {
|
||||
config.vaultToken = nil
|
||||
} else {
|
||||
config.vaultToken = &vaultToken
|
||||
}
|
||||
|
||||
galaxyFile, present := os.LookupEnv("PLUGIN_GALAXY_FILE")
|
||||
if !present {
|
||||
config.galaxyFile = nil
|
||||
} else {
|
||||
config.galaxyFile = &galaxyFile
|
||||
}
|
||||
|
||||
playbook, present := os.LookupEnv("PLUGIN_PLAYBOOK")
|
||||
if !present {
|
||||
sugar.Fatal("⚠️ 'playbook' setting not defined, ABORT!")
|
||||
} else {
|
||||
config.playbook = &playbook
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func main() {
|
||||
// encoderConfig := zapcore.EncoderConfig{
|
||||
// MessageKey: "message",
|
||||
// LevelKey: "level",
|
||||
// EncodeLevel: zapcore.CapitalColorLevelEncoder,
|
||||
// EncodeDuration: zapcore.StringDurationEncoder,
|
||||
// EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
// }
|
||||
// encoder := zapcore.NewConsoleEncoder(encoderConfig)
|
||||
// core := zapcore.NewCore(encoder, os.Stdout, zapcore.InfoLevel)
|
||||
config := zap.NewProductionConfig()
|
||||
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||
config.EncoderConfig.TimeKey = ""
|
||||
config.Encoding = "console"
|
||||
config.DisableCaller = true
|
||||
config.DisableStacktrace = true
|
||||
logger, _ := config.Build()
|
||||
defer logger.Sync()
|
||||
sugar := logger.Sugar()
|
||||
|
||||
sugar.Info("Woodpecker Ansible Runner")
|
||||
pluginConfig := getPluginConfig(sugar)
|
||||
|
||||
if pluginConfig.privateKey != nil {
|
||||
runCommand(sugar, "mkdir", "/root/.ssh")
|
||||
err := os.WriteFile("/root/.ssh/id_ed25519", []byte(*pluginConfig.privateKey), 0400)
|
||||
if err != nil {
|
||||
sugar.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
args := []string{*pluginConfig.playbook}
|
||||
|
||||
if pluginConfig.vaultToken != nil {
|
||||
sugar.Info("💼 Adding vault token to 'credentials/ci_vault_token'")
|
||||
runCommand(sugar, "mkdir", "credentials")
|
||||
err := os.WriteFile("credentials/ci_vault_token", []byte(*pluginConfig.vaultToken), 0644)
|
||||
if err != nil {
|
||||
sugar.Fatal(err)
|
||||
}
|
||||
|
||||
args = append(args, "--vault-password-file=credentials/ci_vault_token")
|
||||
|
||||
sugar.Info("⚙️ Clean ansible.cfg")
|
||||
runCommand(sugar, "sed", "-i", "/vault_password_file.*/d", "./ansible.cfg")
|
||||
}
|
||||
|
||||
if _, err := os.Stat("ansible-ci.cfg"); err == nil {
|
||||
sugar.Info("⚙️ ansible-ci.cfg is present, using it.")
|
||||
os.Remove("ansible.cfg")
|
||||
os.Rename("ansible-ci.cfg", "ansible.cfg")
|
||||
}
|
||||
|
||||
if pluginConfig.galaxyFile != nil {
|
||||
sugar.Infof("🚀 Installing Galaxy dependencies (%s)", *pluginConfig.galaxyFile)
|
||||
runCommand(sugar, "ansible-galaxy", "install", "-r", *pluginConfig.galaxyFile, "--force")
|
||||
}
|
||||
|
||||
if pluginConfig.check_syntax {
|
||||
args = append(args, "--syntax-check")
|
||||
}
|
||||
|
||||
if pluginConfig.check {
|
||||
args = append(args, "--check")
|
||||
}
|
||||
|
||||
if pluginConfig.diff {
|
||||
args = append(args, "--diff")
|
||||
}
|
||||
|
||||
if pluginConfig.verbosity != 0 {
|
||||
verb := "-"
|
||||
for i := 0; i < int(pluginConfig.verbosity); i++ {
|
||||
verb += "v"
|
||||
}
|
||||
args = append(args, verb)
|
||||
}
|
||||
|
||||
if pluginConfig.limit != nil {
|
||||
args = append(args, "--limit", *pluginConfig.limit)
|
||||
}
|
||||
|
||||
if pluginConfig.tags != nil {
|
||||
args = append(args, "--tags", *pluginConfig.tags)
|
||||
}
|
||||
|
||||
// runCommand(sugar, "export", "ANSIBLE_HOST_KEY_CHECKING=False")
|
||||
command := append([]string{"ansible-playbook"}, args...)
|
||||
runCommand(sugar, command...)
|
||||
}
|
10
go.mod
Normal file
10
go.mod
Normal file
@ -0,0 +1,10 @@
|
||||
module woodpecker-ansible-runner
|
||||
|
||||
go 1.20
|
||||
|
||||
require go.uber.org/zap v1.24.0
|
||||
|
||||
require (
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
)
|
18
go.sum
Normal file
18
go.sum
Normal file
@ -0,0 +1,18 @@
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
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/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
57
old.yml
57
old.yml
@ -1,57 +0,0 @@
|
||||
name: Build Docker
|
||||
kind: pipeline
|
||||
type: docker
|
||||
steps:
|
||||
|
||||
- name: Only build image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
repo: harbor.sebclem.fr/sebclem/drone-ansible-runner
|
||||
cache_from: harbor.sebclem.fr/sebclem/drone-ansible-runner
|
||||
registry: harbor.sebclem.fr
|
||||
tags: latest
|
||||
dry_run: true
|
||||
when:
|
||||
target:
|
||||
exclude:
|
||||
- production
|
||||
|
||||
- name: Build and Push docker
|
||||
image: plugins/docker
|
||||
settings:
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
repo: harbor.sebclem.fr/sebclem/drone-ansible-runner
|
||||
cache_from: harbor.sebclem.fr/sebclem/drone-ansible-runner
|
||||
registry: harbor.sebclem.fr
|
||||
tags: latest
|
||||
when:
|
||||
target:
|
||||
- production
|
||||
|
||||
- name: Notify
|
||||
image: drillster/drone-email
|
||||
settings:
|
||||
host:
|
||||
from_secret: mail_host
|
||||
username:
|
||||
from_secret: mail_username
|
||||
password:
|
||||
from_secret: mail_password
|
||||
from:
|
||||
from_secret: mail_from
|
||||
when:
|
||||
status: [ changed, failure ]
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
- custom
|
||||
- promote
|
||||
- rollback
|
Loading…
Reference in New Issue
Block a user