Reverted back to using set through for password configs, also fixes issue #90, other teenie cleanups

This commit is contained in:
Joshua Harlow 2012-03-15 00:38:30 -07:00
parent 725cad4615
commit bd7fbd5474
9 changed files with 111 additions and 78 deletions

View File

@ -69,9 +69,9 @@ class IgnoreMissingConfigParser(ConfigParser.RawConfigParser):
class StackConfigParser(IgnoreMissingConfigParser):
def __init__(self, cache):
def __init__(self):
IgnoreMissingConfigParser.__init__(self)
self.configs_fetched = cache
self.configs_fetched = dict()
def _resolve_value(self, section, option, value_gotten):
if section == 'host' and option == 'ip':
@ -100,6 +100,12 @@ class StackConfigParser(IgnoreMissingConfigParser):
self.configs_fetched[key] = value
return value
def set(self, section, option, value):
key = cfg_helpers.make_id(section, option)
LOG.audit("Setting config value [%s] for param [%s]" % (value, key))
self.configs_fetched[key] = value
IgnoreMissingConfigParser.set(self, section, option, value)
def _resolve_replacements(self, value):
LOG.debug("Performing simple replacement on [%s]", value)

View File

@ -261,18 +261,9 @@ def get_shared_params(config, pw_gen, service_user_name=None):
mp['DEMO_TENANT_NAME'] = mp['DEMO_USER_NAME']
#tokens and passwords
mp['SERVICE_TOKEN'] = pw_gen.get_password(
"service_token",
'the service admin token',
)
mp['ADMIN_PASSWORD'] = pw_gen.get_password(
'horizon_keystone_admin',
'the horizon and keystone admin',
20)
mp['SERVICE_PASSWORD'] = pw_gen.get_password(
'service_password',
'service authentication',
)
mp['SERVICE_TOKEN'] = pw_gen.get_password("service_token")
mp['ADMIN_PASSWORD'] = pw_gen.get_password('horizon_keystone_admin', length=20)
mp['SERVICE_PASSWORD'] = pw_gen.get_password('service_password')
#components of the auth endpoint
keystone_auth_host = config.getdefaulted('keystone', 'keystone_auth_host', host_ip)

View File

@ -43,6 +43,9 @@ PASSWORDS_MAKES = {
'MYSQL_PASSWORD': 'sql',
}
#install root
INSTALL_ROOT = 'INSTALL_ROOT'
#default ports
EC2_PORT = 8773
S3_PORT = 3333
@ -55,9 +58,10 @@ QUOTED_PAT = re.compile(r"^\s*[\"](.*)[\"]\s*$")
class RcWriter(object):
def __init__(self, cfg, pw_gen):
def __init__(self, cfg, pw_gen, root_dir):
self.cfg = cfg
self.pw_gen = pw_gen
self.root_dir = root_dir
def _make_export(self, export_name, value):
escaped_val = sh.shellquote(value)
@ -93,7 +97,7 @@ class RcWriter(object):
def _get_password_envs(self):
to_set = dict()
for (out_name, key) in PASSWORDS_MAKES.items():
to_set[out_name] = self.pw_gen.get_password(key, do_prompt=False)
to_set[out_name] = self.pw_gen.extract(key)
return to_set
def _get_general_envs(self):
@ -101,6 +105,7 @@ class RcWriter(object):
for (out_name, cfg_data) in CFG_MAKE.items():
(section, key) = (cfg_data)
to_set[out_name] = self.cfg.get(section, key)
to_set[INSTALL_ROOT] = self.root_dir
return to_set
def _generate_passwords(self):

View File

