mirror of
https://github.com/thegeeklab/corenetworks.git
synced 2024-11-21 21:20:38 +00:00
initial commit
This commit is contained in:
commit
252a30c087
283
.drone.jsonnet
Normal file
283
.drone.jsonnet
Normal file
@ -0,0 +1,283 @@
|
||||
local PythonVersion(pyversion='2.7') = {
|
||||
name: 'python' + std.strReplace(pyversion, '.', '') + '-ansible',
|
||||
image: 'python:' + pyversion,
|
||||
environment: {
|
||||
PY_COLORS: 1,
|
||||
},
|
||||
commands: [
|
||||
'pip install -r test-requirements.txt -qq',
|
||||
'pip install -qq .',
|
||||
'pytest corenetworks/tests/ --cov=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 test-requirements.txt -qq',
|
||||
'pip install -qq .',
|
||||
'flake8 ./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',
|
||||
'codecov --required',
|
||||
],
|
||||
},
|
||||
],
|
||||
depends_on: [
|
||||
'dependencies',
|
||||
],
|
||||
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 test-requirements.txt -qq',
|
||||
'pip install -qq .',
|
||||
'bandit -r ./corenetworks -x ./corenetworks/tests',
|
||||
],
|
||||
},
|
||||
],
|
||||
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 PipelineDocs = {
|
||||
kind: 'pipeline',
|
||||
name: 'docs',
|
||||
platform: {
|
||||
os: 'linux',
|
||||
arch: 'amd64',
|
||||
},
|
||||
concurrency: {
|
||||
limit: 1,
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
name: 'assets',
|
||||
image: 'byrnedo/alpine-curl',
|
||||
commands: [
|
||||
'mkdir -p docs/themes/hugo-geekdoc/',
|
||||
'curl -L https://github.com/xoxys/hugo-geekdoc/releases/latest/download/hugo-geekdoc.tar.gz | tar -xz -C docs/themes/hugo-geekdoc/ --strip-components=1',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'test',
|
||||
image: 'klakegg/hugo:0.59.1-ext-alpine',
|
||||
commands: [
|
||||
'cd docs/ && hugo-official',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'freeze',
|
||||
image: 'appleboy/drone-ssh:1.5.5',
|
||||
settings: {
|
||||
host: { from_secret: 'ssh_host' },
|
||||
key: { from_secret: 'ssh_key' },
|
||||
script: [
|
||||
'cp -R /var/www/virtual/geeklab/html/corenetworks.geekdocs.de/ /var/www/virtual/geeklab/html/corenetworks_freeze/',
|
||||
'ln -sfn /var/www/virtual/geeklab/html/corenetworks_freeze /var/www/virtual/geeklab/corenetworks.geekdocs.de',
|
||||
],
|
||||
username: { from_secret: 'ssh_username' },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'publish',
|
||||
image: 'appleboy/drone-scp',
|
||||
settings: {
|
||||
host: { from_secret: 'ssh_host' },
|
||||
key: { from_secret: 'ssh_key' },
|
||||
rm: true,
|
||||
source: 'docs/public/*',
|
||||
strip_components: 2,
|
||||
target: '/var/www/virtual/geeklab/html/corenetworks.geekdocs.de/',
|
||||
username: { from_secret: 'ssh_username' },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'cleanup',
|
||||
image: 'appleboy/drone-ssh:1.5.5',
|
||||
settings: {
|
||||
host: { from_secret: 'ssh_host' },
|
||||
key: { from_secret: 'ssh_key' },
|
||||
script: [
|
||||
'ln -sfn /var/www/virtual/geeklab/html/corenetworks.geekdocs.de /var/www/virtual/geeklab/corenetworks.geekdocs.de',
|
||||
'rm -rf /var/www/virtual/geeklab/html/corenetworks_freeze/',
|
||||
],
|
||||
username: { from_secret: 'ssh_username' },
|
||||
},
|
||||
},
|
||||
],
|
||||
depends_on: [
|
||||
'build-package',
|
||||
'build-container-amd64',
|
||||
'build-container-arm64',
|
||||
'build-container-arm',
|
||||
],
|
||||
trigger: {
|
||||
ref: ['refs/heads/master', 'refs/tags/**'],
|
||||
},
|
||||
};
|
||||
|
||||
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: [
|
||||
'docs',
|
||||
],
|
||||
trigger: {
|
||||
ref: ['refs/heads/master', 'refs/tags/**'],
|
||||
status: ['success', 'failure'],
|
||||
},
|
||||
};
|
||||
|
||||
[
|
||||
PipelineLint,
|
||||
PipelineTest,
|
||||
PipelineSecurity,
|
||||
PipelineBuildPackage,
|
||||
PipelineDocs,
|
||||
PipelineNotifications,
|
||||
]
|
308
.drone.yml
Normal file
308
.drone.yml
Normal file
@ -0,0 +1,308 @@
|
||||
---
|
||||
kind: pipeline
|
||||
name: lint
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: flake8
|
||||
image: python:3.8
|
||||
commands:
|
||||
- pip install -r test-requirements.txt -qq
|
||||
- pip install -qq .
|
||||
- flake8 ./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-ansible
|
||||
image: python:2.7
|
||||
commands:
|
||||
- pip install -r test-requirements.txt -qq
|
||||
- pip install -qq .
|
||||
- pytest corenetworks/tests/ --cov=corenetworks/ --no-cov-on-fail
|
||||
environment:
|
||||
PY_COLORS: 1
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: python35-ansible
|
||||
image: python:3.5
|
||||
commands:
|
||||
- pip install -r test-requirements.txt -qq
|
||||
- pip install -qq .
|
||||
- pytest corenetworks/tests/ --cov=corenetworks/ --no-cov-on-fail
|
||||
environment:
|
||||
PY_COLORS: 1
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: python36-ansible
|
||||
image: python:3.6
|
||||
commands:
|
||||
- pip install -r test-requirements.txt -qq
|
||||
- pip install -qq .
|
||||
- pytest corenetworks/tests/ --cov=corenetworks/ --no-cov-on-fail
|
||||
environment:
|
||||
PY_COLORS: 1
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: python37-ansible
|
||||
image: python:3.7
|
||||
commands:
|
||||
- pip install -r test-requirements.txt -qq
|
||||
- pip install -qq .
|
||||
- pytest corenetworks/tests/ --cov=corenetworks/ --no-cov-on-fail
|
||||
environment:
|
||||
PY_COLORS: 1
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: python38-ansible
|
||||
image: python:3.8
|
||||
commands:
|
||||
- pip install -r test-requirements.txt -qq
|
||||
- pip install -qq .
|
||||
- pytest corenetworks/tests/ --cov=corenetworks/ --no-cov-on-fail
|
||||
environment:
|
||||
PY_COLORS: 1
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: codecov
|
||||
image: python:3.8
|
||||
commands:
|
||||
- pip install codecov
|
||||
- codecov --required
|
||||
environment:
|
||||
CODECOV_TOKEN:
|
||||
from_secret: codecov_token
|
||||
PY_COLORS: 1
|
||||
|
||||
trigger:
|
||||
ref:
|
||||
- refs/heads/master
|
||||
- refs/tags/**
|
||||
- refs/pull/**
|
||||
|
||||
depends_on:
|
||||
- dependencies
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: security
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: bandit
|
||||
image: python:3.8
|
||||
commands:
|
||||
- pip install -r test-requirements.txt -qq
|
||||
- pip install -qq .
|
||||
- bandit -r ./corenetworks -x ./corenetworks/tests
|
||||
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: docs
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
concurrency:
|
||||
limit: 1
|
||||
|
||||
steps:
|
||||
- name: assets
|
||||
image: byrnedo/alpine-curl
|
||||
commands:
|
||||
- mkdir -p docs/themes/hugo-geekdoc/
|
||||
- curl -L https://github.com/xoxys/hugo-geekdoc/releases/latest/download/hugo-geekdoc.tar.gz | tar -xz -C docs/themes/hugo-geekdoc/ --strip-components=1
|
||||
|
||||
- name: test
|
||||
image: klakegg/hugo:0.59.1-ext-alpine
|
||||
commands:
|
||||
- cd docs/ && hugo-official
|
||||
|
||||
- name: freeze
|
||||
image: appleboy/drone-ssh:1.5.5
|
||||
settings:
|
||||
host:
|
||||
from_secret: ssh_host
|
||||
key:
|
||||
from_secret: ssh_key
|
||||
script:
|
||||
- cp -R /var/www/virtual/geeklab/html/corenetworks.geekdocs.de/ /var/www/virtual/geeklab/html/corenetworks_freeze/
|
||||
- ln -sfn /var/www/virtual/geeklab/html/corenetworks_freeze /var/www/virtual/geeklab/corenetworks.geekdocs.de
|
||||
username:
|
||||
from_secret: ssh_username
|
||||
|
||||
- name: publish
|
||||
image: appleboy/drone-scp
|
||||
settings:
|
||||
host:
|
||||
from_secret: ssh_host
|
||||
key:
|
||||
from_secret: ssh_key
|
||||
rm: true
|
||||
source: docs/public/*
|
||||
strip_components: 2
|
||||
target: /var/www/virtual/geeklab/html/corenetworks.geekdocs.de/
|
||||
username:
|
||||
from_secret: ssh_username
|
||||
|
||||
- name: cleanup
|
||||
image: appleboy/drone-ssh:1.5.5
|
||||
settings:
|
||||
host:
|
||||
from_secret: ssh_host
|
||||
key:
|
||||
from_secret: ssh_key
|
||||
script:
|
||||
- ln -sfn /var/www/virtual/geeklab/html/corenetworks.geekdocs.de /var/www/virtual/geeklab/corenetworks.geekdocs.de
|
||||
- rm -rf /var/www/virtual/geeklab/html/corenetworks_freeze/
|
||||
username:
|
||||
from_secret: ssh_username
|
||||
|
||||
trigger:
|
||||
ref:
|
||||
- refs/heads/master
|
||||
- refs/tags/**
|
||||
|
||||
depends_on:
|
||||
- build-package
|
||||
- build-container-amd64
|
||||
- build-container-arm64
|
||||
- build-container-arm
|
||||
|
||||
---
|
||||
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:
|
||||
- docs
|
||||
|
||||
---
|
||||
kind: signature
|
||||
hmac: e0cd32befb8e01ec9cb6bd0e7bc032fe0816bcda9e16d89f37789a7db9ba9b82
|
||||
|
||||
...
|
18
.flake8
Normal file
18
.flake8
Normal file
@ -0,0 +1,18 @@
|
||||
[flake8]
|
||||
ignore = D103, D107, W503
|
||||
max-line-length = 99
|
||||
inline-quotes = double
|
||||
exclude =
|
||||
.git
|
||||
.tox
|
||||
__pycache__
|
||||
build
|
||||
dist
|
||||
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
|
112
.gitignore
vendored
Normal file
112
.gitignore
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
# ---> 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*
|
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.
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# corenetworks
|
||||
|
||||
Python library for the [https://core-networks.de](https://beta.api.core-networks.de/doc/) DNS API.
|
13
corenetworks/__init__.py
Normal file
13
corenetworks/__init__.py
Normal file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Default package."""
|
||||
|
||||
from corenetworks.client import CoreNetworks # noqa
|
||||
|
||||
__author__ = "Robert Kaussow"
|
||||
__project__ = "corenetworks"
|
||||
__license__ = "MIT"
|
||||
__maintainer__ = "Robert Kaussow"
|
||||
__email__ = "mail@geeklabor.de"
|
||||
__url__ = "https://github.com/xoxys/corenetworks"
|
||||
__version__ = "0.1.0"
|
86
corenetworks/authenticators.py
Normal file
86
corenetworks/authenticators.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Custom authenticators."""
|
||||
|
||||
import json
|
||||
|
||||
from requests import ConnectionError
|
||||
from requests import HTTPError
|
||||
from requests import Request
|
||||
from requests import Session
|
||||
from requests.auth import AuthBase
|
||||
|
||||
from .exceptions import AuthError
|
||||
from .exceptions import CorenetworksError
|
||||
|
||||
|
||||
class CoreNetworksBasicAuth(AuthBase):
|
||||
"""Define token based auth."""
|
||||
|
||||
def __init__(self, user, password, endpoint):
|
||||
self.user = user
|
||||
self.password = password
|
||||
self.endpoint = endpoint
|
||||
self.token = self._login()
|
||||
|
||||
def __eq__(self, other): # noqa
|
||||
return all([
|
||||
self.user == getattr(other, "user", None),
|
||||
self.password == getattr(other, "password", None),
|
||||
])
|
||||
|
||||
def __ne__(self, other): # noqa
|
||||
return not self == other
|
||||
|
||||
def __call__(self, r): # noqa
|
||||
r.headers["Authorization"] = "Bearer {0!s}".format(self.token)
|
||||
return r
|
||||
|
||||
def _login(self):
|
||||
data = {}
|
||||
data["login"] = self.user
|
||||
data["password"] = self.password
|
||||
|
||||
json_data = json.dumps(data)
|
||||
url = "{endpoint}/auth/token".format(endpoint=self.endpoint)
|
||||
|
||||
request = Request(method="POST", url=url, data=json_data)
|
||||
prepared_request = request.prepare()
|
||||
|
||||
try:
|
||||
session = Session()
|
||||
handle = session.send(prepared_request)
|
||||
handle.raise_for_status()
|
||||
except ConnectionError as e:
|
||||
raise CorenetworksError(
|
||||
"Server unreachable: {reason}".format(reason=e.message.reason), payload=e
|
||||
)
|
||||
except HTTPError as e:
|
||||
raise AuthError(
|
||||
"Login failed: {code} {reason}".format(
|
||||
code=e.response.status_code, reason=e.response.reason
|
||||
),
|
||||
payload=e
|
||||
)
|
||||
|
||||
response = handle.json()
|
||||
|
||||
return response["token"]
|
||||
|
||||
|
||||
class CoreNetworksTokenAuth(AuthBase):
|
||||
"""Define token based auth."""
|
||||
|
||||
def __init__(self, token):
|
||||
self.token = token
|
||||
|
||||
def __eq__(self, other): # noqa
|
||||
return all([
|
||||
self.token == getattr(other, "api_token", None),
|
||||
])
|
||||
|
||||
def __ne__(self, other): # noqa
|
||||
return not self == other
|
||||
|
||||
def __call__(self, r): # noqa
|
||||
r.headers["Authorization"] = "Bearer {0!s}".format(self.token)
|
||||
return r
|
231
corenetworks/client.py
Normal file
231
corenetworks/client.py
Normal file
@ -0,0 +1,231 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""API client."""
|
||||
|
||||
import copy
|
||||
import json
|
||||
|
||||
import jsonschema
|
||||
from requests import ConnectionError
|
||||
from requests import HTTPError
|
||||
from requests import Request
|
||||
from requests import Session
|
||||
from six import iteritems
|
||||
|
||||
import corenetworks
|
||||
|
||||
from .authenticators import CoreNetworksBasicAuth
|
||||
from .authenticators import CoreNetworksTokenAuth
|
||||
from .exceptions import AuthError
|
||||
from .exceptions import CorenetworksError
|
||||
from .exceptions import ValidationError
|
||||
|
||||
|
||||
class CoreNetworks():
|
||||
"""Create authenticated API client."""
|
||||
|
||||
def __init__(self, user=None, password=None, api_token=None):
|
||||
self.__endpoint = "https://beta.api.core-networks.de"
|
||||
self.__user_agent = "Core Networks Python API {version}".format(
|
||||
version=corenetworks.__version__
|
||||
)
|
||||
|
||||
self._schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"ttl": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"type": "string"
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if api_token:
|
||||
self._auth = CoreNetworksTokenAuth(api_token)
|
||||
else:
|
||||
if not user or not password:
|
||||
raise AuthError("Insufficient authentication details provided")
|
||||
|
||||
self._auth = CoreNetworksBasicAuth(user, password, self.__endpoint)
|
||||
|
||||
# RECORDS
|
||||
|
||||
def records(self, zone, data={}):
|
||||
"""
|
||||
Get the list of records for the specific domain.
|
||||
|
||||
Args:
|
||||
zone (str): Name of the target DNS zone.
|
||||
params (dict): Dictionary of filter parameters.
|
||||
See https://beta.api.core-networks.de/doc/#functon_dnszones_records
|
||||
but keep in mind that you have to pass a dict not a string. The required
|
||||
filter string will be created automatically.
|
||||
|
||||
Example: params={"type": ["NS", "SOA"]} will result in filter=?type[]=NS&type[]=SOA
|
||||
|
||||
Returns:
|
||||
list: List of entry dicts.
|
||||
|
||||
"""
|
||||
schema = copy.deepcopy(self._schema)
|
||||
self.__validate(data, schema)
|
||||
|
||||
filter_string = self.__json_to_filter(data)
|
||||
result = self.__rest_helper(
|
||||
"/dnszones/{zone}/records/{filter}".format(zone=zone, filter=filter_string),
|
||||
method="GET"
|
||||
)
|
||||
|
||||
return self.__normalize(result)
|
||||
|
||||
def add_record(self, zone, data):
|
||||
"""
|
||||
Create a record for the given domain.
|
||||
|
||||
Args:
|
||||
param1: The first parameter.
|
||||
param2: The second parameter.
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise.
|
||||
|
||||
"""
|
||||
schema = copy.deepcopy(self._schema)
|
||||
schema["required"] = ["name", "type", "data"]
|
||||
self.__validate(data, schema)
|
||||
|
||||
result = self.__rest_helper(
|
||||
"/dnszones/{zone}/records/".format(zone=zone), data=data, method="POST"
|
||||
)
|
||||
|
||||
return self.__normalize(result)
|
||||
|
||||
def delete_record(self, zone, data):
|
||||
"""
|
||||
Delete all DNS records of a zone that match the data.
|
||||
|
||||
Args:
|
||||
|
||||
"""
|
||||
schema = copy.deepcopy(self._schema)
|
||||
schema["properties"]["force_all"] = {"type": "boolean"}
|
||||
schema["oneOf"] = [{
|
||||
"required": ["name"]
|
||||
}, {
|
||||
"required": ["type"]
|
||||
}, {
|
||||
"required": ["data"]
|
||||
}, {
|
||||
"required": ["force_all"]
|
||||
}]
|
||||
self.__validate(data, schema)
|
||||
|
||||
if data.get("force_all"):
|
||||
data = {}
|
||||
|
||||
print(data)
|
||||
|
||||
# result = self.__rest_helper(
|
||||
# "/dnszones/{zone}/records/delete/".format(zone=zone), data=data, method="POST"
|
||||
# )
|
||||
|
||||
# return self.__normalize(result)
|
||||
|
||||
def __rest_helper(self, url, data=None, params=None, method="GET"):
|
||||
"""Handle requests to the Core Networks API."""
|
||||
url = self.__endpoint + url
|
||||
headers = {
|
||||
"User-Agent": self.__user_agent,
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
if data:
|
||||
json_data = json.dumps(data)
|
||||
else:
|
||||
json_data = None
|
||||
|
||||
request = Request(
|
||||
method=method,
|
||||
url=url,
|
||||
headers=headers,
|
||||
data=json_data,
|
||||
params=params,
|
||||
auth=self._auth
|
||||
)
|
||||
|
||||
prepared_request = request.prepare()
|
||||
|
||||
r_json, r_headers = self.__request_helper(prepared_request)
|
||||
|
||||
return r_json
|
||||
|
||||
@staticmethod
|
||||
def __request_helper(request):
|
||||
"""Handle firing off requests and exception raising."""
|
||||
try:
|
||||
session = Session()
|
||||
handle = session.send(request)
|
||||
|
||||
handle.raise_for_status()
|
||||
except ConnectionError as e:
|
||||
raise CorenetworksError(
|
||||
"Server unreachable: {reason}".format(reason=e.message.reason), payload=e
|
||||
)
|
||||
except HTTPError as e:
|
||||
raise CorenetworksError(
|
||||
"Invalid response: {code} {reason}".format(
|
||||
code=e.response.status_code, reason=e.response.reason
|
||||
),
|
||||
payload=e
|
||||
)
|
||||
|
||||
if handle.status_code == 200:
|
||||
response = handle.json()
|
||||
else:
|
||||
response = []
|
||||
|
||||
return response, handle.headers
|
||||
|
||||
@staticmethod
|
||||
def __normalize(result):
|
||||
if isinstance(result, list):
|
||||
return [el for el in result]
|
||||
elif isinstance(result, dict):
|
||||
return result
|
||||
else:
|
||||
raise CorenetworksError("Unknown type: {}".format(type(result)))
|
||||
|
||||
@staticmethod
|
||||
def __json_to_filter(data):
|
||||
filter_list = []
|
||||
|
||||
for (key, value) in iteritems(data):
|
||||
if isinstance(value, list):
|
||||
for item in value:
|
||||
filter_list.append("{key}[]={value}".format(key=key, value=item))
|
||||
elif isinstance(value, str):
|
||||
filter_list.append("{key}={value}".format(key=key, value=value))
|
||||
else:
|
||||
raise CorenetworksError("Unknown type: {}".format(type(value)))
|
||||
|
||||
filter_string = "&".join(filter_list)
|
||||
|
||||
if filter_string:
|
||||
filter_string = "?{filter}".format(filter=filter_string)
|
||||
|
||||
return filter_string
|
||||
|
||||
@staticmethod
|
||||
def __validate(data, schema):
|
||||
try:
|
||||
jsonschema.validate(data, schema)
|
||||
except jsonschema.exceptions.ValidationError as e:
|
||||
raise ValidationError("Dataset invalid: {reason}".format(reason=e.message), payload=e)
|
31
corenetworks/exceptions.py
Normal file
31
corenetworks/exceptions.py
Normal file
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
"""Custom package exceptions."""
|
||||
|
||||
|
||||
class CoreNetworksException(Exception):
|
||||
"""The main exception class."""
|
||||
|
||||
def __init__(self, message, payload=None):
|
||||
self.message = message
|
||||
self.payload = payload
|
||||
|
||||
def __str__(self): # noqa
|
||||
return str(self.message)
|
||||
|
||||
|
||||
class CorenetworksError(CoreNetworksException):
|
||||
"""Authentication errors exception class."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ValidationError(CoreNetworksException):
|
||||
"""Authentication errors exception class."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AuthError(CoreNetworksException):
|
||||
"""Authentication errors exception class."""
|
||||
|
||||
pass
|
27
setup.cfg
Normal file
27
setup.cfg
Normal file
@ -0,0 +1,27 @@
|
||||
[metadata]
|
||||
description-file = README.md
|
||||
license_file = LICENSE
|
||||
|
||||
[bdist_wheel]
|
||||
universal = 1
|
||||
|
||||
[isort]
|
||||
default_section = THIRDPARTY
|
||||
known_first_party = 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
|
65
setup.py
Normal file
65
setup.py
Normal file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
"""Setup script for the package."""
|
||||
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
PACKAGE_NAME = "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="Python API client for Domain Management Automation "
|
||||
"with Core Networks https://www.core-networks.de/",
|
||||
keywords="dns, automation, nameserver, 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=["*.tests", "tests", "tests.*"]),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,<4",
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Environment :: Console",
|
||||
"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 :: Software Development",
|
||||
],
|
||||
install_requires=["six", "jsonschema"],
|
||||
dependency_links=[],
|
||||
test_suite="tests",
|
||||
)
|
18
test-requirements.txt
Normal file
18
test-requirements.txt
Normal file
@ -0,0 +1,18 @@
|
||||
pipenv-setup
|
||||
pydocstyle<4.0.0
|
||||
flake8
|
||||
flake8-colors
|
||||
flake8-blind-except
|
||||
flake8-builtins
|
||||
flake8-docstrings<=3.0.0
|
||||
flake8-isort
|
||||
flake8-logging-format
|
||||
flake8-polyfill
|
||||
flake8-quotes
|
||||
pep8-naming
|
||||
pytest
|
||||
pytest-mock
|
||||
pytest-cov
|
||||
bandit
|
||||
autopep8
|
||||
yapf
|
Loading…
Reference in New Issue
Block a user