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): class StackConfigParser(IgnoreMissingConfigParser):
def __init__(self, cache): def __init__(self):
IgnoreMissingConfigParser.__init__(self) IgnoreMissingConfigParser.__init__(self)
self.configs_fetched = cache self.configs_fetched = dict()
def _resolve_value(self, section, option, value_gotten): def _resolve_value(self, section, option, value_gotten):
if section == 'host' and option == 'ip': if section == 'host' and option == 'ip':
@ -100,6 +100,12 @@ class StackConfigParser(IgnoreMissingConfigParser):
self.configs_fetched[key] = value self.configs_fetched[key] = value
return 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): def _resolve_replacements(self, value):
LOG.debug("Performing simple replacement on [%s]", 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'] mp['DEMO_TENANT_NAME'] = mp['DEMO_USER_NAME']
#tokens and passwords #tokens and passwords
mp['SERVICE_TOKEN'] = pw_gen.get_password( mp['SERVICE_TOKEN'] = pw_gen.get_password("service_token")
"service_token", mp['ADMIN_PASSWORD'] = pw_gen.get_password('horizon_keystone_admin', length=20)
'the service admin token', mp['SERVICE_PASSWORD'] = pw_gen.get_password('service_password')
)
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',
)
#components of the auth endpoint #components of the auth endpoint
keystone_auth_host = config.getdefaulted('keystone', 'keystone_auth_host', host_ip) keystone_auth_host = config.getdefaulted('keystone', 'keystone_auth_host', host_ip)

View File

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

View File

