installer_checkpoint.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. """Ansible callback plugin to print a summary completion status of installation
  2. phases.
  3. """
  4. from datetime import datetime
  5. from ansible.plugins.callback import CallbackBase
  6. from ansible import constants as C
  7. class CallbackModule(CallbackBase):
  8. """This callback summarizes installation phase status."""
  9. CALLBACK_VERSION = 2.0
  10. CALLBACK_TYPE = 'aggregate'
  11. CALLBACK_NAME = 'installer_checkpoint'
  12. CALLBACK_NEEDS_WHITELIST = False
  13. def __init__(self):
  14. super(CallbackModule, self).__init__()
  15. def v2_playbook_on_stats(self, stats):
  16. # Return if there are no custom stats to process
  17. if stats.custom == {}:
  18. return
  19. phases = stats.custom['_run']
  20. # Find the longest phase title
  21. max_column = 0
  22. for phase in phases:
  23. max_column = max(max_column, len(phases[phase].get('title', '')))
  24. # Sort the phases by start time
  25. ordered_phases = sorted(phases, key=lambda x: (phases[x].get('start', 0)))
  26. self._display.banner('INSTALLER STATUS')
  27. # Display status information for each phase
  28. for phase in ordered_phases:
  29. phase_title = phases[phase].get('title', '')
  30. padding = max_column - len(phase_title) + 2
  31. phase_status = phases[phase]['status']
  32. phase_time = phase_time_delta(phases[phase])
  33. if phase_title:
  34. self._display.display(
  35. '{}{}: {} ({})'.format(phase_title, ' ' * padding, phase_status, phase_time),
  36. color=self.phase_color(phase_status))
  37. # If the phase is not complete, tell the user what playbook to rerun
  38. if phase_status == 'In Progress' and phase != 'installer_phase_initialize':
  39. self._display.display(
  40. '\tThis phase can be restarted by running: {}'.format(
  41. phases[phase]['playbook']))
  42. # Display any extra messages stored during the phase
  43. if 'message' in phases[phase]:
  44. self._display.display(
  45. '\t{}'.format(
  46. phases[phase]['message']))
  47. def phase_color(self, status):
  48. """ Return color code for installer phase"""
  49. valid_status = [
  50. 'In Progress',
  51. 'Complete',
  52. ]
  53. if status not in valid_status:
  54. self._display.warning('Invalid phase status defined: {}'.format(status))
  55. if status == 'Complete':
  56. phase_color = C.COLOR_OK
  57. elif status == 'In Progress':
  58. phase_color = C.COLOR_ERROR
  59. else:
  60. phase_color = C.COLOR_WARN
  61. return phase_color
  62. def phase_time_delta(phase):
  63. """ Calculate the difference between phase start and end times """
  64. if not phase.get('start'):
  65. return ''
  66. time_format = '%Y%m%d%H%M%SZ'
  67. phase_start = datetime.strptime(phase['start'], time_format)
  68. if 'end' not in phase:
  69. # The phase failed so set the end time to now
  70. phase_end = datetime.now()
  71. else:
  72. phase_end = datetime.strptime(phase['end'], time_format)
  73. delta = str(phase_end - phase_start).split(".")[0] # Trim microseconds
  74. return delta