Repository: AnalogJ/lexicon

Issue:
LuaDNS _list_records fails due to missing "id" in API response
I'm using certbot with the luadns plugin which in turn uses lexicon.
I've been experiencing the error reported here: https://community.letsencrypt.org/t/luadns-renew-error/89634

```
2019-08-29 06:32:43,517:DEBUG:urllib3.connectionpool:https://api.luadns.com:443 "GET /v1/zones/[XXXXXX]/records HTTP/1.1" 200 None
2019-08-29 06:32:43,520:ERROR:certbot.error_handler:Encountered exception during recovery: 
Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python2.7/site-packages/certbot/error_handler.py", line 124, in _call_registered
    self.funcs[-1]()
  File "/home/ubuntu/.local/lib/python2.7/site-packages/certbot/auth_handler.py", line 220, in _cleanup_challenges
    self.auth.cleanup(achalls)
  File "/home/ubuntu/.local/lib/python2.7/site-packages/certbot/plugins/dns_common.py", line 77, in cleanup
    self._cleanup(domain, validation_domain_name, validation)
  File "/usr/local/lib/python2.7/dist-packages/certbot_dns_luadns/dns_luadns.py", line 55, in _cleanup
    self._get_luadns_client().del_txt_record(domain, validation_name, validation)
  File "/home/ubuntu/.local/lib/python2.7/site-packages/certbot/plugins/dns_common_lexicon.py", line 65, in del_txt_record
    self.provider.delete_record(type='TXT', name=record_name, content=record_content)
  File "/usr/local/lib/python2.7/dist-packages/lexicon/providers/base.py", line 118, in delete_record
    return self._delete_record(identifier=identifier, rtype=rtype, name=name, content=content)
  File "/usr/local/lib/python2.7/dist-packages/lexicon/providers/luadns.py", line 111, in _delete_record
    records = self._list_records(rtype, name, content)
  File "/usr/local/lib/python2.7/dist-packages/lexicon/providers/luadns.py", line 71, in _list_records
    'id': record['id']
KeyError: 'id'
```
I've replaced the zone id with [XXXXXX].

Code line that errors: https://github.com/AnalogJ/lexicon/blob/master/lexicon/providers/luadns.py#L71

Running the call directly towards the LuaDNS api shows that my REDIRECT record does not return an "id" -> no wonder it fails.

```
...
[
    {
        "id": XXXXXXXXX,
        "name": "sub.some.domain.",
        "type": "A",
        "content": "111.111.111.111",
        "ttl": 300,
        "zone_id": XXXXX,
        "generated": false,
        "created_at": "2019-08-27T05:59:34.219211Z",
        "updated_at": "2019-08-27T05:59:34.219213Z"
    },
    {
        "name": "some.domain.",
        "type": "REDIRECT",
        "content": "1 https://sub.some.domain",
        "ttl": 300,
        "zone_id": XXXXX,
        "generated": false,
        "created_at": "2019-08-29T07:05:09.757404499Z",
        "updated_at": "2019-08-29T07:05:09.757406053Z"
    }
]
...
```

My question is: How do I go forward with this? (for now, I've just deleted the REDIRECT record and everything works fine)
1) Send PR to lexicon to ignore records that does not have id? ( if 'id' in record )
2) Reach out to LuaDNS for API fix?

Any input would be great :)


Discussion:

Resolving patch:
diff --git a/lexicon/providers/luadns.py b/lexicon/providers/luadns.py
--- a/lexicon/providers/luadns.py
+++ b/lexicon/providers/luadns.py
@@ -63,14 +63,15 @@ def _list_records(self, rtype=None, name=None, content=None):
 
         records = []
         for record in payload:
-            processed_record = {
-                'type': record['type'],
-                'name': self._full_name(record['name']),
-                'ttl': record['ttl'],
-                'content': record['content'],
-                'id': record['id']
-            }
-            records.append(processed_record)
+            if 'id' in record:
+                processed_record = {
+                    'id': record['id'],
+                    'type': record['type'],
+                    'name': self._full_name(record['name']),
+                    'ttl': record['ttl'],
+                    'content': record['content']
+                }
+                records.append(processed_record)
 
         if rtype:
             records = [record for record in records if record['type'] == rtype]


Test patch: