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