Esempio n. 1
0
    def check(self):
        """Performs checks to see if the deployment is ready for upgrade.

        These checks are expected to be run BEFORE services are restarted with
        new code. These checks also require access to potentially all of the
        Nova databases (nova, nova_api, nova_api_cell0) and external services
        such as the placement API service.
        :returns: UpgradeCheckCode
        """
        return_code = UpgradeCheckCode.SUCCESS
        # This is a list if 2-item tuples for the check name and it's results.
        check_results = []
        for name, func in self._upgrade_checks:
            result = func(self)
            # store the result of the check for the summary table
            check_results.append((name, result))
            # we want to end up with the highest level code of all checks
            if result.code > return_code:
                return_code = result.code

        # TODO(bnemec): Consider using cliff for this so we can output in
        # different formats like JSON or CSV.
        # We're going to build a summary table that looks like:
        # +----------------------------------------------------+
        # | Upgrade Check Results                              |
        # +----------------------------------------------------+
        # | Check: Cells v2                                    |
        # | Result: Success                                    |
        # | Details: None                                      |
        # +----------------------------------------------------+
        # | Check: Placement API                               |
        # | Result: Failure                                    |
        # | Details: There is no placement-api endpoint in the |
        # |          service catalog.                          |
        # +----------------------------------------------------+
        t = prettytable.PrettyTable([_('Upgrade Check Results')],
                                    hrules=prettytable.ALL)
        t.align = 'l'
        for name, result in check_results:
            cell = (
                _('Check: %(name)s\n'
                  'Result: %(result)s\n'
                  'Details: %(details)s') %
                {
                    'name': name,
                    'result': UPGRADE_CHECK_MSG_MAP[result.code],
                    'details': self._get_details(result),
                }
            )
            t.add_row([cell])
        print(t)

        return return_code
Esempio n. 2
0
def run(conf):
    """Run the requested command.

    :param conf: An oslo.confg ConfigOpts instance on which the upgrade
                 commands have been previously registered.
    """
    try:
        return conf.command.action_fn()
    except Exception:
        print(_('Error:\n%s') % traceback.format_exc())
        # This is 255 so it's not confused with the upgrade check exit codes.
        return 255
Esempio n. 3
0
def main(check_callback):
    """Simple implementation of main for upgrade checks

    This can be used in upgrade check commands to provide the minimum
    necessary parameter handling and logic.

    :param check_callback: The check function from the concrete implementation
                           of UpgradeCommands.
    """
    add_parsers = functools.partial(_add_parsers,
                                    check_callback=check_callback)
    opt = cfg.SubCommandOpt('category', handler=add_parsers)
    conf = cfg.ConfigOpts()
    conf.register_cli_opt(opt)
    conf(sys.argv[1:])

    try:
        return conf.category.action_fn()
    except Exception:
        print(_('Error:\n%s') % traceback.format_exc())
        # This is 255 so it's not confused with the upgrade check exit codes.
        return 255
Esempio n. 4
0
    def check(self):
        """Performs checks to see if the deployment is ready for upgrade.

        These checks are expected to be run BEFORE services are restarted with
        new code.

        :returns: Code
        """
        return_code = Code.SUCCESS
        # This is a list if 2-item tuples for the check name and it's results.
        check_results = []
        for name, func in self._upgrade_checks:
            if isinstance(func, tuple):
                func_name, kwargs = func
                result = func_name(self, **kwargs)
            else:
                result = func(self)
            # store the result of the check for the summary table
            check_results.append((name, result))
            # we want to end up with the highest level code of all checks
            if result.code > return_code:
                return_code = result.code

        # We're going to build a summary table that looks like:
        # +----------------------------------------------------+
        # | Upgrade Check Results                              |
        # +----------------------------------------------------+
        # | Check: Cells v2                                    |
        # | Result: Success                                    |
        # | Details: None                                      |
        # +----------------------------------------------------+
        # | Check: Placement API                               |
        # | Result: Failure                                    |
        # | Details: There is no placement-api endpoint in the |
        # |          service catalog.                          |
        # +----------------------------------------------------+

        # Since registering opts can be overridden by consuming code, we can't
        # assume that our locally defined option exists.
        if (hasattr(CONF, 'command') and hasattr(CONF.command, 'json')
                and CONF.command.json):
            # NOTE(bnemec): We use str on the translated string to
            # force immediate translation if lazy translation is in use.
            # See lp1801761 for details.
            output = {'name': str(self.display_title), 'checks': []}
            for name, result in check_results:
                output['checks'].append({
                    'check': name,
                    'result': result.code,
                    'details': result.details
                })
            print(json.dumps(output))
        else:
            # NOTE(bnemec): We use str on the translated string to
            # force immediate translation if lazy translation is in use.
            # See lp1801761 for details.
            t = prettytable.PrettyTable([str(self.display_title)],
                                        hrules=prettytable.ALL)
            t.align = 'l'
            for name, result in check_results:
                cell = (_('Check: %(name)s\n'
                          'Result: %(result)s\n'
                          'Details: %(details)s') % {
                              'name': name,
                              'result': UPGRADE_CHECK_MSG_MAP[result.code],
                              'details': self._get_details(result),
                          })
                t.add_row([cell])
            print(t)

        return return_code
