]> git.decadent.org.uk Git - dak.git/blob - dak/dakdb/update83.py
auto-decruft: Expand NVI in cmd line argument names
[dak.git] / dak / dakdb / update83.py
1 #!/usr/bin/env python
2 # coding=utf8
3
4 """
5 switch to new ACL implementation and add pre-suite NEW
6
7 @contact: Debian FTP Master <ftpmaster@debian.org>
8 @copyright: 2012 Ansgar Burchardt <ansgar@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 statements = [
33 """ALTER TABLE suite ADD COLUMN new_queue_id INT REFERENCES policy_queue(id)""",
34
35 """CREATE TABLE acl (
36     id SERIAL PRIMARY KEY NOT NULL,
37     name TEXT NOT NULL,
38     is_global BOOLEAN NOT NULL DEFAULT 'f',
39
40     match_fingerprint BOOLEAN NOT NULL DEFAULT 'f',
41     match_keyring_id INTEGER REFERENCES keyrings(id),
42
43     allow_new BOOLEAN NOT NULL DEFAULT 'f',
44     allow_source BOOLEAN NOT NULL DEFAULT 'f',
45     allow_binary BOOLEAN NOT NULL DEFAULT 'f',
46     allow_binary_all BOOLEAN NOT NULL DEFAULT 'f',
47     allow_binary_only BOOLEAN NOT NULL DEFAULT 'f',
48     allow_hijack BOOLEAN NOT NULL DEFAULT 'f',
49     allow_per_source BOOLEAN NOT NULL DEFAULT 'f',
50     deny_per_source BOOLEAN NOT NULL DEFAULT 'f'
51     )""",
52
53 """CREATE TABLE acl_architecture_map (
54     acl_id INTEGER NOT NULL REFERENCES acl(id) ON DELETE CASCADE,
55     architecture_id INTEGER NOT NULL REFERENCES architecture(id) ON DELETE CASCADE,
56     PRIMARY KEY (acl_id, architecture_id)
57     )""",
58
59 """CREATE TABLE acl_fingerprint_map (
60     acl_id INTEGER NOT NULL REFERENCES acl(id) ON DELETE CASCADE,
61     fingerprint_id INTEGER NOT NULL REFERENCES fingerprint(id) ON DELETE CASCADE,
62     PRIMARY KEY (acl_id, fingerprint_id)
63     )""",
64
65 """CREATE TABLE acl_per_source (
66     acl_id INTEGER NOT NULL REFERENCES acl(id) ON DELETE CASCADE,
67     fingerprint_id INTEGER NOT NULL REFERENCES fingerprint(id) ON DELETE CASCADE,
68     source TEXT NOT NULL,
69     reason TEXT,
70     PRIMARY KEY (acl_id, fingerprint_id, source)
71     )""",
72
73 """CREATE TABLE suite_acl_map (
74     suite_id INTEGER NOT NULL REFERENCES suite(id) ON DELETE CASCADE,
75     acl_id INTEGER NOT NULL REFERENCES acl(id),
76     PRIMARY KEY (suite_id, acl_id)
77     )""",
78 ]
79
80 ################################################################################
81
82 def get_buildd_acl_id(c, keyring_id):
83     c.execute("""
84         SELECT 'buildd-' || STRING_AGG(a.arch_string, '+' ORDER BY a.arch_string)
85           FROM keyring_acl_map kam
86           JOIN architecture a ON kam.architecture_id = a.id
87          WHERE kam.keyring_id = %(keyring_id)s
88         """, {'keyring_id': keyring_id})
89     acl_name, = c.fetchone()
90
91     c.execute('SELECT id FROM acl WHERE name = %(acl_name)s', {'acl_name': acl_name})
92     row = c.fetchone()
93     if row is not None:
94         return row[0]
95
96     c.execute("""
97         INSERT INTO acl
98                (        name, allow_new, allow_source, allow_binary, allow_binary_all, allow_binary_only, allow_hijack)
99         VALUES (%(acl_name)s,       't',          'f',          't',              'f',               't',          't')
100         RETURNING id""", {'acl_name': acl_name})
101     acl_id, = c.fetchone()
102
103     c.execute("""INSERT INTO acl_architecture_map (acl_id, architecture_id)
104                  SELECT %(acl_id)s, architecture_id
105                    FROM keyring_acl_map
106                   WHERE keyring_id = %(keyring_id)s""",
107               {'acl_id': acl_id, 'keyring_id': keyring_id})
108
109     return acl_id
110
111 def get_acl_id(c, acl_dd, acl_dm, keyring_id, source_acl_id, binary_acl_id):
112     c.execute('SELECT access_level FROM source_acl WHERE id = %(source_acl_id)s', {'source_acl_id': source_acl_id})
113     row = c.fetchone()
114     if row is not None:
115         source_acl = row[0]
116     else:
117         source_acl = None
118
119     c.execute('SELECT access_level FROM binary_acl WHERE id = %(binary_acl_id)s', {'binary_acl_id': binary_acl_id})
120     row = c.fetchone()
121     if row is not None:
122         binary_acl = row[0]
123     else:
124         binary_acl = None
125
126     if source_acl == 'full' and binary_acl == 'full':
127         return acl_dd
128     elif source_acl == 'dm' and binary_acl == 'full':
129         return acl_dm
130     elif source_acl is None and binary_acl == 'map':
131         return get_buildd_acl_id(c, keyring_id)
132
133     raise Exception('Cannot convert ACL combination automatically: binary_acl={0}, source_acl={1}'.format(binary_acl, source_acl))
134
135 def do_update(self):
136     print __doc__
137     try:
138         cnf = Config()
139
140         c = self.db.cursor()
141
142         for stmt in statements:
143             c.execute(stmt)
144
145         c.execute("""
146             INSERT INTO acl
147                    (name, allow_new, allow_source, allow_binary, allow_binary_all, allow_binary_only, allow_hijack)
148             VALUES ('dd',       't',          't',          't',              't',               't',          't')
149             RETURNING id""")
150         acl_dd, = c.fetchone()
151
152         c.execute("""
153             INSERT INTO acl
154                    (name, allow_new, allow_source, allow_binary, allow_binary_all, allow_binary_only, allow_per_source, allow_hijack)
155             VALUES ('dm',       'f',          't',          't',              't',               'f',              't',          'f')
156             RETURNING id""")
157         acl_dm, = c.fetchone()
158
159         # convert per-fingerprint ACLs
160
161         c.execute('ALTER TABLE fingerprint ADD COLUMN acl_id INTEGER REFERENCES acl(id)')
162         c.execute("""SELECT id, keyring, source_acl_id, binary_acl_id
163                        FROM fingerprint
164                       WHERE source_acl_id IS NOT NULL OR binary_acl_id IS NOT NULL""")
165         for fingerprint_id, keyring_id, source_acl_id, binary_acl_id in c.fetchall():
166             acl_id = get_acl_id(c, acl_dd, acl_dm, keyring_id, source_acl_id, binary_acl_id)
167             c.execute('UPDATE fingerprint SET acl_id = %(acl_id)s WHERE id = %(fingerprint_id)s',
168                       {'acl_id': acl_id, 'fingerprint_id': fingerprint_id})
169         c.execute("""ALTER TABLE fingerprint
170                        DROP COLUMN source_acl_id,
171                        DROP COLUMN binary_acl_id,
172                        DROP COLUMN binary_reject""")
173
174         # convert per-keyring ACLs
175         c.execute('ALTER TABLE keyrings ADD COLUMN acl_id INTEGER REFERENCES acl(id)')
176         c.execute('SELECT id, default_source_acl_id, default_binary_acl_id FROM keyrings')
177         for keyring_id, source_acl_id, binary_acl_id in c.fetchall():
178             acl_id = get_acl_id(c, acl_dd, acl_dm, keyring_id, source_acl_id, binary_acl_id)
179             c.execute('UPDATE keyrings SET acl_id = %(acl_id)s WHERE id = %(keyring_id)s',
180                       {'acl_id': acl_id, 'keyring_id': keyring_id})
181         c.execute("""ALTER TABLE keyrings
182                        DROP COLUMN default_source_acl_id,
183                        DROP COLUMN default_binary_acl_id,
184                        DROP COLUMN default_binary_reject""")
185
186         c.execute("DROP TABLE keyring_acl_map")
187         c.execute("DROP TABLE binary_acl_map")
188         c.execute("DROP TABLE binary_acl")
189         c.execute("DROP TABLE source_acl")
190
191         # convert upload blocks
192         c.execute("""
193             INSERT INTO acl
194                    (    name, is_global, allow_new, allow_source, allow_binary, allow_binary_all, allow_hijack, allow_binary_only, deny_per_source)
195             VALUES ('blocks',       't',       't',          't',          't',              't',          't',               't',             't')
196             RETURNING id""")
197         acl_block, = c.fetchone()
198         c.execute("SELECT source, fingerprint_id, reason FROM upload_blocks")
199         for source, fingerprint_id, reason in c.fetchall():
200             if fingerprint_id is None:
201                 raise Exception(
202                     "ERROR: upload blocks based on uid are no longer supported\n"
203                     "=========================================================\n"
204                     "\n"
205                     "dak now only supports upload blocks based on fingerprints. Please remove\n"
206                     "any uid-specific block by running\n"
207                     "   DELETE FROM upload_blocks WHERE fingerprint_id IS NULL\n"
208                     "and try again.")
209
210             c.execute('INSERT INTO acl_match_source_map (acl_id, fingerprint_id, source, reason) VALUES (%(acl_id)s, %(fingerprint_id)s, %(source)s, %(reason)s)',
211                       {'acl_id': acl_block, 'fingerprint_id': fingerprint_id, 'source': source, 'reason': reason})
212         c.execute("DROP TABLE upload_blocks")
213
214         c.execute("UPDATE config SET value = '83' WHERE name = 'db_revision'")
215         self.db.commit()
216
217     except psycopg2.ProgrammingError as msg:
218         self.db.rollback()
219         raise DBUpdateError('Unable to apply sick update 83, rollback issued. Error message: {0}'.format(msg))