@ -19,11 +19,9 @@ from optparse import OptionParser, OptionGroup
from devstack import log as logging from devstack import log as logging
from devstack import settings from devstack import settings
from devstack import shell as sh
from devstack import version from devstack import version
HELP_WIDTH = 80 HELP_WIDTH = 80
DEF_OS_DIR = "openstack"
LOG = logging.getLogger("devstack.opts") LOG = logging.getLogger("devstack.opts")
@ -61,16 +59,13 @@ def parse():
dest="action", dest="action",
metavar="ACTION", metavar="ACTION",
help="required action to perform: %s" % (_format_list(settings.ACTIONS))) 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", base_group.add_option("-d", "--directory",
action="store", action="store",
type="string", type="string",
dest="dir", dest="dir",
metavar="DIR", metavar="DIR",
default=default_dir,
help=("empty root DIR for install or " help=("empty root DIR for install or "
"DIR with existing components for start/stop/uninstall " "DIR with existing components for start/stop/uninstall"))
"(default: %default)"))
base_group.add_option("-i", "--ignore-deps", base_group.add_option("-i", "--ignore-deps",
action="store_false", action="store_false",
dest="ensure_deps", 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 binascii
import getpass import getpass
import logging import logging
import os import os
import re import re
from devstack import cfg_helpers
LOG = logging.getLogger("devstack.passwords") LOG = logging.getLogger("devstack.passwords")
PW_SECTION = 'passwords' PW_SECTION = 'passwords'
HELPFUL_DESCRIPTIONS = { HELPFUL_DESCRIPTIONS = {
'sql': 'the database user', '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): class PasswordGenerator(object):
def __init__(self, kv_cache, cfg, def __init__(self, cfg, prompt_user=True):
prompt_user=True):
self.cfg = cfg self.cfg = cfg
self.config_cache = kv_cache
self.prompt_user = prompt_user 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): def _prompt_user(self, prompt_text):
LOG.debug('Asking the user for a %r password', prompt_text) LOG.debug('Asking the user for a %r password', prompt_text)
message = ("Enter a password to use for %s " message = ("Enter a password to use for %s "
@ -43,20 +66,19 @@ class PasswordGenerator(object):
rc = "" rc = ""
while True: while True:
rc = getpass.getpass(message) rc = getpass.getpass(message)
if len(rc) == 0: if len(rc) == 0 or self._valid_password(rc):
break 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: else:
break LOG.warn("Invalid password \"%s\" (please try again)" % (rc))
return 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.""" """Returns a password identified by the configuration location."""
if not prompt_text: if not prompt_text:
@ -64,18 +86,16 @@ class PasswordGenerator(object):
LOG.debug('Looking for password %s (%s)', option, prompt_text) 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) # Look in the configuration file(s)
password = None
from_config = False
if not password: if not password:
try: password = self.cfg.get(PW_SECTION, option)
password = self.cfg.get(PW_SECTION, option) if password:
except ConfigParser.Error: from_config = True
password = ''
# Optionally ask the user # 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) password = self._prompt_user(prompt_text)
# If we still don't have a value, make one up. # If we still don't have a value, make one up.
@ -84,8 +104,8 @@ class PasswordGenerator(object):
option, prompt_text) option, prompt_text)
password = generate_random(length) password = generate_random(length)
# Update the cache so that other parts of the # Update via set through to the config
# code can find the value. if not from_config:
self.config_cache[cache_key] = password self._set_through(option, password)
return password return password

View File

@ -164,7 +164,6 @@ class ActionRunner(object):
self.force = kargs.get('force', False) self.force = kargs.get('force', False)
self.ignore_deps = kargs.get('ignore_deps', False) self.ignore_deps = kargs.get('ignore_deps', False)
self.ref_components = kargs.get("ref_components") self.ref_components = kargs.get("ref_components")
self.rc_file = sh.abspth(settings.OSRC_FN)
self.gen_rc = action in _RC_FILE_MAKE_ACTIONS self.gen_rc = action in _RC_FILE_MAKE_ACTIONS
def _get_components(self): def _get_components(self):
@ -233,13 +232,6 @@ class ActionRunner(object):
def _pre_run(self, instances, component_order): def _pre_run(self, instances, component_order):
if not sh.isdir(self.directory): if not sh.isdir(self.directory):
sh.mkdir(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.") LOG.info("Verifying that the components are ready to rock-n-roll.")
for component in component_order: for component in component_order:
inst = instances[component] inst = instances[component]
@ -248,15 +240,15 @@ class ActionRunner(object):
for component in component_order: for component in component_order:
inst = instances[component] inst = instances[component]
inst.warm_configs() inst.warm_configs()
if self.gen_rc and self.rc_file: if self.gen_rc:
writer = env_rc.RcWriter(self.cfg, self.pw_gen) writer = env_rc.RcWriter(self.cfg, self.pw_gen, self.directory)
if not sh.isfile(self.rc_file): if not sh.isfile(settings.OSRC_FN):
LOG.info("Generating a file at [%s] that will contain your environment settings." % (self.rc_file)) LOG.info("Generating a file at [%s] that will contain your environment settings." % (settings.OSRC_FN))
writer.write(self.rc_file) writer.write(settings.OSRC_FN)
else: else:
LOG.info("Updating a file at [%s] that contains your environment settings." % (self.rc_file)) LOG.info("Updating a file at [%s] that contains your environment settings." % (settings.OSRC_FN))
am_upd = writer.update(self.rc_file) am_upd = writer.update(settings.OSRC_FN)
LOG.info("Updated [%s] settings in rc file [%s]" % (am_upd, self.rc_file)) LOG.info("Updated [%s] settings in rc file [%s]" % (am_upd, settings.OSRC_FN))
def _run_instances(self, instances, component_order): def _run_instances(self, instances, component_order):
component_order = self._apply_reverse(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) return cls(distro, keep_packages)
def get_config(cfg_fn=None, kv_cache=None): def get_config(cfg_fn=None):
if not cfg_fn: if not cfg_fn:
cfg_fn = sh.canon_path(settings.STACK_CONFIG_LOCATION) cfg_fn = sh.canon_path(settings.STACK_CONFIG_LOCATION)
if kv_cache is None: config_instance = cfg.StackConfigParser()
kv_cache = dict()
config_instance = cfg.StackConfigParser(kv_cache)
config_instance.read(cfg_fn) config_instance.read(cfg_fn)
return config_instance 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. # Adjust logging verbose level based on the command line switch.
log_level = logging.INFO log_level = logging.INFO
if verbosity_level >= 2: if verbosity_level >= 3:
log_level = logging.DEBUG log_level = logging.DEBUG
elif dry_run: elif verbosity_level == 2 or dry_run:
log_level = logging.AUDIT log_level = logging.AUDIT
root_logger.setLevel(log_level) root_logger.setLevel(log_level)

38
stack
View File

@ -22,6 +22,8 @@ import traceback
from devstack import cfg_helpers from devstack import cfg_helpers
from devstack import date from devstack import date
from devstack import env
from devstack import env_rc
from devstack import log as logging from devstack import log as logging
from devstack import opts from devstack import opts
from devstack import passwords from devstack import passwords
@ -87,19 +89,39 @@ def dump_config(config_cache):
map_print(entries) 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): def run(args):
(distro, platform) = utils.determine_distro() (distro, platform) = utils.determine_distro()
if distro is None: if distro is None:
print("Unsupported platform " + utils.color_text(platform, "red") + "!") print("Unsupported platform " + utils.color_text(platform, "red") + "!")
return False return False
action = args.pop("action").strip().lower() action = args.pop("action").strip().lower()
if not (action in settings.ACTIONS): if not (action in settings.ACTIONS):
print(utils.color_text("No valid action specified!", "red")) print(utils.color_text("No valid action specified!", "red"))
return False return False
loaded_rcs = False
rootdir = args.pop("dir") rootdir = args.pop("dir")
if not rootdir: if not rootdir:
print(utils.color_text("No root directory specified!", "red")) load_rc_files()
return False 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! #welcome!
(repeat_string, line_max_len) = utils.welcome(_WELCOME_MAP.get(action)) (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) #here on out we should be using the logger (and not print)
start_time = time.time() 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 # Stash the dryrun value (if any) into the global configuration
sh.set_dryrun(args['dryrun']) sh.set_dryrun(args['dryrun'])
config_kv_cache = dict() config = common.get_config()
config = common.get_config(kv_cache=config_kv_cache) pw_gen = passwords.PasswordGenerator(config, args['prompt_for_passwords'])
pw_gen = passwords.PasswordGenerator(config_kv_cache, config, args['prompt_for_passwords'])
pkg_manager = common.get_packager(distro, args['keep_old']) pkg_manager = common.get_packager(distro, args['keep_old'])
components = utils.parse_components(args.pop("components")) 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("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)) 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 return True