@ -19,11 +19,9 @@ from optparse import OptionParser, OptionGroup
from devstack import log as logging
from devstack import settings
from devstack import shell as sh
from devstack import version
HELP_WIDTH = 80
DEF_OS_DIR = "openstack"
LOG = logging.getLogger("devstack.opts")
@ -61,16 +59,13 @@ def parse():
dest="action",
metavar="ACTION",
help="required action to perform: %s" % (_format_list(settings.ACTIONS)))
default_dir = sh.joinpths(sh.gethomedir(), DEF_OS_DIR)
base_group.add_option("-d", "--directory",
action="store",
type="string",
dest="dir",
metavar="DIR",
default=default_dir,
help=("empty root DIR for install or "
"DIR with existing components for start/stop/uninstall "
"(default: %default)"))
"DIR with existing components for start/stop/uninstall"))
base_group.add_option("-i", "--ignore-deps",
action="store_false",
dest="ensure_deps",

View File

@ -1,18 +1,34 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
# Copyright (C) 2012 Dreamhost Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ConfigParser
import binascii
import getpass
import logging
import os
import re
from devstack import cfg_helpers
LOG = logging.getLogger("devstack.passwords")
PW_SECTION = 'passwords'
HELPFUL_DESCRIPTIONS = {
'sql': 'the database user',
'rabbit': 'the rabbit user',
'horizon_keystone_admin': 'the horizon and keystone admin',
'service_password': 'service authentication',
"service_token": 'the service admin token',
}
@ -29,12 +45,19 @@ def generate_random(length):
class PasswordGenerator(object):
def __init__(self, kv_cache, cfg,
prompt_user=True):
def __init__(self, cfg, prompt_user=True):
self.cfg = cfg
self.config_cache = kv_cache
self.prompt_user = prompt_user
def _valid_password(self, pw):
# FIXME: More efficient way to look for whitespace?
if re.match(r"^(\s+)$", pw) or \
re.match(r"^(\s+)(\S+)(\s+)$", pw) or \
re.match(r"^(\S+)(\s+)$", pw) or \
re.match(r"^(\s+)(\S+)$", pw):
return False
return True
def _prompt_user(self, prompt_text):
LOG.debug('Asking the user for a %r password', prompt_text)
message = ("Enter a password to use for %s "
@ -43,20 +66,19 @@ class PasswordGenerator(object):
rc = ""
while True:
rc = getpass.getpass(message)
if len(rc) == 0:
if len(rc) == 0 or self._valid_password(rc):
break
# FIXME: More efficient way to look for whitespace?
if re.match(r"^(\s+)$", rc):
LOG.warning("Whitespace not allowed as a password!")
elif re.match(r"^(\s+)(\S+)(\s+)$", rc) or \
re.match(r"^(\S+)(\s+)$", rc) or \
re.match(r"^(\s+)(\S+)$", rc):
LOG.warning("Whitespace can not start or end a password!")
else:
break
LOG.warn("Invalid password \"%s\" (please try again)" % (rc))
return rc
def get_password(self, option, prompt_text=None, length=8, do_prompt=True):
def extract(self, option):
return self.cfg.get(PW_SECTION, option)
def _set_through(self, option, value):
self.cfg.set(PW_SECTION, option, value)
def get_password(self, option, prompt_text=None, length=8):
"""Returns a password identified by the configuration location."""
if not prompt_text:
@ -64,18 +86,16 @@ class PasswordGenerator(object):
LOG.debug('Looking for password %s (%s)', option, prompt_text)
cache_key = cfg_helpers.make_id(PW_SECTION, option)
password = self.config_cache.get(cache_key)
# Look in the configuration file(s)
password = None
from_config = False
if not password:
try:
password = self.cfg.get(PW_SECTION, option)
except ConfigParser.Error:
password = ''
password = self.cfg.get(PW_SECTION, option)
if password:
from_config = True
# Optionally ask the user
if not password and self.prompt_user and do_prompt:
if not password and self.prompt_user:
password = self._prompt_user(prompt_text)
# If we still don't have a value, make one up.
@ -84,8 +104,8 @@ class PasswordGenerator(object):
option, prompt_text)
password = generate_random(length)
# Update the cache so that other parts of the
# code can find the value.
self.config_cache[cache_key] = password
# Update via set through to the config
if not from_config:
self._set_through(option, password)
return password

View File

@ -164,7 +164,6 @@ class ActionRunner(object):
self.force = kargs.get('force', False)
self.ignore_deps = kargs.get('ignore_deps', False)
self.ref_components = kargs.get("ref_components")
self.rc_file = sh.abspth(settings.OSRC_FN)
self.gen_rc = action in _RC_FILE_MAKE_ACTIONS
def _get_components(self):
@ -233,13 +232,6 @@ class ActionRunner(object):
def _pre_run(self, instances, component_order):
if not sh.isdir(self.directory):
sh.mkdir(self.directory)
if self.rc_file:
try:
LOG.info("Attempting to load rc file at [%s] which has your environment settings." % (self.rc_file))
am_loaded = env_rc.RcReader().load(self.rc_file)
LOG.info("Loaded [%s] settings from rc file [%s]" % (am_loaded, self.rc_file))
except IOError:
LOG.warn('Error reading rc file located at [%s]. Skipping loading it.' % (self.rc_file))
LOG.info("Verifying that the components are ready to rock-n-roll.")
for component in component_order:
inst = instances[component]
@ -248,15 +240,15 @@ class ActionRunner(object):
for component in component_order:
inst = instances[component]
inst.warm_configs()
if self.gen_rc and self.rc_file:
writer = env_rc.RcWriter(self.cfg, self.pw_gen)
if not sh.isfile(self.rc_file):
LOG.info("Generating a file at [%s] that will contain your environment settings." % (self.rc_file))
writer.write(self.rc_file)
if self.gen_rc:
writer = env_rc.RcWriter(self.cfg, self.pw_gen, self.directory)
if not sh.isfile(settings.OSRC_FN):
LOG.info("Generating a file at [%s] that will contain your environment settings." % (settings.OSRC_FN))
writer.write(settings.OSRC_FN)
else:
LOG.info("Updating a file at [%s] that contains your environment settings." % (self.rc_file))
am_upd = writer.update(self.rc_file)
LOG.info("Updated [%s] settings in rc file [%s]" % (am_upd, self.rc_file))
LOG.info("Updating a file at [%s] that contains your environment settings." % (settings.OSRC_FN))
am_upd = writer.update(settings.OSRC_FN)
LOG.info("Updated [%s] settings in rc file [%s]" % (am_upd, settings.OSRC_FN))
def _run_instances(self, instances, component_order):
component_order = self._apply_reverse(component_order)

View File

@ -155,12 +155,10 @@ def get_packager(distro, keep_packages):
return cls(distro, keep_packages)
def get_config(cfg_fn=None, kv_cache=None):
def get_config(cfg_fn=None):
if not cfg_fn:
cfg_fn = sh.canon_path(settings.STACK_CONFIG_LOCATION)
if kv_cache is None:
kv_cache = dict()
config_instance = cfg.StackConfigParser(kv_cache)
config_instance = cfg.StackConfigParser()
config_instance.read(cfg_fn)
return config_instance

View File

@ -88,9 +88,9 @@ def configure_logging(verbosity_level=1, dry_run=False):
# Adjust logging verbose level based on the command line switch.
log_level = logging.INFO
if verbosity_level >= 2:
if verbosity_level >= 3:
log_level = logging.DEBUG
elif dry_run:
elif verbosity_level == 2 or dry_run:
log_level = logging.AUDIT
root_logger.setLevel(log_level)

38
stack
View File

@ -22,6 +22,8 @@ import traceback
from devstack import cfg_helpers
from devstack import date
from devstack import env
from devstack import env_rc
from devstack import log as logging
from devstack import opts
from devstack import passwords
@ -87,19 +89,39 @@ def dump_config(config_cache):
map_print(entries)
def load_rc_files():
fns = [settings.OSRC_FN]
for fn in fns:
try:
LOG.debug("Attempting to load rc file at [%s] which has your environment settings." % (fn))
am_loaded = env_rc.RcReader().load(fn)
LOG.debug("Loaded [%s] settings from rc file [%s]" % (am_loaded, fn))
except IOError:
LOG.warn('Error reading rc file located at [%s]. Skipping loading it.' % (fn))
return len(fns)
def run(args):
(distro, platform) = utils.determine_distro()
if distro is None:
print("Unsupported platform " + utils.color_text(platform, "red") + "!")
return False
action = args.pop("action").strip().lower()
if not (action in settings.ACTIONS):
print(utils.color_text("No valid action specified!", "red"))
return False
loaded_rcs = False
rootdir = args.pop("dir")
if not rootdir:
print(utils.color_text("No root directory specified!", "red"))
return False
load_rc_files()
loaded_rcs = True
rootdir = env.get_key(env_rc.INSTALL_ROOT)
if not rootdir:
print(utils.color_text("No root directory specified!", "red"))
return False
#welcome!
(repeat_string, line_max_len) = utils.welcome(_WELCOME_MAP.get(action))
@ -108,12 +130,16 @@ def run(args):
#here on out we should be using the logger (and not print)
start_time = time.time()
# if we didn't load them before, load them now
if not loaded_rcs:
load_rc_files()
loaded_rcs = True
# Stash the dryrun value (if any) into the global configuration
sh.set_dryrun(args['dryrun'])
config_kv_cache = dict()
config = common.get_config(kv_cache=config_kv_cache)
pw_gen = passwords.PasswordGenerator(config_kv_cache, config, args['prompt_for_passwords'])
config = common.get_config()
pw_gen = passwords.PasswordGenerator(config, args['prompt_for_passwords'])
pkg_manager = common.get_packager(distro, args['keep_old'])
components = utils.parse_components(args.pop("components"))
@ -125,7 +151,7 @@ def run(args):
LOG.info("It took (%s) to complete action [%s]" % (common.format_secs_taken((time.time() - start_time)), action))
LOG.info("After action [%s] your settings which were created or read are:" % (action))
dump_config(config_kv_cache)
dump_config(config.configs_fetched)
return True