OpenStack Compute (Nova)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

210 lines
7.5 KiB

  1. # Copyright 2016 IBM Corp.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. # not use this file except in compliance with the License. You may obtain
  5. # a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations
  13. # under the License.
  14. """
  15. CLI interface for nova status commands.
  16. """
  17. from __future__ import print_function
  18. import functools
  19. import sys
  20. import textwrap
  21. import traceback
  22. # enum comes from the enum34 package if python < 3.4, else it's stdlib
  23. import enum
  24. from oslo_config import cfg
  25. import prettytable
  26. from nova.cmd import common as cmd_common
  27. import nova.conf
  28. from nova import config
  29. from nova.i18n import _
  30. from nova import version
  31. CONF = nova.conf.CONF
  32. class UpgradeCheckCode(enum.IntEnum):
  33. """These are the status codes for the nova-status upgrade check command
  34. and internal check commands.
  35. """
  36. # All upgrade readiness checks passed successfully and there is
  37. # nothing to do.
  38. SUCCESS = 0
  39. # At least one check encountered an issue and requires further
  40. # investigation. This is considered a warning but the upgrade may be OK.
  41. WARNING = 1
  42. # There was an upgrade status check failure that needs to be
  43. # investigated. This should be considered something that stops an upgrade.
  44. FAILURE = 2
  45. UPGRADE_CHECK_MSG_MAP = {
  46. UpgradeCheckCode.SUCCESS: _('Success'),
  47. UpgradeCheckCode.WARNING: _('Warning'),
  48. UpgradeCheckCode.FAILURE: _('Failure'),
  49. }
  50. class UpgradeCheckResult(object):
  51. """Class used for 'nova-status upgrade check' results.
  52. The 'code' attribute is an UpgradeCheckCode enum.
  53. The 'details' attribute is a translated message generally only used for
  54. checks that result in a warning or failure code. The details should provide
  55. information on what issue was discovered along with any remediation.
  56. """
  57. def __init__(self, code, details=None):
  58. super(UpgradeCheckResult, self).__init__()
  59. self.code = code
  60. self.details = details
  61. class UpgradeCommands(object):
  62. """Commands related to upgrades.
  63. The subcommands here must not rely on the nova object model since they
  64. should be able to run on n-1 data. Any queries to the database should be
  65. done through the sqlalchemy query language directly like the database
  66. schema migrations.
  67. """
  68. def _check_cellsv2(self):
  69. # TODO(mriedem): perform the same checks as the 030_require_cell_setup
  70. # API DB migration.
  71. return UpgradeCheckResult(UpgradeCheckCode.SUCCESS)
  72. def _check_placement(self):
  73. # TODO(mriedem): check to see that the placement API service is running
  74. # and we can connect to it, and that the number of resource providers
  75. # in the placement service is greater than or equal to the number of
  76. # compute nodes in the database.
  77. return UpgradeCheckResult(UpgradeCheckCode.SUCCESS)
  78. # The format of the check functions is to return an UpgradeCheckResult
  79. # object with the appropriate UpgradeCheckCode and details set. If the
  80. # check hits warnings or failures then those should be stored in the
  81. # returned UpgradeCheckResult's "details" attribute. The summary will
  82. # be rolled up at the end of the check() function.
  83. _upgrade_checks = {
  84. # Added in Ocata
  85. _('Cells v2'): _check_cellsv2,
  86. # Added in Ocata
  87. _('Placement API'): _check_placement,
  88. }
  89. def _get_details(self, upgrade_check_result):
  90. if upgrade_check_result.details is not None:
  91. # wrap the text on the details to 60 characters
  92. return '\n'.join(textwrap.wrap(upgrade_check_result.details, 60,
  93. subsequent_indent=' '))
  94. def check(self):
  95. """Performs checks to see if the deployment is ready for upgrade.
  96. These checks are expected to be run BEFORE services are restarted with
  97. new code. These checks also require access to potentially all of the
  98. Nova databases (nova, nova_api, nova_api_cell0) and external services
  99. such as the placement API service.
  100. :returns: UpgradeCheckCode
  101. """
  102. return_code = UpgradeCheckCode.SUCCESS
  103. # This is a list if 2-item tuples for the check name and it's results.
  104. check_results = []
  105. # Sort the checks by name so that we have predictable test results.
  106. for name in sorted(self._upgrade_checks.keys()):
  107. func = self._upgrade_checks[name]
  108. result = func(self)
  109. # store the result of the check for the summary table
  110. check_results.append((name, result))
  111. # we want to end up with the highest level code of all checks
  112. if result.code > return_code:
  113. return_code = result.code
  114. # We're going to build a summary table that looks like:
  115. # +----------------------------------------------------+
  116. # | Upgrade Check Results |
  117. # +----------------------------------------------------+
  118. # | Check: Cells v2 |
  119. # | Result: Success |
  120. # | Details: None |
  121. # +----------------------------------------------------+
  122. # | Check: Placement API |
  123. # | Result: Failure |
  124. # | Details: There is no placement-api endpoint in the |
  125. # | service catalog. |
  126. # +----------------------------------------------------+
  127. t = prettytable.PrettyTable([_('Upgrade Check Results')],
  128. hrules=prettytable.ALL)
  129. t.align = 'l'
  130. for name, result in check_results:
  131. cell = (
  132. _('Check: %(name)s\n'
  133. 'Result: %(result)s\n'
  134. 'Details: %(details)s') %
  135. {
  136. 'name': name,
  137. 'result': UPGRADE_CHECK_MSG_MAP[result.code],
  138. 'details': self._get_details(result),
  139. }
  140. )
  141. t.add_row([cell])
  142. print(t)
  143. return return_code
  144. CATEGORIES = {
  145. 'upgrade': UpgradeCommands,
  146. }
  147. add_command_parsers = functools.partial(cmd_common.add_command_parsers,
  148. categories=CATEGORIES)
  149. category_opt = cfg.SubCommandOpt('category',
  150. title='Command categories',
  151. help='Available categories',
  152. handler=add_command_parsers)
  153. def main():
  154. """Parse options and call the appropriate class/method."""
  155. CONF.register_cli_opt(category_opt)
  156. config.parse_args(sys.argv)
  157. if CONF.category.name == "version":
  158. print(version.version_string_with_package())
  159. return 0
  160. if CONF.category.name == "bash-completion":
  161. cmd_common.print_bash_completion(CATEGORIES)
  162. return 0
  163. try:
  164. fn, fn_args, fn_kwargs = cmd_common.get_action_fn()
  165. ret = fn(*fn_args, **fn_kwargs)
  166. return(ret)
  167. except Exception:
  168. print(_('Error:\n%s') % traceback.format_exc())
  169. # This is 10 so it's not confused with the upgrade check exit codes.
  170. return 10