diff options
Diffstat (limited to 'lmi/scripts/common/command/select.py')
-rw-r--r-- | lmi/scripts/common/command/select.py | 195 |
1 files changed, 0 insertions, 195 deletions
diff --git a/lmi/scripts/common/command/select.py b/lmi/scripts/common/command/select.py deleted file mode 100644 index 5f89994..0000000 --- a/lmi/scripts/common/command/select.py +++ /dev/null @@ -1,195 +0,0 @@ -# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -# The views and conclusions contained in the software and documentation are -# those of the authors and should not be interpreted as representing official -# policies, either expressed or implied, of the FreeBSD Project. -# -# Authors: Michal Minar <miminar@redhat.com> -# -""" -Defines command class used to choose other commands depending on -profile and class requirements. -""" - -from docopt import docopt -from pyparsing import ParseException - -from lmi.scripts.common import get_logger -from lmi.scripts.common import errors -from lmi.scripts.common.command import base -from lmi.scripts.common.command import meta -from lmi.scripts.common.session import SessionProxy -from lmi.scripts.common.versioncheck import eval_respl - -class LmiSelectCommand(base.LmiBaseCommand): - """ - Base class for command selectors. It does not process command line - arguments. Thery are passed unchanged to selected command whose - requirements are met. Its doc string is not interpreted in any way. - - If there are more hosts, conditions are evaluated per each. They are then - split into groups, each fulfilling particular condition. Associated - commands are then invoked on these groups separately. - - Example usage: :: - - class MySelect(LmiSelectCommand): - SELECT = [ - ( 'OpenLMI-Hardware >= 0.4.2' - , 'lmi.scripts.hardware.current.Cmd'), - ('OpenLMI-Hardware', 'lmi.scripts.hardware.pre042.Cmd') - ] - DEFAULT = MissingHwProviderCmd - - Using metaclass: :py:class:`.meta.SelectMetaClass`. - """ - __metaclass__ = meta.SelectMetaClass - - @classmethod - def is_end_point(cls): - return False - - @classmethod - def is_multiplexer(cls): - return False - - @classmethod - def get_conditionals(cls): - """ - Get the expressions with associated commands. This shall be overriden - by a subclass. - - :returns: Pair of ``(expressions, default)``. - Where ``expressions`` is a list of pairs ``(condition, command)``. - And ``default`` is the same as ``command`` used in case no - ``condition`` is satisfied. - :rtype: list - """ - raise NotImplementedError( - "get_conditionals needs to be defined in subclass") - - def eval_expr(self, expr, hosts, cache=None): - """ - Evaluate expression on group of hosts. - - :param string expr: Expression to evaluate. - :param list hosts: Group of hosts that shall be checked. - :param dictionary cache: Optional cache object speeding up evaluation - by reducing number of queries to broker. - :returns: Subset of hosts satisfying *expr*. - :rtype: list - """ - if cache is None: - cache = dict() - session = self.session - satisfied = [] - try: - for host in hosts: # TODO: could be done concurrently - conn = session[host] - if not conn: - continue - if eval_respl(expr, conn, cache=cache): - satisfied.append(host) - except ParseException: - raise errors.LmiBadSelectExpression(self.__class__.__module__, - self.__class__.__name__, "Bad select expression: %s" % expr) - return satisfied - - def select_cmds(self, cache=None): - """ - Generator of command factories with associated groups of hosts. It - evaluates given expressions on session. In this process all expressions - from :py:meth:`get_conditionals` are checked in a row. Host satisfying - some expression is added to group associated with it and is excluded - from processing following expressions. - - :param dictionary cache: Optional cache object speeding up the evaluation - by reducing number of queries to broker. - :returns: Pairs in form ``(command_factory, session_proxy)``. - :rtype: generator - :raises: - * :py:class:`~lmi.scripts.common.errors.LmiUnsatisfiedDependencies` - if no condition is satisfied for at least one host. Note that - this exception is raised at the end of evaluation. This lets - you choose whether you want to process satisfied hosts - by - processing the generator at once. Or whether you want to be - sure it is satisfied by all of them - you turn the generator - into a list. - * :py:class:`~lmi.scripts.common.errors.LmiNoConnections` - if no successful connection was done. - """ - if cache is None: - cache = dict() - conds, default = self.get_conditionals() - def get_cmd_factory(cmd): - if isinstance(cmd, basestring): - i = cmd.rindex('.') - module = __import__(cmd[:i], fromlist=cmd[i+1:]) - return getattr(module, cmd[i+1:]) - else: - return cmd - - session = self.session - unsatisfied = set(session.hostnames) - - for expr, cmd in conds: - hosts = self.eval_expr(expr, unsatisfied, cache) - if hosts: - yield get_cmd_factory(cmd), SessionProxy(session, hosts) - hosts = set(hosts).union(set(session.get_unconnected())) - unsatisfied.difference_update(hosts) - if not unsatisfied: - break - if default is not None and unsatisfied: - yield get_cmd_factory(default), SessionProxy(session, unsatisfied) - unsatisfied.clear() - if len(unsatisfied): - raise errors.LmiUnsatisfiedDependencies(unsatisfied) - if len(session) == len(session.get_unconnected()): - raise errors.LmiNoConnections("No successful connection!") - - def get_usage(self, proper=False): - """ - Try to get usage of any command satisfying some expression. - - :raises: Same exceptions as :py:meth:`select_cmds`. - """ - for cmd_cls, _ in self.select_cmds(): - cmd = cmd_cls(self.app, self.cmd_name, self.parent) - return cmd.get_usage(proper) - - def run(self, args): - """ - Iterate over command factories with associated sessions and - execute them with unchanged *args*. - """ - result = 0 - for cmd_cls, session in self.select_cmds(): - cmd = cmd_cls(self.app, self.cmd_name, self.parent) - cmd.set_session_proxy(session) - ret = cmd.run(args) - if result == 0: - result = ret - return result - |