sequences.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # -*- coding: utf-8 -*-
  2. # Licensed under the Apache License, Version 2.0 (the "License");
  3. # you may not use this file except in compliance with the License.
  4. # You may obtain a copy of the License at
  5. #
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. #
  8. # Unless required by applicable law or agreed to in writing, software
  9. # distributed under the License is distributed on an "AS IS" BASIS,
  10. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  11. # implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """
  15. Base class for steps & sequences
  16. """
  17. import sys
  18. import logging
  19. import traceback
  20. from .. import utils
  21. from ..exceptions import SequenceError
  22. class Step(object):
  23. """
  24. Wrapper for function representing single setup step.
  25. """
  26. def __init__(self, name, function, title=None):
  27. self.name = name
  28. self.title = title or ('Step: %s' % name)
  29. # process step function
  30. if function and not callable(function):
  31. raise SequenceError("Function object have to be callable. "
  32. "Object %s is not callable." % function)
  33. self.function = function
  34. def run(self, config=None, messages=None):
  35. config = config if config is not None else {}
  36. messages = messages if messages is not None else []
  37. # TO-DO: complete logger name when logging will be setup correctly
  38. logger = logging.getLogger()
  39. logger.debug('Running step %s.' % self.name)
  40. # execute and report state
  41. try:
  42. self.function(config, messages)
  43. except Exception as ex:
  44. logger.debug(traceback.format_exc())
  45. state = utils.state_message(self.title, 'ERROR', 'red')
  46. sys.stdout.write('%s\n' % state)
  47. sys.stdout.flush()
  48. raise
  49. else:
  50. state = utils.state_message(self.title, 'DONE', 'green')
  51. sys.stdout.write('%s\n' % state)
  52. sys.stdout.flush()
  53. class Sequence(object):
  54. """
  55. Wrapper for sequence of setup steps.
  56. """
  57. def __init__(self, name, steps, title=None, condition=None,
  58. cond_match=None):
  59. self.name = name
  60. self.title = title
  61. self.condition = condition
  62. self.cond_match = cond_match
  63. # process sequence steps
  64. self.steps = utils.SortedDict()
  65. for step in steps:
  66. name, func = step['name'], step['function']
  67. self.steps[name] = Step(name, func, title=step.get('title'))
  68. def validate_condition(self, config):
  69. """
  70. Returns True if config option condition has value given
  71. in cond_match. Otherwise returns False.
  72. """
  73. if not self.condition:
  74. return True
  75. result = config.get(self.condition)
  76. return result == self.cond_match
  77. def run(self, config=None, messages=None, step=None):
  78. """
  79. Runs sequence of steps. Runs only specific step if step's name
  80. is given via 'step' parameter.
  81. """
  82. config = config if config is not None else {}
  83. messages = messages if messages is not None else []
  84. if not self.validate_condition(config):
  85. return
  86. if step:
  87. self.steps[step].run(config=config, messages=messages)
  88. return
  89. logger = logging.getLogger()
  90. logger.debug('Running sequence %s.' % self.name)
  91. if self.title:
  92. sys.stdout.write('%s\n' % self.title)
  93. sys.stdout.flush()
  94. for step in self.steps.itervalues():
  95. step.run(config=config, messages=messages)