]> git.ipfire.org Git - people/stevee/pypdns.git/blob - backend.py
Code rework of the CLI.
[people/stevee/pypdns.git] / backend.py
1 ###############################################################################
2 # #
3 # pyPDNS - A PDNS administration tool, written in pure python. #
4 # Copyright (C) 2012 IPFire development team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 ###############################################################################
20 # #
21 # Basic information about the database layout can be found here: #
22 # http://doc.powerdns.com/gsqlite.html #
23 # #
24 # More details about the database tables and fields can be found here: #
25 # http://wiki.powerdns.com/trac/wiki/fields #
26 # #
27 ###############################################################################
28
29 import database
30 import sqlite3
31
32 from errors import *
33
34 DB = "/var/lib/pdns/pdns.db"
35
36 # Create the primary DNS class.
37 class DNS(object):
38 """
39 Primary DNS class.
40
41 Uses the database class from imported database module.
42 Connects to the PDNS sqlite database.
43 """
44 def __init__(self, db):
45 # Try to connect to database or raise an exception.
46 try:
47 self.db = database.Database(db)
48
49 except sqlite3.OperationalError, e:
50 raise DatabaseException, "Could not open database: %s" % e
51
52
53
54 # Get all configured domains.
55 def get_domains(self):
56 """
57 Fetch all configured domains.
58 """
59 # Create an empty list.
60 domains = []
61
62 # Add fetched domains to the previous created empty list.
63 for row in self.db.query("SELECT id FROM domains"):
64 domain = Domain(self, row.id)
65 domains.append(domain)
66
67 return domains
68
69 # Get a domain by it's name.
70 def get_domain(self, name):
71 """
72 Get a domain by a given name.
73 """
74 row = self.db.get("SELECT id FROM domains WHERE name = ?", name)
75
76 # Check if an id has been returned from database or return None.
77 if not row:
78 return None
79
80 return Domain(self, row.id)
81
82
83 # Create Domain class.
84 class Domain(object):
85 """
86 Domain class.
87
88 Uses query method from database module to get requested information
89 from domain.
90
91 The domain is specified by it's unique database id.
92 """
93 def __init__(self, dns, domain_id):
94 self.dns = dns
95 self.id = domain_id
96
97 self.__data = None
98
99 @property
100 def db(self):
101 return self.dns.db
102
103 # Cache.
104 @property
105 def data(self):
106 if self.__data is None:
107 self.__data = self.db.get("SELECT * FROM domains \
108 WHERE id = ?", self.id)
109 assert self.__data
110
111 return self.__data
112
113 # Determine the name of the zone by a given id.
114 @property
115 def name(self):
116 return self.data.name
117
118 # Get information of the master nameserver from which the domain should
119 # be slaved.
120 @property
121 def master(self):
122 return self.data.master
123
124 # Fetch data of the last check from the domain.
125 @property
126 def last_check(self):
127 return self.data.last_check
128
129 # Get the type of the domain.
130 @property
131 def type(self):
132 return self.data.type
133
134 # Get the last notified serial of a used master domain.
135 @property
136 def notified_serial(self):
137 return self.data.notified_serial
138
139 # Gain if a certain host is a supermaster for a certain domain name.
140 @property
141 def account(self):
142 return self.data.account
143
144 # Get count of records of a zone. Return true if there is at least one
145 # or false.
146 def has_records(self):
147 count = self.db.get("SELECT COUNT(*) AS num FROM records \
148 WHERE domain_id = ?", self.id)
149
150 if count.num > 0:
151 return True
152
153 return False
154
155 # Get all records from zone.
156 @property
157 def records(self):
158 """
159 Get all records from the zone.
160 """
161 # Fetch records from zone and categorize them into their
162 # different record types.
163 for row in self.db.query("SELECT id, type FROM records \
164 WHERE domain_id = ?", self.id):
165
166 if row.type == "SOA":
167 record = SOARecord(self, row.id)
168 elif row.type == "A":
169 record = ARecord(self, row.id)
170 else:
171 record = Record(self, row.id)
172
173 yield record
174
175 # Get records by a specified type.
176 def get_records_by_type(self, type):
177 records = []
178 for record in self.records:
179 if record.type == type:
180 records.append(record)
181
182 return records
183
184 # Quick function to get the first SOA record from the domain.
185 @property
186 def SOA(self):
187 records = self.get_records_by_type("SOA")
188 if records:
189 return records[0]
190
191
192 # Create class for domain records.
193 class Record(object):
194 """
195 Record class
196
197 It is used to get details about configured records.
198 The domain and record is's are specified by their unique database id's.
199 """
200 def __init__(self, domain, record_id):
201 self.domain = domain
202 self.id = record_id
203
204 # Cache.
205 self.__data = None
206
207 @property
208 def db(self):
209 return self.domain.db
210
211 @property
212 def data(self):
213 if self.__data is None:
214 self.__data = self.db.get("SELECT * FROM records \
215 WHERE id = ?", self.id)
216 assert self.__data
217
218 return self.__data
219
220 # Determine the type of the record.
221 @property
222 def type(self):
223 return self.data.type
224
225 # Get the configured DNS name of the record.
226 @property
227 def dnsname(self):
228 return self.data.name
229
230
231 # Fetch content like the address to which the record points.
232 @property
233 def content(self):
234 return self.data.content
235
236 # Get the "Time to live" for the record.
237 @property
238 def ttl(self):
239 return self.data.ttl
240
241 # Gain the configured record priority.
242 @property
243 def priority(self):
244 return self.data.prio
245
246 # Get the change_date.
247 @property
248 def change_date(self):
249 return self.data.change_date
250
251 # Fetch the ordername.
252 @property
253 def ordername(self):
254 return self.data.ordername
255
256 # Gain all information about records authentication.
257 @property
258 def authentication(self):
259 return self.data.auth
260
261
262 # Create an own class to deal with "SOA" records.
263 class SOARecord(Record):
264 """
265 SOA Record class.
266 This is an own class to deal with "SOA" records.
267
268 Uses splitt() to generate a list of the content string from the
269 database.
270
271 Returns the requested entries.
272 """
273 def __init__(self, domain, record_id):
274 Record.__init__(self, domain, record_id)
275
276 self.soa_attrs = self.content.split()
277
278 # Check if the content from database is valid.
279 # (It contains all 7 required information)
280 if not len(self.soa_attrs) == 7:
281 raise InvalidRecordDataException, "Your SOA record \
282 doesn't contain all required seven elements."
283
284 # Primary NS - the domain name of the name server that was the
285 # original source of the data.
286 @property
287 def mname(self):
288 return self.soa_attrs[0]
289
290 # E-mail address of the person which is responsible for this domain.
291 @property
292 def email(self):
293 return self.soa_attrs[1]
294
295 # The serial which increases allways after a change on the domain has
296 # been made.
297 @property
298 def serial(self):
299 return self.soa_attrs[2]
300
301 # The number of seconds between the time that a secondary name server
302 # gets a copy of the domain.
303 @property
304 def refresh(self):
305 return self.soa_attrs[3]
306
307 # The number of seconds during the next refresh attempt if the
308 # previous fails.
309 @property
310 def retry(self):
311 return self.soa_attrs[4]
312
313 # The number of seconds that lets the secondary name server(s) know
314 # how long they can hold the information.
315 @property
316 def expire(self):
317 return self.soa_attrs[5]
318
319 # The number of seconds that the records in the domain are valid.
320 @property
321 def minimum(self):
322 return self.soa_attrs[6]
323
324
325
326 class ARecord(Record):
327 pass