mirror of
https://github.com/thegeeklab/certbot-dns-corenetworks.git
synced 2024-11-24 19:40:41 +00:00
initial commit
This commit is contained in:
commit
a5a7cb9f9b
212
.drone.jsonnet
Normal file
212
.drone.jsonnet
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
local PythonVersion(pyversion='2.7') = {
|
||||||
|
name: 'python' + std.strReplace(pyversion, '.', ''),
|
||||||
|
image: 'python:' + pyversion,
|
||||||
|
environment: {
|
||||||
|
PY_COLORS: 1,
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'pip install -r dev-requirements.txt -qq',
|
||||||
|
'pip install -qq .',
|
||||||
|
'pytest tests --cov=certbot_dns_corenetworks --no-cov-on-fail',
|
||||||
|
],
|
||||||
|
depends_on: [
|
||||||
|
'clone',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
local PipelineLint = {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: 'lint',
|
||||||
|
platform: {
|
||||||
|
os: 'linux',
|
||||||
|
arch: 'amd64',
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'flake8',
|
||||||
|
image: 'python:3.8',
|
||||||
|
environment: {
|
||||||
|
PY_COLORS: 1,
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'pip install -r dev-requirements.txt -qq',
|
||||||
|
'pip install -qq .',
|
||||||
|
'flake8 ./certbot_dns_corenetworks',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
ref: ['refs/heads/master', 'refs/tags/**', 'refs/pull/**'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
local PipelineTest = {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: 'test',
|
||||||
|
platform: {
|
||||||
|
os: 'linux',
|
||||||
|
arch: 'amd64',
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
PythonVersion(pyversion='2.7'),
|
||||||
|
PythonVersion(pyversion='3.5'),
|
||||||
|
PythonVersion(pyversion='3.6'),
|
||||||
|
PythonVersion(pyversion='3.7'),
|
||||||
|
PythonVersion(pyversion='3.8'),
|
||||||
|
{
|
||||||
|
name: 'codecov',
|
||||||
|
image: 'python:3.8',
|
||||||
|
environment: {
|
||||||
|
PY_COLORS: 1,
|
||||||
|
CODECOV_TOKEN: { from_secret: 'codecov_token' },
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'pip install codecov -qq',
|
||||||
|
'codecov --required -X gcov',
|
||||||
|
],
|
||||||
|
depends_on: [
|
||||||
|
'python27',
|
||||||
|
'python35',
|
||||||
|
'python36',
|
||||||
|
'python37',
|
||||||
|
'python38',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
depends_on: [
|
||||||
|
'lint',
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
ref: ['refs/heads/master', 'refs/tags/**', 'refs/pull/**'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
local PipelineSecurity = {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: 'security',
|
||||||
|
platform: {
|
||||||
|
os: 'linux',
|
||||||
|
arch: 'amd64',
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'bandit',
|
||||||
|
image: 'python:3.8',
|
||||||
|
environment: {
|
||||||
|
PY_COLORS: 1,
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'pip install -r dev-requirements.txt -qq',
|
||||||
|
'pip install -qq .',
|
||||||
|
'bandit -r ./certbot_dns_corenetworks -x ./certbot_dns_corenetworks/test',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
depends_on: [
|
||||||
|
'test',
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
ref: ['refs/heads/master', 'refs/tags/**', 'refs/pull/**'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
local PipelineBuildPackage = {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: 'build-package',
|
||||||
|
platform: {
|
||||||
|
os: 'linux',
|
||||||
|
arch: 'amd64',
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'build',
|
||||||
|
image: 'python:3.8',
|
||||||
|
environment: {
|
||||||
|
SETUPTOOLS_SCM_PRETEND_VERSION: '${DRONE_TAG##v}',
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'python setup.py sdist bdist_wheel',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'checksum',
|
||||||
|
image: 'alpine',
|
||||||
|
commands: [
|
||||||
|
'cd dist/ && sha256sum * > ../sha256sum.txt',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'publish-github',
|
||||||
|
image: 'plugins/github-release',
|
||||||
|
settings: {
|
||||||
|
overwrite: true,
|
||||||
|
api_key: { from_secret: 'github_token' },
|
||||||
|
files: ['dist/*', 'sha256sum.txt'],
|
||||||
|
title: '${DRONE_TAG}',
|
||||||
|
note: 'CHANGELOG.md',
|
||||||
|
},
|
||||||
|
when: {
|
||||||
|
ref: ['refs/tags/**'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'publish-pypi',
|
||||||
|
image: 'plugins/pypi',
|
||||||
|
settings: {
|
||||||
|
username: { from_secret: 'pypi_username' },
|
||||||
|
password: { from_secret: 'pypi_password' },
|
||||||
|
repository: 'https://upload.pypi.org/legacy/',
|
||||||
|
skip_build: true,
|
||||||
|
},
|
||||||
|
when: {
|
||||||
|
ref: ['refs/tags/**'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
depends_on: [
|
||||||
|
'security',
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
ref: ['refs/heads/master', 'refs/tags/**', 'refs/pull/**'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
local PipelineNotifications = {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: 'notifications',
|
||||||
|
platform: {
|
||||||
|
os: 'linux',
|
||||||
|
arch: 'amd64',
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'matrix',
|
||||||
|
image: 'plugins/matrix',
|
||||||
|
settings: {
|
||||||
|
homeserver: { from_secret: 'matrix_homeserver' },
|
||||||
|
roomid: { from_secret: 'matrix_roomid' },
|
||||||
|
template: 'Status: **{{ build.status }}**<br/> Build: [{{ repo.Owner }}/{{ repo.Name }}]({{ build.link }}) ({{ build.branch }}) by {{ build.author }}<br/> Message: {{ build.message }}',
|
||||||
|
username: { from_secret: 'matrix_username' },
|
||||||
|
password: { from_secret: 'matrix_password' },
|
||||||
|
},
|
||||||
|
when: {
|
||||||
|
status: ['success', 'failure'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
depends_on: [
|
||||||
|
'build-package',
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
ref: ['refs/heads/master', 'refs/tags/**'],
|
||||||
|
status: ['success', 'failure'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
[
|
||||||
|
PipelineLint,
|
||||||
|
PipelineTest,
|
||||||
|
PipelineSecurity,
|
||||||
|
PipelineBuildPackage,
|
||||||
|
PipelineNotifications,
|
||||||
|
]
|
240
.drone.yml
Normal file
240
.drone.yml
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: lint
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: flake8
|
||||||
|
image: python:3.8
|
||||||
|
commands:
|
||||||
|
- pip install -r dev-requirements.txt -qq
|
||||||
|
- pip install -qq .
|
||||||
|
- flake8 ./certbot_dns_corenetworks
|
||||||
|
environment:
|
||||||
|
PY_COLORS: 1
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/tags/**
|
||||||
|
- refs/pull/**
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: test
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: python27
|
||||||
|
image: python:2.7
|
||||||
|
commands:
|
||||||
|
- pip install -r dev-requirements.txt -qq
|
||||||
|
- pip install -qq .
|
||||||
|
- pytest tests --cov=certbot_dns_corenetworks --no-cov-on-fail
|
||||||
|
environment:
|
||||||
|
PY_COLORS: 1
|
||||||
|
depends_on:
|
||||||
|
- clone
|
||||||
|
|
||||||
|
- name: python35
|
||||||
|
image: python:3.5
|
||||||
|
commands:
|
||||||
|
- pip install -r dev-requirements.txt -qq
|
||||||
|
- pip install -qq .
|
||||||
|
- pytest tests --cov=certbot_dns_corenetworks --no-cov-on-fail
|
||||||
|
environment:
|
||||||
|
PY_COLORS: 1
|
||||||
|
depends_on:
|
||||||
|
- clone
|
||||||
|
|
||||||
|
- name: python36
|
||||||
|
image: python:3.6
|
||||||
|
commands:
|
||||||
|
- pip install -r dev-requirements.txt -qq
|
||||||
|
- pip install -qq .
|
||||||
|
- pytest tests --cov=certbot_dns_corenetworks --no-cov-on-fail
|
||||||
|
environment:
|
||||||
|
PY_COLORS: 1
|
||||||
|
depends_on:
|
||||||
|
- clone
|
||||||
|
|
||||||
|
- name: python37
|
||||||
|
image: python:3.7
|
||||||
|
commands:
|
||||||
|
- pip install -r dev-requirements.txt -qq
|
||||||
|
- pip install -qq .
|
||||||
|
- pytest tests --cov=certbot_dns_corenetworks --no-cov-on-fail
|
||||||
|
environment:
|
||||||
|
PY_COLORS: 1
|
||||||
|
depends_on:
|
||||||
|
- clone
|
||||||
|
|
||||||
|
- name: python38
|
||||||
|
image: python:3.8
|
||||||
|
commands:
|
||||||
|
- pip install -r dev-requirements.txt -qq
|
||||||
|
- pip install -qq .
|
||||||
|
- pytest tests --cov=certbot_dns_corenetworks --no-cov-on-fail
|
||||||
|
environment:
|
||||||
|
PY_COLORS: 1
|
||||||
|
depends_on:
|
||||||
|
- clone
|
||||||
|
|
||||||
|
- name: codecov
|
||||||
|
image: python:3.8
|
||||||
|
commands:
|
||||||
|
- pip install codecov -qq
|
||||||
|
- codecov --required -X gcov
|
||||||
|
environment:
|
||||||
|
CODECOV_TOKEN:
|
||||||
|
from_secret: codecov_token
|
||||||
|
PY_COLORS: 1
|
||||||
|
depends_on:
|
||||||
|
- python27
|
||||||
|
- python35
|
||||||
|
- python36
|
||||||
|
- python37
|
||||||
|
- python38
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/tags/**
|
||||||
|
- refs/pull/**
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- lint
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: security
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: bandit
|
||||||
|
image: python:3.8
|
||||||
|
commands:
|
||||||
|
- pip install -r dev-requirements.txt -qq
|
||||||
|
- pip install -qq .
|
||||||
|
- bandit -r ./certbot_dns_corenetworks -x ./certbot_dns_corenetworks/test
|
||||||
|
environment:
|
||||||
|
PY_COLORS: 1
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/tags/**
|
||||||
|
- refs/pull/**
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- test
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: build-package
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build
|
||||||
|
image: python:3.8
|
||||||
|
commands:
|
||||||
|
- python setup.py sdist bdist_wheel
|
||||||
|
environment:
|
||||||
|
SETUPTOOLS_SCM_PRETEND_VERSION: ${DRONE_TAG##v}
|
||||||
|
|
||||||
|
- name: checksum
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- cd dist/ && sha256sum * > ../sha256sum.txt
|
||||||
|
|
||||||
|
- name: publish-github
|
||||||
|
image: plugins/github-release
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: github_token
|
||||||
|
files:
|
||||||
|
- dist/*
|
||||||
|
- sha256sum.txt
|
||||||
|
note: CHANGELOG.md
|
||||||
|
overwrite: true
|
||||||
|
title: ${DRONE_TAG}
|
||||||
|
when:
|
||||||
|
ref:
|
||||||
|
- refs/tags/**
|
||||||
|
|
||||||
|
- name: publish-pypi
|
||||||
|
image: plugins/pypi
|
||||||
|
settings:
|
||||||
|
password:
|
||||||
|
from_secret: pypi_password
|
||||||
|
repository: https://upload.pypi.org/legacy/
|
||||||
|
skip_build: true
|
||||||
|
username:
|
||||||
|
from_secret: pypi_username
|
||||||
|
when:
|
||||||
|
ref:
|
||||||
|
- refs/tags/**
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/tags/**
|
||||||
|
- refs/pull/**
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- security
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: notifications
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: matrix
|
||||||
|
image: plugins/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 }}) ({{ build.branch }}) by {{ build.author }}<br/> Message: {{ build.message }}"
|
||||||
|
username:
|
||||||
|
from_secret: matrix_username
|
||||||
|
when:
|
||||||
|
status:
|
||||||
|
- success
|
||||||
|
- failure
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/tags/**
|
||||||
|
status:
|
||||||
|
- success
|
||||||
|
- failure
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- build-package
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: signature
|
||||||
|
hmac: 09f1f5c2f46dd90b159b5c5de705afce849ea7fb4772b96aa9827a6d6bb97e3e
|
||||||
|
|
||||||
|
...
|
19
.flake8
Normal file
19
.flake8
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[flake8]
|
||||||
|
ignore = D103, D107, W503
|
||||||
|
max-line-length = 99
|
||||||
|
inline-quotes = double
|
||||||
|
exclude =
|
||||||
|
.git
|
||||||
|
.tox
|
||||||
|
__pycache__
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
test
|
||||||
|
tests
|
||||||
|
*.pyc
|
||||||
|
*.egg-info
|
||||||
|
.cache
|
||||||
|
.eggs
|
||||||
|
env*
|
||||||
|
application-import-names = corenetworks
|
||||||
|
format = ${cyan}%(path)s:%(row)d:%(col)d${reset}: ${red_bold}%(code)s${reset} %(text)s
|
60
.github/settings.yml
vendored
Normal file
60
.github/settings.yml
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
repository:
|
||||||
|
name: corenetworks
|
||||||
|
description: Python library for the core-networks.de DNS API
|
||||||
|
homepage: https://corenetworks.geekdocs.de
|
||||||
|
topics: corenetworks, api, dns, python
|
||||||
|
|
||||||
|
private: false
|
||||||
|
has_issues: true
|
||||||
|
has_projects: false
|
||||||
|
has_wiki: false
|
||||||
|
has_downloads: false
|
||||||
|
|
||||||
|
default_branch: master
|
||||||
|
|
||||||
|
allow_squash_merge: true
|
||||||
|
allow_merge_commit: true
|
||||||
|
allow_rebase_merge: true
|
||||||
|
|
||||||
|
labels:
|
||||||
|
- name: bug
|
||||||
|
color: d73a4a
|
||||||
|
description: Something isn't working
|
||||||
|
- name: documentation
|
||||||
|
color: 0075ca
|
||||||
|
description: Improvements or additions to documentation
|
||||||
|
- name: duplicate
|
||||||
|
color: cfd3d7
|
||||||
|
description: This issue or pull request already exists
|
||||||
|
- name: enhancement
|
||||||
|
color: a2eeef
|
||||||
|
description: New feature or request
|
||||||
|
- name: good first issue
|
||||||
|
color: 7057ff
|
||||||
|
description: Good for newcomers
|
||||||
|
- name: help wanted
|
||||||
|
color: 008672
|
||||||
|
description: Extra attention is needed
|
||||||
|
- name: invalid
|
||||||
|
color: e4e669
|
||||||
|
description: This doesn't seem right
|
||||||
|
- name: question
|
||||||
|
color: d876e3
|
||||||
|
description: Further information is requested
|
||||||
|
- name: wontfix
|
||||||
|
color: ffffff
|
||||||
|
description: This will not be worked on
|
||||||
|
|
||||||
|
branches:
|
||||||
|
- name: master
|
||||||
|
protection:
|
||||||
|
required_pull_request_reviews: null
|
||||||
|
required_status_checks:
|
||||||
|
strict: true
|
||||||
|
contexts:
|
||||||
|
- continuous-integration/drone/pr
|
||||||
|
enforce_admins: null
|
||||||
|
restrictions: null
|
||||||
|
|
||||||
|
...
|
113
.gitignore
vendored
Normal file
113
.gitignore
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
# ---> Python
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*,cover
|
||||||
|
.hypothesis/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# dotenv
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# virtualenv
|
||||||
|
.venv
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env/
|
||||||
|
env*/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# Ignore ide addons
|
||||||
|
.server-script
|
||||||
|
.on-save.json
|
||||||
|
.vscode
|
||||||
|
.pytest_cache
|
||||||
|
|
||||||
|
pip-wheel-metadata
|
||||||
|
|
||||||
|
# Hugo documentation
|
||||||
|
docs/themes/
|
||||||
|
docs/public/
|
||||||
|
resources/_gen/
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.local/
|
||||||
|
.corenetworks*
|
||||||
|
docs/content/api/corenetworks/
|
1
CHANGELOG.md
Normal file
1
CHANGELOG.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
* initial release
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Robert Kaussow <mail@geeklabor.de>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
|
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||||
|
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# certbot-dns-corenetworks
|
||||||
|
|
||||||
|
[![Build Status](https://img.shields.io/drone/build/xoxys/certbot-dns-corenetworks?logo=drone)](https://cloud.drone.io/xoxys/certbot-dns-corenetworks)
|
||||||
|
[![Python Version](https://img.shields.io/pypi/pyversions/certbot-dns-corenetworks.svg)](https://pypi.org/project/certbot-dns-corenetworks/)
|
||||||
|
[![PyPi Status](https://img.shields.io/pypi/status/certbot-dns-corenetworks.svg)](https://pypi.org/project/certbot-dns-corenetworks/)
|
||||||
|
[![PyPi Release](https://img.shields.io/pypi/v/certbot-dns-corenetworks.svg)](https://pypi.org/project/certbot-dns-corenetworks/)
|
||||||
|
[![License: MIT](https://img.shields.io/github/license/xoxys/certbot-dns-corenetworks)](LICENSE)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
|
## Maintainers and Contributors
|
||||||
|
|
||||||
|
[Robert Kaussow](https://github.com/xoxys)
|
10
certbot_dns_corenetworks/__init__.py
Normal file
10
certbot_dns_corenetworks/__init__.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Default package."""
|
||||||
|
|
||||||
|
__author__ = "Robert Kaussow"
|
||||||
|
__project__ = "certbot_dns_corenetworks"
|
||||||
|
__license__ = "MIT"
|
||||||
|
__maintainer__ = "Robert Kaussow"
|
||||||
|
__email__ = "mail@geeklabor.de"
|
||||||
|
__url__ = "https://github.com/xoxys/certbot-dns-corenetworks"
|
||||||
|
__version__ = "0.1.0"
|
228
certbot_dns_corenetworks/dns_corenetworks.py
Normal file
228
certbot_dns_corenetworks/dns_corenetworks.py
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
"""DNS Authenticator for Core Networks."""
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
import zope.interface # noqa
|
||||||
|
from certbot import errors
|
||||||
|
from certbot import interfaces
|
||||||
|
from certbot.plugins import dns_common
|
||||||
|
from corenetworks import CoreNetworks
|
||||||
|
from corenetworks.exceptions import AuthError
|
||||||
|
from corenetworks.exceptions import CoreNetworksException
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||||
|
@zope.interface.provider(interfaces.IPluginFactory)
|
||||||
|
class Authenticator(dns_common.DNSAuthenticator):
|
||||||
|
"""DNS Authenticator for Core Networks DNS API."""
|
||||||
|
|
||||||
|
description = (
|
||||||
|
"Obtain certificates using a DNS TXT record "
|
||||||
|
"(if you are using Core Networks for your domains)."
|
||||||
|
)
|
||||||
|
ttl = 300
|
||||||
|
|
||||||
|
clientCache = {} # noqa
|
||||||
|
nameCache = {} # noqa
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Initialize an Core Networks Authenticator."""
|
||||||
|
super(Authenticator, self).__init__(*args, **kwargs)
|
||||||
|
self.credentials = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_parser_arguments(cls, add): # noqa
|
||||||
|
super(Authenticator, cls).add_parser_arguments(add, default_propagation_seconds=60)
|
||||||
|
add(
|
||||||
|
"credentials",
|
||||||
|
help=("Path to Core Networks account credentials INI file"),
|
||||||
|
default="/etc/letsencrypt/corenetworks.cfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
def more_info(self): # noqa
|
||||||
|
return "This plugin configures a DNS TXT record to respond to a dns-01 challenge using " \
|
||||||
|
"the Core Networks DNS API."
|
||||||
|
|
||||||
|
def _setup_credentials(self):
|
||||||
|
self.credentials = self._configure_credentials(
|
||||||
|
"credentials", "path to Core Networks API credentials INI file", {
|
||||||
|
"username": "Username of the Core Networks API account.",
|
||||||
|
"password": "Password of the Core Networks API account.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def _follow_cnames(self, domain, validation_name):
|
||||||
|
"""
|
||||||
|
Perform recursive CNAME lookups.
|
||||||
|
|
||||||
|
In case there exist a CNAME for the given validation name a recursive CNAME lookup
|
||||||
|
will be performed automatically. If the optional dependency dnspython is not installed,
|
||||||
|
the given name is simply returned.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import dns.exception # noqa
|
||||||
|
import dns.resolver # noqa
|
||||||
|
import dns.name # noqa
|
||||||
|
except ImportError:
|
||||||
|
return validation_name
|
||||||
|
|
||||||
|
resolver = dns.resolver.Resolver()
|
||||||
|
name = dns.name.from_text(validation_name)
|
||||||
|
while 1:
|
||||||
|
try:
|
||||||
|
answer = resolver.query(name, "CNAME")
|
||||||
|
if 1 <= len(answer):
|
||||||
|
name = answer[0].target
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
|
||||||
|
break
|
||||||
|
except (dns.exception.Timeout, dns.resolver.YXDOMAIN, dns.resolver.NoNameservers):
|
||||||
|
raise errors.PluginError(
|
||||||
|
"Failed to lookup CNAMEs on your requested domain {0}".format(domain)
|
||||||
|
)
|
||||||
|
return name.to_text(True)
|
||||||
|
|
||||||
|
def _perform(self, domain, validation_name, validation):
|
||||||
|
if validation_name in Authenticator.nameCache:
|
||||||
|
resolved = Authenticator.nameCache[validation_name]
|
||||||
|
else:
|
||||||
|
resolved = self._follow_cnames(domain, validation_name)
|
||||||
|
Authenticator.nameCache[validation_name] = resolved
|
||||||
|
|
||||||
|
if resolved != validation_name:
|
||||||
|
logger.info("Validation record for %s redirected by CNAME(s) to %s", domain, resolved)
|
||||||
|
|
||||||
|
self._get_corenetworks_client().add_txt_record(domain, resolved, validation, self.ttl)
|
||||||
|
|
||||||
|
def _cleanup(self, domain, validation_name, validation):
|
||||||
|
resolved = Authenticator.nameCache[validation_name]
|
||||||
|
self._get_corenetworks_client().del_txt_record(domain, resolved, validation)
|
||||||
|
|
||||||
|
def _get_corenetworks_client(self):
|
||||||
|
key = self.conf("credentials")
|
||||||
|
|
||||||
|
if key in Authenticator.clientCache:
|
||||||
|
client = Authenticator.clientCache[key]
|
||||||
|
else:
|
||||||
|
client = _CorenetworksClient(
|
||||||
|
self.credentials.conf("username"), self.credentials.conf("password")
|
||||||
|
)
|
||||||
|
Authenticator.clientCache[key] = client
|
||||||
|
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
class _CorenetworksClient(object):
|
||||||
|
"""Encapsulates all communication with the Core Networks API."""
|
||||||
|
|
||||||
|
def __init__(self, user, password, auto_commit=True):
|
||||||
|
try:
|
||||||
|
self.client = CoreNetworks(user, password, auto_commit=auto_commit)
|
||||||
|
except AuthError as e:
|
||||||
|
raise errors.PluginError("Login failed: {0}".format(str(e)))
|
||||||
|
|
||||||
|
def add_txt_record(self, domain_name, record_name, record_content, record_ttl):
|
||||||
|
"""
|
||||||
|
Add a TXT record using the supplied information.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
domain_name (str): The requested domain for validation.
|
||||||
|
record_name (str): The record name (typically beginning with "_acme-challenge.").
|
||||||
|
record_content (str): The record content (typically the challenge validation).
|
||||||
|
record_ttl(int): The record TTL (number of seconds that the record may be cached).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
certbot.errors.PluginError: If an error occurs communicating with the DNS server
|
||||||
|
|
||||||
|
"""
|
||||||
|
zone = self._find_zone(record_name)
|
||||||
|
name = re.sub(r"\.{}$".format(zone), "", record_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.client.add_record(
|
||||||
|
zone, {
|
||||||
|
"name": name,
|
||||||
|
"type": "TXT",
|
||||||
|
"data": record_content,
|
||||||
|
"ttl": record_ttl
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except CoreNetworksException:
|
||||||
|
raise errors.PluginError(
|
||||||
|
"Failed to add TXT DNS record {record} to {zone} for {domain}".format(
|
||||||
|
record=record_name, zone=zone, domain=domain_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def del_txt_record(self, domain_name, record_name, record_content):
|
||||||
|
"""
|
||||||
|
Delete a TXT record using the supplied information.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
domain_name (str): The requested domain for validation.
|
||||||
|
record_name (str): The record name (typically beginning with "_acme-challenge.").
|
||||||
|
record_content (str): The record content (typically the challenge validation).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
certbot.errors.PluginError: if an error occurs communicating with the DNS server
|
||||||
|
|
||||||
|
"""
|
||||||
|
zone = self._find_zone(record_name)
|
||||||
|
name = re.sub(r"\.{}$".format(zone), "", record_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
info = self.client.records(zone, {"name": name, "type": "TXT", "data": record_content})
|
||||||
|
if (len(info) != 1 or info[0]["name"] != name):
|
||||||
|
raise NameError("Unknown record")
|
||||||
|
except NameError as e:
|
||||||
|
raise errors.PluginError(
|
||||||
|
"Record {record} not found: {err}".format(record=record_name, err=e)
|
||||||
|
)
|
||||||
|
except CoreNetworksException as e:
|
||||||
|
raise errors.PluginError(
|
||||||
|
"Could not lookup record {record}: {err}".format(record=record_name, err=e)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.client.delete_record(zone, {"name": name, "type": "TXT", "data": record_content})
|
||||||
|
except CoreNetworksException:
|
||||||
|
raise errors.PluginError(
|
||||||
|
"Failed to delete TXT DNS record {record} of {zone} for {domain}".format(
|
||||||
|
record=record_name, zone=zone, domain=domain_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _find_zone(self, domain_name):
|
||||||
|
"""
|
||||||
|
Find the base domain name for a given domain name.
|
||||||
|
|
||||||
|
:param str domain_name: The domain name for which to find the corresponding base domain.
|
||||||
|
:returns: The base domain name, if found.
|
||||||
|
:rtype: str
|
||||||
|
:raises certbot.errors.PluginError: if no matching domain is found.
|
||||||
|
"""
|
||||||
|
domain_name_guesses = dns_common.base_domain_name_guesses(domain_name)
|
||||||
|
|
||||||
|
for guess in domain_name_guesses:
|
||||||
|
logger.debug("Testing {0} for domain {1}...".format(guess, domain_name))
|
||||||
|
try:
|
||||||
|
info = self.client.zone(guess)[0]
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.debug("Found zone '{zone}': {info}".format(zone=guess, info=info))
|
||||||
|
if not info.get("active"):
|
||||||
|
raise errors.PluginError("Zone {0} is not active".format(guess))
|
||||||
|
if info.get("type") != "master":
|
||||||
|
raise errors.PluginError("Zone {0} is not a master zone".format(guess))
|
||||||
|
|
||||||
|
return guess
|
||||||
|
|
||||||
|
raise errors.PluginError(
|
||||||
|
"Unable to determine base domain for {0} using names: {1}".format(
|
||||||
|
domain_name, domain_name_guesses
|
||||||
|
)
|
||||||
|
)
|
19
dev-requirements.txt
Normal file
19
dev-requirements.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
pydocstyle
|
||||||
|
flake8
|
||||||
|
flake8-colors
|
||||||
|
flake8-blind-except
|
||||||
|
flake8-builtins
|
||||||
|
flake8-docstrings
|
||||||
|
flake8-isort
|
||||||
|
flake8-logging-format
|
||||||
|
flake8-polyfill
|
||||||
|
flake8-quotes
|
||||||
|
flake8-pep3101
|
||||||
|
flake8-eradicate; python_version >= "3.6"
|
||||||
|
pep8-naming
|
||||||
|
wheel
|
||||||
|
pytest
|
||||||
|
pytest-mock
|
||||||
|
pytest-cov
|
||||||
|
bandit
|
||||||
|
yapf
|
30
setup.cfg
Normal file
30
setup.cfg
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
[metadata]
|
||||||
|
description-file = README.md
|
||||||
|
license_file = LICENSE
|
||||||
|
|
||||||
|
[bdist_wheel]
|
||||||
|
universal = 1
|
||||||
|
|
||||||
|
[isort]
|
||||||
|
default_section = THIRDPARTY
|
||||||
|
known_first_party = certbot_dns_corenetworks
|
||||||
|
sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
|
||||||
|
force_single_line = true
|
||||||
|
line_length = 99
|
||||||
|
skip_glob = **/.env*,**/env/*,**/docs/*
|
||||||
|
|
||||||
|
[yapf]
|
||||||
|
based_on_style = google
|
||||||
|
column_limit = 99
|
||||||
|
dedent_closing_brackets = true
|
||||||
|
coalesce_brackets = true
|
||||||
|
split_before_logical_operator = true
|
||||||
|
|
||||||
|
[tool:pytest]
|
||||||
|
filterwarnings =
|
||||||
|
ignore::FutureWarning
|
||||||
|
ignore:.*collections.*:DeprecationWarning
|
||||||
|
ignore:.*pep8.*:FutureWarning
|
||||||
|
|
||||||
|
[coverage:run]
|
||||||
|
omit = **/test/*
|
78
setup.py
Normal file
78
setup.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Setup script for the package."""
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
from setuptools import find_packages
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
PACKAGE_NAME = "certbot_dns_corenetworks"
|
||||||
|
|
||||||
|
|
||||||
|
def get_property(prop, project):
|
||||||
|
current_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
result = re.search(
|
||||||
|
r'{}\s*=\s*[\'"]([^\'"]*)[\'"]'.format(prop),
|
||||||
|
open(os.path.join(current_dir, project, "__init__.py")).read(),
|
||||||
|
)
|
||||||
|
return result.group(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_readme(filename="README.md"):
|
||||||
|
this = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
with io.open(os.path.join(this, filename), encoding="utf-8") as f:
|
||||||
|
long_description = f.read()
|
||||||
|
return long_description
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name=get_property("__project__", PACKAGE_NAME),
|
||||||
|
description="Core Networks DNS Authenticator plugin for Certbot",
|
||||||
|
keywords="dns, certbot, automation, corenetworks",
|
||||||
|
version=get_property("__version__", PACKAGE_NAME),
|
||||||
|
author=get_property("__author__", PACKAGE_NAME),
|
||||||
|
author_email=get_property("__email__", PACKAGE_NAME),
|
||||||
|
url=get_property("__url__", PACKAGE_NAME),
|
||||||
|
license=get_property("__license__", PACKAGE_NAME),
|
||||||
|
long_description=get_readme(),
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
packages=find_packages(exclude=["*.test", "test", "test.*"]),
|
||||||
|
include_package_data=True,
|
||||||
|
zip_safe=False,
|
||||||
|
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,<4",
|
||||||
|
entry_points={
|
||||||
|
"certbot.plugins": [
|
||||||
|
"dns-corenetworks = certbot_dns_corenetworks.dns_corenetworks:Authenticator"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
classifiers=[
|
||||||
|
"Development Status :: 5 - Production/Stable",
|
||||||
|
"Environment :: Plugins",
|
||||||
|
"Intended Audience :: System Administrators",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Natural Language :: English",
|
||||||
|
"Operating System :: POSIX",
|
||||||
|
"Programming Language :: Python :: 2",
|
||||||
|
"Programming Language :: Python :: 2.7",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.5",
|
||||||
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Topic :: Security",
|
||||||
|
"Topic :: System :: Networking",
|
||||||
|
"Topic :: Utilities",
|
||||||
|
],
|
||||||
|
install_requires=[
|
||||||
|
"acme",
|
||||||
|
"certbot>=0.15",
|
||||||
|
"setuptools",
|
||||||
|
"zope.interface",
|
||||||
|
"corenetworks",
|
||||||
|
],
|
||||||
|
dependency_links=[],
|
||||||
|
)
|
84
tests/dns_corenetwork_test.py
Normal file
84
tests/dns_corenetwork_test.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
"""Tests for certbot_dns_ispconfig.dns_ispconfig."""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from certbot import errors
|
||||||
|
from certbot.compat import os
|
||||||
|
from certbot.plugins import dns_test_common
|
||||||
|
from certbot.plugins.dns_test_common import DOMAIN
|
||||||
|
from certbot.tests import util as test_util
|
||||||
|
|
||||||
|
API_USER = "my_user"
|
||||||
|
API_PASSWORD = "secure"
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticatorTest(test_util.TempDirTestCase, dns_test_common.BaseAuthenticatorTest):
|
||||||
|
"""Test for Hetzner DNS Authenticator."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
from certbot_dns_corenetworks.dns_corenetworks import Authenticator
|
||||||
|
|
||||||
|
super(AuthenticatorTest, self).setUp()
|
||||||
|
|
||||||
|
path = os.path.join(self.tempdir, "file.ini")
|
||||||
|
dns_test_common.write({
|
||||||
|
"corenetworks_username": API_USER,
|
||||||
|
"corenetworks_password": API_PASSWORD
|
||||||
|
}, path)
|
||||||
|
|
||||||
|
self.config = mock.MagicMock(
|
||||||
|
corenetworks_credentials=path, corenetworks_propagation_seconds=0
|
||||||
|
) # don't wait during tests
|
||||||
|
|
||||||
|
self.auth = Authenticator(self.config, "corenetworks")
|
||||||
|
|
||||||
|
self.mock_client = mock.MagicMock()
|
||||||
|
# _get_corenetworks_client | pylint: disable=protected-access
|
||||||
|
self.auth._get_corenetworks_client = mock.MagicMock(return_value=self.mock_client)
|
||||||
|
|
||||||
|
def test_perform(self):
|
||||||
|
self.auth.perform([self.achall])
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
mock.call.add_txt_record(DOMAIN, "_acme-challenge." + DOMAIN, mock.ANY, mock.ANY)
|
||||||
|
]
|
||||||
|
self.assertEqual(expected, self.mock_client.mock_calls)
|
||||||
|
|
||||||
|
def test_cleanup(self):
|
||||||
|
# _attempt_cleanup | pylint: disable=protected-access
|
||||||
|
self.auth.nameCache["_acme-challenge." + DOMAIN] = "_acme-challenge." + DOMAIN
|
||||||
|
self.auth._attempt_cleanup = True
|
||||||
|
self.auth.cleanup([self.achall])
|
||||||
|
|
||||||
|
expected = [mock.call.del_txt_record(DOMAIN, "_acme-challenge." + DOMAIN, mock.ANY)]
|
||||||
|
self.assertEqual(expected, self.mock_client.mock_calls)
|
||||||
|
|
||||||
|
def test_creds(self):
|
||||||
|
dns_test_common.write({
|
||||||
|
"corenetworks_username": API_USER,
|
||||||
|
"corenetworks_password": API_PASSWORD
|
||||||
|
}, self.config.corenetworks_credentials)
|
||||||
|
self.auth.perform([self.achall])
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
mock.call.add_txt_record(DOMAIN, "_acme-challenge." + DOMAIN, mock.ANY, mock.ANY)
|
||||||
|
]
|
||||||
|
self.assertEqual(expected, self.mock_client.mock_calls)
|
||||||
|
|
||||||
|
def test_no_creds(self):
|
||||||
|
dns_test_common.write({}, self.config.corenetworks_credentials)
|
||||||
|
self.assertRaises(errors.PluginError, self.auth.perform, [self.achall])
|
||||||
|
|
||||||
|
def test_missing_user_or_password(self):
|
||||||
|
dns_test_common.write({"corenetworks_username": API_USER},
|
||||||
|
self.config.corenetworks_credentials)
|
||||||
|
self.assertRaises(errors.PluginError, self.auth.perform, [self.achall])
|
||||||
|
|
||||||
|
dns_test_common.write({"corenetworks_password": API_PASSWORD},
|
||||||
|
self.config.corenetworks_credentials)
|
||||||
|
self.assertRaises(errors.PluginError, self.auth.perform, [self.achall])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue
Block a user