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