Reverted back to using set through for password configs, also fixes issue #90, other teenie cleanups
This commit is contained in:
parent
725cad4615
commit
bd7fbd5474
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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):
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
38
stack
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user