]> git.llucax.com Git - software/pymin.git/blob - services/dns/handler.py
Use logging module to report errors in pymind.
[software/pymin.git] / services / dns / handler.py
1 # vim: set encoding=utf-8 et sw=4 sts=4 :
2
3 # TODO COMMENT
4 from os import path
5 from os import unlink
6 import logging ; log = logging.getLogger('pymin.services.dns')
7
8 from pymin.seqtools import Sequence
9 from pymin.dispatcher import handler, HandlerError, Handler
10 from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
11                                TransactionalHandler, ParametersHandler, \
12                                DictComposedSubHandler, DictSubHandler, call
13
14 __all__ = ('DnsHandler')
15
16
17 class Host(Sequence):
18     def __init__(self, name, ip):
19         self.name = name
20         self.ip = ip
21     def update(self, ip=None):
22         if ip is not None: self.ip = ip
23     def as_tuple(self):
24         return (self.name, self.ip)
25
26 class HostHandler(DictComposedSubHandler):
27     handler_help = u"Manage DNS hosts"
28     _comp_subhandler_cont = 'zones'
29     _comp_subhandler_attr = 'hosts'
30     _comp_subhandler_class = Host
31
32 class MailExchange(Sequence):
33     def __init__(self, mx, prio):
34         self.mx = mx
35         self.prio = prio
36     def update(self, prio=None):
37         if prio is not None: self.prio = prio
38     def as_tuple(self):
39         return (self.mx, self.prio)
40
41 class MailExchangeHandler(DictComposedSubHandler):
42     handler_help = u"Manage DNS mail exchangers (MX)"
43     _comp_subhandler_cont = 'zones'
44     _comp_subhandler_attr = 'mxs'
45     _comp_subhandler_class = MailExchange
46
47 class NameServer(Sequence):
48     def __init__(self, name):
49         self.name = name
50     def as_tuple(self):
51         return (self.name,)
52
53 class NameServerHandler(DictComposedSubHandler):
54     handler_help = u"Manage DNS name servers (NS)"
55     _comp_subhandler_cont = 'zones'
56     _comp_subhandler_attr = 'nss'
57     _comp_subhandler_class = NameServer
58
59 class Zone(Sequence):
60     def __init__(self, name):
61         self.name = name
62         self.hosts = dict()
63         self.mxs = dict()
64         self.nss = dict()
65         self._add = False
66         self._update = False
67         self._delete = False
68     def as_tuple(self):
69         return (self.name, self.hosts, self.mxs, self.nss)
70
71 class ZoneHandler(DictSubHandler):
72     handler_help = u"Manage DNS zones"
73     _cont_subhandler_attr = 'zones'
74     _cont_subhandler_class = Zone
75
76 class DnsHandler(Restorable, ConfigWriter, InitdHandler, TransactionalHandler,
77                  ParametersHandler):
78     r"""DnsHandler([pickle_dir[, config_dir]]) -> DnsHandler instance.
79
80     Handles DNS service commands for the dns program.
81
82     pickle_dir - Directory where to write the persistent configuration data.
83
84     config_dir - Directory where to store de generated configuration files.
85
86     Both defaults to the current working directory.
87     """
88
89     handler_help = u"Manage DNS service"
90
91     _initd_name = 'named'
92
93     _persistent_attrs = ('params', 'zones')
94
95     _restorable_defaults = dict(
96             zones = dict(),
97             params  = dict(
98                 isp_dns1 = '',
99                 isp_dns2 = '',
100                 bind_addr1 = '',
101                 bind_addr2 = ''
102             ),
103     )
104
105     _config_writer_files = ('named.conf', 'zoneX.zone')
106     _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
107
108     def __init__(self, pickle_dir='.', config_dir='.'):
109         r"Initialize DnsHandler object, see class documentation for details."
110         log.debug(u'DnsHandler(%r, %r)', pickle_dir, config_dir)
111         self._persistent_dir = pickle_dir
112         self._config_writer_cfg_dir = config_dir
113         self._update = False
114         self._config_build_templates()
115         InitdHandler.__init__(self)
116         self.host = HostHandler(self)
117         self.zone = ZoneHandler(self)
118         self.mx = MailExchangeHandler(self)
119         self.ns = NameServerHandler(self)
120
121     def _zone_filename(self, zone):
122         return zone.name + '.zone'
123
124     def _get_config_vars(self, config_file):
125         return dict(zones=self.zones.values(), **self.params)
126
127     def _write_config(self):
128         r"_write_config() -> None :: Generate all the configuration files."
129         log.debug(u'DnsHandler._write_config()')
130         delete_zones = list()
131         for a_zone in self.zones.values():
132             log.debug(u'DnsHandler._write_config: processing zone %s', a_zone)
133             if a_zone._update or a_zone._add:
134                 if not a_zone._add and self._service_running:
135                     log.debug(u'DnsHandler._write_config: zone updated and '
136                                 u'the service is running, freezing zone')
137                     call(('rndc', 'freeze', a_zone.name))
138                 vars = dict(
139                     zone = a_zone,
140                     hosts = a_zone.hosts.values(),
141                     mxs = a_zone.mxs.values(),
142                     nss = a_zone.nss.values()
143                 )
144                 self._write_single_config('zoneX.zone',
145                                             self._zone_filename(a_zone), vars)
146                 a_zone._update = False
147                 if not a_zone._add and self._service_running:
148                     log.debug(u'DnsHandler._write_config: unfreezing zone')
149                     call(('rndc', 'thaw', a_zone.name))
150                 else :
151                     self._update = True
152                     a_zone._add = False
153             if a_zone._delete:
154                 #borro el archivo .zone
155                 log.debug(u'DnsHandler._write_config: zone deleted, removing '
156                             u'the file %r', self._zone_filename(a_zone))
157                 try:
158                     self._update = True
159                     unlink(self._zone_filename(a_zone))
160                 except OSError:
161                     #la excepcion pude darse en caso que haga un add de una zona y
162                     #luego el del, como no hice commit, no se crea el archivo
163                     log.debug(u'DnsHandler._write_config: file not found')
164                     pass
165                 delete_zones.append(a_zone.name)
166         #borro las zonas
167         for z in delete_zones:
168             del self.zones[z]
169         #archivo general
170         if self._update:
171             self._write_single_config('named.conf')
172             self._update = False
173             return False # Do reload
174         return True # we don't need to reload
175
176     # HACK!!!!
177     def handle_timer(self):
178         log.debug(u'DnsHandler.handle_timer()')
179         import subprocess
180         p = subprocess.Popen(('pgrep', '-f', '/usr/sbin/named'),
181                                 stdout=subprocess.PIPE)
182         pid = p.communicate()[0]
183         if p.returncode == 0 and len(pid) > 0:
184             log.debug(u'DnsHandler.handle_timer: pid present, running')
185             self._service_running = True
186         else:
187             log.debug(u'DnsHandler.handle_timer: pid absent, NOT running')
188             self._service_running = False
189
190
191
192 if __name__ == '__main__':
193
194     logging.basicConfig(
195         level   = logging.DEBUG,
196         format  = '%(asctime)s %(levelname)-8s %(message)s',
197         datefmt = '%H:%M:%S',
198     )
199
200     dns = DnsHandler();
201
202     dns.set('isp_dns1','la_garcha.com')
203     dns.set('bind_addr1','localhost')
204     dns.zone.add('zona_loca.com')
205     #dns.zone.update('zona_loca.com','ns1.dominio.com')
206
207     dns.host.add('zona_loca.com','hostname_loco','192.168.0.23')
208     dns.host.update('zona_loca.com','hostname_loco','192.168.0.66')
209
210     dns.host.add('zona_loca.com','hostname_kuak','192.168.0.23')
211     dns.host.delete('zona_loca.com','hostname_kuak')
212
213     dns.host.add('zona_loca.com','hostname_kuang','192.168.0.24')
214     dns.host.add('zona_loca.com','hostname_chan','192.168.0.25')
215     dns.host.add('zona_loca.com','hostname_kaine','192.168.0.26')
216
217     dns.mx.add('zona_loca.com','mx1.sarasa.com',10)
218     dns.mx.update('zona_loca.com','mx1.sarasa.com',20)
219     dns.mx.add('zona_loca.com','mx2.sarasa.com',30)
220     dns.mx.add('zona_loca.com','mx3.sarasa.com',40)
221     dns.mx.delete('zona_loca.com','mx3.sarasa.com')
222
223     dns.ns.add('zona_loca.com','ns1.jua.com')
224     dns.ns.add('zona_loca.com','ns2.jua.com')
225     dns.ns.add('zona_loca.com','ns3.jua.com')
226     dns.ns.delete('zona_loca.com','ns3.jua.com')
227
228     dns.zone.add('zona_oscura')
229
230     dns.host.add('zona_oscura','hostname_a','192.168.0.24')
231     dns.host.add('zona_oscura','hostname_b','192.168.0.25')
232     dns.host.add('zona_oscura','hostname_c','192.168.0.26')
233
234     dns.zone.delete('zona_oscura')
235
236     dns.commit()
237
238     print 'ZONAS :', dns.zone.show()
239     for z in dns.zones:
240         print 'HOSTS from', z, ':', dns.host.show(z)
241
242     #test zone errors
243     #try:
244     #    dns.zone.update('zone-sarasa','lalal')
245     #except ZoneNotFoundError, inst:
246     #    print 'Error: ', inst
247
248     from pymin.services.util import ItemNotFoundError, ItemAlreadyExistsError, \
249                                     ContainerNotFoundError
250
251     try:
252         dns.zone.delete('zone-sarasa')
253     except ItemNotFoundError, inst:
254         print 'Error: ', inst
255
256     #try:
257     #    dns.zone.add('zona_loca.com','ns1.dom.com','ns2.dom.com')
258     #except ZoneAlreadyExistsError, inst:
259     #    print 'Error: ', inst
260
261
262     #test hosts errors
263     try:
264         dns.host.update('zone-sarasa','kuak','192.68')
265     except ContainerNotFoundError, inst:
266         print 'Error: ', inst
267
268     try:
269         dns.host.update('zona_loca.com','kuak','192.68')
270     except ItemNotFoundError, inst:
271         print 'Error: ', inst
272
273     try:
274         dns.host.delete('zone-sarasa','lala')
275     except ContainerNotFoundError, inst:
276         print 'Error: ', inst
277
278     try:
279         dns.host.delete('zona_loca.com','lala')
280     except ItemNotFoundError, inst:
281         print 'Error: ', inst
282
283     try:
284         dns.host.add('zona','hostname_loco','192.168.0.23')
285     except ContainerNotFoundError, inst:
286         print 'Error: ', inst
287
288     try:
289         dns.host.add('zona_loca.com','hostname_loco','192.168.0.23')
290     except ItemAlreadyExistsError, inst:
291         print 'Error: ', inst