]> git.ipfire.org Git - oddments/ddns.git/blame - src/ddns/database.py
Hold back further updates after failed updates for a while
[oddments/ddns.git] / src / ddns / database.py
CommitLineData
37e24fbf
MT
1#!/usr/bin/python
2###############################################################################
3# #
4# ddns - A dynamic DNS client for IPFire #
5# Copyright (C) 2014 IPFire development team #
6# #
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. #
11# #
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. #
16# #
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/>. #
19# #
20###############################################################################
21
22import datetime
23import os.path
24import sqlite3
25
26# Initialize the logger.
27import logging
28logger = logging.getLogger("ddns.database")
29logger.propagate = 1
30
31class DDNSDatabase(object):
32 def __init__(self, core, path):
33 self.core = core
34
35 # Open the database file
36 self._db = self._open_database(path)
37
38 def __del__(self):
39 self._close_database()
40
41 def _open_database(self, path):
42 logger.debug("Opening database %s" % path)
43
44 exists = os.path.exists(path)
45
46 conn = sqlite3.connect(path, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
47 conn.isolation_level = None
48
49 if not exists:
50 logger.debug("Initialising database layout")
51 c = conn.cursor()
52 c.executescript("""
53 CREATE TABLE updates (
54 hostname TEXT NOT NULL,
55 status TEXT NOT NULL,
56 message TEXT,
57 timestamp timestamp NOT NULL
58 );
59
60 CREATE TABLE settings (
61 k TEXT NOT NULL,
62 v TEXT NOT NULL
63 );
64 """)
65 c.execute("INSERT INTO settings(k, v) VALUES(?, ?)", ("version", "1"))
66
67 return conn
68
69 def _close_database(self):
70 if self._db:
71 self._db_close()
72 self._db = None
73
74 def _execute(self, query, *parameters):
75 c = self._db.cursor()
76 try:
77 c.execute(query, parameters)
78 finally:
79 c.close()
80
81 def add_update(self, hostname, status, message=None):
82 self._execute("INSERT INTO updates(hostname, status, message, timestamp) \
83 VALUES(?, ?, ?, ?)", hostname, status, message, datetime.datetime.utcnow())
84
85 def log_success(self, hostname):
86 logger.debug("Logging successful update for %s" % hostname)
87
88 return self.add_update(hostname, "success")
89
90 def log_failure(self, hostname, exception):
91 if exception:
92 message = "%s: %s" % (exception.__class__.__name__, exception.reason)
93 else:
94 message = None
95
96 logger.debug("Logging failed update for %s: %s" % (hostname, message or ""))
97
98 return self.add_update(hostname, "failure", message=message)
99
112d3fb8
MT
100 def last_update(self, hostname, status=None):
101 """
102 Returns the timestamp of the last update (with the given status code).
103 """
37e24fbf
MT
104 c = self._db.cursor()
105
106 try:
112d3fb8
MT
107 if status:
108 c.execute("SELECT timestamp FROM updates WHERE hostname = ? AND status = ? \
109 ORDER BY timestamp DESC LIMIT 1", (hostname, status))
110 else:
111 c.execute("SELECT timestamp FROM updates WHERE hostname = ? \
112 ORDER BY timestamp DESC LIMIT 1", (hostname,))
113
114 for row in c:
115 return row[0]
116 finally:
117 c.close()
118
119 def last_update_status(self, hostname):
120 """
121 Returns the update status of the last update.
122 """
123 c = self._db.cursor()
124
125 try:
126 c.execute("SELECT status FROM updates WHERE hostname = ? \
127 ORDER BY timestamp DESC LIMIT 1", (hostname,))
128
129 for row in c:
130 return row[0]
131 finally:
132 c.close()
133
134 def last_update_failure_message(self, hostname):
135 """
136 Returns the reason string for the last failed update (if any).
137 """
138 c = self._db.cursor()
139
140 try:
141 c.execute("SELECT message FROM updates WHERE hostname = ? AND status = ? \
142 ORDER BY timestamp DESC LIMIT 1", (hostname, "failure"))
37e24fbf
MT
143
144 for row in c:
145 return row[0]
146 finally:
147 c.close()