Compare commits

...

12 Commits
v4.0.0 ... main

Author SHA1 Message Date
Robert Kaussow 0c6944bb1b
ci: fix gitea release plugin [skip ci]
ci/woodpecker/tag/lint Pipeline was successful Details
ci/woodpecker/tag/unit-test Pipeline was successful Details
ci/woodpecker/tag/sanity-test Pipeline was successful Details
ci/woodpecker/tag/build-package Pipeline was successful Details
ci/woodpecker/tag/docs Pipeline was successful Details
ci/woodpecker/tag/notify Pipeline was successful Details
2024-03-26 13:44:24 +01:00
Robert Kaussow cc5a102211
fix: use get to access network key
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/unit-test Pipeline was successful Details
ci/woodpecker/push/sanity-test Pipeline was successful Details
ci/woodpecker/push/build-package Pipeline was successful Details
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/notify Pipeline was successful Details
ci/woodpecker/tag/lint Pipeline was successful Details
ci/woodpecker/tag/unit-test Pipeline was successful Details
ci/woodpecker/tag/sanity-test Pipeline was successful Details
ci/woodpecker/tag/build-package Pipeline failed Details
ci/woodpecker/tag/docs unknown status Details
ci/woodpecker/tag/notify Pipeline was successful Details
2024-03-26 13:11:35 +01:00
Robert Kaussow 1d7240fff6
cleanup ci syntax
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/unit-test Pipeline was successful Details
ci/woodpecker/push/sanity-test Pipeline was successful Details
ci/woodpecker/push/build-package Pipeline was successful Details
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/notify Pipeline was successful Details
2024-01-16 14:30:08 +01:00
Robert Kaussow 1acc16352b
remove unnecessary git fetch command from ci
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/unit-test Pipeline was successful Details
ci/woodpecker/push/sanity-test Pipeline was successful Details
ci/woodpecker/push/build-package Pipeline was successful Details
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/notify Pipeline was successful Details
2024-01-04 21:56:25 +01:00
Robert Kaussow 181dd5ce32 ci: cleanup env vars and fix linting (#8)
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/unit-test Pipeline was successful Details
ci/woodpecker/push/sanity-test Pipeline was successful Details
ci/woodpecker/push/build-package Pipeline was successful Details
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/notify Pipeline was successful Details
Reviewed-on: #8
Co-authored-by: Robert Kaussow <mail@thegeeklab.de>
Co-committed-by: Robert Kaussow <mail@thegeeklab.de>
2023-12-15 13:05:48 +01:00
Robert Kaussow 4331062148
cleanup readme
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/unit-test Pipeline was successful Details
ci/woodpecker/push/sanity-test Pipeline was successful Details
ci/woodpecker/push/build-package Pipeline was successful Details
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/notify Pipeline was successful Details
2023-12-13 11:25:39 +01:00
Robert Kaussow fa92fd43ee ci: migrate to woodpecker ci (#7)
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/unit-test Pipeline was successful Details
ci/woodpecker/push/build-package unknown status Details
ci/woodpecker/push/docs unknown status Details
ci/woodpecker/push/sanity-test Pipeline failed Details
ci/woodpecker/push/notify Pipeline was successful Details
Reviewed-on: #7
Co-authored-by: Robert Kaussow <mail@thegeeklab.de>
Co-committed-by: Robert Kaussow <mail@thegeeklab.de>
2023-12-13 11:23:28 +01:00
Robert Kaussow 8e11973364
temp remove git branch publishing step
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2023-07-30 22:48:23 +02:00
Robert Kaussow d37d217a78 ci: fix docs and create release branches (#6)
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is failing Details
Reviewed-on: #6
Co-authored-by: Robert Kaussow <mail@thegeeklab.de>
Co-committed-by: Robert Kaussow <mail@thegeeklab.de>
2023-07-30 13:05:35 +02:00
Robert Kaussow 9226ab6209 feat: add hashivault_unseal module (#5)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #5
Co-authored-by: Robert Kaussow <mail@thegeeklab.de>
Co-committed-by: Robert Kaussow <mail@thegeeklab.de>
2023-07-30 12:43:36 +02:00
Robert Kaussow 14999b6f12
fix drone-matrix template
continuous-integration/drone/push Build is passing Details
2023-02-08 21:27:04 +01:00
Robert Kaussow f8edc9269f fix: fix proxmox env var support for inventory plugin and kvm module (#4)
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2023-01-31 21:35:03 +01:00
35 changed files with 1620 additions and 1266 deletions

View File

@ -1,23 +0,0 @@
# Changelog
{{ range .Versions -}}
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }})
{{ range .CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ (regexReplaceAll "(.*)/issues/(.*)" (regexReplaceAll "(Co-\\w*-by.*)" .Subject "") "${1}/pulls/${2}") | trim }}
{{ end }}
{{- end -}}
{{- if .NoteGroups -}}
{{ range .NoteGroups -}}
### {{ .Title }}
{{ range .Notes }}
{{ .Body }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}

View File

@ -1,24 +0,0 @@
style: github
template: CHANGELOG.tpl.md
info:
title: CHANGELOG
repository_url: https://gitea.rknet.org/ansible/xoxys.general
options:
commit_groups:
title_maps:
feat: Features
fix: Bug Fixes
perf: Performance Improvements
refactor: Code Refactoring
chore: Others
test: Testing
ci: CI Pipeline
header:
pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$"
pattern_maps:
- Type
- Scope
- Subject
notes:
keywords:
- BREAKING CHANGE

2
.dictionary Normal file
View File

@ -0,0 +1,2 @@
Ansible
Kaussow

View File

@ -1,260 +0,0 @@
local PythonVersion(pyversion='3.8') = {
name: 'python' + std.strReplace(pyversion, '.', '') + '-pytest',
image: 'python:' + pyversion,
environment: {
PY_COLORS: 1,
},
commands: [
'pip install poetry -qq',
'poetry config experimental.new-installer false',
'poetry install --all-extras',
'poetry run pytest',
],
depends_on: [
'clone',
],
};
local AnsibleVersion(version='devel') = {
local gitversion = if version == 'devel' then 'devel' else 'stable-' + version,
name: 'ansible-' + std.strReplace(version, '.', ''),
image: 'python:3.9',
environment: {
PY_COLORS: 1,
},
commands: [
'pip install poetry -qq',
'poetry config experimental.new-installer false',
'poetry install',
'poetry run pip install https://github.com/ansible/ansible/archive/' + gitversion + '.tar.gz --disable-pip-version-check',
'poetry run ansible --version',
'poetry run ansible-test sanity --exclude .chglog/ --exclude .drone.yml --python 3.9',
],
depends_on: [
'clone',
],
};
local PipelineLint = {
kind: 'pipeline',
name: 'lint',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'check-format',
image: 'python:3.11',
environment: {
PY_COLORS: 1,
},
commands: [
'git fetch -tq',
'pip install poetry -qq',
'poetry config experimental.new-installer false',
'poetry install --all-extras',
'poetry run yapf -dr ./plugins',
],
},
{
name: 'check-coding',
image: 'python:3.11',
environment: {
PY_COLORS: 1,
},
commands: [
'git fetch -tq',
'pip install poetry -qq',
'poetry config experimental.new-installer false',
'poetry install --all-extras',
'poetry run ruff ./plugins',
],
},
],
trigger: {
ref: ['refs/heads/main', 'refs/tags/**', 'refs/pull/**'],
},
};
local PipelineUnitTest = {
kind: 'pipeline',
name: 'unit-test',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
PythonVersion(pyversion='3.8'),
PythonVersion(pyversion='3.9'),
PythonVersion(pyversion='3.10'),
PythonVersion(pyversion='3.11'),
],
depends_on: [
'lint',
],
trigger: {
ref: ['refs/heads/main', 'refs/tags/**', 'refs/pull/**'],
},
};
local PipelineSanityTest = {
kind: 'pipeline',
name: 'sanity-test',
platform: {
os: 'linux',
arch: 'amd64',
},
workspace: {
path: '/drone/src/ansible_collections/${DRONE_REPO_NAME/./\\/}',
},
steps: [
AnsibleVersion(version='devel'),
AnsibleVersion(version='2.14'),
AnsibleVersion(version='2.13'),
],
depends_on: [
'unit-test',
],
trigger: {
ref: ['refs/heads/main', 'refs/tags/**', 'refs/pull/**'],
},
};
local PipelineBuild = {
kind: 'pipeline',
name: 'build',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'build',
image: 'python:3.11',
commands: [
'GALAXY_VERSION=${DRONE_TAG##v}',
"sed -i 's/version: 0.0.0/version: '\"$${GALAXY_VERSION:-0.0.0}\"'/g' galaxy.yml",
'pip install poetry -qq',
'poetry config experimental.new-installer false',
'poetry install --all-extras',
'poetry run ansible-galaxy collection build --output-path dist/',
],
},
{
name: 'checksum',
image: 'alpine',
commands: [
'cd dist/ && sha256sum * > ../sha256sum.txt',
],
},
{
name: 'changelog-generate',
image: 'thegeeklab/git-chglog',
commands: [
'git fetch -tq',
'git-chglog --no-color --no-emoji -o CHANGELOG.md ${DRONE_TAG:---next-tag unreleased unreleased}',
],
},
{
name: 'changelog-format',
image: 'thegeeklab/alpine-tools',
commands: [
'prettier CHANGELOG.md',
'prettier -w CHANGELOG.md',
],
},
{
name: 'publish-gitea',
image: 'plugins/gitea-release',
settings: {
overwrite: true,
api_key: { from_secret: 'gitea_token' },
files: ['dist/*', 'sha256sum.txt'],
base_url: 'https://gitea.rknet.org',
title: '${DRONE_TAG}',
note: 'CHANGELOG.md',
},
when: {
ref: ['refs/tags/**'],
},
},
],
depends_on: [
'sanity-test',
],
trigger: {
ref: ['refs/heads/main', 'refs/tags/**', 'refs/pull/**'],
},
};
local PipelineDocumentation = {
kind: 'pipeline',
name: 'documentation',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'publish',
image: 'plugins/gh-pages',
settings: {
netrc_machine: 'gitea.rknet.org',
pages_directory: 'docs/',
password: {
from_secret: 'gitea_token',
},
remote_url: 'https://gitea.rknet.org/ansible/${DRONE_REPO_NAME}',
target_branch: 'docs',
username: {
from_secret: 'gitea_username',
},
},
},
],
depends_on: [
'build',
],
trigger: {
ref: ['refs/heads/main', 'refs/tags/**'],
},
};
local PipelineNotifications = {
kind: 'pipeline',
name: 'notifications',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'matrix',
image: 'thegeeklab/drone-matrix',
settings: {
homeserver: { from_secret: 'matrix_homeserver' },
roomid: { from_secret: 'matrix_roomid' },
template: 'Status: **{{ build.Status }}**<br/> Build: [{{ repo.Owner }}/{{ repo.Name }}]({{ build.Link }}){{#if build.Branch}} ({{ build.Branch }}){{/if}} by {{ commit.Author }}<br/> Message: {{ commit.Message.Title }}',
username: { from_secret: 'matrix_username' },
password: { from_secret: 'matrix_password' },
},
},
],
depends_on: [
'documentation',
],
trigger: {
ref: ['refs/heads/main', 'refs/tags/**'],
status: ['success', 'failure'],
},
};
[
PipelineLint,
PipelineUnitTest,
PipelineSanityTest,
PipelineBuild,
PipelineDocumentation,
PipelineNotifications,
]

