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 for arch_name in args[3:]:
439 arch = get_architecture(arch_name.lower(), s)
440 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(), arch_name))
447 except SQLAlchemyError as e:
448 die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), arch_name, e))
450 print "Added suite-architecture entry for %s, %s" % (args[2].lower(), arch_name)
457 def __suite_architecture_rm(d, args):
459 die("E: removing an suite-architecture entry requires a suite and arch")
464 suite_name = args[2].lower()
465 suite = get_suite(suite_name, s)
467 die('E: no such suite %s' % suite_name)
468 arch_string = args[3].lower()
469 architecture = get_architecture(arch_string, s)
470 if architecture not in suite.architectures:
471 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
472 suite.architectures.remove(architecture)
474 except IntegrityError as e:
475 die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
476 except SQLAlchemyError as e:
477 die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
479 print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
482 def suite_architecture(command):
483 args = [str(x) for x in command]
484 Cnf = utils.get_conf()
487 die_arglen(args, 2, "E: suite-architecture needs at least a command")
489 mode = args[1].lower()
492 __suite_architecture_list(d, args)
493 elif mode == 'list-arch':
494 __suite_architecture_listarch(d, args)
495 elif mode == 'list-suite':
496 __suite_architecture_listsuite(d, args)
498 __suite_architecture_add(d, args)
500 __suite_architecture_rm(d, args)
502 die("E: suite-architecture command unknown")
504 dispatch['suite-architecture'] = suite_architecture
505 dispatch['s-a'] = suite_architecture
507 ################################################################################
509 def __suite_component_list(d, args):
511 for j in s.query(Suite).order_by(Suite.suite_name):
512 components = j.components
513 print j.suite_name + ': ' + \
514 ', '.join([c.component_name for c in components])
517 def __suite_component_listcomponent(d, args):
518 die_arglen(args, 3, "E: suite-component list-component requires a suite")
519 suite = get_suite(args[2].lower(), d.session())
521 die('E: suite %s is invalid' % args[2].lower())
522 for c in suite.components:
523 print c.component_name
526 def __suite_component_listsuite(d, args):
527 die_arglen(args, 3, "E: suite-component list-suite requires an component")
528 component = get_component(args[2].lower(), d.session())
529 if component is None:
530 die("E: component %s is invalid" % args[2].lower())
531 for s in component.suites:
535 def __suite_component_add(d, args):
537 die("E: adding a suite-component entry requires a suite and component")
541 suite = get_suite(args[2].lower(), s)
542 if suite is None: die("E: Can't find suite %s" % args[2].lower())
544 for component_name in args[3:]:
545 component = get_component(component_name.lower(), s)
546 if component is None: die("E: Can't find component %s" % args[3].lower())
549 suite.components.append(component)
551 except IntegrityError as e:
552 die("E: Can't add suite-component entry (%s, %s) - probably already exists" % (args[2].lower(), component_name))
553 except SQLAlchemyError as e:
554 die("E: Can't add suite-component entry (%s, %s) - %s" % (args[2].lower(), component_name, e))
556 print "Added suite-component entry for %s, %s" % (args[2].lower(), component_name)
562 def __suite_component_rm(d, args):
564 die("E: removing an suite-component entry requires a suite and component")
569 suite_name = args[2].lower()
570 suite = get_suite(suite_name, s)
572 die('E: no such suite %s' % suite_name)
573 component_string = args[3].lower()
574 component = get_component(arch_string, s)
575 if component not in suite.components:
576 die("E: component %s not found in suite %s" % (component_string, suite_name))
577 suite.components.remove(component)
579 except IntegrityError as e:
580 die("E: Can't remove suite-component entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
581 except SQLAlchemyError as e:
582 die("E: Can't remove suite-component entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
584 print "Removed suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())
587 def suite_component(command):
588 args = [str(x) for x in command]
589 Cnf = utils.get_conf()
592 die_arglen(args, 2, "E: suite-component needs at least a command")
594 mode = args[1].lower()
597 __suite_component_list(d, args)
598 elif mode == 'list-component':
599 __suite_component_listcomponent(d, args)
600 elif mode == 'list-suite':
601 __suite_component_listsuite(d, args)
603 __suite_component_add(d, args)
605 # __suite_architecture_rm(d, args)
607 die("E: suite-component command unknown")
609 dispatch['suite-component'] = suite_component
610 dispatch['s-c'] = suite_component
612 ################################################################################
615 session = DBConn().session()
616 for archive in session.query(Archive).order_by(Archive.archive_name):
617 print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
619 def archive_add(args):
620 (name, path, description) = args[0:3]
625 description=description,
628 for option in args[3:]:
629 (key, value) = option.split('=')
630 attributes[key] = value
632 session = DBConn().session()
635 for key, value in attributes.iteritems():
636 setattr(archive, key, value)
646 def archive_rm(name):
647 session = DBConn().session()
648 archive = get_archive(name, session)
649 session.delete(archive)
657 def archive_rename(oldname, newname):
658 session = DBConn().session()
659 archive = get_archive(oldname, session)
660 archive.archive_name = newname
668 def archive(command):
672 elif mode == 'rename':
673 archive_rename(command[2], command[3])
675 archive_add(command[2:])
677 archive_rm(command[2])
679 die("E: archive command unknown")
681 dispatch['archive'] = archive
683 ################################################################################
685 def __version_check_list(d):
686 session = d.session()
687 for s in session.query(Suite).order_by(Suite.suite_name):
688 __version_check_list_suite(d, s.suite_name)
690 def __version_check_list_suite(d, suite_name):
691 vcs = get_version_checks(suite_name)
693 print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
695 def __version_check_add(d, suite_name, check, reference_name):
696 suite = get_suite(suite_name)
698 die("E: Could not find suite %s." % (suite_name))
699 reference = get_suite(reference_name)
701 die("E: Could not find reference suite %s." % (reference_name))
703 session = d.session()
707 vc.reference = reference
711 def __version_check_rm(d, suite_name, check, reference_name):
712 suite = get_suite(suite_name)
714 die("E: Could not find suite %s." % (suite_name))
715 reference = get_suite(reference_name)
717 die("E: Could not find reference suite %s." % (reference_name))
719 session = d.session()
721 vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
724 except NoResultFound:
725 print "W: version-check not found."
727 def version_check(command):
728 args = [str(x) for x in command]
729 Cnf = utils.get_conf()
732 die_arglen(args, 2, "E: version-check needs at least a command")
733 mode = args[1].lower()
736 __version_check_list(d)
737 elif mode == 'list-suite':
739 die("E: version-check list-suite needs a single parameter")
740 __version_check_list_suite(d, args[2])
743 die("E: version-check add needs three parameters")
744 __version_check_add(d, args[2], args[3], args[4])
747 die("E: version-check rm needs three parameters")
748 __version_check_rm(d, args[2], args[3], args[4])
750 die("E: version-check command unknown")
752 dispatch['version-check'] = version_check
753 dispatch['v-c'] = version_check
755 ################################################################################
757 def show_config(command):
758 args = [str(x) for x in command]
759 cnf = utils.get_conf()
761 die_arglen(args, 2, "E: config needs at least a command")
763 mode = args[1].lower()
767 if cnf.has_key("DB::Service"):
769 connstr = "postgresql://service=%s" % cnf["DB::Service"]
770 elif cnf.has_key("DB::Host"):
772 connstr = "postgres://%s" % cnf["DB::Host"]
773 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
774 connstr += ":%s" % cnf["DB::Port"]
775 connstr += "/%s" % cnf["DB::Name"]
778 connstr = "postgres:///%s" % cnf["DB::Name"]
779 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
780 connstr += "?port=%s" % cnf["DB::Port"]
782 elif mode == 'db-shell':
784 if cnf.has_key("DB::Service"):
785 e.append('PGSERVICE')
786 print "PGSERVICE=%s" % cnf["DB::Service"]
787 if cnf.has_key("DB::Name"):
788 e.append('PGDATABASE')
789 print "PGDATABASE=%s" % cnf["DB::Name"]
790 if cnf.has_key("DB::Host"):
791 print "PGHOST=%s" % cnf["DB::Host"]
793 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
794 print "PGPORT=%s" % cnf["DB::Port"]
796 print "export " + " ".join(e)
798 print cnf.get(args[2])
800 session = DBConn().session()
802 o = session.query(DBConfig).filter_by(name = mode).one()
804 except NoResultFound:
805 print "W: option '%s' not set" % mode
807 dispatch['config'] = show_config
808 dispatch['c'] = show_config
810 ################################################################################
812 def show_keyring(command):
813 args = [str(x) for x in command]
814 cnf = utils.get_conf()
816 die_arglen(args, 2, "E: keyring needs at least a command")
818 mode = args[1].lower()
822 q = d.session().query(Keyring).filter(Keyring.active == True)
824 if mode == 'list-all':
826 elif mode == 'list-binary':
827 q = q.join(Keyring.acl).filter(ACL.allow_source == False)
828 elif mode == 'list-source':
829 q = q.join(Keyring.acl).filter(ACL.allow_source == True)
831 die("E: keyring command unknown")
836 def keyring_add_buildd(command):
838 arch_names = command[3:]
840 session = DBConn().session()
841 arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names))
844 acl.name = 'buildd-{0}'.format('+'.join(arch_names))
845 acl.architectures.update(arches)
847 acl.allow_binary = True
848 acl.allow_binary_only = True
849 acl.allow_hijack = True
853 k.keyring_name = name
860 def keyring(command):
861 if command[1].startswith('list-'):
862 show_keyring(command)
863 elif command[1] == 'add-buildd':
864 keyring_add_buildd(command)
866 die("E: keyring command unknown")
868 dispatch['keyring'] = keyring
869 dispatch['k'] = keyring
871 ################################################################################
874 """Perform administrative work on the dak database"""
876 Cnf = utils.get_conf()
877 arguments = [('h', "help", "Admin::Options::Help"),
878 ('n', "dry-run", "Admin::Options::Dry-Run")]
879 for i in [ "help", "dry-run" ]:
880 if not Cnf.has_key("Admin::Options::%s" % (i)):
881 Cnf["Admin::Options::%s" % (i)] = ""
883 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
885 options = Cnf.subtree("Admin::Options")
886 if options["Help"] or len(arguments) < 1:
888 if options["Dry-Run"]:
891 subcommand = str(arguments[0])
893 if subcommand in dispatch.keys():
894 dispatch[subcommand](arguments)
896 die("E: Unknown command")
898 ################################################################################
900 if __name__ == '__main__':