Esempio n. 5
0
class UpgradeCommands(object):
    """Base class for upgrade checks

    This class should be inherited by a class in each project that provides
    the actual checks. Those checks should be added to the _upgrade_checks
    class member so that they are run when the ``check`` method is called.

    The subcommands here must not rely on the service object model since they
    should be able to run on n-1 data. Any queries to the database should be
    done through the sqlalchemy query language directly like the database
    schema migrations.
    """
    display_title = _('Upgrade Check Results')
    _upgrade_checks = ()

    def _get_details(self, upgrade_check_result):
        if upgrade_check_result.details is not None:
            # wrap the text on the details to 60 characters
            return '\n'.join(
                textwrap.wrap(upgrade_check_result.details,
                              60,
                              subsequent_indent='  '))

    def check(self):
        """Performs checks to see if the deployment is ready for upgrade.

        These checks are expected to be run BEFORE services are restarted with
        new code.

        :returns: Code
        """
        return_code = Code.SUCCESS
        # This is a list if 2-item tuples for the check name and it's results.
        check_results = []
        for name, func in self._upgrade_checks:
            if isinstance(func, tuple):
                func_name, kwargs = func
                result = func_name(self, **kwargs)
            else:
                result = func(self)
            # store the result of the check for the summary table
            check_results.append((name, result))
            # we want to end up with the highest level code of all checks
            if result.code > return_code:
                return_code = result.code

        # We're going to build a summary table that looks like:
        # +----------------------------------------------------+
        # | Upgrade Check Results                              |
        # +----------------------------------------------------+
        # | Check: Cells v2                                    |
        # | Result: Success                                    |
        # | Details: None                                      |
        # +----------------------------------------------------+
        # | Check: Placement API                               |
        # | Result: Failure                                    |
        # | Details: There is no placement-api endpoint in the |
        # |          service catalog.                          |
        # +----------------------------------------------------+

        # Since registering opts can be overridden by consuming code, we can't
        # assume that our locally defined option exists.
        if (hasattr(CONF, 'command') and hasattr(CONF.command, 'json')
                and CONF.command.json):
            # NOTE(bnemec): We use str on the translated string to
            # force immediate translation if lazy translation is in use.
            # See lp1801761 for details.
            output = {'name': str(self.display_title), 'checks': []}
            for name, result in check_results:
                output['checks'].append({
                    'check': name,
                    'result': result.code,
                    'details': result.details
                })
            print(json.dumps(output))
        else:
            # NOTE(bnemec): We use str on the translated string to
            # force immediate translation if lazy translation is in use.
            # See lp1801761 for details.
            t = prettytable.PrettyTable([str(self.display_title)],
                                        hrules=prettytable.ALL)
            t.align = 'l'
            for name, result in check_results:
                cell = (_('Check: %(name)s\n'
                          'Result: %(result)s\n'
                          'Details: %(details)s') % {
                              'name': name,
                              'result': UPGRADE_CHECK_MSG_MAP[result.code],
                              'details': self._get_details(result),
                          })
                t.add_row([cell])
            print(t)

        return return_code
Esempio n. 6
0
    # All upgrade readiness checks passed successfully and there is
    # nothing to do.
    SUCCESS = 0

    # At least one check encountered an issue and requires further
    # investigation. This is considered a warning but the upgrade may be OK.
    WARNING = 1

    # There was an upgrade status check failure that needs to be
    # investigated. This should be considered something that stops an upgrade.
    FAILURE = 2


UPGRADE_CHECK_MSG_MAP = {
    Code.SUCCESS: _('Success'),
    Code.WARNING: _('Warning'),
    Code.FAILURE: _('Failure'),
}


class Result(object):
    """Class used for 'nova-status upgrade check' results.

    The 'code' attribute is a Code enum.
    The 'details' attribute is a translated message generally only used for
    checks that result in a warning or failure code. The details should provide
    information on what issue was discovered along with any remediation.
    """
    def __init__(self, code, details=None):
        super(Result, self).__init__()
Esempio n. 7
0
    # All upgrade readiness checks passed successfully and there is
    # nothing to do.
    SUCCESS = 0

    # At least one check encountered an issue and requires further
    # investigation. This is considered a warning but the upgrade may be OK.
    WARNING = 1

    # There was an upgrade status check failure that needs to be
    # investigated. This should be considered something that stops an upgrade.
    FAILURE = 2


UPGRADE_CHECK_MSG_MAP = {
    UpgradeCheckCode.SUCCESS: _('Success'),
    UpgradeCheckCode.WARNING: _('Warning'),
    UpgradeCheckCode.FAILURE: _('Failure'),
}


class UpgradeCheckResult(object):
    """Class used for 'nova-status upgrade check' results.

    The 'code' attribute is an UpgradeCheckCode enum.
    The 'details' attribute is a translated message generally only used for
    checks that result in a warning or failure code. The details should provide
    information on what issue was discovered along with any remediation.
    """

    def __init__(self, code, details=None):