change to debugable
This commit is contained in:
parent
f6bc5bc9e9
commit
d6b0bf9f05
5 changed files with 58 additions and 40 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,6 +3,8 @@
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,python
|
# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,python
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,visualstudiocode,python
|
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,visualstudiocode,python
|
||||||
|
|
||||||
|
my_debug/
|
||||||
|
|
||||||
### Python ###
|
### Python ###
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Python: Current File",
|
||||||
|
"type": "python",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "/home/pi/dev/certbot/venv3/bin/certbot",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"args": ["certonly", "-a", "dns-ionos", "-d", "example.com", "--config-dir", "my_debug/config", "--work-dir", "my_debug/work", "--logs-dir", "my_debug/logs"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
"""DNS Authenticator for ISPConfig."""
|
"""DNS Authenticator for IONOS."""
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
@ -16,12 +16,12 @@ logger = logging.getLogger(__name__)
|
||||||
@zope.interface.implementer(interfaces.IAuthenticator)
|
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||||
@zope.interface.provider(interfaces.IPluginFactory)
|
@zope.interface.provider(interfaces.IPluginFactory)
|
||||||
class Authenticator(dns_common.DNSAuthenticator):
|
class Authenticator(dns_common.DNSAuthenticator):
|
||||||
"""DNS Authenticator for ISPConfig
|
"""DNS Authenticator for IONOS
|
||||||
|
|
||||||
This Authenticator uses the ISPConfig Remote REST API to fulfill a dns-01 challenge.
|
This Authenticator uses the IONOS Remote REST API to fulfill a dns-01 challenge.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
description = "Obtain certificates using a DNS TXT record (if you are using ISPConfig for DNS)."
|
description = "Obtain certificates using a DNS TXT record (if you are using IONOS for DNS)."
|
||||||
ttl = 60
|
ttl = 60
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -33,53 +33,53 @@ class Authenticator(dns_common.DNSAuthenticator):
|
||||||
super(Authenticator, cls).add_parser_arguments(
|
super(Authenticator, cls).add_parser_arguments(
|
||||||
add, default_propagation_seconds=120
|
add, default_propagation_seconds=120
|
||||||
)
|
)
|
||||||
add("credentials", help="ISPConfig credentials INI file.")
|
add("credentials", help="IONOS credentials INI file.")
|
||||||
|
|
||||||
def more_info(self): # pylint: disable=missing-docstring,no-self-use
|
def more_info(self): # pylint: disable=missing-docstring,no-self-use
|
||||||
return (
|
return (
|
||||||
"This plugin configures a DNS TXT record to respond to a dns-01 challenge using "
|
"This plugin configures a DNS TXT record to respond to a dns-01 challenge using "
|
||||||
+ "the ISPConfig Remote REST API."
|
+ "the IONOS Remote REST API."
|
||||||
)
|
)
|
||||||
|
|
||||||
def _setup_credentials(self):
|
def _setup_credentials(self):
|
||||||
self.credentials = self._configure_credentials(
|
self.credentials = self._configure_credentials(
|
||||||
"credentials",
|
"credentials",
|
||||||
"ISPConfig credentials INI file",
|
"IONOS credentials INI file",
|
||||||
{
|
{
|
||||||
"endpoint": "URL of the ISPConfig Remote API.",
|
"endpoint": "URL of the IONOS Remote API.",
|
||||||
"username": "Username for ISPConfig Remote API.",
|
"prefix": "Prefix for IONOS Remote API.",
|
||||||
"password": "Password for ISPConfig Remote API.",
|
"secret": "Secret for IONOS Remote API.",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def _perform(self, domain, validation_name, validation):
|
def _perform(self, domain, validation_name, validation):
|
||||||
self._get_ispconfig_client().add_txt_record(
|
self._get_ionos_client().add_txt_record(
|
||||||
domain, validation_name, validation, self.ttl
|
domain, validation_name, validation, self.ttl
|
||||||
)
|
)
|
||||||
|
|
||||||
def _cleanup(self, domain, validation_name, validation):
|
def _cleanup(self, domain, validation_name, validation):
|
||||||
self._get_ispconfig_client().del_txt_record(
|
self._get_ionos_client().del_txt_record(
|
||||||
domain, validation_name, validation, self.ttl
|
domain, validation_name, validation, self.ttl
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_ispconfig_client(self):
|
def _get_ionos_client(self):
|
||||||
return _ISPConfigClient(
|
return _ionosClient(
|
||||||
self.credentials.conf("endpoint"),
|
self.credentials.conf("endpoint"),
|
||||||
self.credentials.conf("username"),
|
self.credentials.conf("prefix"),
|
||||||
self.credentials.conf("password"),
|
self.credentials.conf("secret"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class _ISPConfigClient(object):
|
class _ionosClient(object):
|
||||||
"""
|
"""
|
||||||
Encapsulates all communication with the ISPConfig Remote REST API.
|
Encapsulates all communication with the IONOS Remote REST API.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, endpoint, username, password):
|
def __init__(self, endpoint, prefix, secret):
|
||||||
logger.debug("creating ispconfigclient")
|
logger.debug("creating ionosclient")
|
||||||
self.endpoint = endpoint
|
self.endpoint = endpoint
|
||||||
self.username = username
|
self.prefix = prefix
|
||||||
self.password = password
|
self.secret = secret
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
self.session_id = None
|
self.session_id = None
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class _ISPConfigClient(object):
|
||||||
if self.session_id is not None:
|
if self.session_id is not None:
|
||||||
return
|
return
|
||||||
logger.debug("logging in")
|
logger.debug("logging in")
|
||||||
logindata = {"username": self.username, "password": self.password}
|
logindata = {"prefix": self.prefix, "secret": self.secret}
|
||||||
self.session_id = self._api_request("login", logindata)
|
self.session_id = self._api_request("login", logindata)
|
||||||
logger.debug("session id is %s", self.session_id)
|
logger.debug("session id is %s", self.session_id)
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ class _ISPConfigClient(object):
|
||||||
:param str record_name: The record name (typically beginning with '_acme-challenge.').
|
:param str record_name: The record name (typically beginning with '_acme-challenge.').
|
||||||
:param str record_content: The record content (typically the challenge validation).
|
:param str record_content: The record content (typically the challenge validation).
|
||||||
:param int record_ttl: The record TTL (number of seconds that the record may be cached).
|
:param int record_ttl: The record TTL (number of seconds that the record may be cached).
|
||||||
:raises certbot.errors.PluginError: if an error occurs communicating with the ISPConfig API
|
:raises certbot.errors.PluginError: if an error occurs communicating with the IONOS API
|
||||||
"""
|
"""
|
||||||
self._login()
|
self._login()
|
||||||
zone_id, zone_name = self._find_managed_zone_id(domain, record_name)
|
zone_id, zone_name = self._find_managed_zone_id(domain, record_name)
|
||||||
|
@ -165,7 +165,7 @@ class _ISPConfigClient(object):
|
||||||
:param str record_name: The record name (typically beginning with '_acme-challenge.').
|
:param str record_name: The record name (typically beginning with '_acme-challenge.').
|
||||||
:param str record_content: The record content (typically the challenge validation).
|
:param str record_content: The record content (typically the challenge validation).
|
||||||
:param int record_ttl: The record TTL (number of seconds that the record may be cached).
|
:param int record_ttl: The record TTL (number of seconds that the record may be cached).
|
||||||
:raises certbot.errors.PluginError: if an error occurs communicating with the ISPConfig API
|
:raises certbot.errors.PluginError: if an error occurs communicating with the IONOS API
|
||||||
"""
|
"""
|
||||||
self._login()
|
self._login()
|
||||||
zone_id, zone_name = self._find_managed_zone_id(domain, record_name)
|
zone_id, zone_name = self._find_managed_zone_id(domain, record_name)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
"""Tests for certbot_dns_ispconfig.dns_ispconfig."""
|
"""Tests for certbot_dns_ionos.dns_ionos."""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -24,28 +24,28 @@ class AuthenticatorTest(
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(AuthenticatorTest, self).setUp()
|
super(AuthenticatorTest, self).setUp()
|
||||||
|
|
||||||
from certbot_dns_ispconfig.dns_ispconfig import Authenticator
|
from certbot_dns_ionos.dns_ionos import Authenticator
|
||||||
|
|
||||||
path = os.path.join(self.tempdir, "file.ini")
|
path = os.path.join(self.tempdir, "file.ini")
|
||||||
dns_test_common.write(
|
dns_test_common.write(
|
||||||
{
|
{
|
||||||
"ispconfig_prefix": FAKE_PREFIX,
|
"ionos_prefix": FAKE_PREFIX,
|
||||||
"ispconfig_secret": FAKE_SECRET,
|
"ionos_secret": FAKE_SECRET,
|
||||||
"ispconfig_endpoint": FAKE_ENDPOINT,
|
"ionos_endpoint": FAKE_ENDPOINT,
|
||||||
},
|
},
|
||||||
path,
|
path,
|
||||||
)
|
)
|
||||||
|
|
||||||
super(AuthenticatorTest, self).setUp()
|
super(AuthenticatorTest, self).setUp()
|
||||||
self.config = mock.MagicMock(
|
self.config = mock.MagicMock(
|
||||||
ispconfig_credentials=path, ispconfig_propagation_seconds=0
|
ionos_credentials=path, ionos_propagation_seconds=0
|
||||||
) # don't wait during tests
|
) # don't wait during tests
|
||||||
|
|
||||||
self.auth = Authenticator(self.config, "ispconfig")
|
self.auth = Authenticator(self.config, "ionos")
|
||||||
|
|
||||||
self.mock_client = mock.MagicMock()
|
self.mock_client = mock.MagicMock()
|
||||||
# _get_ispconfig_client | pylint: disable=protected-access
|
# _get_ionos_client | pylint: disable=protected-access
|
||||||
self.auth._get_ispconfig_client = mock.MagicMock(return_value=self.mock_client)
|
self.auth._get_ionos_client = mock.MagicMock(return_value=self.mock_client)
|
||||||
|
|
||||||
def test_perform(self):
|
def test_perform(self):
|
||||||
self.auth.perform([self.achall])
|
self.auth.perform([self.achall])
|
||||||
|
@ -70,17 +70,17 @@ class AuthenticatorTest(
|
||||||
self.assertEqual(expected, self.mock_client.mock_calls)
|
self.assertEqual(expected, self.mock_client.mock_calls)
|
||||||
|
|
||||||
|
|
||||||
class ISPConfigClientTest(unittest.TestCase):
|
class ionosClientTest(unittest.TestCase):
|
||||||
record_name = "foo"
|
record_name = "foo"
|
||||||
record_content = "bar"
|
record_content = "bar"
|
||||||
record_ttl = 42
|
record_ttl = 42
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
from certbot_dns_ispconfig.dns_ispconfig import _ISPConfigClient
|
from certbot_dns_ionos.dns_ionos import _ionosClient
|
||||||
|
|
||||||
self.adapter = requests_mock.Adapter()
|
self.adapter = requests_mock.Adapter()
|
||||||
|
|
||||||
self.client = _ISPConfigClient(FAKE_ENDPOINT, FAKE_PREFIX, FAKE_SECRET)
|
self.client = _ionosClient(FAKE_ENDPOINT, FAKE_PREFIX, FAKE_SECRET)
|
||||||
self.client.session.mount("mock", self.adapter)
|
self.client.session.mount("mock", self.adapter)
|
||||||
|
|
||||||
def _register_response(
|
def _register_response(
|
||||||
|
|
6
setup.py
6
setup.py
|
@ -1,7 +1,7 @@
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
from setuptools import find_packages
|
from setuptools import find_packages
|
||||||
|
|
||||||
version = "0.0.1"
|
version = "0.0.2"
|
||||||
|
|
||||||
install_requires = [
|
install_requires = [
|
||||||
"acme>=0.29.0",
|
"acme>=0.29.0",
|
||||||
|
@ -56,8 +56,8 @@ setup(
|
||||||
install_requires=install_requires,
|
install_requires=install_requires,
|
||||||
entry_points={
|
entry_points={
|
||||||
"certbot.plugins": [
|
"certbot.plugins": [
|
||||||
"dns-ispconfig = certbot_dns_ispconfig.dns_ispconfig:Authenticator"
|
"dns-ionos = certbot_dns_ionos.dns_ionos:Authenticator"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
test_suite="certbot_dns_ispconfig",
|
test_suite="certbot_dns_ionos",
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue