]> git.decadent.org.uk Git - dak.git/blob - dak/dakdb/update66.py
10c1583b8f4b005010e0cd7982f2ea586345ea6c
[dak.git] / dak / dakdb / update66.py
1 #!/usr/bin/env python
2 # coding=utf8
3
4 """
5 Add audit schema and initial package table and triggers
6
7 @contact: Debian FTP Master <ftpmaster@debian.org>
8 @copyright: 2011 Mark Hymers <mhy@debian.org>
9 @license: GNU General Public License version 2 or later
10 """
11
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
16
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
26 ################################################################################
27
28 import psycopg2
29 from daklib.dak_exceptions import DBUpdateError
30 from daklib.config import Config
31
32 ################################################################################
33 def do_update(self):
34     """
35     Add audit schema and initial package table and triggers
36     """
37     print __doc__
38     try:
39         c = self.db.cursor()
40
41         c.execute("CREATE SCHEMA audit");
42         c.execute("GRANT USAGE on SCHEMA audit TO public")
43         c.execute("GRANT USAGE on SCHEMA audit TO ftpteam")
44         c.execute("GRANT USAGE on SCHEMA audit TO ftpmaster")
45
46         c.execute("""CREATE TABLE audit.package_changes (
47    changedate TIMESTAMP NOT NULL DEFAULT now(),
48    package TEXT NOT NULL,
49    version DEBVERSION NOT NULL,
50    architecture TEXT NOT NULL,
51    suite TEXT NOT NULL,
52    event TEXT NOT NULL,
53    priority TEXT,
54    component TEXT,
55    section TEXT
56 )""")
57
58         c.execute("GRANT INSERT ON audit.package_changes TO dak")
59         c.execute("GRANT SELECT ON audit.package_changes TO PUBLIC")
60
61         c.execute("""CREATE OR REPLACE FUNCTION trigger_binsrc_assoc_update() RETURNS TRIGGER AS $$
62 tablename = TD["table_name"]
63 event = TD["event"]
64
65 # We only handle bin/src_associations in this trigger
66 if tablename not in ['bin_associations', 'src_associations']:
67     return None
68
69 if event == 'INSERT':
70     dat = TD['new']
71     pkg_event = 'I'
72 elif event == 'DELETE':
73     dat = TD['old']
74     pkg_event = 'D'
75 else:
76     # We don't handle other changes on these tables
77     return None
78
79 # Find suite information
80 suite_info = plpy.execute(plpy.prepare("SELECT suite_name FROM suite WHERE id = $1", ["int"]), [dat["suite"]])
81 # Couldn't find suite
82 if len(suite_info) != 1:
83     return None
84 suite_name = suite_info[0]['suite_name']
85
86 # Some defaults in case we can't find the overrides
87 component = ""
88 section = ""
89 priority = ""
90
91 if tablename == 'bin_associations':
92     pkg_info = plpy.execute(plpy.prepare("SELECT package, version, arch_string FROM binaries LEFT JOIN architecture ON (architecture.id = binaries.architecture) WHERE binaries.id = $1", ["int"]), [dat["bin"]])
93
94     # Couldn't find binary: shouldn't happen, but be careful
95     if len(pkg_info) != 1:
96         return None
97
98     package = pkg_info[0]['package']
99     version = pkg_info[0]['version']
100     arch = pkg_info[0]['arch_string']
101
102     bin_override_q = '''SELECT component.name AS component,
103                              priority.priority AS priority,
104                              section.section AS section,
105                              override_type.type
106                         FROM override
107                    LEFT JOIN override_type ON (override.type = override_type.id)
108                    LEFT JOIN priority ON (priority.id = override.priority)
109                    LEFT JOIN section ON (section.id = override.section)
110                    LEFT JOIN component ON (override.component = component.id)
111                    LEFT JOIN suite ON (suite.id = override.suite)
112                        WHERE override_type.type != 'dsc'
113                          AND package = $1
114                          AND suite.id = $2'''
115
116     bin_overrides = plpy.execute(plpy.prepare(bin_override_q, ["text", "int"]), [package, dat["suite"]])
117     # Only fill in the values if we find the unique override
118     if len(bin_overrides) == 1:
119         component = bin_overrides[0]['component']
120         priority = bin_overrides[0]['priority']
121         section = bin_overrides[0]['section']
122
123 elif tablename == 'src_associations':
124     pkg_info = plpy.execute(plpy.prepare("SELECT source, version FROM source WHERE source.id = $1", ["int"]), [dat["source"]])
125
126     # Couldn't find source: shouldn't happen, but be careful
127     if len(pkg_info) != 1:
128         return None
129
130     package = pkg_info[0]['source']
131     version = pkg_info[0]['version']
132     arch = 'source'
133
134     src_override_q = '''SELECT component.name AS component,
135                              priority.priority AS priority,
136                              section.section AS section,
137                              override_type.type
138                         FROM override
139                    LEFT JOIN override_type ON (override.type = override_type.id)
140                    LEFT JOIN priority ON (priority.id = override.priority)
141                    LEFT JOIN section ON (section.id = override.section)
142                    LEFT JOIN component ON (override.component = component.id)
143                    LEFT JOIN suite ON (suite.id = override.suite)
144                        WHERE override_type.type = 'dsc'
145                          AND package = $1
146                          AND suite.id = $2'''
147
148     src_overrides = plpy.execute(plpy.prepare(src_override_q, ["text", "int"]), [package, dat["suite"]])
149     # Only fill in the values if we find the unique override
150     if len(src_overrides) == 1:
151         component = src_overrides[0]['component']
152         priority = src_overrides[0]['priority']
153         section = src_overrides[0]['section']
154
155 # Insert the audit row
156 plpy.execute(plpy.prepare("INSERT INTO audit.package_changes (package, version, architecture, suite, event, priority, component, section) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
157              ["text", "text", "text", "text", "text", "text", "text", "text"]),
158              [package, version, arch, suite_name, pkg_event, priority, component, section])
159
160 $$ LANGUAGE plpythonu VOLATILE SECURITY DEFINER""")
161
162         c.execute("""CREATE OR REPLACE FUNCTION trigger_override_update() RETURNS TRIGGER AS $$
163 tablename = TD["table_name"]
164 event = TD["event"]
165
166 if tablename != 'override':
167     return None
168
169 if event != 'UPDATE':
170     # We only care about UPDATE event here
171     return None
172
173 # Deal with some pathologically stupid cases we ignore
174 if (TD['new']['package'] != TD['old']['package']) or \
175    (TD['new']['type'] != TD['old']['type']) or \
176    (TD['new']['suite'] != TD['old']['suite']):
177     return None
178
179 package = TD['old']['package']
180
181 # Get the priority, component and section out
182 priority_row = plpy.execute(plpy.prepare("SELECT priority FROM priority WHERE id = $1", ["int"]), [TD['new']['priority']])
183 if len(priority_row) != 1:
184     return None
185 priority = priority_row[0]['priority']
186
187 component_row = plpy.execute(plpy.prepare("SELECT name AS component FROM component WHERE id = $1", ["int"]), [TD['new']['component']])
188 if len(component_row) != 1:
189     return None
190 component = component_row[0]['component']
191
192 section_row = plpy.execute(plpy.prepare("SELECT section FROM section WHERE id = $1", ["int"]), [TD['new']['section']])
193 if len(section_row) != 1:
194     return None
195 section = section_row[0]['section']
196
197 # Find out if we're doing src or binary overrides
198 src_override_types = plpy.execute(plpy.prepare("SELECT id FROM override_type WHERE type = 'dsc'"), [])
199 if len(src_override_types) != 1:
200     return None
201 src_override_id = src_override_types[0]['id']
202
203 if TD['old']['type'] == src_override_id:
204     # Doing a src_association link
205     ## Find all of the relevant suites to work on
206     for suite_row in plpy.execute(plpy.prepare('''SELECT source.version, suite_name
207                                             FROM source
208                                        LEFT JOIN src_associations ON (source.id = src_associations.source)
209                                        LEFT JOIN suite ON (suite.id = src_associations.suite)
210                                        WHERE source.source = $1
211                                        AND suite = $2''', ["text", "int"]), [package, TD['new']['suite']]):
212         # INSERT one row per affected source package
213         plpy.execute(plpy.prepare("INSERT INTO audit.package_changes (package, version, architecture, suite, event, priority, component, section) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
214              ["text", "text", "text", "text", "text", "text", "text", "text"]),
215              [package, suite_row['version'], 'source', suite_row['suite_name'],
216               'U', priority, component, section])
217 else:
218     # Doing a bin_association link; Find all of the relevant suites to work on
219     for suite_row in plpy.execute(plpy.prepare('''SELECT binaries.version, arch_string, suite_name
220                                             FROM binaries
221                                        LEFT JOIN bin_associations ON (binaries.id = bin_associations.bin)
222                                        LEFT JOIN architecture ON (architecture.id = binaries.architecture)
223                                        LEFT JOIN suite ON (suite.id = bin_associations.suite)
224                                        WHERE package = $1
225                                        AND suite = $2''', ["text", "int"]), [package, TD['new']['suite']]):
226         # INSERT one row per affected binary
227         plpy.execute(plpy.prepare("INSERT INTO audit.package_changes (package, version, architecture, suite, event, priority, component, section) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
228              ["text", "text", "text", "text", "text", "text", "text", "text"]),
229              [package, suite_row['version'], suite_row['arch_string'], suite_row['suite_name'],
230               'U', priority, component, section])
231
232 $$ LANGUAGE plpythonu VOLATILE SECURITY DEFINER;
233 """)
234
235         c.execute("CREATE TRIGGER trigger_bin_associations_audit AFTER INSERT OR DELETE ON bin_associations FOR EACH ROW EXECUTE PROCEDURE trigger_binsrc_assoc_update()")
236         c.execute("CREATE TRIGGER trigger_src_associations_audit AFTER INSERT OR DELETE ON src_associations FOR EACH ROW EXECUTE PROCEDURE trigger_binsrc_assoc_update()")
237         c.execute("CREATE TRIGGER trigger_override_audit AFTER UPDATE ON override FOR EACH ROW EXECUTE PROCEDURE trigger_override_update()")
238
239         c.execute("UPDATE config SET value = '66' WHERE name = 'db_revision'")
240         self.db.commit()
241
242     except psycopg2.ProgrammingError, msg:
243         self.db.rollback()
244         raise DBUpdateError, 'Unable to apply sick update 66, rollback issued. Error message : %s' % (str(msg))