3 """Configure dak parameters in the database"""
4 # Copyright (C) 2009 Mark Hymers <mhy@debian.org>
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 2 of the License, or
9 # (at your option) any later version.
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.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 ################################################################################
26 from daklib import utils
27 from daklib.dbconn import *
28 from sqlalchemy.orm.exc import NoResultFound
30 ################################################################################
35 ################################################################################
37 print >> sys.stderr, msg
39 def die(msg, exit_code=1):
40 print >> sys.stderr, msg
43 def die_arglen(args, args_needed, msg):
44 if len(args) < args_needed:
47 def usage(exit_code=0):
48 """Perform administrative work on the dak database."""
50 print """Usage: dak admin COMMAND
51 Perform administrative work on the dak database.
53 -h, --help show this help and exit.
54 -n, --dry-run don't do anything, just show what would have been done
55 (only applies to add or rm operations).
57 Commands can use a long or abbreviated form:
61 c db-shell show db config in a usable form for psql
62 c NAME show option NAME as set in configuration table
65 k list-all list all keyrings
66 k list-binary list all keyrings with a NULL source acl
67 k list-source list all keyrings with a non NULL source acl
68 k add-buildd NAME ARCH... add buildd keyring with upload permission
69 for the given architectures
72 a list show a list of architectures
73 a rm ARCH remove an architecture (will only work if
74 no longer linked to any suites)
75 a add ARCH DESCRIPTION [SUITELIST]
76 add architecture ARCH with DESCRIPTION.
77 If SUITELIST is given, add to each of the
78 suites at the same time
81 s list show a list of suites
82 s show SUITE show config details for a suite
83 s add SUITE VERSION [ label=LABEL ] [ description=DESCRIPTION ]
84 [ origin=ORIGIN ] [ codename=CODENAME ]
85 [ signingkey=SIGNINGKEY ] [ archive=ARCHIVE ]
86 add suite SUITE, version VERSION.
87 label, description, origin, codename
88 and signingkey are optional.
90 s add-all-arches SUITE VERSION... as "s add" but adds suite-architecture
91 relationships for all architectures
93 suite-architecture / s-a:
94 s-a list show the architectures for all suites
95 s-a list-suite ARCH show the suites an ARCH is in
96 s-a list-arch SUITE show the architectures in a SUITE
97 s-a add SUITE ARCH add ARCH to suite
98 s-a rm SUITE ARCH remove ARCH from suite (will only work if
99 no packages remain for the arch in the suite)
102 archive list list all archives
103 archive add NAME ROOT DESCRIPTION [primary-mirror=MIRROR] [tainted=1]
104 add archive NAME with path ROOT,
105 primary mirror MIRROR.
106 archive rm NAME remove archive NAME (will only work if there are
107 no files and no suites in the archive)
108 archive rename OLD NEW rename archive OLD to NEW
111 v-c list show version checks for all suites
112 v-c list-suite SUITE show version checks for suite SUITE
113 v-c add SUITE CHECK REFERENCE add a version check for suite SUITE
114 v-c rm SUITE CHECK REFERENCE remove a version check
116 CHECK is one of Enhances, MustBeNewerThan, MustBeOlderThan
117 REFERENCE is another suite name
121 ################################################################################
123 def __architecture_list(d, args):
124 q = d.session().query(Architecture).order_by(Architecture.arch_string)
126 # HACK: We should get rid of source from the arch table
127 if j.arch_string == 'source': continue
131 def __architecture_add(d, args):
132 die_arglen(args, 4, "E: adding an architecture requires a name and a description")
133 print "Adding architecture %s" % args[2]
134 suites = [str(x) for x in args[4:]]
136 print "Adding to suites %s" % ", ".join(suites)
141 a.arch_string = str(args[2]).lower()
142 a.description = str(args[3])
145 su = get_suite(sn, s)
149 warn("W: Cannot find suite %s" % su)
151 except IntegrityError as e:
152 die("E: Integrity error adding architecture %s (it probably already exists)" % args[2])
153 except SQLAlchemyError as e:
154 die("E: Error adding architecture %s (%s)" % (args[2], e))
155 print "Architecture %s added" % (args[2])
157 def __architecture_rm(d, args):
158 die_arglen(args, 3, "E: removing an architecture requires at least a name")
159 print "Removing architecture %s" % args[2]
163 a = get_architecture(args[2].lower(), s)
165 die("E: Cannot find architecture %s" % args[2])
168 except IntegrityError as e:
169 die("E: Integrity error removing architecture %s (suite-arch entries probably still exist)" % args[2])
170 except SQLAlchemyError as e:
171 die("E: Error removing architecture %s (%s)" % (args[2], e))
172 print "Architecture %s removed" % args[2]
174 def architecture(command):
175 args = [str(x) for x in command]
176 Cnf = utils.get_conf()
179 die_arglen(args, 2, "E: architecture needs at least a command")
181 mode = args[1].lower()
183 __architecture_list(d, args)
185 __architecture_add(d, args)
187 __architecture_rm(d, args)
189 die("E: architecture command unknown")
191 dispatch['architecture'] = architecture
192 dispatch['a'] = architecture
194 ################################################################################
196 def __suite_list(d, args):
198 for j in s.query(Suite).order_by(Suite.suite_name).all():
201 def __suite_show(d, args):
203 die("E: showing an suite entry requires a suite")
206 su = get_suite(args[2].lower())
208 die("E: can't find suite entry for %s" % (args[2].lower()))
212 def __suite_add(d, args, addallarches=False):
213 die_arglen(args, 4, "E: adding a suite requires at least a name and a version")
214 suite_name = args[2].lower()
218 def get_field(field):
220 if varval.startswith(field + '='):
221 return varval.split('=')[1]
224 print "Adding suite %s" % suite_name
229 suite.suite_name = suite_name
230 suite.overridecodename = suite_name
231 suite.version = version
232 suite.label = get_field('label')
233 suite.description = get_field('description')
234 suite.origin = get_field('origin')
235 suite.codename = get_field('codename')
236 signingkey = get_field('signingkey')
237 if signingkey is not None:
238 suite.signingkeys = [signingkey.upper()]
239 archive_name = get_field('archive')
240 if archive_name is not None:
241 suite.archive = get_archive(archive_name, s)
243 suite.archive = s.query(Archive).filter(~Archive.archive_name.in_(['build-queues', 'new', 'policy'])).one()
244 suite.srcformats = s.query(SrcFormat).all()
247 except IntegrityError as e:
248 die("E: Integrity error adding suite %s (it probably already exists)" % suite_name)
249 except SQLAlchemyError as e:
250 die("E: Error adding suite %s (%s)" % (suite_name, e))
251 print "Suite %s added" % (suite_name)
255 q = s.query(Architecture).order_by(Architecture.arch_string)
257 suite.architectures.append(arch)
258 arches.append(arch.arch_string)
260 print "Architectures %s added to %s" % (','.join(arches), suite_name)
266 args = [str(x) for x in command]
267 Cnf = utils.get_conf()
270 die_arglen(args, 2, "E: suite needs at least a command")
272 mode = args[1].lower()
275 __suite_list(d, args)
277 __suite_show(d, args)
279 __suite_add(d, args, False)
280 elif mode == 'add-all-arches':
281 __suite_add(d, args, True)
283 die("E: suite command unknown")
285 dispatch['suite'] = suite
286 dispatch['s'] = suite
288 ################################################################################
290 def __suite_architecture_list(d, args):
292 for j in s.query(Suite).order_by(Suite.suite_name):
293 architectures = j.get_architectures(skipsrc = True, skipall = True)
294 print j.suite_name + ': ' + \
295 ', '.join([a.arch_string for a in architectures])
297 def __suite_architecture_listarch(d, args):
298 die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
299 suite = get_suite(args[2].lower(), d.session())
301 die('E: suite %s is invalid' % args[2].lower())
302 a = suite.get_architectures(skipsrc = True, skipall = True)
307 def __suite_architecture_listsuite(d, args):
308 die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
309 architecture = get_architecture(args[2].lower(), d.session())
310 if architecture is None:
311 die("E: architecture %s is invalid" % args[2].lower())
312 for j in architecture.suites:
316 def __suite_architecture_add(d, args):
318 die("E: adding a suite-architecture entry requires a suite and arch")
322 suite = get_suite(args[2].lower(), s)
323 if suite is None: die("E: Can't find suite %s" % args[2].lower())
325 arch = get_architecture(args[3].lower(), s)
326 if arch is None: die("E: Can't find architecture %s" % args[3].lower())
330 suite.architectures.append(arch)
332 except IntegrityError as e:
333 die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
334 except SQLAlchemyError as e:
335 die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
337 print "Added suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
340 def __suite_architecture_rm(d, args):
342 die("E: removing an suite-architecture entry requires a suite and arch")
347 suite_name = args[2].lower()
348 suite = get_suite(suite_name, s)
350 die('E: no such suite %s' % suite_name)
351 arch_string = args[3].lower()
352 architecture = get_architecture(arch_string, s)
353 if architecture not in suite.architectures:
354 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
355 suite.architectures.remove(architecture)
357 except IntegrityError as e:
358 die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
359 except SQLAlchemyError as e:
360 die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
362 print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
365 def suite_architecture(command):
366 args = [str(x) for x in command]
367 Cnf = utils.get_conf()
370 die_arglen(args, 2, "E: suite-architecture needs at least a command")
372 mode = args[1].lower()
375 __suite_architecture_list(d, args)
376 elif mode == 'list-arch':
377 __suite_architecture_listarch(d, args)
378 elif mode == 'list-suite':
379 __suite_architecture_listsuite(d, args)
381 __suite_architecture_add(d, args)
383 __suite_architecture_rm(d, args)
385 die("E: suite-architecture command unknown")
387 dispatch['suite-architecture'] = suite_architecture
388 dispatch['s-a'] = suite_architecture
390 ################################################################################
393 session = DBConn().session()
394 for archive in session.query(Archive).order_by(Archive.archive_name):
395 print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
397 def archive_add(args):
398 (name, path, description) = args[0:3]
403 description=description,
406 for option in args[3:]:
407 (key, value) = option.split('=')
408 attributes[key] = value
410 session = DBConn().session()
413 for key, value in attributes.iteritems():
414 setattr(archive, key, value)
424 def archive_rm(name):
425 session = DBConn().session()
426 archive = session.query(Archive).filter_by(archive_name=name).one()
427 session.delete(archive)
435 def archive_rename(oldname, newname):
436 session = DBConn().session()
437 archive = get_archive(oldname, session)
438 archive.archive_name = newname
446 def archive(command):
450 elif mode == 'rename':
451 archive_rename(command[2], command[3])
453 archive_add(command[2:])
455 archive_rm(command[2])
457 die("E: archive command unknown")
459 dispatch['archive'] = archive
461 ################################################################################
463 def __version_check_list(d):
464 session = d.session()
465 for s in session.query(Suite).order_by(Suite.suite_name):
466 __version_check_list_suite(d, s.suite_name)
468 def __version_check_list_suite(d, suite_name):
469 vcs = get_version_checks(suite_name)
471 print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
473 def __version_check_add(d, suite_name, check, reference_name):
474 suite = get_suite(suite_name)
476 die("E: Could not find suite %s." % (suite_name))
477 reference = get_suite(reference_name)
479 die("E: Could not find reference suite %s." % (reference_name))
481 session = d.session()
485 vc.reference = reference
489 def __version_check_rm(d, suite_name, check, reference_name):
490 suite = get_suite(suite_name)
492 die("E: Could not find suite %s." % (suite_name))
493 reference = get_suite(reference_name)
495 die("E: Could not find reference suite %s." % (reference_name))
497 session = d.session()
499 vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
502 except NoResultFound:
503 print "W: version-check not found."
505 def version_check(command):
506 args = [str(x) for x in command]
507 Cnf = utils.get_conf()
510 die_arglen(args, 2, "E: version-check needs at least a command")
511 mode = args[1].lower()
514 __version_check_list(d)
515 elif mode == 'list-suite':
517 die("E: version-check list-suite needs a single parameter")
518 __version_check_list_suite(d, args[2])
521 die("E: version-check add needs three parameters")
522 __version_check_add(d, args[2], args[3], args[4])
525 die("E: version-check rm needs three parameters")
526 __version_check_rm(d, args[2], args[3], args[4])
528 die("E: version-check command unknown")
530 dispatch['version-check'] = version_check
531 dispatch['v-c'] = version_check
533 ################################################################################
535 def show_config(command):
536 args = [str(x) for x in command]
537 cnf = utils.get_conf()
539 die_arglen(args, 2, "E: config needs at least a command")
541 mode = args[1].lower()
545 if cnf.has_key("DB::Service"):
547 connstr = "postgresql://service=%s" % cnf["DB::Service"]
548 elif cnf.has_key("DB::Host"):
550 connstr = "postgres://%s" % cnf["DB::Host"]
551 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
552 connstr += ":%s" % cnf["DB::Port"]
553 connstr += "/%s" % cnf["DB::Name"]
556 connstr = "postgres:///%s" % cnf["DB::Name"]
557 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
558 connstr += "?port=%s" % cnf["DB::Port"]
560 elif mode == 'db-shell':
562 if cnf.has_key("DB::Service"):
563 e.append('PGSERVICE')
564 print "PGSERVICE=%s" % cnf["DB::Service"]
565 if cnf.has_key("DB::Name"):
566 e.append('PGDATABASE')
567 print "PGDATABASE=%s" % cnf["DB::Name"]
568 if cnf.has_key("DB::Host"):
569 print "PGHOST=%s" % cnf["DB::Host"]
571 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
572 print "PGPORT=%s" % cnf["DB::Port"]
574 print "export " + " ".join(e)
576 print cnf.get(args[2])
578 session = DBConn().session()
580 o = session.query(DBConfig).filter_by(name = mode).one()
582 except NoResultFound:
583 print "W: option '%s' not set" % mode
585 dispatch['config'] = show_config
586 dispatch['c'] = show_config
588 ################################################################################
590 def show_keyring(command):
591 args = [str(x) for x in command]
592 cnf = utils.get_conf()
594 die_arglen(args, 2, "E: keyring needs at least a command")
596 mode = args[1].lower()
600 q = d.session().query(Keyring).filter(Keyring.active == True)
602 if mode == 'list-all':
604 elif mode == 'list-binary':
605 q = q.join(Keyring.acl).filter(ACL.allow_source == False)
606 elif mode == 'list-source':
607 q = q.join(Keyring.acl).filter(ACL.allow_source == True)
609 die("E: keyring command unknown")
614 def keyring_add_buildd(command):
616 arch_names = command[3:]
618 session = DBConn().session()
619 arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names))
622 acl.name = 'buildd-{0}'.format('+'.join(arch_names))
623 acl.architectures.update(arches)
625 acl.allow_binary = True
626 acl.allow_binary_only = True
627 acl.allow_hijack = True
631 k.keyring_name = name
638 def keyring(command):
639 if command[1].startswith('list-'):
640 show_keyring(command)
641 elif command[1] == 'add-buildd':
642 keyring_add_buildd(command)
644 die("E: keyring command unknown")
646 dispatch['keyring'] = keyring
647 dispatch['k'] = keyring
649 ################################################################################
652 """Perform administrative work on the dak database"""
654 Cnf = utils.get_conf()
655 arguments = [('h', "help", "Admin::Options::Help"),
656 ('n', "dry-run", "Admin::Options::Dry-Run")]
657 for i in [ "help", "dry-run" ]:
658 if not Cnf.has_key("Admin::Options::%s" % (i)):
659 Cnf["Admin::Options::%s" % (i)] = ""
661 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
663 options = Cnf.subtree("Admin::Options")
664 if options["Help"] or len(arguments) < 1:
666 if options["Dry-Run"]:
669 subcommand = str(arguments[0])
671 if subcommand in dispatch.keys():
672 dispatch[subcommand](arguments)
674 die("E: Unknown command")
676 ################################################################################
678 if __name__ == '__main__':