View File

@ -1,294 +0,0 @@
---
kind: pipeline
name: lint
platform:
os: linux
arch: amd64
steps:
- name: check-format
image: python:3.11
commands:
- git fetch -tq
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install --all-extras
- poetry run yapf -dr ./plugins
environment:
PY_COLORS: 1
- name: check-coding
image: python:3.11
commands:
- git fetch -tq
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install --all-extras
- poetry run ruff ./plugins
environment:
PY_COLORS: 1
trigger:
ref:
- refs/heads/main
- refs/tags/**
- refs/pull/**
---
kind: pipeline
name: unit-test
platform:
os: linux
arch: amd64
steps:
- name: python38-pytest
image: python:3.8
commands:
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install --all-extras
- poetry run pytest
environment:
PY_COLORS: 1
depends_on:
- clone
- name: python39-pytest
image: python:3.9
commands:
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install --all-extras
- poetry run pytest
environment:
PY_COLORS: 1
depends_on:
- clone
- name: python310-pytest
image: python:3.10
commands:
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install --all-extras
- poetry run pytest
environment:
PY_COLORS: 1
depends_on:
- clone
- name: python311-pytest
image: python:3.11
commands:
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install --all-extras
- poetry run pytest
environment:
PY_COLORS: 1
depends_on:
- clone
trigger:
ref:
- refs/heads/main
- refs/tags/**
- refs/pull/**
depends_on:
- lint
---
kind: pipeline
name: sanity-test
platform:
os: linux
arch: amd64
workspace:
path: /drone/src/ansible_collections/${DRONE_REPO_NAME/./\/}
steps:
- name: ansible-devel
image: python:3.9
commands:
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install
- poetry run pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
- poetry run ansible --version
- poetry run ansible-test sanity --exclude .chglog/ --exclude .drone.yml --python 3.9
environment:
PY_COLORS: 1
depends_on:
- clone
- name: ansible-214
image: python:3.9
commands:
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install
- poetry run pip install https://github.com/ansible/ansible/archive/stable-2.14.tar.gz --disable-pip-version-check
- poetry run ansible --version
- poetry run ansible-test sanity --exclude .chglog/ --exclude .drone.yml --python 3.9
environment:
PY_COLORS: 1
depends_on:
- clone
- name: ansible-213
image: python:3.9
commands:
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install
- poetry run pip install https://github.com/ansible/ansible/archive/stable-2.13.tar.gz --disable-pip-version-check
- poetry run ansible --version
- poetry run ansible-test sanity --exclude .chglog/ --exclude .drone.yml --python 3.9
environment:
PY_COLORS: 1
depends_on:
- clone
trigger:
ref:
- refs/heads/main
- refs/tags/**
- refs/pull/**
depends_on:
- unit-test
---
kind: pipeline
name: build
platform:
os: linux
arch: amd64
steps:
- name: build
image: python:3.11
commands:
- GALAXY_VERSION=${DRONE_TAG##v}
- "sed -i 's/version: 0.0.0/version: '\"$${GALAXY_VERSION:-0.0.0}\"'/g' galaxy.yml"
- pip install poetry -qq
- poetry config experimental.new-installer false
- poetry install --all-extras
- poetry run ansible-galaxy collection build --output-path dist/
- name: checksum
image: alpine
commands:
- cd dist/ && sha256sum * > ../sha256sum.txt
- name: changelog-generate
image: thegeeklab/git-chglog
commands:
- git fetch -tq
- git-chglog --no-color --no-emoji -o CHANGELOG.md ${DRONE_TAG:---next-tag unreleased unreleased}
- name: changelog-format
image: thegeeklab/alpine-tools
commands:
- prettier CHANGELOG.md
- prettier -w CHANGELOG.md
- name: publish-gitea
image: plugins/gitea-release
settings:
api_key:
from_secret: gitea_token
base_url: https://gitea.rknet.org
files:
- dist/*
- sha256sum.txt
note: CHANGELOG.md
overwrite: true
title: ${DRONE_TAG}
when:
ref:
- refs/tags/**
trigger:
ref:
- refs/heads/main
- refs/tags/**
- refs/pull/**
depends_on:
- sanity-test
---
kind: pipeline
name: documentation
platform:
os: linux
arch: amd64
steps:
- name: publish
image: plugins/gh-pages
settings:
netrc_machine: gitea.rknet.org
pages_directory: docs/
password:
from_secret: gitea_token
remote_url: https://gitea.rknet.org/ansible/${DRONE_REPO_NAME}
target_branch: docs
username:
from_secret: gitea_username
trigger:
ref:
- refs/heads/main
- refs/tags/**
depends_on:
- build
---
kind: pipeline
name: notifications
platform:
os: linux
arch: amd64
steps:
- name: matrix
image: thegeeklab/drone-matrix
settings:
homeserver:
from_secret: matrix_homeserver
password:
from_secret: matrix_password
roomid:
from_secret: matrix_roomid
template: "Status: **{{ build.Status }}**<br/> Build: [{{ repo.Owner }}/{{ repo.Name }}]({{ build.Link }}){{#if build.Branch}} ({{ build.Branch }}){{/if}} by {{ commit.Author }}<br/> Message: {{ commit.Message.Title }}"
username:
from_secret: matrix_username
trigger:
ref:
- refs/heads/main
- refs/tags/**
status:
- success
- failure
depends_on:
- documentation
---
kind: signature
hmac: 407d145ab4483651c579eea4e1e9375536caee1aa0579abcdf57b5653e595cb5
...

47
.gitsv/config.yml Normal file
View File

@ -0,0 +1,47 @@
---
version: "1.1"
versioning:
update-major: []
update-minor: [feat]
update-patch: [fix, perf, refactor, chore, test, ci, docs]
tag:
pattern: "v%d.%d.%d"
release-notes:
sections:
- name: Features
commit-types: [feat]
section-type: commits
- name: Bug Fixes
commit-types: [fix]
section-type: commits
- name: Performance Improvements
commit-types: [perf]
section-type: commits
- name: Code Refactoring
commit-types: [refactor]
section-type: commits
- name: Others
commit-types: [chore]
section-type: commits
- name: Testing
commit-types: [test]
section-type: commits
- name: CI Pipeline
commit-types: [ci]
section-type: commits
- name: Documentation
commit-types: [docs]
section-type: commits
- name: Breaking Changes
section-type: breaking-changes
commit-message:
footer:
issue:
key: issue
add-value-prefix: "#"
issue:
regex: "#?[0-9]+"

7
.markdownlint.yml Normal file
View File

@ -0,0 +1,7 @@
---
default: True
MD013: False
MD041: False
MD024: False
MD004:
style: dash

View File

@ -1,3 +1,2 @@
.drone.yml
*.tpl.md *.tpl.md
LICENSE LICENSE

View File

@ -0,0 +1,46 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
steps:
- name: build
image: docker.io/library/python:3.12
commands:
- GALAXY_VERSION=${CI_COMMIT_TAG##v}
- 'sed -i ''s/version: 0.0.0/version: ''"$${GALAXY_VERSION:-0.0.0}"''/g'' galaxy.yml'
- pip install poetry -qq
- poetry install --all-extras --no-root
- poetry run ansible-galaxy collection build --output-path dist/
- name: checksum
image: quay.io/thegeeklab/alpine-tools
commands:
- cd dist/ && sha256sum * > ../sha256sum.txt
- name: changelog
image: quay.io/thegeeklab/git-sv
commands:
- git sv current-version
- git sv release-notes -t ${CI_COMMIT_TAG:-next} -o CHANGELOG.md
- cat CHANGELOG.md
- name: publish-gitea
image: quay.io/thegeeklab/wp-gitea-release
settings:
api_key:
from_secret: gitea_token
base_url: https://gitea.rknet.org
files:
- dist/*
- sha256sum.txt
note: CHANGELOG.md
title: ${CI_COMMIT_TAG}
when:
- event: [tag]
depends_on:
- unit-test
- sanity-test

49
.woodpecker/docs.yml Normal file
View File

@ -0,0 +1,49 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
steps:
- name: markdownlint
image: quay.io/thegeeklab/markdownlint-cli
group: test
commands:
- markdownlint 'docs/**/*.md' 'README.md'
- name: spellcheck
image: quay.io/thegeeklab/alpine-tools
group: test
commands:
- spellchecker --files 'docs/**/*.md' 'README.md' -d .dictionary -p spell indefinite-article syntax-urls frontmatter --frontmatter-keys title tags
environment:
FORCE_COLOR: "true"
- name: link-validation
image: docker.io/lycheeverse/lychee
group: test
commands:
- lychee --no-progress --format detailed docs/ README.md
- name: publish
image: quay.io/thegeeklab/wp-git-action
settings:
action:
- pages
author_email: shipper@rknet.org
author_name: shipper
branch: docs
message: auto-update documentation
netrc_machine: gitea.rknet.org
netrc_password:
from_secret: gitea_token
pages_directory: docs/
remote_url: https://gitea.rknet.org/ansible/${CI_REPO_NAME}
when:
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
depends_on:
- build-package

