Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ccbc99b

Browse files
authoredApr 30, 2021
Merge pull request #6 from vesellov/master
automatically reconnect to the EPP backend
2 parents 8f5b7bd + 7790350 commit ccbc99b

File tree

6 files changed

+530
-257
lines changed

6 files changed

+530
-257
lines changed
 

‎src/epp/commands/domain.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
single = "<domain:name>%s</domain:name>"
22

33

4-
single_contact = '<domain:contact type="%(type)s">%(id)s</domain:contact>'
4+
single_contact1 = '<domain:contact type="%(type)s">%(id)s</domain:contact>'
55

6+
single_contact2 = ' <domain:contact type="%(type)s">%(id)s</domain:contact>'
67

7-
single_registrant = "<domain:registrant>%s</domain:registrant>"
88

9+
single_contact_update = '<domain:contact type="%(type)s">%(id)s</domain:contact>'
910

10-
single_nameserver = " <domain:ns><domain:hostObj>%s</domain:hostObj></domain:ns>"
1111

12+
single_registrant = """
13+
<domain:registrant>%s</domain:registrant>"""
1214

13-
auth_info = "<domain:authInfo><domain:pw>%s</domain:pw></domain:authInfo>"
15+
16+
single_nameserver = " <domain:ns><domain:hostObj>%s</domain:hostObj></domain:ns>"
17+
18+
19+
auth_info = """ <domain:authInfo><domain:pw>%s</domain:pw></domain:authInfo>
20+
"""
21+
22+
auth_info2 = """ <domain:authInfo><domain:pw>%s</domain:pw></domain:authInfo>
23+
"""
1424

1525

1626
period = '<domain:period unit="%(units)s">%(value)s</domain:period>'
@@ -35,8 +45,7 @@
3545
<info>
3646
<domain:info xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
3747
<domain:name hosts="all">%(domain_name)s</domain:name>
38-
%(auth_info)s
39-
</domain:info>
48+
%(auth_info)s</domain:info>
4049
</info>
4150
<clTRID>%(cltrid)s</clTRID>
4251
</command>
@@ -55,8 +64,7 @@
5564
%(contact_admin)s
5665
%(contact_billing)s
5766
%(contact_tech)s
58-
%(auth_info)s
59-
</domain:create>
67+
%(auth_info)s</domain:create>
6068
</create>
6169
<clTRID>%(cltrid)s</clTRID>
6270
</command>
@@ -85,20 +93,17 @@
8593
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
8694
<domain:name>%(domain_name)s</domain:name>
8795
<domain:add>
88-
%(add_nameservers)s
89-
%(add_contacts)s
96+
%(add_nameservers)s
97+
%(add_contacts)s
9098
</domain:add>
9199
<domain:rem>
92-
%(remove_nameservers)s
93-
%(remove_contacts)s
100+
%(remove_nameservers)s
101+
%(remove_contacts)s
94102
</domain:rem>
95-
<domain:chg>
96-
%(change_registrant)s
97-
%(auth_info)s
98-
</domain:chg>
103+
<domain:chg>%(change_registrant)s
104+
%(auth_info)s</domain:chg>
99105
</domain:update>
100-
</update>
101-
%(restore_extension)s
106+
</update>%(restore_extension)s
102107
<clTRID>%(cltrid)s</clTRID>
103108
</command>
104109
</epp>"""
@@ -109,8 +114,7 @@
109114
<rgp:update xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0">
110115
<rgp:restore op="request"></rgp:restore>
111116
</rgp:update>
112-
</extension>
113-
"""
117+
</extension>"""
114118

115119

116120
restore_report_extension = """
@@ -129,8 +133,7 @@
129133
</rgp:report>
130134
</rgp:restore>
131135
</rgp:update>
132-
</extension>
133-
"""
136+
</extension>"""
134137

135138

136139
transfer = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
@@ -139,9 +142,8 @@
139142
<transfer op="request">
140143
<domain:transfer xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
141144
<domain:name>%(domain_name)s</domain:name>
142-
%(auth_info)s
143145
%(period)s
144-
</domain:transfer>
146+
%(auth_info)s</domain:transfer>
145147
</transfer>
146148
<clTRID>%(cltrid)s</clTRID>
147149
</command>

‎src/epp/epp_client.py

