From 9eb3db849ba11ac49ced872a585f001bad3d8384 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 3 Oct 2012 15:27:34 -0400 Subject: prompt for locations of bcfg2 keypair in Init, using sane OS defaults --- src/lib/Bcfg2/Server/Admin/Init.py | 219 +++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 119 deletions(-) (limited to 'src/lib/Bcfg2/Server/Admin/Init.py') diff --git a/src/lib/Bcfg2/Server/Admin/Init.py b/src/lib/Bcfg2/Server/Admin/Init.py index 62f150055..5d5888ff2 100644 --- a/src/lib/Bcfg2/Server/Admin/Init.py +++ b/src/lib/Bcfg2/Server/Admin/Init.py @@ -1,3 +1,4 @@ +""" Interactively initialize a new repository. """ import getpass import os import random @@ -10,17 +11,17 @@ import subprocess import Bcfg2.Server.Admin import Bcfg2.Server.Plugin import Bcfg2.Options -from Bcfg2.Compat import input +from Bcfg2.Compat import input # pylint: disable=W0622 # default config file -config = '''[server] +CONFIG = '''[server] repository = %s plugins = %s [statistics] sendmailpath = %s #web_debug = False -#time_zone = +#time_zone = [database] #engine = sqlite3 @@ -48,7 +49,7 @@ bcfg2 = %s ''' # Default groups -groups = ''' +GROUPS = ''' @@ -65,13 +66,13 @@ groups = ''' ''' # Default contents of clients.xml -clients = ''' +CLIENTS = ''' ''' # Mapping of operating system names to groups -os_list = [('Red Hat/Fedora/RHEL/RHAS/Centos', 'redhat'), +OS_LIST = [('Red Hat/Fedora/RHEL/RHAS/Centos', 'redhat'), ('SUSE/SLES', 'suse'), ('Mandrake', 'mandrake'), ('Debian', 'debian'), @@ -80,43 +81,11 @@ os_list = [('Red Hat/Fedora/RHEL/RHAS/Centos', 'redhat'), ('FreeBSD', 'freebsd'), ('Arch', 'arch')] -# Complete list of plugins -plugin_list = ['Account', - 'Base', - 'Bundler', - 'Bzr', - 'Cfg', - 'Decisions', - 'Deps', - 'Git', - 'Guppy', - 'Hg', - 'Metadata', - 'NagiosGen', - 'Ohai', - 'Packages', - 'Pkgmgr', - 'Probes', - 'Properties', - 'Rules', - 'Snapshots', - 'SSHbase', - 'SSLCA', - 'Statistics', - 'TCheetah', - 'TGenshi'] - -# Default list of plugins to use -default_plugins = Bcfg2.Options.SERVER_PLUGINS.default - def gen_password(length): """Generates a random alphanumeric password with length characters.""" chars = string.letters + string.digits - newpasswd = '' - for i in range(length): - newpasswd = newpasswd + random.choice(chars) - return newpasswd + return "".join(random.choice(chars) for i in range(length)) def create_key(hostname, keypath, certpath, country, state, location): @@ -140,7 +109,8 @@ def create_key(hostname, keypath, certpath, country, state, location): os.chmod(keypath, stat.S_IRUSR | stat.S_IWUSR) # 0600 -def create_conf(confpath, confdata, keypath): +def create_conf(confpath, confdata): + """ create the config file """ # Don't overwrite existing bcfg2.conf file if os.path.exists(confpath): result = input("\nWarning: %s already exists. " @@ -152,14 +122,14 @@ def create_conf(confpath, confdata, keypath): open(confpath, "w").write(confdata) os.chmod(confpath, stat.S_IRUSR | stat.S_IWUSR) # 0600 except Exception: - e = sys.exc_info()[1] - print("Error %s occured while trying to write configuration " - "file to '%s'.\n" % - (e, confpath)) + err = sys.exc_info()[1] + print("Error trying to write configuration file '%s': %s" % + (confpath, err)) raise SystemExit(1) class Init(Bcfg2.Server.Admin.Mode): + """Interactively initialize a new repository.""" __shorthelp__ = ("Interactively initialize a new repository.") __longhelp__ = __shorthelp__ + "\n\nbcfg2-admin init" __usage__ = "bcfg2-admin init" @@ -168,24 +138,38 @@ class Init(Bcfg2.Server.Admin.Mode): 'proto': Bcfg2.Options.SERVER_PROTOCOL, 'repo': Bcfg2.Options.SERVER_REPOSITORY, 'sendmail': Bcfg2.Options.SENDMAIL_PATH} - repopath = "" - response = "" - def _set_defaults(self): + def __init__(self, setup): + Bcfg2.Server.Admin.Mode.__init__(self, setup) + self.data = dict() + self.plugins = Bcfg2.Options.SERVER_PLUGINS.default + + def _set_defaults(self, opts): """Set default parameters.""" - self.configfile = self.opts['configfile'] - self.repopath = self.opts['repo'] - self.password = gen_password(8) - self.server_uri = "https://%s:6789" % socket.getfqdn() - self.plugins = default_plugins + self.data['configfile'] = opts['configfile'] + self.data['repopath'] = opts['repo'] + self.data['password'] = gen_password(8) + self.data['server_uri'] = "https://%s:6789" % socket.getfqdn() + self.data['sendmail'] = opts['sendmail'] + self.data['proto'] = opts['proto'] + if os.path.exists("/etc/pki/tls"): + self.data['keypath'] = "/etc/pki/tls/private/bcfg2.key" + self.data['certpath'] = "/etc/pki/tls/certs/bcfg2.crt" + elif os.path.exists("/etc/ssl"): + self.data['keypath'] = "/etc/ssl/bcfg2.key" + self.data['certpath'] = "/etc/ssl/bcfg2.crt" + else: + basepath = os.path.dirname(self.configfile) + self.data['keypath'] = os.path.join(basepath, "bcfg2.key") + self.data['certpath'] = os.path.join(basepath, 'bcfg2.crt') def __call__(self, args): Bcfg2.Server.Admin.Mode.__call__(self, args) # Parse options - self.opts = Bcfg2.Options.OptionParser(self.options) - self.opts.parse(args) - self._set_defaults() + opts = Bcfg2.Options.OptionParser(self.options) + opts.parse(args) + self._set_defaults(opts) # Prompt the user for input self._prompt_config() @@ -194,7 +178,7 @@ class Init(Bcfg2.Server.Admin.Mode): self._prompt_hostname() self._prompt_server() self._prompt_groups() - # self._prompt_plugins() + self._prompt_keypath() self._prompt_certificate() # Initialize the repository @@ -205,27 +189,27 @@ class Init(Bcfg2.Server.Admin.Mode): data = input("What is the server's hostname [%s]: " % socket.getfqdn()) if data != '': - self.shostname = data + self.data['shostname'] = data else: - self.shostname = socket.getfqdn() + self.data['shostname'] = socket.getfqdn() def _prompt_config(self): """Ask for the configuration file path.""" newconfig = input("Store Bcfg2 configuration in [%s]: " % self.configfile) if newconfig != '': - self.configfile = os.path.abspath(newconfig) + self.data['configfile'] = os.path.abspath(newconfig) def _prompt_repopath(self): """Ask for the repository path.""" while True: newrepo = input("Location of Bcfg2 repository [%s]: " % - self.repopath) + self.data['repopath']) if newrepo != '': - self.repopath = os.path.abspath(newrepo) - if os.path.isdir(self.repopath): - response = input("Directory %s exists. Overwrite? [y/N]:" \ - % self.repopath) + self.data['repopath'] = os.path.abspath(newrepo) + if os.path.isdir(self.data['repopath']): + response = input("Directory %s exists. Overwrite? [y/N]:" % + self.data['repopath']) if response.lower().strip() == 'y': break else: @@ -237,45 +221,29 @@ class Init(Bcfg2.Server.Admin.Mode): "Input password used for communication verification " "(without echoing; leave blank for a random): ").strip() if len(newpassword) != 0: - self.password = newpassword + self.data['password'] = newpassword def _prompt_server(self): """Ask for the server name.""" newserver = input("Input the server location [%s]: " % - self.server_uri) + self.data['server_uri']) if newserver != '': - self.server_uri = newserver + self.data['server_uri'] = newserver def _prompt_groups(self): """Create the groups.xml file.""" prompt = '''Input base Operating System for clients:\n''' - for entry in os_list: - prompt += "%d: %s\n" % (os_list.index(entry) + 1, entry[0]) + for entry in OS_LIST: + prompt += "%d: %s\n" % (OS_LIST.index(entry) + 1, entry[0]) prompt += ': ' while True: try: osidx = int(input(prompt)) - self.os_sel = os_list[osidx - 1][1] + self.data['os_sel'] = OS_LIST[osidx - 1][1] break except ValueError: continue - def _prompt_plugins(self): - default = input("Use default plugins? (%s) [Y/n]: " % - ''.join(default_plugins)).lower() - if default != 'y' or default != '': - while True: - plugins_are_valid = True - plug_str = input("Specify plugins: ") - plugins = plug_str.split(',') - for plugin in plugins: - plugin = plugin.strip() - if not plugin in plugin_list: - plugins_are_valid = False - print("ERROR: Plugin %s not recognized" % plugin) - if plugins_are_valid: - break - def _prompt_certificate(self): """Ask for the key details (country, state, and location).""" print("The following questions affect SSL certificate generation.") @@ -283,73 +251,86 @@ class Init(Bcfg2.Server.Admin.Mode): newcountry = input("Country name (2 letter code) for certificate: ") if newcountry != '': if len(newcountry) == 2: - self.country = newcountry + self.data['country'] = newcountry else: while len(newcountry) != 2: newcountry = input("2 letter country code (eg. US): ") if len(newcountry) == 2: - self.country = newcountry + self.data['country'] = newcountry break else: - self.country = 'US' + self.data['country'] = 'US' - newstate = input("State or Province Name (full name) for certificate: ") + newstate = input("State or Province Name (full name) for " + "certificate: ") if newstate != '': - self.state = newstate + self.data['state'] = newstate else: - self.state = 'Illinois' + self.data['state'] = 'Illinois' newlocation = input("Locality Name (eg, city) for certificate: ") if newlocation != '': - self.location = newlocation + self.data['location'] = newlocation else: - self.location = 'Argonne' + self.data['location'] = 'Argonne' + + def _prompt_keypath(self): + """ Ask for the key pair location. Try to use sensible + defaults depending on the OS """ + keypath = input("Path where Bcfg2 server private key will be created " + "[%s]: " % self.data['keypath']) + if keypath: + self.data['keypath'] = keypath + certpath = input("Path where Bcfg2 server cert will be created" + "[%s]: " % self.data['certpath']) + if certpath: + self.data['certpath'] = certpath def _init_plugins(self): """Initialize each plugin-specific portion of the repository.""" for plugin in self.plugins: if plugin == 'Metadata': Bcfg2.Server.Plugins.Metadata.Metadata.init_repo( - self.repopath, - groups_xml=groups % self.os_sel, - clients_xml=clients % socket.getfqdn()) + self.data['repopath'], + groups_xml=GROUPS % self.data['os_sel'], + clients_xml=CLIENTS % socket.getfqdn()) else: try: module = __import__("Bcfg2.Server.Plugins.%s" % plugin, '', '', ["Bcfg2.Server.Plugins"]) cls = getattr(module, plugin) - cls.init_repo(self.repopath) - except Exception: - e = sys.exc_info()[1] + cls.init_repo(self.data['repopath']) + except: # pylint: disable=W0702 + err = sys.exc_info()[1] print("Plugin setup for %s failed: %s\n" - "Check that dependencies are installed?" % (plugin, e)) + "Check that dependencies are installed" % (plugin, + err)) def init_repo(self): - """Setup a new repo and create the content of the configuration file.""" - keypath = os.path.dirname(self.configfile) - kpath = os.path.join(keypath, 'bcfg2.key') - cpath = os.path.join(keypath, 'bcfg2.crt') - - confdata = config % (self.repopath, + """Setup a new repo and create the content of the + configuration file.""" + confdata = CONFIG % (self.data['repopath'], ','.join(self.plugins), - self.opts['sendmail'], - self.opts['proto'], - self.password, - cpath, - kpath, - cpath, - self.server_uri) + self.data['sendmail'], + self.data['proto'], + self.data['password'], + self.data['certpath'], + self.data['keypath'], + self.data['certpath'], + self.data['server_uri']) # Create the configuration file and SSL key - create_conf(self.configfile, confdata, keypath) - create_key(self.shostname, kpath, cpath, self.country, - self.state, self.location) + create_conf(self.data['configfile'], confdata) + create_key(self.data['shostname'], self.data['keypath'], + self.data['certpath'], self.data['country'], + self.data['state'], self.data['location']) # Create the repository - path = os.path.join(self.repopath, 'etc') + path = os.path.join(self.data['repopath'], 'etc') try: os.makedirs(path) self._init_plugins() - print("Repository created successfuly in %s" % (self.repopath)) + print("Repository created successfuly in %s" % + self.data['repopath']) except OSError: print("Failed to create %s." % path) -- cgit v1.2.3-1-g7c22