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)
264 def __suite_rm(d, args):
265 die_arglen(args, 3, "E: removing a suite requires at least a name")
267 print "Removing suite {0}".format(name)
271 su = get_suite(name.lower())
273 die("E: Cannot find suite {0}".format(name))
276 except IntegrityError as e:
277 die("E: Integrity error removing suite {0} (suite-arch entries probably still exist)".format(name))
278 except SQLAlchemyError as e:
279 die("E: Error removing suite {0} ({1})".format(name, e))
280 print "Suite {0} removed".format(name)
283 args = [str(x) for x in command]
284 Cnf = utils.get_conf()
287 die_arglen(args, 2, "E: suite needs at least a command")
289 mode = args[1].lower()
292 __suite_list(d, args)
294 __suite_show(d, args)
298 __suite_add(d, args, False)
299 elif mode == 'add-all-arches':
300 __suite_add(d, args, True)
302 die("E: suite command unknown")
304 dispatch['suite'] = suite
305 dispatch['s'] = suite
307 ################################################################################
309 def __suite_architecture_list(d, args):
311 for j in s.query(Suite).order_by(Suite.suite_name):
312 architectures = j.get_architectures(skipsrc = True, skipall = True)
313 print j.suite_name + ': ' + \
314 ', '.join([a.arch_string for a in architectures])
316 def __suite_architecture_listarch(d, args):
317 die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
318 suite = get_suite(args[2].lower(), d.session())
320 die('E: suite %s is invalid' % args[2].lower())
321 a = suite.get_architectures(skipsrc = True, skipall = True)
326 def __suite_architecture_listsuite(d, args):
327 die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
328 architecture = get_architecture(args[2].lower(), d.session())
329 if architecture is None:
330 die("E: architecture %s is invalid" % args[2].lower())
331 for j in architecture.suites:
335 def __suite_architecture_add(d, args):
337 die("E: adding a suite-architecture entry requires a suite and arch")
341 suite = get_suite(args[2].lower(), s)
342 if suite is None: die("E: Can't find suite %s" % args[2].lower())
344 arch = get_architecture(args[3].lower(), s)
345 if arch is None: die("E: Can't find architecture %s" % args[3].lower())
349 suite.architectures.append(arch)
351 except IntegrityError as e:
352 die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
353 except SQLAlchemyError as e:
354 die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
356 print "Added suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
359 def __suite_architecture_rm(d, args):
361 die("E: removing an suite-architecture entry requires a suite and arch")
366 suite_name = args[2].lower()
367 suite = get_suite(suite_name, s)
369 die('E: no such suite %s' % suite_name)
370 arch_string = args[3].lower()
371 architecture = get_architecture(arch_string, s)
372 if architecture not in suite.architectures:
373 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
374 suite.architectures.remove(architecture)
376 except IntegrityError as e:
377 die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
378 except SQLAlchemyError as e:
379 die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
381 print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
384 def suite_architecture(command):
385 args = [str(x) for x in command]
386 Cnf = utils.get_conf()
389 die_arglen(args, 2, "E: suite-architecture needs at least a command")
391 mode = args[1].lower()
394 __suite_architecture_list(d, args)
395 elif mode == 'list-arch':
396 __suite_architecture_listarch(d, args)
397 elif mode == 'list-suite':
398 __suite_architecture_listsuite(d, args)
400 __suite_architecture_add(d, args)
402 __suite_architecture_rm(d, args)
404 die("E: suite-architecture command unknown")
406 dispatch['suite-architecture'] = suite_architecture
407 dispatch['s-a'] = suite_architecture
409 ################################################################################
412 session = DBConn().session()
413 for archive in session.query(Archive).order_by(Archive.archive_name):
414 print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
416 def archive_add(args):
417 (name, path, description) = args[0:3]
422 description=description,
425 for option in args[3:]:
426 (key, value) = option.split('=')
427 attributes[key] = value
429 session = DBConn().session()
432 for key, value in attributes.iteritems():
433 setattr(archive, key, value)
443 def archive_rm(name):
444 session = DBConn().session()
445 archive = session.query(Archive).filter_by(archive_name=name).one()
446 session.delete(archive)
454 def archive_rename(oldname, newname):
455 session = DBConn().session()
456 archive = get_archive(oldname, session)
457 archive.archive_name = newname
465 def archive(command):
469 elif mode == 'rename':
470 archive_rename(command[2], command[3])
472 archive_add(command[2:])
474 archive_rm(command[2])
476 die("E: archive command unknown")
478 dispatch['archive'] = archive
480 ################################################################################
482 def __version_check_list(d):
483 session = d.session()
484 for s in session.query(Suite).order_by(Suite.suite_name):
485 __version_check_list_suite(d, s.suite_name)
487 def __version_check_list_suite(d, suite_name):
488 vcs = get_version_checks(suite_name)
490 print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
492 def __version_check_add(d, suite_name, check, reference_name):
493 suite = get_suite(suite_name)
495 die("E: Could not find suite %s." % (suite_name))
496 reference = get_suite(reference_name)
498 die("E: Could not find reference suite %s." % (reference_name))
500 session = d.session()
504 vc.reference = reference
508 def __version_check_rm(d, suite_name, check, reference_name):
509 suite = get_suite(suite_name)
511 die("E: Could not find suite %s." % (suite_name))
512 reference = get_suite(reference_name)
514 die("E: Could not find reference suite %s." % (reference_name))
516 session = d.session()
518 vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
521 except NoResultFound:
522 print "W: version-check not found."
524 def version_check(command):
525 args = [str(x) for x in command]
526 Cnf = utils.get_conf()
529 die_arglen(args, 2, "E: version-check needs at least a command")
530 mode = args[1].lower()
533 __version_check_list(d)
534 elif mode == 'list-suite':
536 die("E: version-check list-suite needs a single parameter")
537 __version_check_list_suite(d, args[2])
540 die("E: version-check add needs three parameters")
541 __version_check_add(d, args[2], args[3], args[4])
544 die("E: version-check rm needs three parameters")
545 __version_check_rm(d, args[2], args[3], args[4])
547 die("E: version-check command unknown")
549 dispatch['version-check'] = version_check
550 dispatch['v-c'] = version_check
552 ################################################################################
554 def show_config(command):
555 args = [str(x) for x in command]
556 cnf = utils.get_conf()
558 die_arglen(args, 2, "E: config needs at least a command")
560 mode = args[1].lower()
564 if cnf.has_key("DB::Service"):
566 connstr = "postgresql://service=%s" % cnf["DB::Service"]
567 elif cnf.has_key("DB::Host"):
569 connstr = "postgres://%s" % cnf["DB::Host"]
570 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
571 connstr += ":%s" % cnf["DB::Port"]
572 connstr += "/%s" % cnf["DB::Name"]
575 connstr = "postgres:///%s" % cnf["DB::Name"]
576 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
577 connstr += "?port=%s" % cnf["DB::Port"]
579 elif mode == 'db-shell':
581 if cnf.has_key("DB::Service"):
582 e.append('PGSERVICE')
583 print "PGSERVICE=%s" % cnf["DB::Service"]
584 if cnf.has_key("DB::Name"):
585 e.append('PGDATABASE')
586 print "PGDATABASE=%s" % cnf["DB::Name"]
587 if cnf.has_key("DB::Host"):
588 print "PGHOST=%s" % cnf["DB::Host"]
590 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
591 print "PGPORT=%s" % cnf["DB::Port"]
593 print "export " + " ".join(e)
595 print cnf.get(args[2])
597 session = DBConn().session()
599 o = session.query(DBConfig).filter_by(name = mode).one()
601 except NoResultFound:
602 print "W: option '%s' not set" % mode
604 dispatch['config'] = show_config
605 dispatch['c'] = show_config
607 ################################################################################
609 def show_keyring(command):
610 args = [str(x) for x in command]
611 cnf = utils.get_conf()
613 die_arglen(args, 2, "E: keyring needs at least a command")
615 mode = args[1].lower()
619 q = d.session().query(Keyring).filter(Keyring.active == True)
621 if mode == 'list-all':
623 elif mode == 'list-binary':
624 q = q.join(Keyring.acl).filter(ACL.allow_source == False)
625 elif mode == 'list-source':
626 q = q.join(Keyring.acl).filter(ACL.allow_source == True)
628 die("E: keyring command unknown")
633 def keyring_add_buildd(command):
635 arch_names = command[3:]
637 session = DBConn().session()
638 arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names))
641 acl.name = 'buildd-{0}'.format('+'.join(arch_names))
642 acl.architectures.update(arches)
644 acl.allow_binary = True
645 acl.allow_binary_only = True
646 acl.allow_hijack = True
650 k.keyring_name = name
657 def keyring(command):
658 if command[1].startswith('list-'):
659 show_keyring(command)
660 elif command[1] == 'add-buildd':
661 keyring_add_buildd(command)
663 die("E: keyring command unknown")
665 dispatch['keyring'] = keyring
666 dispatch['k'] = keyring
668 ################################################################################
671 """Perform administrative work on the dak database"""
673 Cnf = utils.get_conf()
674 arguments = [('h', "help", "Admin::Options::Help"),
675 ('n', "dry-run", "Admin::Options::Dry-Run")]
676 for i in [ "help", "dry-run" ]:
677 if not Cnf.has_key("Admin::Options::%s" % (i)):
678 Cnf["Admin::Options::%s" % (i)] = ""
680 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
682 options = Cnf.subtree("Admin::Options")
683 if options["Help"] or len(arguments) < 1:
685 if options["Dry-Run"]:
688 subcommand = str(arguments[0])
690 if subcommand in dispatch.keys():
691 dispatch[subcommand](arguments)
693 die("E: Unknown command")
695 ################################################################################
697 if __name__ == '__main__':