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