Lines changed: 109 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ def int_to_net(value, format_32):
4949

5050
#------------------------------------------------------------------------------
5151

52+
class EPPConnectionAlreadyClosedError(Exception):
53+
pass
54+
55+
56+
class EPPResponseEmptyError(Exception):
57+
pass
58+
59+
#------------------------------------------------------------------------------
60+
61+
5262
class EPPConnection:
5363

5464
def __init__(self, host, port, user, password, verbose=False, raise_errors=False):
@@ -63,7 +73,7 @@ def __init__(self, host, port, user, password, verbose=False, raise_errors=False
6373
self.verbose = verbose
6474
self.raise_errors = raise_errors
6575

66-
def open(self, timeout=2):
76+
def open(self, timeout=10):
6777
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
6878
self.socket.settimeout(timeout)
6979
try:
@@ -116,7 +126,7 @@ def close(self):
116126
if self.raise_errors:
117127
raise exc
118128
if self.verbose:
119-
logger.exception('connection was not properly connected')
129+
logger.exception('connection was not properly closed')
120130
return False
121131
if self.verbose:
122132
logger.debug('EPP connection closed')
@@ -129,17 +139,20 @@ def read(self):
129139
if length:
130140
i = int_from_net(length, self.format_32) - 4
131141
ret = self.ssl.read(i)
142+
except (ssl.SSLEOFError, ssl.SSLZeroReturnError, ) as exc:
143+
if self.verbose:
144+
logger.exception('EPP connection already closed')
145+
raise EPPConnectionAlreadyClosedError(exc)
132146
except Exception as exc:
133147
if self.raise_errors:
134148
raise exc
135149
if self.verbose:
136150
logger.exception('failed to receive EPP response')
137151
return None
138152
if ret is None:
139-
if self.raise_errors:
140-
raise Exception('nothing was received from EPP connection')
141153
if self.verbose:
142154
logger.error('nothing was received from EPP connection')
155+
raise EPPResponseEmptyError()
143156
return ret
144157

145158
def write(self, xml):
@@ -150,6 +163,10 @@ def write(self, xml):
150163
try:
151164
self.ssl.send(length)
152165
ret = self.ssl.send((epp_as_string + "\r\n").encode())
166+
except (ssl.SSLEOFError, ssl.SSLZeroReturnError, ) as exc:
167+
if self.verbose:
168+
logger.exception('EPP connection already closed')
169+
raise EPPConnectionAlreadyClosedError(exc)
153170
except Exception as exc:
154171
if self.raise_errors:
155172
raise exc
@@ -178,9 +195,9 @@ def call(self, cmd, soup=False):
178195
raise exc
179196
if self.verbose:
180197
logger.exception('failed to read EPP response command')
181-
return None
198+
return ''
182199
return soup
183-
return raw
200+
return raw or ''
184201

185202
#------------------------------------------------------------------------------
186203

@@ -235,88 +252,23 @@ def poll_ack(self, msg_id):
235252
msgid=msg_id,
236253
))
237254

