]>
git.ipfire.org Git - ddns.git/blob - src/ddns/database.py
2 ###############################################################################
4 # ddns - A dynamic DNS client for IPFire #
5 # Copyright (C) 2014 IPFire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
26 # Initialize the logger.
28 logger
= logging
.getLogger("ddns.database")
31 class DDNSDatabase(object):
32 def __init__(self
, core
, path
):
36 # We won't open the connection to the database directly
37 # so that we do not do it unnecessarily.
41 self
._close
_database
()
43 def _open_database(self
, path
):
44 logger
.debug("Opening database %s" % path
)
46 exists
= os
.path
.exists(path
)
48 conn
= sqlite3
.connect(path
, detect_types
=sqlite3
.PARSE_DECLTYPES|sqlite3
.PARSE_COLNAMES
)
49 conn
.isolation_level
= None
51 if not exists
and self
.is_writable():
52 logger
.debug("Initialising database layout")
55 CREATE TABLE updates (
56 hostname TEXT NOT NULL,
59 timestamp timestamp NOT NULL
62 CREATE TABLE settings (
67 CREATE INDEX idx_updates_hostname ON updates(hostname);
69 c
.execute("INSERT INTO settings(k, v) VALUES(?, ?)", ("version", "1"))
73 def is_writable(self
):
74 # Check if the database file exists and is writable.
75 ret
= os
.access(self
.path
, os
.W_OK
)
79 # If not, we check if we are able to write to the directory.
80 # In that case the database file will be created in _open_database().
81 return os
.access(os
.path
.dirname(self
.path
), os
.W_OK
)
83 def _close_database(self
):
88 def _execute(self
, query
, *parameters
):
90 self
._db
= self
._open
_database
(self
.path
)
94 c
.execute(query
, parameters
)
98 def add_update(self
, hostname
, status
, message
=None):
99 if not self
.is_writable():
100 logger
.warning("Could not log any updates because the database is not writable")
103 self
._execute
("INSERT INTO updates(hostname, status, message, timestamp) \
104 VALUES(?, ?, ?, ?)", hostname
, status
, message
, datetime
.datetime
.utcnow())
106 def log_success(self
, hostname
):
107 logger
.debug("Logging successful update for %s" % hostname
)
109 return self
.add_update(hostname
, "success")
111 def log_failure(self
, hostname
, exception
):
113 message
= "%s: %s" % (exception
.__class
__.__name
__, exception
.reason
)
117 logger
.debug("Logging failed update for %s: %s" % (hostname
, message
or ""))
119 return self
.add_update(hostname
, "failure", message
=message
)
121 def last_update(self
, hostname
, status
=None):
123 Returns the timestamp of the last update (with the given status code).
125 c
= self
._db
.cursor()
129 c
.execute("SELECT timestamp FROM updates WHERE hostname = ? AND status = ? \
130 ORDER BY timestamp DESC LIMIT 1", (hostname
, status
))
132 c
.execute("SELECT timestamp FROM updates WHERE hostname = ? \
133 ORDER BY timestamp DESC LIMIT 1", (hostname
,))
140 def last_update_status(self
, hostname
):
142 Returns the update status of the last update.
144 c
= self
._db
.cursor()
147 c
.execute("SELECT status FROM updates WHERE hostname = ? \
148 ORDER BY timestamp DESC LIMIT 1", (hostname
,))
155 def last_update_failure_message(self
, hostname
):
157 Returns the reason string for the last failed update (if any).
159 c
= self
._db
.cursor()
162 c
.execute("SELECT message FROM updates WHERE hostname = ? AND status = ? \
163 ORDER BY timestamp DESC LIMIT 1", (hostname
, "failure"))