puppet.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. import logging
  15. import os
  16. import re
  17. from packstack.installer.exceptions import PuppetError
  18. # TODO: Fill logger name when logging system will be refactored
  19. logger = logging.getLogger()
  20. re_color = re.compile('\x1b.*?\d\dm')
  21. re_error = re.compile(
  22. 'err:|Syntax error at|^Duplicate definition:|^Invalid tag|'
  23. '^No matching value for selector param|^Parameter name failed:|Error:|'
  24. '^Invalid parameter|^Duplicate declaration:|^Could not find resource|'
  25. '^Could not parse for|^/usr/bin/puppet:\d+: .+|.+\(LoadError\)|'
  26. '^Could not autoload|'
  27. '^\/usr\/bin\/env\: jruby\: No such file or directory|'
  28. 'failed to execute puppet'
  29. )
  30. re_ignore = re.compile(
  31. # Puppet preloads a provider using the mysql command before it is installed
  32. 'Command mysql is missing|'
  33. # Puppet preloads a database_grant provider which fails if /root/.my.cnf
  34. # is missing, this is ok because it will be retried later if needed
  35. 'Could not prefetch database_grant provider.*?\\.my\\.cnf|'
  36. # Swift Puppet module tries to install swift-plugin-s3, there is no such
  37. # package on RHEL, fixed in the upstream puppet module
  38. 'yum.*?install swift-plugin-s3|'
  39. # facter gives a weird NM error when it's disabled, due to
  40. # https://tickets.puppetlabs.com/browse/FACT-697
  41. 'NetworkManager is not running'
  42. )
  43. re_notice = re.compile(r"notice: .*Notify\[packstack_info\]"
  44. "\/message: defined \'message\' as "
  45. "\'(?P<message>.*)\'")
  46. surrogates = [
  47. # Value in /etc/sysctl.conf cannot be changed
  48. ('Sysctl::Value\[.*\]\/Sysctl\[(?P<arg1>.*)\].*Field \'val\' is required',
  49. 'Cannot change value of %(arg1)s in /etc/sysctl.conf'),
  50. # Package is not found in yum repos
  51. ('Package\[.*\]\/ensure.*yum.*install (?P<arg1>.*)\'.*Nothing to do',
  52. 'Package %(arg1)s has not been found in enabled Yum repos.'),
  53. ('Execution of \'.*yum.*install (?P<arg1>.*)\'.*Nothing to do',
  54. 'Package %(arg1)s has not been found in enabled Yum repos.'),
  55. # Packstack does not cooperate with jruby
  56. ('jruby', 'Your Puppet installation uses jruby instead of ruby. Package '
  57. 'jruby does not cooperate with Packstack well. You will have to '
  58. 'fix this manually.'),
  59. ]
  60. def validate_logfile(logpath):
  61. """
  62. Check given Puppet log file for errors and raise PuppetError if there is
  63. any error
  64. """
  65. manifestpath = os.path.splitext(logpath)[0]
  66. manifestfile = os.path.basename(manifestpath)
  67. with open(logpath) as logfile:
  68. for line in logfile:
  69. line = line.strip()
  70. if re_error.search(line) is None:
  71. continue
  72. error = re_color.sub('', line) # remove colors
  73. if re_ignore.search(line):
  74. msg = ('Ignoring expected error during Puppet run %s: %s' %
  75. (manifestfile, error))
  76. logger.debug(msg)
  77. continue
  78. for regex, surrogate in surrogates:
  79. match = re.search(regex, error)
  80. if match is None:
  81. continue
  82. args = {}
  83. num = 1
  84. while True:
  85. try:
  86. args['arg%d' % num] = match.group(num)
  87. num += 1
  88. except IndexError:
  89. break
  90. error = surrogate % args
  91. message = ('Error appeared during Puppet run: %s\n%s\n'
  92. 'You will find full trace in log %s' %
  93. (manifestfile, error, logpath))
  94. raise PuppetError(message)
  95. def scan_logfile(logpath):
  96. """
  97. Returns list of packstack_info/packstack_warn notices parsed from
  98. given puppet log file.
  99. """
  100. output = []
  101. with open(logpath) as logfile:
  102. for line in logfile:
  103. match = re_notice.search(line)
  104. if match:
  105. output.append(match.group('message'))
  106. return output