238-
def domain_check(self, domain_name):
239-
return self.call(cmd=commands.domain.check % dict(
240-
cltrid=make_cltrid(),
241-
domain_names=commands.domain.single % domain_name,
242-
))
243-
244-
def domain_check_multiple(self, domains_list):
245-
return self.call(cmd=commands.domain.check % dict(
246-
cltrid=make_cltrid(),
247-
domain_names='\n'.join([
248-
commands.domain.single % d for d in domains_list
249-
]),
250-
))
251-
252-
def domain_info(self, domain_name, auth_info=None):
253-
return self.call(cmd=commands.domain.info % dict(
254-
cltrid=make_cltrid(),
255-
domain_name=domain_name,
256-
auth_info='' if not auth_info else commands.domain.auth_info % auth_info,
257-
))
258-
259-
def domain_create(self, domain_name, registrant, nameservers=[], period=1, period_units='y',
260-
contact_admin=None, contact_billing=None, contact_tech=None, auth_info=None):
261-
return self.call(cmd=commands.domain.create % dict(
262-
cltrid=make_cltrid(),
263-
domain_name=domain_name,
264-
registrant=registrant,
265-
nameservers='\n'.join([
266-
commands.domain.single_nameserver % ns for ns in nameservers
267-
]),
268-
period='' if period is None else commands.domain.period % dict(value=period, units=period_units or 'y'),
269-
contact_admin='' if not contact_admin else commands.domain.single_contact % dict(type='admin', id=contact_admin),
270-
contact_billing='' if not contact_billing else commands.domain.single_contact % dict(type='billing', id=contact_billing),
271-
contact_tech='' if not contact_tech else commands.domain.single_contact % dict(type='tech', id=contact_tech),
272-
auth_info='' if not auth_info else commands.domain.auth_info % auth_info,
273-
))
274-
275-
def domain_renew(self, domain_name, cur_exp_date, period=1, period_units='y'):
276-
return self.call(cmd=commands.domain.renew % dict(
255+
def host_check(self, nameservers_list):
256+
return self.call(cmd=commands.nameserver.check % dict(
277257
cltrid=make_cltrid(),
278-
domain_name=domain_name,
279-
cur_exp_date=cur_exp_date,
280-
period='' if period is None else commands.domain.period % dict(value=period, units=period_units or 'y'),
258+
nameservers='\n'.join([commands.nameserver.single % ns for ns in nameservers_list]),
281259
))
282260

283-
def domain_update(self, domain_name, auth_info=None,
284-
add_nameservers=[], remove_nameservers=[],
285-
add_contacts=[], remove_contacts=[], change_registrant=None,
286-
rgp_restore=None, rgp_restore_report=None):
287-
restore_extension = ''
288-
if rgp_restore:
289-
restore_extension = commands.domain.restore_request_extension
290-
if rgp_restore_report:
291-
restore_extension = commands.domain.restore_report_extension % rgp_restore_report
292-
return self.call(cmd=commands.domain.update % dict(
261+
def host_info(self, nameserver):
262+
return self.call(cmd=commands.nameserver.info % dict(
293263
cltrid=make_cltrid(),
294-
domain_name=domain_name,
295-
auth_info='' if not auth_info else commands.domain.auth_info % auth_info,
296-
add_nameservers='\n'.join([
297-
commands.domain.single_nameserver % ns for ns in add_nameservers
298-
]),
299-
remove_nameservers='\n'.join([
300-
commands.domain.single_nameserver % ns for ns in remove_nameservers
301-
]),
302-
add_contacts='\n'.join([
303-
commands.domain.single_contact % c for c in add_contacts
304-
]),
305-
remove_contacts='\n'.join([
306-
commands.domain.single_contact % c for c in remove_contacts
307-
]),
308-
change_registrant='' if not change_registrant else (
309-
commands.domain.single_registrant % change_registrant
310-
),
311-
restore_extension=restore_extension,
264+
nameserver=nameserver,
312265
))
313266

314-
def domain_transfer(self, domain_name, auth_info=None, period=None, period_units=None):
315-
return self.call(cmd=commands.domain.transfer % dict(
267+
def host_create(self, nameserver, ip_addresses_list):
268+
return self.call(cmd=commands.nameserver.create % dict(
316269
cltrid=make_cltrid(),
317-
domain_name=domain_name,
318-
auth_info='' if not auth_info else commands.domain.auth_info % auth_info,
319-
period='' if period is None else commands.domain.period % dict(value=period, units=period_units or 'y'),
270+
nameserver=nameserver,
271+
ip_addresses='\n'.join([commands.nameserver.ip_address % ipaddr for ipaddr in ip_addresses_list])
320272
))
321273

322274
def contact_check(self, contact):
@@ -397,26 +349,91 @@ def contact_update(self, contact_id, voice=None, fax=None, email=None, contacts=
397349
))
398350

399351
def contact_delete(self, contact_id):
400-
return self.call(cmd=commands.contact.info % dict(
352+
return self.call(cmd=commands.contact.delete % dict(
401353
cltrid=make_cltrid(),
402354
contact_id=contact_id,
403355
))
404356

405-
def host_check(self, nameservers_list):
406-
return self.call(cmd=commands.nameserver.check % dict(
357+
def domain_check(self, domain_name):
358+
return self.call(cmd=commands.domain.check % dict(
407359
cltrid=make_cltrid(),
408-
nameservers='\n'.join([commands.nameserver.single % ns for ns in nameservers_list]),
360+
domain_names=commands.domain.single % domain_name,
409361
))
410362

411-
def host_info(self, nameserver):
412-
return self.call(cmd=commands.nameserver.info % dict(
363+
def domain_check_multiple(self, domains_list):
364+
return self.call(cmd=commands.domain.check % dict(
413365
cltrid=make_cltrid(),
414-
nameserver=nameserver,
366+
domain_names='\n'.join([
367+
commands.domain.single % d for d in domains_list
368+
]),
415369
))
416370

417-
def host_create(self, nameserver, ip_addresses_list):
418-
return self.call(cmd=commands.nameserver.create % dict(
371+
def domain_info(self, domain_name, auth_info=None):
372+
return self.call(cmd=commands.domain.info % dict(
419373
cltrid=make_cltrid(),
420-
nameserver=nameserver,
421-
ip_addresses='\n'.join([commands.nameserver.ip_address % ipaddr for ipaddr in ip_addresses_list])
374+
domain_name=domain_name,
375+
auth_info='' if not auth_info else commands.domain.auth_info % auth_info,
376+
))
377+
378+
def domain_create(self, domain_name, registrant, nameservers=[], period=1, period_units='y',
379+
contact_admin=None, contact_billing=None, contact_tech=None, auth_info=None):
380+
return self.call(cmd=commands.domain.create % dict(
381+
cltrid=make_cltrid(),
382+
domain_name=domain_name,
383+
registrant=registrant,
384+
nameservers='\n'.join([
385+
commands.domain.single_nameserver % ns for ns in nameservers
386+
]),
387+
period='' if period is None else commands.domain.period % dict(value=period, units=period_units or 'y'),
388+
contact_admin='' if not contact_admin else commands.domain.single_contact1 % dict(type='admin', id=contact_admin),
389+
contact_billing='' if not contact_billing else commands.domain.single_contact1 % dict(type='billing', id=contact_billing),
390+
contact_tech='' if not contact_tech else commands.domain.single_contact1 % dict(type='tech', id=contact_tech),
391+
auth_info='' if not auth_info else commands.domain.auth_info % auth_info,
392+
))
393+
394+
def domain_renew(self, domain_name, cur_exp_date, period=1, period_units='y'):
395+
return self.call(cmd=commands.domain.renew % dict(
396+
cltrid=make_cltrid(),
397+
domain_name=domain_name,
398+
cur_exp_date=cur_exp_date,
399+
period='' if period is None else commands.domain.period % dict(value=period, units=period_units or 'y'),
400+
))
401+
402+
def domain_update(self, domain_name, auth_info=None,
403+
add_nameservers=[], remove_nameservers=[],
404+
add_contacts=[], remove_contacts=[], change_registrant=None,
405+
rgp_restore=None, rgp_restore_report=None):
406+
restore_extension = ''
407+
if rgp_restore:
408+
restore_extension = commands.domain.restore_request_extension
409+
if rgp_restore_report:
410+
restore_extension = commands.domain.restore_report_extension % rgp_restore_report
411+
return self.call(cmd=commands.domain.update % dict(
412+
cltrid=make_cltrid(),
413+
domain_name=domain_name,
414+
auth_info='' if not auth_info else commands.domain.auth_info2 % auth_info,
415+
add_nameservers='\n'.join([
416+
commands.domain.single_nameserver % ns for ns in add_nameservers
417+
]),
418+
remove_nameservers='\n'.join([
419+
commands.domain.single_nameserver % ns for ns in remove_nameservers
420+
]),
421+
add_contacts='\n'.join([
422+
commands.domain.single_contact2 % c for c in add_contacts
423+
]),
424+
remove_contacts='\n'.join([
425+
commands.domain.single_contact2 % c for c in remove_contacts
426+
]),
427+
change_registrant='' if not change_registrant else (
428+
commands.domain.single_registrant % change_registrant
429+
),
430+
restore_extension=restore_extension,
431+
))
432+
433+
def domain_transfer(self, domain_name, auth_info=None, period=None, period_units=None):
434+
return self.call(cmd=commands.domain.transfer % dict(
435+
cltrid=make_cltrid(),
436+
domain_name=domain_name,
437+
auth_info='' if not auth_info else commands.domain.auth_info % auth_info,
438+
period='' if period is None else commands.domain.period % dict(value=period, units=period_units or 'y'),
422439
))

0 commit comments

Comments
 (0)
Please sign in to comment.