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:
parent
71770eea80
commit
89656fb253
@ -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]))
|
||||
|
@ -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
59
devstack/colorizer.py
Normal 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
|
@ -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)
|
@ -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')
|
||||
|
@ -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(
|
||||
|
@ -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))
|
||||
|
@ -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.
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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
58
stack
@ -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:
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user