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 [--print-archive]
91 s show SUITE show config details for a suite
92 s add SUITE VERSION [ label=LABEL ] [ description=DESCRIPTION ]
93 [ origin=ORIGIN ] [ codename=CODENAME ]
94 [ signingkey=SIGNINGKEY ] [ archive=ARCHIVE ]
95 add suite SUITE, version VERSION.
96 label, description, origin, codename
97 and signingkey are optional.
99 s add-all-arches SUITE VERSION... as "s add" but adds suite-architecture
100 relationships for all architectures
102 suite-architecture / s-a:
103 s-a list show the architectures for all suites
104 s-a list-suite ARCH show the suites an ARCH is in
105 s-a list-arch SUITE show the architectures in a SUITE
106 s-a add SUITE ARCH add ARCH to suite
107 s-a rm SUITE ARCH remove ARCH from suite (will only work if
108 no packages remain for the arch in the suite)
110 suite-component / s-c:
111 s-c list show the architectures for all suites
112 s-c list-suite COMPONENT
113 show the suites a COMPONENT is in
114 s-c list-component SUITE
115 show the components in a SUITE
116 s-c add SUITE COMPONENT
117 add COMPONENT to suite
118 s-c rm SUITE COMPONENT remove component from suite (will only work if
119 no packages remain for the component in the suite)
122 archive list list all archives
123 archive add NAME ROOT DESCRIPTION [primary-mirror=MIRROR] [tainted=1]
124 add archive NAME with path ROOT,
125 primary mirror MIRROR.
126 archive rm NAME remove archive NAME (will only work if there are
127 no files and no suites in the archive)
128 archive rename OLD NEW rename archive OLD to NEW
131 v-c list show version checks for all suites
132 v-c list-suite SUITE show version checks for suite SUITE
133 v-c add SUITE CHECK REFERENCE add a version check for suite SUITE
134 v-c rm SUITE CHECK REFERENCE remove a version check
136 CHECK is one of Enhances, MustBeNewerThan, MustBeOlderThan
137 REFERENCE is another suite name
141 ################################################################################
143 def __architecture_list(d, args):
144 q = d.session().query(Architecture).order_by(Architecture.arch_string)
146 # HACK: We should get rid of source from the arch table
147 if j.arch_string == 'source': continue
151 def __architecture_add(d, args):
152 die_arglen(args, 4, "E: adding an architecture requires a name and a description")
153 print "Adding architecture %s" % args[2]
154 suites = [str(x) for x in args[4:]]
156 print "Adding to suites %s" % ", ".join(suites)
161 a.arch_string = str(args[2]).lower()
162 a.description = str(args[3])
165 su = get_suite(sn, s)
169 warn("W: Cannot find suite %s" % su)
171 except IntegrityError as e:
172 die("E: Integrity error adding architecture %s (it probably already exists)" % args[2])
173 except SQLAlchemyError as e:
174 die("E: Error adding architecture %s (%s)" % (args[2], e))
175 print "Architecture %s added" % (args[2])
177 def __architecture_rm(d, args):
178 die_arglen(args, 3, "E: removing an architecture requires at least a name")
179 print "Removing architecture %s" % args[2]
183 a = get_architecture(args[2].lower(), s)
185 die("E: Cannot find architecture %s" % args[2])
188 except IntegrityError as e:
189 die("E: Integrity error removing architecture %s (suite-arch entries probably still exist)" % args[2])
190 except SQLAlchemyError as e:
191 die("E: Error removing architecture %s (%s)" % (args[2], e))
192 print "Architecture %s removed" % args[2]
194 def architecture(command):
195 args = [str(x) for x in command]
196 Cnf = utils.get_conf()
199 die_arglen(args, 2, "E: architecture needs at least a command")
201 mode = args[1].lower()
203 __architecture_list(d, args)
205 __architecture_add(d, args)
207 __architecture_rm(d, args)
209 die("E: architecture command unknown")
211 dispatch['architecture'] = architecture
212 dispatch['a'] = architecture
214 ################################################################################
216 def component_list():
217 session = DBConn().session()
218 for component in session.query(Component).order_by(Component.component_name):
219 print "{0} ordering={1}".format(component.component_name, component.ordering)
221 def component_add(args):
222 (name, description, ordering) = args[0:3]
226 description=description,
230 for option in args[3:]:
231 (key, value) = option.split('=')
232 attributes[key] = value
234 session = DBConn().session()
236 component = Component()
237 for key, value in attributes.iteritems():
238 setattr(component, key, value)
240 session.add(component)
248 def component_rm(name):
249 session = DBConn().session()
250 component = get_component(name, session)
251 session.delete(component)
259 def component_rename(oldname, newname):
260 session = DBConn().session()
261 component = get_component(oldname, session)
262 component.component_name = newname
270 def component(command):
274 elif mode == 'rename':
275 component_rename(command[2], command[3])
277 component_add(command[2:])
279 component_rm(command[2])
281 die("E: component command unknown")
283 dispatch['component'] = component
285 ################################################################################
287 def __suite_list(d, args):
289 for j in s.query(Suite).join(Suite.archive).order_by(Archive.archive_name, Suite.suite_name).all():
290 if len(args) > 2 and args[2] == "--print-archive":
291 print "{0} {1}".format(j.archive.archive_name, j.suite_name)
293 print "{0}".format(j.suite_name)
295 def __suite_show(d, args):
297 die("E: showing an suite entry requires a suite")
300 su = get_suite(args[2].lower())
302 die("E: can't find suite entry for %s" % (args[2].lower()))
306 def __suite_add(d, args, addallarches=False):
307 die_arglen(args, 4, "E: adding a suite requires at least a name and a version")
308 suite_name = args[2].lower()
312 def get_field(field):
314 if varval.startswith(field + '='):
315 return varval.split('=')[1]
318 print "Adding suite %s" % suite_name
323 suite.suite_name = suite_name
324 suite.overridecodename = suite_name
325 suite.version = version
326 suite.label = get_field('label')
327 suite.description = get_field('description')
328 suite.origin = get_field('origin')
329 suite.codename = get_field('codename')
330 signingkey = get_field('signingkey')
331 if signingkey is not None:
332 suite.signingkeys = [signingkey.upper()]
333 archive_name = get_field('archive')
334 if archive_name is not None:
335 suite.archive = get_archive(archive_name, s)
337 suite.archive = s.query(Archive).filter(~Archive.archive_name.in_(['build-queues', 'new', 'policy'])).one()
338 suite.srcformats = s.query(SrcFormat).all()
341 except IntegrityError as e:
342 die("E: Integrity error adding suite %s (it probably already exists)" % suite_name)
343 except SQLAlchemyError as e:
344 die("E: Error adding suite %s (%s)" % (suite_name, e))
345 print "Suite %s added" % (suite_name)
349 q = s.query(Architecture).order_by(Architecture.arch_string)
351 suite.architectures.append(arch)
352 arches.append(arch.arch_string)
354 print "Architectures %s added to %s" % (','.join(arches), suite_name)
358 def __suite_rm(d, args):
359 die_arglen(args, 3, "E: removing a suite requires at least a name")
361 print "Removing suite {0}".format(name)
365 su = get_suite(name.lower())
367 die("E: Cannot find suite {0}".format(name))
370 except IntegrityError as e:
371 die("E: Integrity error removing suite {0} (suite-arch entries probably still exist)".format(name))
372 except SQLAlchemyError as e:
373 die("E: Error removing suite {0} ({1})".format(name, e))
374 print "Suite {0} removed".format(name)
377 args = [str(x) for x in command]
378 Cnf = utils.get_conf()
381 die_arglen(args, 2, "E: suite needs at least a command")
383 mode = args[1].lower()
386 __suite_list(d, args)
388 __suite_show(d, args)
392 __suite_add(d, args, False)
393 elif mode == 'add-all-arches':
394 __suite_add(d, args, True)
396 die("E: suite command unknown")
398 dispatch['suite'] = suite
399 dispatch['s'] = suite
401 ################################################################################
403 def __suite_architecture_list(d, args):
405 for j in s.query(Suite).order_by(Suite.suite_name):
406 architectures = j.get_architectures(skipsrc = True, skipall = True)
407 print j.suite_name + ': ' + \
408 ', '.join([a.arch_string for a in architectures])
410 def __suite_architecture_listarch(d, args):
411 die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
412 suite = get_suite(args[2].lower(), d.session())
414 die('E: suite %s is invalid' % args[2].lower())
415 a = suite.get_architectures(skipsrc = True, skipall = True)
420 def __suite_architecture_listsuite(d, args):
421 die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
422 architecture = get_architecture(args[2].lower(), d.session())
423 if architecture is None:
424 die("E: architecture %s is invalid" % args[2].lower())
425 for j in architecture.suites:
429 def __suite_architecture_add(d, args):
431 die("E: adding a suite-architecture entry requires a suite and arch")
435 suite = get_suite(args[2].lower(), s)
436 if suite is None: die("E: Can't find suite %s" % args[2].lower())
438 arch = get_architecture(args[3].lower(), s)
439 if arch is None: die("E: Can't find architecture %s" % args[3].lower())
443 suite.architectures.append(arch)
445 except IntegrityError as e:
446 die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
447 except SQLAlchemyError as e:
448 die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
450 print "Added suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
453 def __suite_architecture_rm(d, args):
455 die("E: removing an suite-architecture entry requires a suite and arch")
460 suite_name = args[2].lower()
461 suite = get_suite(suite_name, s)
463 die('E: no such suite %s' % suite_name)
464 arch_string = args[3].lower()
465 architecture = get_architecture(arch_string, s)
466 if architecture not in suite.architectures:
467 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
468 suite.architectures.remove(architecture)
470 except IntegrityError as e:
471 die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
472 except SQLAlchemyError as e:
473 die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
475 print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
478 def suite_architecture(command):
479 args = [str(x) for x in command]
480 Cnf = utils.get_conf()
483 die_arglen(args, 2, "E: suite-architecture needs at least a command")
485 mode = args[1].lower()
488 __suite_architecture_list(d, args)
489 elif mode == 'list-arch':
490 __suite_architecture_listarch(d, args)
491 elif mode == 'list-suite':
492 __suite_architecture_listsuite(d, args)
494 __suite_architecture_add(d, args)
496 __suite_architecture_rm(d, args)
498 die("E: suite-architecture command unknown")
500 dispatch['suite-architecture'] = suite_architecture
501 dispatch['s-a'] = suite_architecture
503 ################################################################################
505 def __suite_component_list(d, args):
507 for j in s.query(Suite).order_by(Suite.suite_name):
508 components = j.components
509 print j.suite_name + ': ' + \
510 ', '.join([c.component_name for c in components])
513 def __suite_component_listcomponent(d, args):
514 die_arglen(args, 3, "E: suite-component list-component requires a suite")
515 suite = get_suite(args[2].lower(), d.session())
517 die('E: suite %s is invalid' % args[2].lower())
518 for c in suite.components:
519 print c.component_name
522 def __suite_component_listsuite(d, args):
523 die_arglen(args, 3, "E: suite-component list-suite requires an component")
524 component = get_component(args[2].lower(), d.session())
525 if component is None:
526 die("E: component %s is invalid" % args[2].lower())
527 for s in component.suites:
531 def __suite_component_add(d, args):
533 die("E: adding a suite-component entry requires a suite and component")
537 suite = get_suite(args[2].lower(), s)
538 if suite is None: die("E: Can't find suite %s" % args[2].lower())
540 component = get_component(args[3].lower(), s)
541 if component is None: die("E: Can't find component %s" % args[3].lower())
545 suite.components.append(component)
547 except IntegrityError as e:
548 die("E: Can't add suite-component entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
549 except SQLAlchemyError as e:
550 die("E: Can't add suite-component entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
552 print "Added suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())
555 def __suite_component_rm(d, args):
557 die("E: removing an suite-component entry requires a suite and component")
562 suite_name = args[2].lower()
563 suite = get_suite(suite_name, s)
565 die('E: no such suite %s' % suite_name)
566 component_string = args[3].lower()
567 component = get_component(arch_string, s)
568 if component not in suite.components:
569 die("E: component %s not found in suite %s" % (component_string, suite_name))
570 suite.components.remove(component)
572 except IntegrityError as e:
573 die("E: Can't remove suite-component entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
574 except SQLAlchemyError as e:
575 die("E: Can't remove suite-component entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
577 print "Removed suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())
580 def suite_component(command):
581 args = [str(x) for x in command]
582 Cnf = utils.get_conf()
585 die_arglen(args, 2, "E: suite-component needs at least a command")
587 mode = args[1].lower()
590 __suite_component_list(d, args)
591 elif mode == 'list-component':
592 __suite_component_listcomponent(d, args)
593 elif mode == 'list-suite':
594 __suite_component_listsuite(d, args)
596 __suite_component_add(d, args)
598 # __suite_architecture_rm(d, args)
600 die("E: suite-component command unknown")
602 dispatch['suite-component'] = suite_component
603 dispatch['s-c'] = suite_component
605 ################################################################################
608 session = DBConn().session()
609 for archive in session.query(Archive).order_by(Archive.archive_name):
610 print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
612 def archive_add(args):
613 (name, path, description) = args[0:3]
618 description=description,
621 for option in args[3:]:
622 (key, value) = option.split('=')
623 attributes[key] = value
625 session = DBConn().session()
628 for key, value in attributes.iteritems():
629 setattr(archive, key, value)
639 def archive_rm(name):
640 session = DBConn().session()
641 archive = get_archive(name, session)
642 session.delete(archive)
650 def archive_rename(oldname, newname):
651 session = DBConn().session()
652 archive = get_archive(oldname, session)
653 archive.archive_name = newname
661 def archive(command):
665 elif mode == 'rename':
666 archive_rename(command[2], command[3])
668 archive_add(command[2:])
670 archive_rm(command[2])
672 die("E: archive command unknown")
674 dispatch['archive'] = archive
676 ################################################################################
678 def __version_check_list(d):
679 session = d.session()
680 for s in session.query(Suite).order_by(Suite.suite_name):
681 __version_check_list_suite(d, s.suite_name)
683 def __version_check_list_suite(d, suite_name):
684 vcs = get_version_checks(suite_name)
686 print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
688 def __version_check_add(d, suite_name, check, reference_name):
689 suite = get_suite(suite_name)
691 die("E: Could not find suite %s." % (suite_name))
692 reference = get_suite(reference_name)
694 die("E: Could not find reference suite %s." % (reference_name))
696 session = d.session()
700 vc.reference = reference
704 def __version_check_rm(d, suite_name, check, reference_name):
705 suite = get_suite(suite_name)
707 die("E: Could not find suite %s." % (suite_name))
708 reference = get_suite(reference_name)
710 die("E: Could not find reference suite %s." % (reference_name))
712 session = d.session()
714 vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
717 except NoResultFound:
718 print "W: version-check not found."
720 def version_check(command):
721 args = [str(x) for x in command]
722 Cnf = utils.get_conf()
725 die_arglen(args, 2, "E: version-check needs at least a command")
726 mode = args[1].lower()
729 __version_check_list(d)
730 elif mode == 'list-suite':
732 die("E: version-check list-suite needs a single parameter")
733 __version_check_list_suite(d, args[2])
736 die("E: version-check add needs three parameters")
737 __version_check_add(d, args[2], args[3], args[4])
740 die("E: version-check rm needs three parameters")
741 __version_check_rm(d, args[2], args[3], args[4])
743 die("E: version-check command unknown")
745 dispatch['version-check'] = version_check
746 dispatch['v-c'] = version_check
748 ################################################################################
750 def show_config(command):
751 args = [str(x) for x in command]
752 cnf = utils.get_conf()
754 die_arglen(args, 2, "E: config needs at least a command")
756 mode = args[1].lower()
760 if cnf.has_key("DB::Service"):
762 connstr = "postgresql://service=%s" % cnf["DB::Service"]
763 elif cnf.has_key("DB::Host"):
765 connstr = "postgres://%s" % cnf["DB::Host"]
766 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
767 connstr += ":%s" % cnf["DB::Port"]
768 connstr += "/%s" % cnf["DB::Name"]
771 connstr = "postgres:///%s" % cnf["DB::Name"]
772 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
773 connstr += "?port=%s" % cnf["DB::Port"]
775 elif mode == 'db-shell':
777 if cnf.has_key("DB::Service"):
778 e.append('PGSERVICE')
779 print "PGSERVICE=%s" % cnf["DB::Service"]
780 if cnf.has_key("DB::Name"):
781 e.append('PGDATABASE')
782 print "PGDATABASE=%s" % cnf["DB::Name"]
783 if cnf.has_key("DB::Host"):
784 print "PGHOST=%s" % cnf["DB::Host"]
786 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
787 print "PGPORT=%s" % cnf["DB::Port"]
789 print "export " + " ".join(e)
791 print cnf.get(args[2])
793 session = DBConn().session()
795 o = session.query(DBConfig).filter_by(name = mode).one()
797 except NoResultFound:
798 print "W: option '%s' not set" % mode
800 dispatch['config'] = show_config
801 dispatch['c'] = show_config
803 ################################################################################
805 def show_keyring(command):
806 args = [str(x) for x in command]
807 cnf = utils.get_conf()
809 die_arglen(args, 2, "E: keyring needs at least a command")
811 mode = args[1].lower()
815 q = d.session().query(Keyring).filter(Keyring.active == True)
817 if mode == 'list-all':
819 elif mode == 'list-binary':
820 q = q.join(Keyring.acl).filter(ACL.allow_source == False)
821 elif mode == 'list-source':
822 q = q.join(Keyring.acl).filter(ACL.allow_source == True)
824 die("E: keyring command unknown")
829 def keyring_add_buildd(command):
831 arch_names = command[3:]
833 session = DBConn().session()
834 arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names))
837 acl.name = 'buildd-{0}'.format('+'.join(arch_names))
838 acl.architectures.update(arches)
840 acl.allow_binary = True
841 acl.allow_binary_only = True
842 acl.allow_hijack = True
846 k.keyring_name = name
853 def keyring(command):
854 if command[1].startswith('list-'):
855 show_keyring(command)
856 elif command[1] == 'add-buildd':
857 keyring_add_buildd(command)
859 die("E: keyring command unknown")
861 dispatch['keyring'] = keyring
862 dispatch['k'] = keyring
864 ################################################################################
867 """Perform administrative work on the dak database"""
869 Cnf = utils.get_conf()
870 arguments = [('h', "help", "Admin::Options::Help"),
871 ('n', "dry-run", "Admin::Options::Dry-Run")]
872 for i in [ "help", "dry-run" ]:
873 if not Cnf.has_key("Admin::Options::%s" % (i)):
874 Cnf["Admin::Options::%s" % (i)] = ""
876 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
878 options = Cnf.subtree("Admin::Options")
879 if options["Help"] or len(arguments) < 1:
881 if options["Dry-Run"]:
884 subcommand = str(arguments[0])
886 if subcommand in dispatch.keys():
887 dispatch[subcommand](arguments)
889 die("E: Unknown command")
891 ################################################################################
893 if __name__ == '__main__':