]>
Commit | Line | Data |
---|---|---|
1336cd4e SS |
1 | ############################################################################### |
2 | # # | |
3 | # pyPDNS - A PDNS administration tool, written in pure python. # | |
9deb9e05 | 4 | # Copyright (C) 2012 IPFire development team # |
1336cd4e SS |
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 | # # | |
a8b3a646 SS |
21 | # Basic information about the database layout can be found here: # |
22 | # http://doc.powerdns.com/gsqlite.html # | |
23 | # # | |
1336cd4e SS |
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 | |
a7ceb5de | 30 | import sqlite3 |
1336cd4e | 31 | |
9253a8af SS |
32 | from errors import * |
33 | ||
1336cd4e SS |
34 | DB = "/var/lib/pdns/pdns.db" |
35 | ||
36 | # Create the primary DNS class. | |
1336cd4e | 37 | class DNS(object): |
a7ceb5de SS |
38 | """ |
39 | Primary DNS class. | |
259f19af | 40 | |
a7ceb5de SS |
41 | Uses the database class from imported database module. |
42 | Connects to the PDNS sqlite database. | |
43 | """ | |
1336cd4e | 44 | def __init__(self, db): |
a7ceb5de SS |
45 | # Try to connect to database or raise an exception. |
46 | try: | |
47 | self.db = database.Database(db) | |
48 | ||
49 | except sqlite3.OperationalError, e: | |
9253a8af | 50 | raise DatabaseException, "Could not open database: %s" % e |
a7ceb5de SS |
51 | |
52 | ||
1336cd4e SS |
53 | |
54 | # Get all configured domains. | |
55 | def get_domains(self): | |
259f19af SS |
56 | """ |
57 | Fetch all configured domains. | |
58 | """ | |
59 | # Create an empty list. | |
1336cd4e SS |
60 | domains = [] |
61 | ||
259f19af | 62 | # Add fetched domains to the previous created empty list. |
1336cd4e SS |
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): | |
259f19af SS |
71 | """ |
72 | Get a domain by a given name. | |
73 | """ | |
1336cd4e | 74 | row = self.db.get("SELECT id FROM domains WHERE name = ?", name) |
1336cd4e | 75 | |
9253a8af SS |
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) | |
d267bece | 81 | |
1336cd4e SS |
82 | |
83 | # Create Domain class. | |
1336cd4e | 84 | class Domain(object): |
a7ceb5de SS |
85 | """ |
86 | Domain class. | |
259f19af | 87 | |
a7ceb5de SS |
88 | Uses query method from database module to get requested information from domain. |
89 | The domain is specified by it's unique database id. | |
90 | """ | |
1336cd4e SS |
91 | def __init__(self, dns, domain_id): |
92 | self.dns = dns | |
93 | self.id = domain_id | |
94 | ||
9253a8af SS |
95 | self.__data = None |
96 | ||
1336cd4e SS |
97 | @property |
98 | def db(self): | |
99 | return self.dns.db | |
100 | ||
9253a8af SS |
101 | # Cache. |
102 | @property | |
103 | def data(self): | |
104 | if self.__data is None: | |
105 | self.__data = self.db.get("SELECT * FROM domains WHERE id = ?", self.id) | |
106 | assert self.__data | |
107 | ||
108 | return self.__data | |
109 | ||
1336cd4e SS |
110 | # Determine the name of the zone by a given id. |
111 | @property | |
112 | def name(self): | |
9253a8af | 113 | return self.data.name |
1336cd4e SS |
114 | |
115 | # Get information of the master nameserver from which the domain should be slaved. | |
116 | @property | |
117 | def master(self): | |
9253a8af | 118 | return self.data.master |
1336cd4e SS |
119 | |
120 | # Fetch data of the last check from the domain. | |
121 | @property | |
122 | def last_check(self): | |
9253a8af | 123 | return self.data.last_check |
1336cd4e SS |
124 | |
125 | # Get the type of the domain. | |
126 | @property | |
127 | def type(self): | |
9253a8af | 128 | return self.data.type |
1336cd4e SS |
129 | |
130 | # Get the last notified serial of a used master domain. | |
131 | @property | |
132 | def notified_serial(self): | |
9253a8af | 133 | return self.data.notified_serial |
1336cd4e SS |
134 | |
135 | # Gain if a certain host is a supermaster for a certain domain name. | |
136 | @property | |
137 | def account(self): | |
9253a8af | 138 | return self.data.account |
1336cd4e SS |
139 | |
140 | # Get all records from zone. | |
141 | @property | |
142 | def records(self): | |
259f19af SS |
143 | """ |
144 | Get all records from the zone. | |
145 | """ | |
259f19af | 146 | # Fetch records from zone and categorize them into their different record types. |
abccf64a SS |
147 | for row in self.db.query("SELECT id, type FROM records WHERE domain_id = ?", self.id): |
148 | if row.type == "SOA": | |
149 | record = SOARecord(self, row.id) | |
150 | elif row.type == "A": | |
151 | record = ARecord(self, row.id) | |
152 | else: | |
9253a8af | 153 | record = Record(self, row.id) |
1336cd4e | 154 | |
9253a8af | 155 | yield record |
1336cd4e | 156 | |
abccf64a SS |
157 | # Get records by a specified type. |
158 | def get_records_by_type(self, type): | |
159 | records = [] | |
160 | for record in self.records: | |
161 | if record.type == type: | |
162 | records.append(record) | |
163 | ||
164 | return records | |
165 | ||
166 | # Quick function to get the first SOA record from the domain. | |
167 | @property | |
168 | def SOA(self): | |
169 | records = self.get_records_by_type("SOA") | |
170 | if records: | |
171 | return records[0] | |
1336cd4e SS |
172 | |
173 | ||
174 | # Create class for domain records. | |
1336cd4e | 175 | class Record(object): |
a7ceb5de SS |
176 | """ |
177 | Record class | |
259f19af | 178 | |
a7ceb5de SS |
179 | It is used to get details about configured records. |
180 | The domain and record is's are specified by their unique database id's. | |
181 | """ | |
1336cd4e SS |
182 | def __init__(self, domain, record_id): |
183 | self.domain = domain | |
184 | self.id = record_id | |
185 | ||
9253a8af SS |
186 | # Cache. |
187 | self.__data = None | |
188 | ||
1336cd4e SS |
189 | @property |
190 | def db(self): | |
191 | return self.domain.db | |
192 | ||
9253a8af SS |
193 | @property |
194 | def data(self): | |
195 | if self.__data is None: | |
196 | self.__data = self.db.get("SELECT * FROM records WHERE id = ?", self.id) | |
197 | assert self.__data | |
198 | ||
199 | return self.__data | |
200 | ||
1336cd4e SS |
201 | # Determine the type of the record. |
202 | @property | |
203 | def type(self): | |
9253a8af | 204 | return self.data.type |
1336cd4e SS |
205 | |
206 | # Get the configured DNS name of the record. | |
207 | @property | |
208 | def dnsname(self): | |
9253a8af | 209 | return self.data.name |
1336cd4e SS |
210 | |
211 | ||
212 | # Fetch content like the address to which the record points. | |
213 | @property | |
214 | def content(self): | |
9253a8af | 215 | return self.data.content |
1336cd4e SS |
216 | |
217 | # Get the "Time to live" for the record. | |
218 | @property | |
219 | def ttl(self): | |
9253a8af | 220 | return self.data.ttl |
1336cd4e SS |
221 | |
222 | # Gain the configured record priority. | |
223 | @property | |
224 | def priority(self): | |
9253a8af | 225 | return self.data.prio |
1336cd4e SS |
226 | |
227 | # Get the change_date. | |
228 | @property | |
229 | def change_date(self): | |
9253a8af | 230 | return self.data.change_date |
1336cd4e SS |
231 | |
232 | # Fetch the ordername. | |
233 | @property | |
234 | def ordername(self): | |
9253a8af | 235 | return self.data.ordername |
1336cd4e | 236 | |
abccf64a | 237 | # Gain all information about records authentication. |
1336cd4e | 238 | @property |
abccf64a | 239 | def authentication(self): |
9253a8af | 240 | return self.data.auth |
abccf64a SS |
241 | |
242 | ||
243 | # Create an own class to deal with "SOA" records. | |
abccf64a | 244 | class SOARecord(Record): |
a7ceb5de SS |
245 | """ |
246 | SOA Record class. | |
247 | This is an own class to deal with "SOA" records. | |
259f19af | 248 | |
a7ceb5de SS |
249 | Uses splitt() to generate a list of the content string from the database. |
250 | Returns the requested entries. | |
251 | """ | |
abccf64a SS |
252 | def __init__(self, domain, record_id): |
253 | Record.__init__(self, domain, record_id) | |
254 | ||
255 | self.soa_attrs = self.content.split() | |
256 | ||
257 | # Check if the content from database is valid (It contains all 7 required information). | |
258 | if not len(self.soa_attrs) == 7: | |
a7ceb5de SS |
259 | raise InvalidRecordDataException, "Your SOA record \ |
260 | doesn't contain all required seven elements." | |
abccf64a SS |
261 | |
262 | # Primary NS - the domain name of the name server that was the original source of the data. | |
263 | @property | |
264 | def mname(self): | |
265 | return self.soa_attrs[0] | |
266 | ||
267 | # E-mail address of the person which is responsible for this domain. | |
268 | @property | |
269 | def email(self): | |
270 | return self.soa_attrs[1] | |
271 | ||
272 | # The serial which increases allways after a change on the domain has been made. | |
273 | @property | |
274 | def serial(self): | |
275 | return self.soa_attrs[2] | |
276 | ||
277 | # The number of seconds between the time that a secondary name server gets a copy of the domain. | |
278 | @property | |
279 | def refresh(self): | |
280 | return self.soa_attrs[3] | |
281 | ||
282 | # The number of seconds during the next refresh attempt if the previous fails. | |
283 | @property | |
284 | def retry(self): | |
285 | return self.soa_attrs[4] | |
286 | ||
287 | # The number of seconds that lets the secondary name server(s) know how long they can hold the information. | |
288 | @property | |
289 | def expire(self): | |
290 | return self.soa_attrs[5] | |
291 | ||
292 | # The number of seconds that the records in the domain are valid. | |
293 | @property | |
294 | def minimum(self): | |
295 | return self.soa_attrs[6] | |
296 | ||
297 | ||
298 | ||
299 | class ARecord(Record): | |
300 | pass |