25
.woodpecker/lint.yml Normal file
View File

@ -0,0 +1,25 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
steps:
- name: check-format
image: docker.io/library/python:3.12
commands:
- pip install poetry -qq
- poetry install --all-extras --no-root
- poetry run ruff format --check --diff ./plugins
environment:
PY_COLORS: "1"
- name: check-coding
image: docker.io/library/python:3.12
commands:
- pip install poetry -qq
- poetry install --all-extras --no-root
- poetry run ruff ./plugins
environment:
PY_COLORS: "1"

26
.woodpecker/notify.yml Normal file
View File

@ -0,0 +1,26 @@
---
when:
- event: [tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
runs_on: [success, failure]
steps:
- name: matrix
image: quay.io/thegeeklab/wp-matrix
settings:
homeserver:
from_secret: matrix_homeserver
password:
from_secret: matrix_password
roomid:
from_secret: matrix_roomid
username:
from_secret: matrix_username
when:
- status: [success, failure]
depends_on:
- docs

View File

@ -0,0 +1,45 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
variables:
- &ansible_base
image: docker.io/library/python:3.10
group: ansible
commands:
- pip install poetry -qq
- poetry install --all-extras --no-root
- poetry run pip install https://github.com/ansible/ansible/archive/$${ANSIBLE_VERSION}.tar.gz --disable-pip-version-check
- poetry run ansible --version
- poetry run ansible-test sanity --exclude .gitsv/ --exclude .woodpecker/ --python 3.10
- &ansible_env
PY_COLORS: "1"
workspace:
base: /woodpecker/src
path: ansible_collections/${CI_REPO_NAME/./\/}
steps:
- name: ansible-devel
<<: *ansible_base
environment:
ANSIBLE_VERSION: "devel"
<<: *ansible_env
- name: ansible-216
<<: *ansible_base
environment:
ANSIBLE_VERSION: "stable-2.16"
<<: *ansible_env
- name: ansible-215
<<: *ansible_base
environment:
ANSIBLE_VERSION: "stable-2.15"
<<: *ansible_env
depends_on:
- lint

36
.woodpecker/unit-test.yml Normal file
View File

@ -0,0 +1,36 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
variables:
- &pytest_base
group: pytest
commands:
- pip install poetry -qq
- poetry install --all-extras --no-root
- poetry run pytest
environment:
PY_COLORS: "1"
steps:
- name: pyton-312
image: docker.io/library/python:3.12
<<: *pytest_base
- name: pyton-311
image: docker.io/library/python:3.11
<<: *pytest_base
- name: pyton-310
image: docker.io/library/python:3.10
<<: *pytest_base
- name: pyton-39
image: docker.io/library/python:3.9
<<: *pytest_base
depends_on:
- lint

View File

@ -1,14 +1,10 @@
# xoxys.general # xoxys.general
[![Build Status](https://img.shields.io/drone/build/ansible/xoxys.general?logo=drone&server=https%3A%2F%2Fdrone.rknet.org)](https://drone.rknet.org/ansible/xoxys.general) [![Build Status](https://ci.rknet.org/api/badges/ansible/xoxys.general/status.svg)](https://ci.rknet.org/repos/ansible/xoxys.general)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?label=license)](LICENSE) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?label=license)](https://gitea.rknet.org/ansible/xoxys.general/src/branch/main/LICENSE)
Custom general Ansible collection. Custom general Ansible collection.
## License ## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. This project is licensed under the MIT License - see the [LICENSE](https://gitea.rknet.org/ansible/xoxys.general/src/branch/main/LICENSE) file for details.
## Maintainers and Contributors
[Robert Kaussow](https://gitea.rknet.org/xoxys)

View File

@ -6,5 +6,7 @@ geekdocFlatSection: true
General custom content collection for Ansible. General custom content collection for Ansible.
<!-- spellchecker-disable --> <!-- spellchecker-disable -->
{{< toc-tree >}} {{< toc-tree >}}
<!-- spellchecker-enable --> <!-- spellchecker-enable -->

View File

@ -14,6 +14,7 @@ my_list:
``` ```
Or pass a custom prefix: Or pass a custom prefix:
```Yaml ```Yaml
my_list: my_list:
- item1 - item1

View File

@ -14,6 +14,7 @@ my_list:
``` ```
Or pass a custom wrapper: Or pass a custom wrapper:
```Yaml ```Yaml
my_list: my_list:
- item1 - item1

View File

@ -1,7 +1,7 @@
--- ---
namespace: xoxys namespace: xoxys
name: general name: general
# The version is generated during the release by Drone CI. # The version is generated during the release by Woocpecker CI.
version: 0.0.0 version: 0.0.0
readme: README.md readme: README.md
authors: authors:

View File

@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Implement documentation fragment for Hashivault module."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class ModuleDocFragment: # noqa
# Standard documentation
DOCUMENTATION = r"""
requirements:
- hvac>=0.10.1
- ansible>=2.0.0
- requests
options:
url:
description:
- URL of the Vault server.
- You can use C(VAULT_ADDR) environment variable.
default: ""
type: str
ca_cert:
description:
- Path to a PEM-encoded CA cert file to use to verify the Vault server
TLS certificate.
- You can use C(VAULT_CACERT) environment variable.
default: ""
type: str
ca_path:
description:
- Path to a directory of PEM-encoded CA cert files to verify the Vault server
TLS certificate. If ca_cert is specified, its value will take precedence.
- You can use C(VAULT_CAPATH) environment variable.
default: ""
type: str
client_cert:
description:
- Path to a PEM-encoded client certificate for TLS authentication to the Vault
server.
- You can use C(VAULT_CLIENT_CERT) environment variable.
default: ""
type: str
client_key:
description:
- Path to an unencrypted PEM-encoded private key matching the client certificate.
- You can use C(VAULT_CLIENT_KEY) environment variable.
default: ""
type: str
verify:
description:
- If set, do not verify presented TLS certificate before communicating with Vault
server. Setting this variable is not recommended except during testing.
- You can use C(VAULT_SKIP_VERIFY) environment variable.
default: false
type: bool
authtype:
description:
- Authentication type.
- You can use C(VAULT_AUTHTYPE) environment variable.
default: "token"
type: str
choices: ["token", "userpass", "github", "ldap", "approle"]
login_mount_point:
description:
- Authentication mount point.
- You can use C(VAULT_LOGIN_MOUNT_POINT) environment variable.
type: str
token:
description:
- Token for vault.
- You can use C(VAULT_TOKEN) environment variable.
type: str
username:
description:
- Username to login to vault.
- You can use C(VAULT_USER) environment variable.
default: ""
type: str
password:
description:
- Password to login to vault.
- You can use C(VAULT_PASSWORD) environment variable.
type: str
role_id:
description:
- Role id for vault.
- You can use C(VAULT_ROLE_ID) environment variable.
type: str
secret_id:
description:
- Secret id for vault.
- You can use C(VAULT_SECRET_ID) environment variable.
type: str
aws_header:
description:
- X-Vault-AWS-IAM-Server-ID Header value to prevent replay attacks.
- You can use C(VAULT_AWS_HEADER) environment variable.
type: str
namespace:
description:
- Namespace for vault.
- You can use C(VAULT_NAMESPACE) environment variable.
type: str
"""

View File

@ -1,6 +1,6 @@
"""Filter to prefix all itams from a list.""" """Filter to prefix all itams from a list."""
from __future__ import (absolute_import, division, print_function) from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
@ -10,6 +10,5 @@ def prefix(value, prefix="--"):
class FilterModule(object): # noqa class FilterModule(object): # noqa
def filters(self): def filters(self):
return {"prefix": prefix} return {"prefix": prefix}

View File

@ -1,6 +1,6 @@
"""Filter to wrap all items from a list.""" """Filter to wrap all items from a list."""
from __future__ import (absolute_import, division, print_function) from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
@ -10,6 +10,5 @@ def wrap(value, wrapper="'"):
class FilterModule(object): # noqa class FilterModule(object): # noqa
def filters(self): def filters(self):
return {"wrap": wrap} return {"wrap": wrap}

View File

@ -4,7 +4,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Dynamic inventory plugin for Proxmox VE.""" """Dynamic inventory plugin for Proxmox VE."""
from __future__ import (absolute_import, division, print_function) from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
@ -28,24 +28,33 @@ options:
- Specify the target host of the Proxmox VE cluster. - Specify the target host of the Proxmox VE cluster.
type: str type: str
required: true required: true
env:
- name: PROXMOX_SERVER
api_user: api_user:
description: description:
- Specify the user to authenticate with. - Specify the user to authenticate with.
type: str type: str
required: true required: true
env:
- name: PROXMOX_USER
api_password: api_password:
description: description:
- Specify the password to authenticate with. - Specify the password to authenticate with.
- You can use C(PROXMOX_PASSWORD) environment variable.
type: str type: str
env:
- name: PROXMOX_PASSWORD
api_token_id: api_token_id:
description: description:
- Specify the token ID. - Specify the token ID.
type: str type: str
env:
- name: PROXMOX_TOKEN_ID
api_token_secret: api_token_secret:
description: description:
- Specify the token secret. - Specify the token secret.
type: str type: str
env:
- name: PROXMOX_TOKEN_SECRET
verify_ssl: verify_ssl:
description: description:
- If C(false), SSL certificates will not be validated. - If C(false), SSL certificates will not be validated.
@ -90,26 +99,29 @@ import json
import re import re
import socket import socket
from collections import defaultdict from collections import defaultdict
from distutils.version import LooseVersion
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
from ansible.module_utils._text import to_native from ansible.module_utils._text import to_native
from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.parsing.convert_bool import boolean
from ansible.module_utils.six import iteritems from ansible.module_utils.six import iteritems
from ansible.plugins.inventory import BaseInventoryPlugin from ansible.plugins.inventory import BaseInventoryPlugin
from ansible_collections.xoxys.general.plugins.module_utils.version import LooseVersion
try: try:
from proxmoxer import ProxmoxAPI from proxmoxer import ProxmoxAPI
HAS_PROXMOXER = True HAS_PROXMOXER = True
except ImportError: except ImportError:
HAS_PROXMOXER = False HAS_PROXMOXER = False
try: try:
from requests.packages import urllib3 from requests.packages import urllib3
HAS_URLLIB3 = True HAS_URLLIB3 = True
except ImportError: except ImportError:
try: try:
import urllib3 import urllib3
HAS_URLLIB3 = True HAS_URLLIB3 = True
except ImportError: except ImportError:
HAS_URLLIB3 = False HAS_URLLIB3 = False
@ -120,7 +132,7 @@ class InventoryModule(BaseInventoryPlugin):
NAME = "xoxys.general.proxmox" NAME = "xoxys.general.proxmox"
def _auth(self): def _proxmox_auth(self):
auth_args = {"user": self.get_option("api_user")} auth_args = {"user": self.get_option("api_user")}
if not (self.get_option("api_token_id") and self.get_option("api_token_secret")): if not (self.get_option("api_token_id") and self.get_option("api_token_secret")):
auth_args["password"] = self.get_option("api_password") auth_args["password"] = self.get_option("api_password")
@ -132,11 +144,11 @@ class InventoryModule(BaseInventoryPlugin):
if not verify_ssl and HAS_URLLIB3: if not verify_ssl and HAS_URLLIB3:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
return ProxmoxAPI( self.client = ProxmoxAPI(
self.get_option("api_host"), self.get_option("api_host"),
verify_ssl=verify_ssl, verify_ssl=verify_ssl,
timeout=self.get_option("auth_timeout"), timeout=self.get_option("auth_timeout"),
**auth_args **auth_args,
) )
def _get_version(self): def _get_version(self):
@ -166,7 +178,6 @@ class InventoryModule(BaseInventoryPlugin):
return variables return variables
def _get_ip_address(self, pve_type, pve_node, vmid): def _get_ip_address(self, pve_type, pve_node, vmid):
def validate(address): def validate(address):
try: try:
# IP address validation # IP address validation
@ -189,7 +200,7 @@ class InventoryModule(BaseInventoryPlugin):
if networks and isinstance(networks, list): if networks and isinstance(networks, list):
for network in networks: for network in networks:
for ip_address in network["ip-addresses"]: for ip_address in network.get("ip-addresses", []):
address = validate(ip_address["ip-address"]) address = validate(ip_address["ip-address"])
else: else:
try: try:
@ -237,8 +248,9 @@ class InventoryModule(BaseInventoryPlugin):
pve_type = "qemu" pve_type = "qemu"
try: try:
description = self.client.nodes(node).get(pve_type, vmid, description = self.client.nodes(node).get(pve_type, vmid, "config")[
"config")["description"] "description"
]
except KeyError: except KeyError:
description = None description = None
except Exception as e: # noqa except Exception as e: # noqa
@ -307,5 +319,5 @@ class InventoryModule(BaseInventoryPlugin):
super().parse(inventory, loader, path) super().parse(inventory, loader, path)
self._read_config_data(path) self._read_config_data(path)
self.client = self._auth() self._proxmox_auth()
self._propagate() self._propagate()

View File

@ -0,0 +1,402 @@
"""Provide helper functions for Hashivault module."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import os
import traceback
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
HVAC_IMP_ERR = None
try:
import hvac
from hvac.exceptions import InvalidPath
HAS_HVAC = True
except ImportError:
HAS_HVAC = False
HVAC_IMP_ERR = traceback.format_exc()
def hashivault_argspec():
return dict(
url=dict(required=False, default=os.environ.get("VAULT_ADDR", ""), type="str"),
ca_cert=dict(required=False, default=os.environ.get("VAULT_CACERT", ""), type="str"),
ca_path=dict(required=False, default=os.environ.get("VAULT_CAPATH", ""), type="str"),
client_cert=dict(
required=False, default=os.environ.get("VAULT_CLIENT_CERT", ""), type="str"
),
client_key=dict(
required=False, default=os.environ.get("VAULT_CLIENT_KEY", ""), type="str", no_log=True
),
verify=dict(
required=False, default=(not os.environ.get("VAULT_SKIP_VERIFY", "False")), type="bool"
),
authtype=dict(
required=False,
default=os.environ.get("VAULT_AUTHTYPE", "token"),
type="str",
choices=["token", "userpass", "github", "ldap", "approle"],
),
login_mount_point=dict(
required=False, default=os.environ.get("VAULT_LOGIN_MOUNT_POINT", None), type="str"
),
token=dict(
required=False,
fallback=(hashivault_default_token, ["VAULT_TOKEN"]),
type="str",
no_log=True,
),
username=dict(required=False, default=os.environ.get("VAULT_USER", ""), type="str"),
password=dict(
required=False, fallback=(env_fallback, ["VAULT_PASSWORD"]), type="str", no_log=True
),
role_id=dict(
required=False, fallback=(env_fallback, ["VAULT_ROLE_ID"]), type="str", no_log=True
),
secret_id=dict(
required=False, fallback=(env_fallback, ["VAULT_SECRET_ID"]), type="str", no_log=True
),
aws_header=dict(
required=False, fallback=(env_fallback, ["VAULT_AWS_HEADER"]), type="str", no_log=True
),
namespace=dict(
required=False, default=os.environ.get("VAULT_NAMESPACE", None), type="str"
),
)
def hashivault_init(
argument_spec,
supports_check_mode=False,
required_if=None,
required_together=None,
required_one_of=None,
mutually_exclusive=None,
):
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=supports_check_mode,
required_if=required_if,
required_together=required_together,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
)
if not HAS_HVAC:
module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMP_ERR)
module.no_log_values.discard("0")
module.no_log_values.discard(0)
module.no_log_values.discard("1")
module.no_log_values.discard(1)
module.no_log_values.discard(True)
module.no_log_values.discard(False)
module.no_log_values.discard("ttl")
return module
def hashivault_client(params):
url = params.get("url")
ca_cert = params.get("ca_cert")
ca_path = params.get("ca_path")
client_cert = params.get("client_cert")
client_key = params.get("client_key")
cert = (client_cert, client_key)
check_verify = params.get("verify")
namespace = params.get("namespace", None)
if check_verify == "" or check_verify:
if ca_cert:
verify = ca_cert
elif ca_path:
verify = ca_path
else:
verify = check_verify
else:
verify = check_verify
return hvac.Client(url=url, cert=cert, verify=verify, namespace=namespace)
def hashivault_auth(client, params):
token = params.get("token")
authtype = params.get("authtype")
login_mount_point = params.get("login_mount_point", authtype)
if not login_mount_point:
login_mount_point = authtype
username = params.get("username")
password = params.get("password")
secret_id = params.get("secret_id")
role_id = params.get("role_id")
if authtype == "github":
client.auth.github.login(token, mount_point=login_mount_point)
elif authtype == "userpass":
client.auth_userpass(username, password, mount_point=login_mount_point)
elif authtype == "ldap":
client.auth.ldap.login(username, password, mount_point=login_mount_point)
elif authtype == "approle":
client = AppRoleClient(client, role_id, secret_id, mount_point=login_mount_point)
elif authtype == "tls":
client.auth_tls()
else:
client.token = token
return client
def hashivault_auth_client(params):
client = hashivault_client(params)
return hashivault_auth(client, params)
def hashiwrapper(function):
def wrapper(*args, **kwargs):
result = {"changed": False, "rc": 0}
result.update(function(*args, **kwargs))
return result
return wrapper
def hashivault_default_token(env):
"""Get a default Vault token from an environment variable or a file."""
envvar = env[0]
if envvar in os.environ:
return os.environ[envvar]
token_file = os.path.expanduser("~/.vault-token")
if os.path.exists(token_file):
with open(token_file) as f:
return f.read().strip()
return ""
@hashiwrapper
def hashivault_read(params):
result = {"changed": False, "rc": 0}
client = hashivault_auth_client(params)
version = params.get("version")
mount_point = params.get("mount_point")
secret = params.get("secret")
secret_version = params.get("secret_version")
key = params.get("key")
default = params.get("default")
if secret.startswith("/"):
secret = secret.lstrip("/")
mount_point = ""
secret_path = f"{mount_point}/{secret}" if mount_point else secret
try:
if version == 2:
response = client.secrets.kv.v2.read_secret_version(
secret, mount_point=mount_point, version=secret_version
)
else:
response = client.secrets.kv.v1.read_secret(secret, mount_point=mount_point)
except InvalidPath:
response = None
except Exception as e: # noqa: BLE001
result["rc"] = 1
result["failed"] = True
error_string = f"{e.__class__.__name__}({e})"
result["msg"] = f"Error {error_string} reading {secret_path}"
return result
if not response:
if default is not None:
result["value"] = default
return result
result["rc"] = 1
result["failed"] = True
result["msg"] = f"Secret {secret_path} is not in vault"
return result
if version == 2:
try:
data = response.get("data", {})
data = data.get("data", {})
except Exception: # noqa: BLE001
data = str(response)
else:
data = response["data"]
lease_duration = response.get("lease_duration", None)
if lease_duration is not None:
result["lease_duration"] = lease_duration
lease_id = response.get("lease_id", None)
if lease_id is not None:
result["lease_id"] = lease_id
renewable = response.get("renewable", None)
if renewable is not None:
result["renewable"] = renewable
wrap_info = response.get("wrap_info", None)
if wrap_info is not None:
result["wrap_info"] = wrap_info
if key and key not in data:
if default is not None:
result["value"] = default
return result
result["rc"] = 1
result["failed"] = True
result["msg"] = f"Key {key} is not in secret {secret_path}"
return result
value = data[key] if key else data
result["value"] = value
return result
class AppRoleClient:
"""
hvac.Client decorator generate and set a new approle token.
This allows multiple calls to Vault without having to manually
generate and set a token on every Vault call.
"""
def __init__(self, client, role_id, secret_id, mount_point):
object.__setattr__(self, "client", client)
object.__setattr__(self, "role_id", role_id)
object.__setattr__(self, "secret_id", secret_id)
object.__setattr__(self, "login_mount_point", mount_point)
def __setattr__(self, name, val):
client = object.__getattribute__(self, "client")
client.__setattr__(name, val)
def __getattribute__(self, name):
client = object.__getattribute__(self, "client")
attr = client.__getattribute__(name)
role_id = object.__getattribute__(self, "role_id")
secret_id = object.__getattribute__(self, "secret_id")
login_mount_point = object.__getattribute__(self, "login_mount_point")
resp = client.auth_approle(role_id, secret_id=secret_id, mount_point=login_mount_point)
client.token = str(resp["auth"]["client_token"])
return attr
def _compare_state(desired_state, current_state, ignore=None):
"""
Compare desired state to current state.
Returns true if objects are equal.
Recursively walks dict object to compare all keys.
:param desired_state: The state user desires.
:param current_state: The state that currently exists.
:param ignore: Ignore these keys.
:type ignore: list
:return: True if the states are the same.
:rtype: bool
"""
if ignore is None:
ignore = []
if isinstance(desired_state, list):
if not isinstance(current_state, list) or (len(desired_state) != len(current_state)):
return False
return set(desired_state) == set(current_state)
if isinstance(desired_state, dict):
if not isinstance(current_state, dict):
return False
# iterate over dictionary keys
for key in desired_state:
if key in ignore:
continue
v = desired_state[key]
if (key not in current_state) or (not _compare_state(v, current_state.get(key))):
return False
return True
# Lots of things get handled as strings in ansible that aren"t necessarily strings,
# can extend this list later.
if isinstance(desired_state, str) and isinstance(current_state, int):
current_state = str(current_state)
return desired_state == current_state
def _convert_to_seconds(original_value):
try:
value = str(original_value)
seconds = 0
if "h" in value:
ray = value.split("h")
seconds = int(ray.pop(0)) * 3600
value = "".join(ray)
if "m" in value:
ray = value.split("m")
seconds += int(ray.pop(0)) * 60
value = "".join(ray)
if value:
ray = value.split("s")
seconds += int(ray.pop(0))
return seconds
except Exception: # noqa: BLE001,S110
pass
return original_value
def get_keys_updated(desired_state, current_state, ignore=None):
"""
Return list of keys that have different values.
Recursively walks dict object to compare all keys.
:param desired_state: The state user desires.
:type desired_state: dict
:param current_state: The state that currently exists.
:type current_state: dict
:param ignore: Ignore these keys.
:type ignore: list
:return: Different items
:rtype: list
"""
if ignore is None:
ignore = []
differences = []
for key in desired_state:
if key in ignore:
continue
if key not in current_state:
differences.append(key)
continue
new_value = desired_state[key]
old_value = current_state[key]
if (
"ttl" in key and (_convert_to_seconds(old_value) != _convert_to_seconds(new_value))
) or not _compare_state(new_value, old_value):
differences.append(key)
return differences
def is_state_changed(desired_state, current_state, ignore=None): # noqa: ARG001
"""
Return list of keys that have different values.
Recursively walks dict object to compare all keys.
:param desired_state: The state user desires.
:type desired_state: dict
:param current_state: The state that currently exists.
:type current_state: dict
:param ignore: Ignore these keys.
:type ignore: list
:return: Different
:rtype: bool
"""
return len(get_keys_updated(desired_state, current_state)) > 0

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, Felix Fontein <felix@fontein.de>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
"""Provide version object to compare version numbers."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.six import raise_from
try:
from ansible.module_utils.compat.version import LooseVersion # noqa: F401,E501 pylint: disable=unused-import
except ImportError:
try:
from distutils.version import LooseVersion # noqa: F401, pylint: disable=unused-import
except ImportError as exc:
msg = (
"To use this plugin or module with ansible-core 2.11, you need to use Python < 3.12 "
"with distutils.version present"
)
raise_from(ImportError(msg), exc)

View File

@ -0,0 +1,72 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Unseal Hashicorp Vault servers."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {"status": ["stableinterface"], "supported_by": "community", "version": "1.1"}
DOCUMENTATION = """
---
module: hashivault_unseal
short_description: Hashicorp Vault unseal module.
version_added: 1.2.0
description:
- "Module to unseal Hashicorp Vault."
options:
keys:
description:
- Vault key shard(s).
type: list
elements: str
required: true
author:
- Robert Kaussow (@xoxys)
extends_documentation_fragment:
- xoxys.general.hashivault
"""
EXAMPLES = """
---
- name: Unseal vault
hashivault_unseal:
keys:
- 26479cc0-54bc-4252-9c34-baca54aa5de7
- 47f942e3-8525-4b44-ba2f-84a4ae81db7d
- 2ee9c868-4275-4836-8747-4f8fb7611aa0
url: https://vault.example.com
"""
from ansible_collections.xoxys.general.plugins.module_utils.hashivault import hashivault_argspec
from ansible_collections.xoxys.general.plugins.module_utils.hashivault import hashivault_client
from ansible_collections.xoxys.general.plugins.module_utils.hashivault import hashivault_init
from ansible_collections.xoxys.general.plugins.module_utils.hashivault import hashiwrapper
def main():
argspec = hashivault_argspec()
argspec["keys"] = dict(required=True, type="list", elements="str", no_log=True)
module = hashivault_init(argspec)
result = hashivault_unseal(module.params)
if result.get("failed"):
module.fail_json(**result)
else:
module.exit_json(**result)
@hashiwrapper
def hashivault_unseal(params):
keys = params.get("keys")
client = hashivault_client(params)
if client.sys.is_sealed():
return {"status": client.sys.submit_unseal_keys(keys), "changed": True}
return {"changed": False}
if __name__ == "__main__":
main()

View File

@ -216,6 +216,7 @@ from collections import defaultdict
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import json from ansible.module_utils.basic import json
from ansible_collections.xoxys.general.plugins.module_utils.version import LooseVersion
# Genereates a diff dictionary from an old and new table dump. # Genereates a diff dictionary from an old and new table dump.
@ -357,7 +358,6 @@ class Iptables:
# Checks if iptables is installed and if we have a correct version. # Checks if iptables is installed and if we have a correct version.
def _check_compatibility(self): def _check_compatibility(self):
from distutils.version import StrictVersion
cmd = [self.bins['iptables'], '--version'] cmd = [self.bins['iptables'], '--version']
rc, stdout, stderr = Iptables.module.run_command(cmd, check_rc=False) rc, stdout, stderr = Iptables.module.run_command(cmd, check_rc=False)
if rc == 0: if rc == 0:
@ -366,7 +366,7 @@ class Iptables:
version = result.group(1) version = result.group(1)
# CentOS 5 ip6tables (v1.3.x) doesn't support comments, # CentOS 5 ip6tables (v1.3.x) doesn't support comments,
# which means it cannot be used with this module. # which means it cannot be used with this module.
if StrictVersion(version) < StrictVersion('1.4'): if LooseVersion(version) < LooseVersion('1.4'):
Iptables.module.fail_json( Iptables.module.fail_json(
msg="This module isn't compatible with ip6tables versions older than 1.4.x" msg="This module isn't compatible with ip6tables versions older than 1.4.x"
) )

View File

@ -4,7 +4,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""OpenSSL PKCS12 module.""" """OpenSSL PKCS12 module."""
from __future__ import (absolute_import, division, print_function) from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
@ -176,7 +176,6 @@ class PkcsError(Exception): # noqa
class Pkcs(object): # noqa class Pkcs(object): # noqa
def __init__(self, module): def __init__(self, module):
self.path = module.params["path"] self.path = module.params["path"]
self.force = module.params["force"] self.force = module.params["force"]
@ -201,16 +200,18 @@ class Pkcs(object): # noqa
def load_privatekey(self, path, passphrase=None): def load_privatekey(self, path, passphrase=None):
"""Load the specified OpenSSL private key.""" """Load the specified OpenSSL private key."""
try: try:
privatekey = crypto.load_privatekey( return (
crypto.FILETYPE_PEM, crypto.load_privatekey(
open(path, "rb").read(), # noqa crypto.FILETYPE_PEM,
passphrase open(path, "rb").read(), # noqa
) if passphrase else crypto.load_privatekey( passphrase,
crypto.FILETYPE_PEM, )
open(path, "rb").read() # noqa if passphrase
else crypto.load_privatekey(
crypto.FILETYPE_PEM,
open(path, "rb").read(), # noqa
)
) )
return privatekey
except OSError as exc: except OSError as exc:
raise PkcsError(exc) from exc raise PkcsError(exc) from exc
@ -218,8 +219,7 @@ class Pkcs(object): # noqa
"""Load the specified certificate.""" """Load the specified certificate."""
try: try:
cert_content = open(path, "rb").read() # noqa cert_content = open(path, "rb").read() # noqa
cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_content) return crypto.load_certificate(crypto.FILETYPE_PEM, cert_content)
return cert
except OSError as exc: except OSError as exc:
raise PkcsError(exc) from exc raise PkcsError(exc) from exc
@ -237,8 +237,7 @@ class Pkcs(object): # noqa
"""Dump the specified OpenSSL private key.""" """Dump the specified OpenSSL private key."""
try: try:
return crypto.dump_privatekey( return crypto.dump_privatekey(
crypto.FILETYPE_PEM, crypto.FILETYPE_PEM, self.load_pkcs12(path).get_privatekey()
self.load_pkcs12(path).get_privatekey()
) )
except OSError as exc: except OSError as exc:
raise PkcsError(exc) from exc raise PkcsError(exc) from exc
@ -247,8 +246,7 @@ class Pkcs(object): # noqa
"""Dump the specified certificate.""" """Dump the specified certificate."""
try: try:
return crypto.dump_certificate( return crypto.dump_certificate(
crypto.FILETYPE_PEM, crypto.FILETYPE_PEM, self.load_pkcs12(path).get_certificate()
self.load_pkcs12(path).get_certificate()
) )
except OSError as exc: except OSError as exc:
raise PkcsError(exc) from exc raise PkcsError(exc) from exc
@ -326,7 +324,6 @@ class Pkcs(object): # noqa
pass pass
def check(self, module, perms_required=True): # noqa def check(self, module, perms_required=True): # noqa
def _check_pkey_passphrase(): def _check_pkey_passphrase():
if self.privatekey_passphrase: if self.privatekey_passphrase:
try: try:
@ -369,7 +366,7 @@ def main():
privatekey_passphrase=dict(type="str", no_log=True), privatekey_passphrase=dict(type="str", no_log=True),
state=dict(default="present", choices=["present", "absent"], type="str"), state=dict(default="present", choices=["present", "absent"], type="str"),
src=dict(type="path"), src=dict(type="path"),
mode=dict(default="0400", type="str", required=False) mode=dict(default="0400", type="str", required=False),
) )
required_if = [ required_if = [
@ -396,7 +393,7 @@ def main():
if not os.path.isdir(base_dir): if not os.path.isdir(base_dir):
module.fail_json( module.fail_json(
name=base_dir, name=base_dir,
msg=f"The directory {base_dir} does not exist or the file is not a directory" msg=f"The directory {base_dir} does not exist or the file is not a directory",
) )
pkcs12 = Pkcs(module) pkcs12 = Pkcs(module)

View File

@ -5,7 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Control Proxmox KVM machines.""" """Control Proxmox KVM machines."""
from __future__ import (absolute_import, division, print_function) from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
@ -36,11 +36,13 @@ options:
api_host: api_host:
description: description:
- Specify the target host of the Proxmox VE cluster. - Specify the target host of the Proxmox VE cluster.
- You can use C(PROXMOX_SERVER) environment variable.
type: str type: str
required: true required: true
api_user: api_user:
description: description:
- Specify the user to authenticate with. - Specify the user to authenticate with.
- You can use C(PROXMOX_USER) environment variable.
type: str type: str
required: true required: true
api_password: api_password:
@ -51,11 +53,13 @@ options:
api_token_id: api_token_id:
description: description:
- Specify the token ID. - Specify the token ID.
- You can use C(PROXMOX_TOKEN_ID) environment variable.
type: str type: str
version_added: 1.3.0 version_added: 1.3.0
api_token_secret: api_token_secret:
description: description:
- Specify the token secret. - Specify the token secret.
- You can use C(PROXMOX_TOKEN_SECRET) environment variable.
type: str type: str
version_added: 1.3.0 version_added: 1.3.0
verify_ssl: verify_ssl:
@ -809,22 +813,25 @@ import string
import time import time
import traceback import traceback
from collections import defaultdict from collections import defaultdict
from distutils.version import LooseVersion
from ansible.module_utils.six.moves.urllib.parse import quote from ansible.module_utils.six.moves.urllib.parse import quote
from ansible_collections.xoxys.general.plugins.module_utils.version import LooseVersion
try: try:
from proxmoxer import ProxmoxAPI from proxmoxer import ProxmoxAPI
HAS_PROXMOXER = True HAS_PROXMOXER = True
except ImportError: except ImportError:
HAS_PROXMOXER = False HAS_PROXMOXER = False
try: try:
from requests.packages import urllib3 from requests.packages import urllib3
HAS_URLLIB3 = True HAS_URLLIB3 = True
except ImportError: except ImportError:
try: try:
import urllib3 import urllib3
HAS_URLLIB3 = True HAS_URLLIB3 = True
except ImportError: except ImportError:
HAS_URLLIB3 = False HAS_URLLIB3 = False
@ -835,12 +842,11 @@ from ansible.module_utils.basic import AnsibleModule, env_fallback
def get_nextvmid(module, proxmox): def get_nextvmid(module, proxmox):
try: try:
vmid = proxmox.cluster.nextid.get() return proxmox.cluster.nextid.get()
return vmid
except Exception as e: # noqa except Exception as e: # noqa
module.fail_json( module.fail_json(
msg=f"Unable to get next vmid. Failed with exception: {to_native(e)}", msg=f"Unable to get next vmid. Failed with exception: {to_native(e)}",
exception=traceback.format_exc() exception=traceback.format_exc(),
) )
@ -889,7 +895,7 @@ def settings(module, proxmox, vmid, node, name, **kwargs): # noqa
# Sanitize kwargs. Remove not defined args and ensure True and False converted to int. # Sanitize kwargs. Remove not defined args and ensure True and False converted to int.
kwargs = dict((k, v) for k, v in kwargs.items() if v is not None) kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
return (proxmox_node.qemu(vmid).config.set(**kwargs) is None) return proxmox_node.qemu(vmid).config.set(**kwargs) is None
def wait_for_task(module, proxmox, node, taskid): def wait_for_task(module, proxmox, node, taskid):
@ -999,7 +1005,9 @@ def create_vm(
# -args and skiplock require root@pam user - but can not use api tokens # -args and skiplock require root@pam user - but can not use api tokens
if ( if (
module.params["api_user"] == "root@pam" and module.params["args"] is None and not update module.params["api_user"] == "root@pam"
and module.params["args"] is None
and not update
and module.params["proxmox_default_behavior"] == "compatibility" and module.params["proxmox_default_behavior"] == "compatibility"
): ):
kwargs["args"] = vm_args kwargs["args"] = vm_args
@ -1013,8 +1021,10 @@ def create_vm(
if update: if update:
return ( return (
proxmox_node.qemu(vmid).config. proxmox_node.qemu(vmid).config.set(
set(name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs) is None name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs
)
is None
) )
if module.params["clone"] is not None: if module.params["clone"] is not None:
@ -1076,11 +1086,17 @@ def main():
acpi=dict(type="bool"), acpi=dict(type="bool"),
agent=dict(type="bool"), agent=dict(type="bool"),
args=dict(type="str"), args=dict(type="str"),
api_host=dict(required=True, type="str"), api_host=dict(required=True, type="str", fallback=(env_fallback, ["PROXMOX_SERVER"])),
api_password=dict(no_log=True, fallback=(env_fallback, ["PROXMOX_PASSWORD"])), api_user=dict(required=True, type="str", fallback=(env_fallback, ["PROXMOX_USER"])),
api_token_id=dict(no_log=True), api_password=dict(
api_token_secret=dict(no_log=True), no_log=True, type="str", fallback=(env_fallback, ["PROXMOX_PASSWORD"])
api_user=dict(required=True), ),
api_token_id=dict(
no_log=True, type="str", fallback=(env_fallback, ["PROXMOX_TOKEN_ID"])
),
api_token_secret=dict(
no_log=True, type="str", fallback=(env_fallback, ["PROXMOX_TOKEN_SECRET"])
),
autostart=dict(type="bool"), autostart=dict(type="bool"),
balloon=dict(type="int"), balloon=dict(type="int"),
bios=dict(choices=["seabios", "ovmf"]), bios=dict(choices=["seabios", "ovmf"]),
@ -1101,7 +1117,7 @@ def main():
force=dict(type="bool"), force=dict(type="bool"),
format=dict( format=dict(
type="str", type="str",
choices=["cloop", "cow", "qcow", "qcow2", "qed", "raw", "vmdk", "unspecified"] choices=["cloop", "cow", "qcow", "qcow2", "qed", "raw", "vmdk", "unspecified"],
), ),
freeze=dict(type="bool"), freeze=dict(type="bool"),
full=dict(type="bool", default=True), full=dict(type="bool", default=True),
@ -1128,8 +1144,18 @@ def main():
onboot=dict(type="bool"), onboot=dict(type="bool"),
ostype=dict( ostype=dict(
choices=[ choices=[
"other", "wxp", "w2k", "w2k3", "w2k8", "wvista", "win7", "win8", "win10", "other",
"l24", "l26", "solaris" "wxp",
"w2k",
"w2k3",
"w2k8",
"wvista",
"win7",
"win8",
"win10",
"l24",
"l26",
"solaris",
] ]
), ),
parallel=dict(type="dict"), parallel=dict(type="dict"),
@ -1141,8 +1167,12 @@ def main():
scsi=dict(type="dict"), scsi=dict(type="dict"),
scsihw=dict( scsihw=dict(
choices=[ choices=[
"lsi", "lsi53c810", "virtio-scsi-pci", "virtio-scsi-single", "megasas", "lsi",
"pvscsi" "lsi53c810",
"virtio-scsi-pci",
"virtio-scsi-single",
"megasas",
"pvscsi",
] ]
), ),
serial=dict(type="dict"), serial=dict(type="dict"),
@ -1157,7 +1187,7 @@ def main():
startup=dict(type="str"), startup=dict(type="str"),
state=dict( state=dict(
default="present", default="present",
choices=["present", "absent", "stopped", "started", "restarted", "current"] choices=["present", "absent", "stopped", "started", "restarted", "current"],
), ),
storage=dict(type="str"), storage=dict(type="str"),
tablet=dict(type="bool"), tablet=dict(type="bool"),
@ -1171,8 +1201,17 @@ def main():
vcpus=dict(type="int"), vcpus=dict(type="int"),
vga=dict( vga=dict(
choices=[ choices=[
"std", "cirrus", "vmware", "qxl", "serial0", "serial1", "serial2", "serial3", "std",
"qxl2", "qxl3", "qxl4" "cirrus",
"vmware",
"qxl",
"serial0",
"serial1",
"serial2",
"serial3",
"qxl2",
"qxl3",
"qxl4",
] ]
), ),
virtio=dict(type="dict"), virtio=dict(type="dict"),
@ -1180,8 +1219,14 @@ def main():
watchdog=dict(type="str"), watchdog=dict(type="str"),
proxmox_default_behavior=dict(type="str", choices=["compatibility", "no_defaults"]), proxmox_default_behavior=dict(type="str", choices=["compatibility", "no_defaults"]),
), ),
mutually_exclusive=[("delete", "revert"), ("delete", "update"), ("revert", "update"), mutually_exclusive=[
("clone", "update"), ("clone", "delete"), ("clone", "revert")], ("delete", "revert"),
("delete", "update"),
("revert", "update"),
("clone", "update"),
("clone", "delete"),
("clone", "revert"),
],
required_together=[("api_token_id", "api_token_secret")], required_together=[("api_token_id", "api_token_secret")],
required_one_of=[("name", "vmid"), ("api_password", "api_token_id")], required_one_of=[("name", "vmid"), ("api_password", "api_token_id")],
required_if=[("state", "present", ["node"])], required_if=[("state", "present", ["node"])],
@ -1285,7 +1330,7 @@ def main():
) )
# Ensure source VM name exists when cloning # Ensure source VM name exists when cloning
if -1 == vmid: if vmid == -1:
module.fail_json(msg=f"VM with name = {clone} does not exist in cluster") module.fail_json(msg=f"VM with name = {clone} does not exist in cluster")
# Ensure source VM id exists when cloning # Ensure source VM id exists when cloning
@ -1310,23 +1355,20 @@ def main():
) )
except Exception as e: # noqa except Exception as e: # noqa
module.fail_json( module.fail_json(
vmid=vmid, vmid=vmid, msg=f"Unable to delete settings on VM {name} with vmid {vmid}: {e!s}"
msg=f"Unable to delete settings on VM {name} with vmid {vmid}: {str(e)}"
) )
if revert is not None: if revert is not None:
try: try:
settings(module, proxmox, vmid, node, name, revert=revert) settings(module, proxmox, vmid, node, name, revert=revert)
module.exit_json( module.exit_json(
changed=True, changed=True, vmid=vmid, msg=f"Settings has reverted on VM {name} with vmid {vmid}"
vmid=vmid,
msg=f"Settings has reverted on VM {name} with vmid {vmid}"
) )
except Exception as e: # noqa except Exception as e: # noqa
module.fail_json( module.fail_json(
vmid=vmid, vmid=vmid,
msg=f"Unable to revert settings on VM {name} with vmid {vmid}:" msg=f"Unable to revert settings on VM {name} with vmid {vmid}:"
f"Maybe is not a pending task...{str(e)}" f"Maybe is not a pending task...{e!s}",
) )
if state == "present": if state == "present":
@ -1354,7 +1396,7 @@ def main():
net=module.params["net"], net=module.params["net"],
sata=module.params["sata"], sata=module.params["sata"],
scsi=module.params["scsi"], scsi=module.params["scsi"],
virtio=module.params["virtio"] virtio=module.params["virtio"],
) )
create_vm( create_vm(
@ -1426,7 +1468,7 @@ def main():
vcpus=module.params["vcpus"], vcpus=module.params["vcpus"],
vga=module.params["vga"], vga=module.params["vga"],
virtio=module.params["virtio"], virtio=module.params["virtio"],
watchdog=module.params["watchdog"] watchdog=module.params["watchdog"],
) )
if update: if update:
@ -1437,7 +1479,7 @@ def main():
module.exit_json( module.exit_json(
changed=True, changed=True,
vmid=vmid, vmid=vmid,
msg=f"VM {name} with newid {newid} cloned from vm with vmid {vmid}" msg=f"VM {name} with newid {newid} cloned from vm with vmid {vmid}",
) )
else: else:
module.exit_json( module.exit_json(
@ -1455,13 +1497,13 @@ def main():
else: else:
module.fail_json( module.fail_json(
vmid=vmid, vmid=vmid,
msg=f"creation of qemu VM {name} with vmid {vmid} failed with exception={e}" msg=f"creation of qemu VM {name} with vmid {vmid} failed with exception={e}",
) )
elif state == "started": elif state == "started":
status = {} status = {}
try: try:
if -1 == vmid: if vmid == -1:
module.fail_json(msg=f"VM with name = {name} does not exist in cluster") module.fail_json(msg=f"VM with name = {name} does not exist in cluster")
vm = get_vm(proxmox, vmid) vm = get_vm(proxmox, vmid)
if not vm: if not vm:
@ -1482,7 +1524,7 @@ def main():
elif state == "stopped": elif state == "stopped":
status = {} status = {}
try: try:
if -1 == vmid: if vmid == -1:
module.fail_json(msg=f"VM with name = {name} does not exist in cluster") module.fail_json(msg=f"VM with name = {name} does not exist in cluster")
vm = get_vm(proxmox, vmid) vm = get_vm(proxmox, vmid)
@ -1507,7 +1549,7 @@ def main():
elif state == "restarted": elif state == "restarted":
status = {} status = {}
try: try:
if -1 == vmid: if vmid == -1:
module.fail_json(msg=f"VM with name = {name} does not exist in cluster") module.fail_json(msg=f"VM with name = {name} does not exist in cluster")
vm = get_vm(proxmox, vmid) vm = get_vm(proxmox, vmid)
@ -1519,8 +1561,9 @@ def main():
changed=False, vmid=vmid, msg=f"VM {vmid} is not running", **status changed=False, vmid=vmid, msg=f"VM {vmid} is not running", **status
) )
if stop_vm(module, proxmox, vm, if stop_vm(module, proxmox, vm, force=module.params["force"]) and start_vm(
force=module.params["force"]) and start_vm(module, proxmox, vm): module, proxmox, vm
):
module.exit_json(changed=True, vmid=vmid, msg=f"VM {vmid} is restarted", **status) module.exit_json(changed=True, vmid=vmid, msg=f"VM {vmid} is restarted", **status)
except Exception as e: # noqa except Exception as e: # noqa
module.fail_json( module.fail_json(
@ -1543,7 +1586,7 @@ def main():
module.exit_json( module.exit_json(
changed=False, changed=False,
vmid=vmid, vmid=vmid,
msg=f"VM {vmid} is running. Stop it before deletion or use force=yes." msg=f"VM {vmid} is running. Stop it before deletion or use force=yes.",
) )
taskid = proxmox_node.qemu.delete(vmid) taskid = proxmox_node.qemu.delete(vmid)
if not wait_for_task(module, proxmox, vm[0]["node"], taskid): if not wait_for_task(module, proxmox, vm[0]["node"], taskid):
@ -1558,7 +1601,7 @@ def main():
elif state == "current": elif state == "current":
status = {} status = {}
if -1 == vmid: if vmid == -1:
module.fail_json(msg=f"VM with name = {name} does not exist in cluster") module.fail_json(msg=f"VM with name = {name} does not exist in cluster")
vm = get_vm(proxmox, vmid) vm = get_vm(proxmox, vmid)
if not vm: if not vm:
@ -1572,7 +1615,7 @@ def main():
changed=False, changed=False,
vmid=vmid, vmid=vmid,
msg=f"VM {name} with vmid = {vmid} is {current}", msg=f"VM {name} with vmid = {vmid} is {current}",
**status **status,
) )

View File

@ -4,7 +4,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Control Univention Corporate Registry.""" """Control Univention Corporate Registry."""
from __future__ import (absolute_import, division, print_function) from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
@ -73,6 +73,7 @@ from ansible.module_utils.basic import AnsibleModule
try: try:
from univention.config_registry import ConfigRegistry from univention.config_registry import ConfigRegistry
from univention.config_registry.frontend import ucr_update from univention.config_registry.frontend import ucr_update
HAS_UNIVENTION = True HAS_UNIVENTION = True
except ImportError: except ImportError:
HAS_UNIVENTION = False HAS_UNIVENTION = False
@ -99,7 +100,7 @@ def main():
module_args = dict( module_args = dict(
path=dict(type="str", required=True, aliases=["name"]), path=dict(type="str", required=True, aliases=["name"]),
value=dict(type="str", required=False, default=""), value=dict(type="str", required=False, default=""),
state=dict(default="present", choices=["present", "absent"], type="str") state=dict(default="present", choices=["present", "absent"], type="str"),
) )
required_if = [["state", "present", ["value"]]] required_if = [["state", "present", ["value"]]]

1127
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -10,10 +10,10 @@ classifiers = [
"Natural Language :: English", "Natural Language :: English",
"Operating System :: POSIX", "Operating System :: POSIX",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Utilities", "Topic :: Utilities",
"Topic :: Software Development", "Topic :: Software Development",
"Topic :: Software Development :: Documentation", "Topic :: Software Development :: Documentation",
@ -26,7 +26,7 @@ repository = "https://gitea.rknet.org/ansible/xoxys.general"
version = "0.0.0" version = "0.0.0"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8.0" python = "^3.9.0"
ansible-core = { version = "<=2.14.0", optional = true } ansible-core = { version = "<=2.14.0", optional = true }
pyopenssl = "23.0.0" pyopenssl = "23.0.0"
proxmoxer = "2.0.1" proxmoxer = "2.0.1"
@ -36,16 +36,18 @@ hcloud = "1.18.2"
ansible = ["ansible-core"] ansible = ["ansible-core"]
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
ruff = "0.0.230" ruff = "0.1.7"
pytest = "7.2.1" pytest = "7.2.1"
pytest-mock = "3.10.0" pytest-mock = "3.10.0"
pytest-cov = "4.0.0" pytest-cov = "4.0.0"
toml = "0.10.2" toml = "0.10.2"
yapf = "0.32.0"
pycodestyle = "2.10.0" pycodestyle = "2.10.0"
yamllint = "1.29.0" yamllint = "1.29.0"
pylint = "2.15.0" pylint = "2.15.0"
voluptuous = "0.13.1" voluptuous = "0.13.1"
pytest-ansible = "3.1.5"
pytest-forked = "1.6.0"
pytest-xdist = "3.3.1"
[tool.pytest.ini_options] [tool.pytest.ini_options]
addopts = "--cov --cov-report=xml:coverage.xml --cov-report=term --cov-append --no-cov-on-fail" addopts = "--cov --cov-report=xml:coverage.xml --cov-report=term --cov-append --no-cov-on-fail"
@ -59,13 +61,14 @@ filterwarnings = [
"ignore::FutureWarning", "ignore::FutureWarning",
"ignore::DeprecationWarning", "ignore::DeprecationWarning",
"ignore:.*pep8.*:FutureWarning", "ignore:.*pep8.*:FutureWarning",
"ignore:AnsibleCollectionFinder.*:UserWarning"
] ]
[tool.coverage.run] [tool.coverage.run]
omit = ["**/tests/*"] omit = ["**/tests/*"]
[build-system] [build-system]
build-backend = "poetry.core.masonry.api" build-backend = "poetry_dynamic_versioning.backend"
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"] requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]
[tool.ruff] [tool.ruff]
@ -80,8 +83,13 @@ exclude = [
".cache", ".cache",
".eggs", ".eggs",
"env*", "env*",
".venv",
"iptables_raw.py", "iptables_raw.py",
] ]
line-length = 99
indent-width = 4
# Explanation of errors # Explanation of errors
# #
# D102: Missing docstring in public method # D102: Missing docstring in public method
@ -114,8 +122,8 @@ ignore = [
"UP001", "UP001",
"UP009", "UP009",
"UP010", "UP010",
"RUF100",
] ]
line-length = 99
select = [ select = [
"D", "D",
"E", "E",
@ -138,12 +146,7 @@ select = [
"RUF", "RUF",
] ]
[tool.ruff.flake8-quotes] [tool.ruff.format]
inline-quotes = "double" quote-style = "double"
indent-style = "space"
[tool.yapf] line-ending = "lf"
based_on_style = "google"
column_limit = 99
dedent_closing_brackets = true
coalesce_brackets = true
split_before_logical_operator = true

View File

@ -1,2 +1,2 @@
modules: modules:
python_requires: ">=3.8" python_requires: ">=3.9"

View File

@ -10,8 +10,7 @@ import pytest
proxmox = pytest.importorskip("proxmoxer") proxmox = pytest.importorskip("proxmoxer")
from ansible.errors import AnsibleError, AnsibleParserError # noqa from ansible_collections.xoxys.general.plugins.inventory.proxmox import InventoryModule
from plugins.inventory.proxmox import InventoryModule
@pytest.fixture @pytest.fixture