]>
Commit | Line | Data |
---|---|---|
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 |