mirror of
https://github.com/certbot/certbot.git
synced 2026-06-04 22:33:00 -04:00
Fallback without dns.resourceRecordSets.list permission (#5678)
* Add rrset list fallback * List dns.resourceRecordSets.list as required * Handle list failures differently for add and del * Quote record content * disable not-callable for iter_entry_points * List update permission
This commit is contained in:
parent
d62c56f9c9
commit
6357e051f4
4 changed files with 37 additions and 9 deletions
|
|
@ -29,6 +29,8 @@ for an account with the following permissions:
|
|||
* ``dns.managedZones.list``
|
||||
* ``dns.resourceRecordSets.create``
|
||||
* ``dns.resourceRecordSets.delete``
|
||||
* ``dns.resourceRecordSets.list``
|
||||
* ``dns.resourceRecordSets.update``
|
||||
|
||||
Google provides instructions for `creating a service account <https://developers
|
||||
.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount>`_ and
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ class _GoogleClient(object):
|
|||
zone_id = self._find_managed_zone_id(domain)
|
||||
|
||||
record_contents = self.get_existing_txt_rrset(zone_id, record_name)
|
||||
if record_contents is None:
|
||||
record_contents = []
|
||||
add_records = record_contents[:]
|
||||
|
||||
if "\""+record_content+"\"" in record_contents:
|
||||
|
|
@ -176,6 +178,8 @@ class _GoogleClient(object):
|
|||
return
|
||||
|
||||
record_contents = self.get_existing_txt_rrset(zone_id, record_name)
|
||||
if record_contents is None:
|
||||
record_contents = ["\"" + record_content + "\""]
|
||||
|
||||
data = {
|
||||
"kind": "dns#change",
|
||||
|
|
@ -216,23 +220,32 @@ class _GoogleClient(object):
|
|||
"""
|
||||
Get existing TXT records from the RRset for the record name.
|
||||
|
||||
If an error occurs while requesting the record set, it is suppressed
|
||||
and None is returned.
|
||||
|
||||
:param str zone_id: The ID of the managed zone.
|
||||
:param str record_name: The record name (typically beginning with '_acme-challenge.').
|
||||
|
||||
:returns: List of TXT record values
|
||||
:rtype: `list` of `string`
|
||||
:returns: List of TXT record values or None
|
||||
:rtype: `list` of `string` or `None`
|
||||
|
||||
"""
|
||||
rrs_request = self.dns.resourceRecordSets() # pylint: disable=no-member
|
||||
request = rrs_request.list(managedZone=zone_id, project=self.project_id)
|
||||
response = request.execute()
|
||||
# Add dot as the API returns absolute domains
|
||||
record_name += "."
|
||||
if response:
|
||||
for rr in response["rrsets"]:
|
||||
if rr["name"] == record_name and rr["type"] == "TXT":
|
||||
return rr["rrdatas"]
|
||||
return []
|
||||
try:
|
||||
response = request.execute()
|
||||
except googleapiclient_errors.Error:
|
||||
logger.info("Unable to list existing records. If you're "
|
||||
"requesting a wildcard certificate, this might not work.")
|
||||
logger.debug("Error was:", exc_info=True)
|
||||
else:
|
||||
if response:
|
||||
for rr in response["rrsets"]:
|
||||
if rr["name"] == record_name and rr["type"] == "TXT":
|
||||
return rr["rrdatas"]
|
||||
return None
|
||||
|
||||
def _find_managed_zone_id(self, domain):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -270,7 +270,19 @@ class GoogleClientTest(unittest.TestCase):
|
|||
found = client.get_existing_txt_rrset(self.zone, "_acme-challenge.example.org")
|
||||
self.assertEquals(found, ["\"example-txt-contents\""])
|
||||
not_found = client.get_existing_txt_rrset(self.zone, "nonexistent.tld")
|
||||
self.assertEquals(not_found, [])
|
||||
self.assertEquals(not_found, None)
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_get_existing_fallback(self, unused_credential_mock):
|
||||
client, unused_changes = self._setUp_client_with_mock(
|
||||
[{'managedZones': [{'id': self.zone}]}])
|
||||
mock_execute = client.dns.resourceRecordSets.return_value.list.return_value.execute
|
||||
mock_execute.side_effect = API_ERROR
|
||||
|
||||
rrset = client.get_existing_txt_rrset(self.zone, "_acme-challenge.example.org")
|
||||
self.assertFalse(rrset)
|
||||
|
||||
def test_get_project_id(self):
|
||||
from certbot_dns_google.dns_google import _GoogleClient
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ class PluginsRegistry(collections.Mapping):
|
|||
def find_all(cls):
|
||||
"""Find plugins using setuptools entry points."""
|
||||
plugins = {}
|
||||
# pylint: disable=not-callable
|
||||
entry_points = itertools.chain(
|
||||
pkg_resources.iter_entry_points(
|
||||
constants.SETUPTOOLS_PLUGINS_ENTRY_POINT),
|
||||
|
|
|
|||
Loading…
Reference in a new issue