Reduce phase messaging + rework colors + move action program to top level (since its only file in its folder) + cleanup logging, adjust phase functions.

This commit is contained in:
Joshua Harlow 2012-04-24 17:23:23 -07:00
parent 71770eea80
commit 89656fb253
16 changed files with 285 additions and 216 deletions

View File

@ -15,7 +15,9 @@
# under the License..
import abc
import collections
from devstack import colorizer
from devstack import date
from devstack import env_rc
from devstack import exceptions as excp
@ -31,6 +33,9 @@ from devstack import utils
LOG = logging.getLogger("devstack.progs.actions")
PhaseFunctors = collections.namedtuple('PhaseFunctors', ['start', 'run', 'end'])
class ActionRunner(object):
__meta__ = abc.ABCMeta
NAME = None
@ -161,27 +166,32 @@ class ActionRunner(object):
}
writer.mark(details)
def _run_phase(self, start_msg, functor, end_msg, component_order, instances, phase_name):
def _run_phase(self, functors, component_order, instances, phase_name):
"""
Run a given 'functor' across all of the components, in order.
"""
component_results = dict()
for c in component_order:
instance = instances[c]
if self._skip_phase(instance, phase_name):
LOG.debug("Skipping phase named %r for component %r", phase_name, c)
else:
if start_msg:
LOG.info(start_msg.format(name=c))
try:
result = functor(instance)
if end_msg:
LOG.info(end_msg.format(name=c, result=result))
if functors.start:
functors.start(c)
result = None
if functors.run:
result = functors.run(instance)
if functors.end:
functors.end(c, result)
component_results[c] = result
self._mark_phase(instance, phase_name)
except (excp.NoTraceException) as e:
if self.force:
LOG.debug("Skipping exception: %s" % (e))
else:
raise
return component_results
def _delete_phase_files(self, names):
phase_dir = self.root_dir
@ -198,8 +208,8 @@ class ActionRunner(object):
components_needing_prereq.append(c)
preq_cls_name = preq_cls.NAME or "???"
if components_needing_prereq:
LOG.info("Processing prerequisite action %r requested by (%s) components.",
preq_cls_name, ", ".join(components_needing_prereq))
LOG.info("Processing prerequisite action %s requested by (%s) components.",
colorizer.quote(preq_cls_name), ", ".join(components_needing_prereq))
prereq_instance = preq_cls(self.distro,
self.cfg,
self.pw_gen,
@ -213,9 +223,9 @@ class ActionRunner(object):
instances = self._construct_instances(persona)
self._handle_prereq(persona, instances)
component_order = self._order_components(persona.wanted_components)
LOG.info("Processing components for action %r", (self.NAME or "???"))
LOG.info("Processing components for action %s.", colorizer.quote(self.NAME or "???"))
utils.log_iterable(component_order,
header="Activating in the following order:",
header="Activating in the following order",
logger=LOG)
self._verify_components(component_order, instances)
self._warm_components(component_order, instances)
@ -242,45 +252,56 @@ class InstallRunner(ActionRunner):
def _run(self, persona, component_order, instances):
self._write_rc_file()
self._run_phase(
'Downloading {name}',
lambda i: i.download(),
"Performed {result} downloads.",
results = self._run_phase(
PhaseFunctors(
start=lambda name: LOG.info('Downloading %s.', colorizer.quote(name)),
run=lambda i: i.download(),
end=lambda name, result: LOG.info("Performed %s downloads.", result),
),
component_order,
instances,
"Download"
)
self._run_phase(
'Configuring {name}',
lambda i: i.configure(),
"Configured {result} items.",
PhaseFunctors(
start=lambda name: LOG.info('Configuring %s.', colorizer.quote(name)),
run=lambda i: i.configure(),
end=lambda name, result: LOG.info("Configured %s items.", colorizer.quote(result)),
),
component_order,
instances,
"Configure"
)
self._run_phase(
'Pre-installing {name}',
lambda i: i.pre_install(),
None,
PhaseFunctors(
start=None,
run=lambda i: i.pre_install(),
end=None,
),
component_order,
instances,
"Pre-install"
)
self._run_phase(
'Installing {name}',
lambda i: i.install(),
"Finished install of {name} - check {result} for information on what was done.",
PhaseFunctors(
start=lambda name: LOG.info('Installing %s.', colorizer.quote(name)),
run=lambda i: i.install(),
end=(lambda name, result: LOG.info("Finished install of %s items - check %s for information on what was done",
colorizer.quote(name), colorizer.quote(result))),
),
component_order,
instances,
"Install"
)
self._run_phase(
'Post-installing {name}',
lambda i: i.post_install(),
None,
PhaseFunctors(
start=lambda name: LOG.info('Post-installing %s.', colorizer.quote(name)),
run=lambda i: i.post_install(),
end=None
),
component_order,
instances,
"Post-install"
"Post-install",
)
@ -296,36 +317,44 @@ class StartRunner(ActionRunner):
def _run(self, persona, component_order, instances):
self._run_phase(
None,
lambda i: i.configure(),
None,
PhaseFunctors(
start=None,
run=lambda i: i.configure(),
end=None,
),
component_order,
instances,
"Configure"
"Configure",
)
self._run_phase(
'Pre-starting {name}',
lambda i: i.pre_start(),
None,
PhaseFunctors(
start=None,
run=lambda i: i.pre_start(),
end=None,
),
component_order,
instances,
"Pre-start"
"Pre-start",
)
self._run_phase(
'Starting {name}',
lambda i: i.start(),
"Started {result} applications",
PhaseFunctors(
start=lambda name: LOG.info('Starting %s.', name),
run=lambda i: i.start(),
end=lambda name, result: LOG.info("Start %s applications", colorizer.quote(result)),
),
component_order,
instances,
"Start"
)
self._run_phase(
'Post-starting {name}',
lambda i: i.post_start(),
None,
PhaseFunctors(
start=lambda name: LOG.info('Post-starting %s.', colorizer.quote(name)),
run=lambda i: i.post_start(),
end=None,
),
component_order,
instances,
"Post-start"
"Post-start",
)
@ -343,9 +372,11 @@ class StopRunner(ActionRunner):
def _run(self, persona, component_order, instances):
self._run_phase(
'Stopping {name}',
lambda i: i.stop(),
'Stopped {result} items',
PhaseFunctors(
start=lambda name: LOG.info('Stopping %s.', colorizer.quote(name)),
run=lambda i: i.stop(),
end=lambda name, result: LOG.info("Stopped %s items", colorizer.quote(result)),
),
component_order,
instances,
"Stopped"
@ -370,36 +401,44 @@ class UninstallRunner(ActionRunner):
def _run(self, persona, component_order, instances):
self._run_phase(
'Unconfiguring {name}',
lambda i: i.unconfigure(),
None,
PhaseFunctors(
start=lambda name: LOG.info('Unconfiguring %s.', colorizer.quote(name)),
run=lambda i: i.unconfigure(),
end=None,
),
component_order,
instances,
"Unconfigure"
)
self._run_phase(
'Pre-uninstalling {name}',
lambda i: i.pre_uninstall(),
None,
PhaseFunctors(
start=None,
run=lambda i: i.pre_uninstall(),
end=None,
),
component_order,
instances,
"Pre-uninstall"
"Pre-uninstall",
)
self._run_phase(
'Uninstalling {name}',
lambda i: i.uninstall(),
None,
PhaseFunctors(
start=lambda name: LOG.info('Uninstalling %s.', colorizer.quote(name)),
run=lambda i: i.uninstall(),
end=None,
),
component_order,
instances,
"Uninstall"
)
self._run_phase(
'Post-uninstalling {name}',
lambda i: i.post_uninstall(),
None,
PhaseFunctors(
start=lambda name: LOG.info('Post-uninstalling %s.', colorizer.quote(name)),
run=lambda i: i.post_uninstall(),
end=None,
),
component_order,
instances,
"Post-uninstall"
"Post-uninstall",
)
self._delete_phase_files(set([self.NAME, InstallRunner.NAME]))

View File

@ -237,14 +237,16 @@ class CliResolver(object):
continue
split_up = c.split("/")
if len(split_up) != 3:
LOG.warn("Badly formatted cli option: %r", c)
LOG.warn("Incorrectly formatted cli option: %r", c)
else:
section = (split_up[0]).strip()
if not section or section.lower() == 'default':
section = 'DEFAULT'
option = split_up[1].strip()
value = split_up[2]
parsed_args[cfg_helpers.make_id(section, option)] = value
if not option:
LOG.warn("Badly formatted cli option - no option name: %r", c)
else:
parsed_args[cfg_helpers.make_id(section, option)] = split_up[2]
return cls(parsed_args)

59
devstack/colorizer.py Normal file
View File

@ -0,0 +1,59 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012 Yahoo! 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 re
import sys
import termcolor
COLORS = termcolor.COLORS.keys()
def is_terminal():
return sys.stdout.isatty()
def quote(data, quote_color='green'):
if not is_terminal():
return "'%s'" % (data)
else:
return color(data, quote_color)
def format(data, params):
text = str(data)
def replacer(match):
param_name = match.group(1)
return color(params[param_name], color=match.group(2).strip())
return re.sub(r"\{([\w\d]+):(.*)\}", replacer, text)
def color(data, color, bold=False, underline=False, blink=False):
text = str(data)
text_attrs = list()
if bold:
text_attrs.append('bold')
if underline:
text_attrs.append('underline')
if blink:
text_attrs.append('blink')
if is_terminal() and color in COLORS:
return termcolor.colored(text, color, attrs=text_attrs)
else:
return text

View File

@ -1,47 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012 Yahoo! 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 logging
from termcolor import colored
COLOR_MAP = {
logging.DEBUG: 'blue',
logging.INFO: 'cyan',
logging.WARNING: 'yellow',
logging.ERROR: 'red',
logging.CRITICAL: 'red',
logging.AUDIT: 'green',
}
COLOR_ATTRS = {
logging.CRITICAL: ['bold', 'blink'],
}
UNKNOWN_COLOR = 'grey'
class TermFormatter(logging.Formatter):
def __init__(self, reg_fmt=None, date_format=None):
logging.Formatter.__init__(self, reg_fmt, date_format)
def format(self, record):
lvl = record.levelno
color = COLOR_MAP.get(lvl, UNKNOWN_COLOR)
record.levelname = colored(record.levelname, color)
attrs = COLOR_ATTRS.get(lvl)
if attrs:
record.msg = colored(record.msg, attrs=attrs)
return logging.Formatter.format(self, record)

View File

@ -32,7 +32,7 @@ RESET_BASE_PW = ''
SQL_RESET_PW_LINKS = [
'https://help.ubuntu.com/community/MysqlPasswordReset',
'http://dev.mysql.com/doc/refman/5.0/en/resetting-permissions.html',
]
]
# Used as a generic error message
BASE_ERROR = 'Currently we do not know how to %r for database type %r'
@ -43,6 +43,7 @@ WARMUP_PWS = [('sql', PASSWORD_PROMPT)]
class DBUninstaller(comp.PkgUninstallComponent):
def __init__(self, *args, **kargs):
comp.PkgUninstallComponent.__init__(self, *args, **kargs)
(runtime_cls, _) = self.distro.extract_component(self.component_name, 'running')

View File

@ -22,6 +22,7 @@ import shlex
import yaml
from devstack import colorizer
from devstack import importer
from devstack import log as logging
from devstack import settings
@ -69,7 +70,7 @@ class Distro(object):
LOG.debug('Looking for distro data for %r (%s)', plt, distname)
for p in cls.load_all():
if p.supports_distro(plt):
LOG.info('Using distro %r for platform %r', p.name, plt)
LOG.info('Using distro %s for platform %s', colorizer.quote(p.name), colorizer.quote(plt))
return p
else:
raise RuntimeError(

View File

@ -18,11 +18,15 @@
# under the License.
import logging
import sys
from logging.handlers import SysLogHandler
from logging.handlers import WatchedFileHandler
# Alist of things we want to replicate from logging levels
from devstack import colorizer
# A list of things we want to replicate from logging levels
CRITICAL = logging.CRITICAL
FATAL = logging.FATAL
ERROR = logging.ERROR
@ -58,19 +62,61 @@ WatchedFileHandler = WatchedFileHandler
SysLogHandler = SysLogHandler
class AuditAdapter(logging.LoggerAdapter):
class TermFormatter(logging.Formatter):
COLOR_MAP = {
logging.DEBUG: 'blue',
logging.INFO: 'cyan',
logging.WARNING: 'yellow',
logging.ERROR: 'red',
logging.CRITICAL: 'red',
logging.AUDIT: 'green',
}
MSG_COLORS = {
logging.CRITICAL: 'red',
}
def __init__(self, reg_fmt=None, date_format=None):
logging.Formatter.__init__(self, reg_fmt, date_format)
def _format_msg(self, lvl, msg):
color_to_be = self.MSG_COLORS.get(lvl)
if color_to_be:
return colorizer.color(msg, color_to_be, bold=True)
else:
return msg
def _format_lvl(self, lvl, lvl_name):
color_to_be = self.COLOR_MAP.get(lvl)
if color_to_be:
return colorizer.color(lvl_name, color_to_be)
else:
return lvl_name
def format(self, record):
record.levelname = self._format_lvl(record.levelno, record.levelname)
record.msg = self._format_msg(record.levelno, record.msg)
return logging.Formatter.format(self, record)
class TermAdapter(logging.LoggerAdapter):
warn = logging.LoggerAdapter.warning
def __init__(self, logger):
logging.LoggerAdapter.__init__(self, logger, dict())
self.logger = logger
def audit(self, msg, *args, **kwargs):
self.log(logging.AUDIT, msg, *args, **kwargs)
def process(self, msg, kwargs):
return msg, kwargs
def setupLogging(log_level, format='%(levelname)s: @%(name)s : %(message)s'):
root_logger = getLogger().logger
console_logger = StreamHandler(sys.stdout)
console_logger.setFormatter(TermFormatter(format))
root_logger.addHandler(console_logger)
root_logger.setLevel(log_level)
def getLogger(name='devstack'):
return AuditAdapter(logging.getLogger(name))
return TermAdapter(logging.getLogger(name))

View File

@ -1,15 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012 Yahoo! 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.

View File

@ -14,9 +14,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import abc
class Runner(object):
__meta__ = abc.ABCMeta
# This is the base class for the various runners
class RunnerBase(object):
def __init__(self, config, component_name, trace_dir):
self.cfg = config
self.component_name = component_name
@ -34,7 +37,8 @@ class RunnerBase(object):
def start(self, app_name, app_pth, app_dir, opts):
# Returns a file name that contains what was started
return None
pass
def stop(self, app_name):
# Stops the given app
pass

View File

@ -46,7 +46,7 @@ NAME = "NAME"
FORK_TEMPL = "%s.fork"
class ForkRunner(base.RunnerBase):
class ForkRunner(base.Runner):
def __init__(self, cfg, component_name, trace_dir):
base.RunnerBase.__init__(self, cfg, component_name, trace_dir)

View File

@ -61,7 +61,7 @@ SCREEN_SOCKET_PERM = 0700
SCREEN_RC = settings.RC_FN_TEMPL % ('screen')
class ScreenRunner(base.RunnerBase):
class ScreenRunner(base.Runner):
def __init__(self, cfg, component_name, trace_dir):
base.RunnerBase.__init__(self, cfg, component_name, trace_dir)
self.socket_dir = sh.joinpths(tempfile.gettempdir(), SCREEN_SOCKET_DIR_NAME)

View File

@ -46,7 +46,7 @@ UPSTART_CONF_TMPL = 'upstart.conf'
EMIT_BASE_CMD = ["/sbin/initctl", "emit"]
class UpstartRunner(base.RunnerBase):
class UpstartRunner(base.Runner):
def __init__(self, cfg, component_name, trace_dir):
base.RunnerBase.__init__(self, cfg, component_name, trace_dir)
self.events = set()

View File

@ -321,13 +321,6 @@ def explode_path(path):
return _explode_form_path(path)
def in_terminal(check_both=False):
if check_both:
return sys.stdout.isatty() and sys.stderr.isatty()
else:
return sys.stdout.isatty()
def remove_parents(child_path, paths):
if not paths:
return list()

View File

@ -28,9 +28,8 @@ import tempfile
import distutils.version
import netifaces
import progressbar
import termcolor
from devstack import colorlog
from devstack import colorizer
from devstack import date
from devstack import exceptions as excp
from devstack import log as logging
@ -72,15 +71,6 @@ COWS['unhappy'] = r'''
'''
def construct_log_level(verbosity_level, dry_run=False):
log_level = logging.INFO
if verbosity_level >= 3:
log_level = logging.DEBUG
elif verbosity_level == 2 or dry_run:
log_level = logging.AUDIT
return log_level
def make_bool(val):
if not val:
return False
@ -140,18 +130,6 @@ def get_from_path(items, path, quiet=True):
return get_from_path(get_method(first_token), remainder)
def configure_logging(log_level, cli_args):
root_logger = logging.getLogger().logger
console_logger = logging.StreamHandler(sys.stdout)
console_format = '%(levelname)s: @%(name)s : %(message)s'
if sh.in_terminal():
console_logger.setFormatter(colorlog.TermFormatter(console_format))
else:
console_logger.setFormatter(logging.Formatter(console_format))
root_logger.addHandler(console_logger)
root_logger.setLevel(log_level)
def load_template(component, template_name):
templ_pth = sh.joinpths(settings.STACK_TEMPLATE_DIR, component, template_name)
return (templ_pth, sh.load_file(templ_pth))
@ -206,7 +184,7 @@ def mark_unexecute_file(fn, kvs, comment_start='#'):
sh.chmod(fn, 0644)
def log_iterable(to_log, header=None, logger=None):
def log_iterable(to_log, header=None, logger=None, do_color=True):
if not logger:
logger = LOG
if header:
@ -214,7 +192,9 @@ def log_iterable(to_log, header=None, logger=None):
header += ":"
logger.info(header)
for c in to_log:
logger.info("|-- %s", color_text(c, 'blue'))
if do_color:
c = colorizer.color(c, 'blue')
logger.info("|-- %s", c)
@contextlib.contextmanager
@ -354,6 +334,10 @@ def joinlinesep(*pieces):
return os.linesep.join(pieces)
def get_class_names(objects):
return map((lambda i: i.__class__.__name__), objects)
def param_replace_list(values, replacements, ignore_missing=False):
new_values = list()
if not values:
@ -486,27 +470,11 @@ def _welcome_slang():
return random.choice(potentials)
def color_text(text, color, bold=False,
underline=False, blink=False,
always_color=False):
text_attrs = list()
if bold:
text_attrs.append('bold')
if underline:
text_attrs.append('underline')
if blink:
text_attrs.append('blink')
if sh.in_terminal() or always_color:
return termcolor.colored(text, color, attrs=text_attrs)
else:
return text
def _color_blob(text, text_color):
def replacer(match):
contents = match.group(1)
return color_text(contents, text_color)
return colorizer.color(contents, text_color)
return MONTY_PYTHON_TEXT_RE.sub(replacer, text)
@ -704,12 +672,12 @@ def _goodbye_header(worked):
def goodbye(worked):
if worked:
cow = COWS['happy']
eye_fmt = color_text('o', 'green')
ear = color_text("^", 'green')
eye_fmt = colorizer.color('o', 'green')
ear = colorizer.color("^", 'green')
else:
cow = COWS['unhappy']
eye_fmt = color_text("o", 'red')
ear = color_text("v", 'red')
eye_fmt = colorizer.color("o", 'red')
ear = colorizer.color("v", 'red')
cow = cow.strip("\n\r")
header = _goodbye_header(worked)
msg = cow.format(eye=eye_fmt, ear=ear,
@ -721,9 +689,9 @@ def welcome():
lower = "| %s |" % (version.version_string())
welcome_header = _get_welcome_stack()
max_line_len = len(max(welcome_header.splitlines(), key=len))
footer = color_text(settings.PROG_NICE_NAME, 'green')
footer = colorizer.color(settings.PROG_NICE_NAME, 'green')
footer += ": "
footer += color_text(lower, 'blue', True)
footer += colorizer.color(lower, 'blue', bold=True)
uncolored_footer = (settings.PROG_NICE_NAME + ": " + lower)
if max_line_len - len(uncolored_footer) > 0:
# This format string will center the uncolored text which
@ -734,5 +702,5 @@ def welcome():
print(footer)
real_max = max(max_line_len, len(uncolored_footer))
slang = center_text(_welcome_slang(), ' ', real_max)
print(color_text(slang, 'magenta', bold=True))
print(colorizer.color(slang, 'magenta', bold=True))
return ("-", real_max)

58
stack
View File

@ -20,8 +20,10 @@ import sys
import time
import traceback as tb
from devstack import actions
from devstack import cfg
from devstack import cfg_helpers
from devstack import colorizer
from devstack import date
from devstack import distro
from devstack import env
@ -34,8 +36,6 @@ from devstack import settings
from devstack import shell as sh
from devstack import utils
from devstack.progs import actions
LOG = logging.getLogger("devstack.stack")
@ -69,12 +69,12 @@ def load_rc_files():
loaded_am = 0
for fn in RC_FILES:
try:
LOG.info("Attempting to load file %r which has your environment settings." % (fn))
LOG.info("Attempting to load file %s which has your environment settings.", colorizer.quote(fn))
am_loaded = env_rc.RcReader().load(fn)
LOG.info("Loaded %s settings from file %r" % (am_loaded, fn))
LOG.info("Loaded %s settings.", colorizer.quote(am_loaded))
loaded_am += 1
except IOError:
LOG.warn('Error reading file located at %r. Skipping loading it.' % (fn))
LOG.warn('Error reading file located at %s. Skipping loading it.', colorizer.quote(fn))
return loaded_am
@ -149,12 +149,20 @@ def establish_config(args):
env_resolver = cfg.EnvResolver(base_config)
proxy_config.add_read_resolver(env_resolver)
proxy_config.add_set_resolver(env_resolver)
utils.log_iterable(map((lambda i: i.__class__.__name__), proxy_config.read_resolvers),
utils.log_iterable(utils.get_class_names(proxy_config.read_resolvers),
header="Config lookup will use the following resolvers:",
logger=LOG)
return proxy_config
def establish_passwords(config, args):
pw_gen = passwords.PasswordGenerator(config, args.get('prompt_for_passwords', True))
utils.log_iterable(utils.get_class_names(pw_gen.lookups),
header="Password finding will use the following lookups:",
logger=LOG)
return pw_gen
def run(args):
"""
Starts the execution of devstackpy after
@ -169,7 +177,7 @@ def run(args):
action = args.pop("action", '').strip().lower()
if action not in actions.get_action_names():
print(utils.color_text("No valid action specified!", "red"))
print(colorizer.color_text("No valid action specified!", "red"))
return False
loaded_rcs = False
@ -185,7 +193,7 @@ def run(args):
persona_fn = args.pop('persona_fn')
if not persona_fn or not sh.isfile(persona_fn):
print(utils.color_text("No valid persona file name specified!", "red"))
print(colorizer.color_text("No valid persona file name specified!", "red"))
return False
persona_fn = sh.abspth(persona_fn)
@ -205,7 +213,7 @@ def run(args):
dist = distro.Distro.get_current()
persona_inst = load_verify_persona(persona_fn, dist)
config = establish_config(args)
pw_gen = passwords.PasswordGenerator(config, args.get('prompt_for_passwords', True))
pw_gen = establish_passwords(config, args)
runner_factory = actions.get_runner_factory(action)
runner = runner_factory(dist,
@ -214,22 +222,32 @@ def run(args):
root_dir=root_dir,
**args)
LOG.info("Starting action %r on %s for distro: %r" % (action, date.rcf8222date(), dist.name))
LOG.info("Using persona: %r" % (persona_fn))
LOG.info("In root directory: %r" % (root_dir))
LOG.info("Starting action %s on %s for distro: %s",
colorizer.quote(action), colorizer.quote(date.rcf8222date()), colorizer.quote(dist.name))
LOG.info("Using persona: %s", colorizer.quote(persona_fn))
LOG.info("In root directory: %s", colorizer.quote(root_dir))
start_time = time.time()
runner.run(persona_inst)
end_time = time.time()
LOG.info("It took (%s) to complete action %r" %
(utils.format_secs_taken((end_time - start_time)), action))
LOG.info("After action %r your settings which were created or read are:" % (action))
LOG.info("It took (%s) to complete action %s.",
colorizer.quote(utils.format_secs_taken((end_time - start_time))), colorizer.quote(action))
LOG.info("After action %s your settings which were created or read are:", colorizer.quote(action))
config.pprint(CFG_GROUPS, CFG_ORDERING)
return True
def construct_log_level(verbosity_level, dry_run=False):
log_level = logging.INFO
if verbosity_level >= 3:
log_level = logging.DEBUG
elif verbosity_level == 2 or dry_run:
log_level = logging.AUDIT
return log_level
def main():
"""
Starts the execution of devstack py without
@ -245,8 +263,8 @@ def main():
prog_name = sys.argv[0]
# Configure logging
log_level = utils.construct_log_level(args['verbosity'], args['dryrun'])
utils.configure_logging(log_level, args)
log_level = construct_log_level(args['verbosity'], args['dryrun'])
logging.setupLogging(log_level)
LOG.debug("Command line options %s" % (args))
LOG.debug("Log level is: %s" % (log_level))
@ -256,7 +274,7 @@ def main():
rest_args = sys.argv[1:]
print("This program requires a user with sudo access.")
msg = "Perhaps you should try %s %s" % \
(utils.color_text("sudo %s" % (prog_name), "red", True), " ".join(rest_args))
(colorizer.color("sudo %s" % (prog_name), "red", True), " ".join(rest_args))
print(msg)
return 1
@ -265,8 +283,8 @@ def main():
sh.user_mode(quiet=False)
started_ok = run(args)
if not started_ok:
me = utils.color_text(prog_name, "red", True)
me += " " + utils.color_text('--help', 'red')
me = colorizer.color(prog_name, "red", True)
me += " " + colorizer.color('--help', 'red')
print("Perhaps you should try %s" % (me))
return 1
else:

View File

@ -31,8 +31,8 @@ if __name__ == "__main__":
(options, args) = parser.parse_args()
uris = options.uris or list()
uri_sep = ",".join(uris)
utils.configure_logging(logging.DEBUG)
config = cfg.StackConfigParser()
logging.setupLogging(logging.DEBUG)
config = cfg.IgnoreMissingConfigParser()
config.add_section('img')
config.set('img', 'image_urls', uri_sep)
pw_gen = passwords.PasswordGenerator(config)