#!/usr/bin/env python # Copyright (C) 2008 Todd Zullinger # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Create a host-specific package for bootstrapping a puppet.""" import os import glob import optparse import puppethost def _main(): usage = '%prog [options] hostname [hostname ...]' parser = optparse.OptionParser(usage=usage) parser.defaults = puppethost.defaults parser.add_option('-a', '--all', dest='allcerts', action='store_true', help='Create packages for all signed certificates') parser.add_option('-d', '--domain', dest='domain', help='Domain append to non fqdn hostnames [%default]') parser.add_option('-f', '--force', dest='force', action='store_true', help='Overwrite existing certs, tarballs, and packages') parser.add_option('--force-cert', dest='force_cert', action='store_true', help='Overwrite existing certs') parser.add_option('--force-tarball', dest='force_tarball', action='store_true', help='Overwrite existing tarballs') parser.add_option('--force-package', dest='force_package', action='store_true', help='Overwrite existing packages') parser.add_option('-D', '--destdir', dest='destdir', metavar='dir', help='Directory where packages are stored [%default]') parser.add_option('--release', dest='release', metavar='num', help='Package release number [%default]') parser.add_option('-s', '--ssldir', dest='ssldir', metavar='dir', help='Directory where ssl certs are stored [%default]') # FIXME improve the help string parser.add_option('-S', '--dest-ssldir', dest='destssldir', metavar='dir', help='Directory where ssl certs are packaged') parser.add_option('--sign', dest='sign', action='store_true', help='Sign packages [%default]') parser.add_option('--sign-as', dest='key', default='', metavar='keyid', help='The key to use for signing (name or keyid)') parser.add_option('-t', '--template', dest='template', metavar='file', help='RPM spec file template [%default]') parser.add_option('-v', '--verbose', dest='verbose', action='count', help='Be verbose (may be used more than once)') parser.add_option('--package-type', help='Package type (%s) [%s]' % (', '.join(sorted(puppethost.package_types)), '%default')) opts, args = parser.parse_args() if opts.force: opts.force_cert = True opts.force_tarball = True opts.force_package = True if opts.allcerts: args = [] for cert in glob.glob('%s/ca/signed/*.pem' % opts.ssldir): basename = os.path.basename(cert) # we need the private key as well as the cert if os.path.exists('%s/private_keys/%s' % (opts.ssldir, basename)): args.append(os.path.splitext(basename)[0]) args.sort() if not args: raise SystemExit(parser.print_usage()) opts.destdir = os.path.expanduser(os.path.abspath(opts.destdir)) opts.ssldir = os.path.expanduser(os.path.abspath(opts.ssldir)) for d in [opts.destdir, opts.ssldir]: if not os.path.isdir(d): raise SystemExit('%s does not exist (or is not a directory)' % d) if not opts.destssldir: opts.destssldir = opts.ssldir else: opts.destssldir = os.path.expanduser(os.path.abspath(opts.destssldir)) opts.template = os.path.expanduser(opts.template % opts.__dict__) if not os.path.isfile(opts.template): raise SystemExit('Template file (%s) does not exist' % opts.template) if opts.key: opts.sign = True packages = [] for hostname in args: if opts.verbose: print '\nCreating a host package for %s' % hostname host = puppethost.PuppetHost(hostname, opts.__dict__) if not os.path.exists(host.files['cert']) or opts.force_cert: try: host.gencert() except puppethost.PuppetHostError, error: host.cleanup() print error continue try: host.package() except Exception, error: host.cleanup() print error continue try: host.cleanup() except Exception, error: print 'Failed to cleanup %s: %s' % (hostname, error) packages.extend(host.packages) if packages and opts.sign: if opts.verbose: keyid = opts.key and opts.key or 'default key' print 'Signing packages using %s' % keyid try: puppethost.sign(packages, key=opts.key, verbose=opts.verbose) except puppethost.PuppetHostError, error: raise SystemExit(error) if __name__ == '__main__': try: _main() except KeyboardInterrupt: raise SystemExit(1)