Skip to content

Commit

Permalink
Merge branch 'main' into default_propagation_seconds
Browse files Browse the repository at this point in the history
  • Loading branch information
fupduck committed Jun 20, 2024
2 parents c2f1550 + d01d568 commit 1d42ad8
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 48 deletions.
48 changes: 18 additions & 30 deletions certbot_dns_hetzner/dns_hetzner.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""DNS Authenticator for Hetzner DNS."""
import tldextract
from certbot.plugins import dns_common, dns_common_lexicon
from lexicon.providers import hetzner
from certbot.plugins import dns_common
from lexicon.client import Client
from lexicon.config import ConfigResolver

TTL = 60

Expand Down Expand Up @@ -47,40 +48,27 @@ def _get_zone(domain):
return '.'.join([zone_name.domain, zone_name.suffix])

def _perform(self, domain, validation_name, validation):
self._get_hetzner_client().add_txt_record(
self._get_zone(domain),
self._fqdn_format(validation_name),
validation
)
with self._get_hetzner_client(domain) as client:
client.create_record("TXT", self._fqdn_format(validation_name), validation)

def _cleanup(self, domain, validation_name, validation):
self._get_hetzner_client().del_txt_record(
self._get_zone(domain),
self._fqdn_format(validation_name),
validation
)
with self._get_hetzner_client(domain) as client:
client.delete_record(None, "TXT", self._fqdn_format(validation_name), validation)

def _get_hetzner_client(self, domain):
config = ConfigResolver().with_env().with_dict({
"provider_name": "hetzner",
"hetzner": {
"auth_token": self.credentials.conf("api_token")
},

def _get_hetzner_client(self):
return _HetznerClient(self.credentials.conf("api_token"))
"ttl": TTL,
"domain": self._get_zone(domain),
})
return Client(config)

@staticmethod
def _fqdn_format(name):
if not name.endswith("."):
return f"{name}."
return name


class _HetznerClient(dns_common_lexicon.LexiconClient):
"""
Encapsulates all communication with the Hetzner via Lexicon.
"""
def __init__(self, auth_token):
super().__init__()

config = dns_common_lexicon.build_lexicon_config('hetzner', {
'ttl': TTL,
}, {
'auth_token': auth_token,
})

self.provider = hetzner.Provider(config)
42 changes: 24 additions & 18 deletions certbot_dns_hetzner/dns_hetzner_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from certbot_dns_hetzner.fakes import FAKE_API_TOKEN, FAKE_RECORD



patch_display_util = test_util.patch_display_util


Expand Down Expand Up @@ -44,52 +43,59 @@ def setUp(self):
self.auth = Authenticator(self.config, "hetzner")

self.mock_client = mock.MagicMock()

mock_client_wrapper = mock.MagicMock()
mock_client_wrapper.__enter__ = mock.MagicMock(
return_value=self.mock_client
)

# _get_ispconfig_client | pylint: disable=protected-access
self.auth._get_hetzner_client = mock.MagicMock(
return_value=self.mock_client)
return_value=mock_client_wrapper
)

@patch_display_util()
def test_perform(self, unused_mock_get_utility):
self.mock_client.add_txt_record.return_value = FAKE_RECORD
def test_perform(self, _unused_mock_get_utility):
self.mock_client.create_record.return_value = FAKE_RECORD
self.auth.perform([self.achall])
self.mock_client.add_txt_record.assert_called_with(
DOMAIN, "_acme-challenge." + DOMAIN + ".", mock.ANY
self.mock_client.create_record.assert_called_with(
"TXT", "_acme-challenge." + DOMAIN + ".", mock.ANY
)

def test_perform_but_raises_plugin_error(self):
self.mock_client.add_txt_record.side_effect = mock.MagicMock(
self.mock_client.create_record.side_effect = mock.MagicMock(
side_effect=PluginError()
)
self.assertRaises(PluginError, self.auth.perform, [self.achall])
self.mock_client.add_txt_record.assert_called_with(
DOMAIN, "_acme-challenge." + DOMAIN + ".", mock.ANY
self.mock_client.create_record.assert_called_with(
"TXT", "_acme-challenge." + DOMAIN + ".", mock.ANY
)

@patch_display_util()
def test_cleanup(self, unused_mock_get_utility):
self.mock_client.add_txt_record.return_value = FAKE_RECORD
def test_cleanup(self, _unused_mock_get_utility):
self.mock_client.create_record.return_value = FAKE_RECORD
# _attempt_cleanup | pylint: disable=protected-access
self.auth.perform([self.achall])
self.auth._attempt_cleanup = True
self.auth.cleanup([self.achall])

self.mock_client.del_txt_record.assert_called_with(
DOMAIN, "_acme-challenge." + DOMAIN + ".", mock.ANY
self.mock_client.delete_record.assert_called_with(
None, "TXT", "_acme-challenge." + DOMAIN + ".", mock.ANY
)

@patch_display_util()
def test_cleanup_but_raises_plugin_error(self, unused_mock_get_utility):
self.mock_client.add_txt_record.return_value = FAKE_RECORD
self.mock_client.del_txt_record.side_effect = mock.MagicMock(
def test_cleanup_but_raises_plugin_error(self, _unused_mock_get_utility):
self.mock_client.create_record.return_value = FAKE_RECORD
self.mock_client.delete_record.side_effect = mock.MagicMock(
side_effect=PluginError()
)
# _attempt_cleanup | pylint: disable=protected-access
self.auth.perform([self.achall])
self.auth._attempt_cleanup = True

self.assertRaises(PluginError, self.auth.cleanup, [self.achall])
self.mock_client.del_txt_record.assert_called_with(
DOMAIN, "_acme-challenge." + DOMAIN + ".", mock.ANY
self.mock_client.delete_record.assert_called_with(
None, "TXT", "_acme-challenge." + DOMAIN + ".", mock.ANY
)


Expand Down

0 comments on commit 1d42ad8

Please sign in to comment.