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 component list show a list of components
82 component rm COMPONENT remove a component (will only work if
84 component add NAME DESCRIPTION ORDERING
85 add component NAME with DESCRIPTION.
89 s list show a list of suites
90 s show SUITE show config details for a suite
91 s add SUITE VERSION [ label=LABEL ] [ description=DESCRIPTION ]
92 [ origin=ORIGIN ] [ codename=CODENAME ]
93 [ signingkey=SIGNINGKEY ] [ archive=ARCHIVE ]
94 add suite SUITE, version VERSION.
95 label, description, origin, codename
96 and signingkey are optional.
98 s add-all-arches SUITE VERSION... as "s add" but adds suite-architecture
99 relationships for all architectures
101 suite-architecture / s-a:
102 s-a list show the architectures for all suites
103 s-a list-suite ARCH show the suites an ARCH is in
104 s-a list-arch SUITE show the architectures in a SUITE
105 s-a add SUITE ARCH add ARCH to suite
106 s-a rm SUITE ARCH remove ARCH from suite (will only work if
107 no packages remain for the arch in the suite)
110 archive list list all archives
111 archive add NAME ROOT DESCRIPTION [primary-mirror=MIRROR] [tainted=1]
112 add archive NAME with path ROOT,
113 primary mirror MIRROR.
114 archive rm NAME remove archive NAME (will only work if there are
115 no files and no suites in the archive)
116 archive rename OLD NEW rename archive OLD to NEW
119 v-c list show version checks for all suites
120 v-c list-suite SUITE show version checks for suite SUITE
121 v-c add SUITE CHECK REFERENCE add a version check for suite SUITE
122 v-c rm SUITE CHECK REFERENCE remove a version check
124 CHECK is one of Enhances, MustBeNewerThan, MustBeOlderThan
125 REFERENCE is another suite name
129 ################################################################################
131 def __architecture_list(d, args):
132 q = d.session().query(Architecture).order_by(Architecture.arch_string)
134 # HACK: We should get rid of source from the arch table
135 if j.arch_string == 'source': continue
139 def __architecture_add(d, args):
140 die_arglen(args, 4, "E: adding an architecture requires a name and a description")
141 print "Adding architecture %s" % args[2]
142 suites = [str(x) for x in args[4:]]
144 print "Adding to suites %s" % ", ".join(suites)
149 a.arch_string = str(args[2]).lower()
150 a.description = str(args[3])
153 su = get_suite(sn, s)
157 warn("W: Cannot find suite %s" % su)
159 except IntegrityError as e:
160 die("E: Integrity error adding architecture %s (it probably already exists)" % args[2])
161 except SQLAlchemyError as e:
162 die("E: Error adding architecture %s (%s)" % (args[2], e))
163 print "Architecture %s added" % (args[2])
165 def __architecture_rm(d, args):
166 die_arglen(args, 3, "E: removing an architecture requires at least a name")
167 print "Removing architecture %s" % args[2]
171 a = get_architecture(args[2].lower(), s)
173 die("E: Cannot find architecture %s" % args[2])
176 except IntegrityError as e:
177 die("E: Integrity error removing architecture %s (suite-arch entries probably still exist)" % args[2])
178 except SQLAlchemyError as e:
179 die("E: Error removing architecture %s (%s)" % (args[2], e))
180 print "Architecture %s removed" % args[2]
182 def architecture(command):
183 args = [str(x) for x in command]
184 Cnf = utils.get_conf()
187 die_arglen(args, 2, "E: architecture needs at least a command")
189 mode = args[1].lower()
191 __architecture_list(d, args)
193 __architecture_add(d, args)
195 __architecture_rm(d, args)
197 die("E: architecture command unknown")
199 dispatch['architecture'] = architecture
200 dispatch['a'] = architecture
202 ################################################################################
204 def component_list():
205 session = DBConn().session()
206 for component in session.query(Component).order_by(Component.component_name):
207 print "{0} ordering={1}".format(component.component_name, component.ordering)
209 def component_add(args):
210 (name, description, ordering) = args[0:3]
214 description=description,
218 for option in args[3:]:
219 (key, value) = option.split('=')
220 attributes[key] = value
222 session = DBConn().session()
224 component = Component()
225 for key, value in attributes.iteritems():
226 setattr(component, key, value)
228 session.add(component)
236 def component_rm(name):
237 session = DBConn().session()
238 component = get_component(name, session)
239 session.delete(component)
247 def component_rename(oldname, newname):
248 session = DBConn().session()
249 component = get_component(oldname, session)
250 component.component_name = newname
258 def component(command):
262 elif mode == 'rename':
263 component_rename(command[2], command[3])
265 component_add(command[2:])
267 component_rm(command[2])
269 die("E: component command unknown")
271 dispatch['component'] = component
273 ################################################################################
275 def __suite_list(d, args):
277 for j in s.query(Suite).order_by(Suite.suite_name).all():
280 def __suite_show(d, args):
282 die("E: showing an suite entry requires a suite")
285 su = get_suite(args[2].lower())
287 die("E: can't find suite entry for %s" % (args[2].lower()))
291 def __suite_add(d, args, addallarches=False):
292 die_arglen(args, 4, "E: adding a suite requires at least a name and a version")
293 suite_name = args[2].lower()
297 def get_field(field):
299 if varval.startswith(field + '='):
300 return varval.split('=')[1]
303 print "Adding suite %s" % suite_name
308 suite.suite_name = suite_name
309 suite.overridecodename = suite_name
310 suite.version = version
311 suite.label = get_field('label')
312 suite.description = get_field('description')
313 suite.origin = get_field('origin')
314 suite.codename = get_field('codename')
315 signingkey = get_field('signingkey')
316 if signingkey is not None:
317 suite.signingkeys = [signingkey.upper()]
318 archive_name = get_field('archive')
319 if archive_name is not None:
320 suite.archive = get_archive(archive_name, s)
322 suite.archive = s.query(Archive).filter(~Archive.archive_name.in_(['build-queues', 'new', 'policy'])).one()
323 suite.srcformats = s.query(SrcFormat).all()
326 except IntegrityError as e:
327 die("E: Integrity error adding suite %s (it probably already exists)" % suite_name)
328 except SQLAlchemyError as e:
329 die("E: Error adding suite %s (%s)" % (suite_name, e))
330 print "Suite %s added" % (suite_name)
334 q = s.query(Architecture).order_by(Architecture.arch_string)
336 suite.architectures.append(arch)
337 arches.append(arch.arch_string)
339 print "Architectures %s added to %s" % (','.join(arches), suite_name)
343 def __suite_rm(d, args):
344 die_arglen(args, 3, "E: removing a suite requires at least a name")
346 print "Removing suite {0}".format(name)
350 su = get_suite(name.lower())
352 die("E: Cannot find suite {0}".format(name))
355 except IntegrityError as e:
356 die("E: Integrity error removing suite {0} (suite-arch entries probably still exist)".format(name))
357 except SQLAlchemyError as e:
358 die("E: Error removing suite {0} ({1})".format(name, e))
359 print "Suite {0} removed".format(name)
362 args = [str(x) for x in command]
363 Cnf = utils.get_conf()
366 die_arglen(args, 2, "E: suite needs at least a command")
368 mode = args[1].lower()
371 __suite_list(d, args)
373 __suite_show(d, args)
377 __suite_add(d, args, False)
378 elif mode == 'add-all-arches':
379 __suite_add(d, args, True)
381 die("E: suite command unknown")
383 dispatch['suite'] = suite
384 dispatch['s'] = suite
386 ################################################################################
388 def __suite_architecture_list(d, args):
390 for j in s.query(Suite).order_by(Suite.suite_name):
391 architectures = j.get_architectures(skipsrc = True, skipall = True)
392 print j.suite_name + ': ' + \
393 ', '.join([a.arch_string for a in architectures])
395 def __suite_architecture_listarch(d, args):
396 die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
397 suite = get_suite(args[2].lower(), d.session())
399 die('E: suite %s is invalid' % args[2].lower())
400 a = suite.get_architectures(skipsrc = True, skipall = True)
405 def __suite_architecture_listsuite(d, args):
406 die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
407 architecture = get_architecture(args[2].lower(), d.session())
408 if architecture is None:
409 die("E: architecture %s is invalid" % args[2].lower())
410 for j in architecture.suites:
414 def __suite_architecture_add(d, args):
416 die("E: adding a suite-architecture entry requires a suite and arch")
420 suite = get_suite(args[2].lower(), s)
421 if suite is None: die("E: Can't find suite %s" % args[2].lower())
423 arch = get_architecture(args[3].lower(), s)
424 if arch is None: die("E: Can't find architecture %s" % args[3].lower())
428 suite.architectures.append(arch)
430 except IntegrityError as e:
431 die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
432 except SQLAlchemyError as e:
433 die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
435 print "Added suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
438 def __suite_architecture_rm(d, args):
440 die("E: removing an suite-architecture entry requires a suite and arch")
445 suite_name = args[2].lower()
446 suite = get_suite(suite_name, s)
448 die('E: no such suite %s' % suite_name)
449 arch_string = args[3].lower()
450 architecture = get_architecture(arch_string, s)
451 if architecture not in suite.architectures:
452 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
453 suite.architectures.remove(architecture)
455 except IntegrityError as e:
456 die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
457 except SQLAlchemyError as e:
458 die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
460 print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
463 def suite_architecture(command):
464 args = [str(x) for x in command]
465 Cnf = utils.get_conf()
468 die_arglen(args, 2, "E: suite-architecture needs at least a command")
470 mode = args[1].lower()
473 __suite_architecture_list(d, args)
474 elif mode == 'list-arch':
475 __suite_architecture_listarch(d, args)
476 elif mode == 'list-suite':
477 __suite_architecture_listsuite(d, args)
479 __suite_architecture_add(d, args)
481 __suite_architecture_rm(d, args)
483 die("E: suite-architecture command unknown")
485 dispatch['suite-architecture'] = suite_architecture
486 dispatch['s-a'] = suite_architecture
488 ################################################################################
491 session = DBConn().session()
492 for archive in session.query(Archive).order_by(Archive.archive_name):
493 print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
495 def archive_add(args):
496 (name, path, description) = args[0:3]
501 description=description,
504 for option in args[3:]:
505 (key, value) = option.split('=')
506 attributes[key] = value
508 session = DBConn().session()
511 for key, value in attributes.iteritems():
512 setattr(archive, key, value)
522 def archive_rm(name):
523 session = DBConn().session()
524 archive = get_archive(name, session)
525 session.delete(archive)
533 def archive_rename(oldname, newname):
534 session = DBConn().session()
535 archive = get_archive(oldname, session)
536 archive.archive_name = newname
544 def archive(command):
548 elif mode == 'rename':
549 archive_rename(command[2], command[3])
551 archive_add(command[2:])
553 archive_rm(command[2])
555 die("E: archive command unknown")
557 dispatch['archive'] = archive
559 ################################################################################
561 def __version_check_list(d):
562 session = d.session()
563 for s in session.query(Suite).order_by(Suite.suite_name):
564 __version_check_list_suite(d, s.suite_name)
566 def __version_check_list_suite(d, suite_name):
567 vcs = get_version_checks(suite_name)
569 print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
571 def __version_check_add(d, suite_name, check, reference_name):
572 suite = get_suite(suite_name)
574 die("E: Could not find suite %s." % (suite_name))
575 reference = get_suite(reference_name)
577 die("E: Could not find reference suite %s." % (reference_name))
579 session = d.session()
583 vc.reference = reference
587 def __version_check_rm(d, suite_name, check, reference_name):
588 suite = get_suite(suite_name)
590 die("E: Could not find suite %s." % (suite_name))
591 reference = get_suite(reference_name)
593 die("E: Could not find reference suite %s." % (reference_name))
595 session = d.session()
597 vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
600 except NoResultFound:
601 print "W: version-check not found."
603 def version_check(command):
604 args = [str(x) for x in command]
605 Cnf = utils.get_conf()
608 die_arglen(args, 2, "E: version-check needs at least a command")
609 mode = args[1].lower()
612 __version_check_list(d)
613 elif mode == 'list-suite':
615 die("E: version-check list-suite needs a single parameter")
616 __version_check_list_suite(d, args[2])
619 die("E: version-check add needs three parameters")
620 __version_check_add(d, args[2], args[3], args[4])
623 die("E: version-check rm needs three parameters")
624 __version_check_rm(d, args[2], args[3], args[4])
626 die("E: version-check command unknown")
628 dispatch['version-check'] = version_check
629 dispatch['v-c'] = version_check
631 ################################################################################
633 def show_config(command):
634 args = [str(x) for x in command]
635 cnf = utils.get_conf()
637 die_arglen(args, 2, "E: config needs at least a command")
639 mode = args[1].lower()
643 if cnf.has_key("DB::Service"):
645 connstr = "postgresql://service=%s" % cnf["DB::Service"]
646 elif cnf.has_key("DB::Host"):
648 connstr = "postgres://%s" % cnf["DB::Host"]
649 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
650 connstr += ":%s" % cnf["DB::Port"]
651 connstr += "/%s" % cnf["DB::Name"]
654 connstr = "postgres:///%s" % cnf["DB::Name"]
655 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
656 connstr += "?port=%s" % cnf["DB::Port"]
658 elif mode == 'db-shell':
660 if cnf.has_key("DB::Service"):
661 e.append('PGSERVICE')
662 print "PGSERVICE=%s" % cnf["DB::Service"]
663 if cnf.has_key("DB::Name"):
664 e.append('PGDATABASE')
665 print "PGDATABASE=%s" % cnf["DB::Name"]
666 if cnf.has_key("DB::Host"):
667 print "PGHOST=%s" % cnf["DB::Host"]
669 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
670 print "PGPORT=%s" % cnf["DB::Port"]
672 print "export " + " ".join(e)
674 print cnf.get(args[2])
676 session = DBConn().session()
678 o = session.query(DBConfig).filter_by(name = mode).one()
680 except NoResultFound:
681 print "W: option '%s' not set" % mode
683 dispatch['config'] = show_config
684 dispatch['c'] = show_config
686 ################################################################################
688 def show_keyring(command):
689 args = [str(x) for x in command]
690 cnf = utils.get_conf()
692 die_arglen(args, 2, "E: keyring needs at least a command")
694 mode = args[1].lower()
698 q = d.session().query(Keyring).filter(Keyring.active == True)
700 if mode == 'list-all':
702 elif mode == 'list-binary':
703 q = q.join(Keyring.acl).filter(ACL.allow_source == False)
704 elif mode == 'list-source':
705 q = q.join(Keyring.acl).filter(ACL.allow_source == True)
707 die("E: keyring command unknown")
712 def keyring_add_buildd(command):
714 arch_names = command[3:]
716 session = DBConn().session()
717 arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names))
720 acl.name = 'buildd-{0}'.format('+'.join(arch_names))
721 acl.architectures.update(arches)
723 acl.allow_binary = True
724 acl.allow_binary_only = True
725 acl.allow_hijack = True
729 k.keyring_name = name
736 def keyring(command):
737 if command[1].startswith('list-'):
738 show_keyring(command)
739 elif command[1] == 'add-buildd':
740 keyring_add_buildd(command)
742 die("E: keyring command unknown")
744 dispatch['keyring'] = keyring
745 dispatch['k'] = keyring
747 ################################################################################
750 """Perform administrative work on the dak database"""
752 Cnf = utils.get_conf()
753 arguments = [('h', "help", "Admin::Options::Help"),
754 ('n', "dry-run", "Admin::Options::Dry-Run")]
755 for i in [ "help", "dry-run" ]:
756 if not Cnf.has_key("Admin::Options::%s" % (i)):
757 Cnf["Admin::Options::%s" % (i)] = ""
759 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
761 options = Cnf.subtree("Admin::Options")
762 if options["Help"] or len(arguments) < 1:
764 if options["Dry-Run"]:
767 subcommand = str(arguments[0])
769 if subcommand in dispatch.keys():
770 dispatch[subcommand](arguments)
772 die("E: Unknown command")
774 ################################################################################
776 if __name__ == '__main__':