script_alert.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #!/usr/bin/env python
  2. """
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing, software
  12. distributed under the License is distributed on an "AS IS" BASIS,
  13. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. See the License for the specific language governing permissions and
  15. limitations under the License.
  16. """
  17. import imp
  18. import logging
  19. import os
  20. import re
  21. from alerts.base_alert import BaseAlert
  22. from resource_management.core.environment import Environment
  23. from symbol import parameters
  24. logger = logging.getLogger()
  25. class ScriptAlert(BaseAlert):
  26. def __init__(self, alert_meta, alert_source_meta):
  27. """ ScriptAlert reporting structure is output from the script itself """
  28. alert_source_meta['reporting'] = {
  29. 'ok': { 'text': '{0}' },
  30. 'warning': { 'text': '{0}' },
  31. 'critical': { 'text': '{0}' },
  32. 'unknown': { 'text': '{0}' }
  33. }
  34. super(ScriptAlert, self).__init__(alert_meta, alert_source_meta)
  35. self.path = None
  36. self.stacks_dir = None
  37. self.common_services_dir = None
  38. self.host_scripts_dir = None
  39. self.path_to_script = None
  40. if 'path' in alert_source_meta:
  41. self.path = alert_source_meta['path']
  42. if 'common_services_directory' in alert_source_meta:
  43. self.common_services_dir = alert_source_meta['common_services_directory']
  44. if 'stacks_directory' in alert_source_meta:
  45. self.stacks_dir = alert_source_meta['stacks_directory']
  46. if 'host_scripts_directory' in alert_source_meta:
  47. self.host_scripts_dir = alert_source_meta['host_scripts_directory']
  48. # execute the get_tokens() method so that this script correctly populates
  49. # its list of keys
  50. try:
  51. cmd_module = self._load_source()
  52. tokens = cmd_module.get_tokens()
  53. # for every token, populate the array keys that this alert will need
  54. if tokens is not None:
  55. for token in tokens:
  56. # append the key to the list of keys for this alert
  57. self._find_lookup_property(token)
  58. except:
  59. logger.exception("Unable to parameterize tokens for script {0}".format(self.path))
  60. pass
  61. def _collect(self):
  62. cmd_module = self._load_source()
  63. if cmd_module is not None:
  64. # convert the dictionary from
  65. # {'foo-site/bar': 'baz'} into
  66. # {'{{foo-site/bar}}': 'baz'}
  67. parameters = {}
  68. for key in self.config_value_dict:
  69. parameters['{{' + key + '}}'] = self.config_value_dict[key]
  70. # try to get basedir for scripts
  71. # it's needed for server side scripts to properly use resource management
  72. matchObj = re.match( r'((.*)services\/(.*)\/package\/)', self.path_to_script)
  73. if matchObj:
  74. basedir = matchObj.group(1)
  75. with Environment(basedir) as env:
  76. return cmd_module.execute(parameters, self.host_name)
  77. else:
  78. return cmd_module.execute(parameters, self.host_name)
  79. else:
  80. return (self.RESULT_UNKNOWN, ["Unable to execute script {0}".format(self.path)])
  81. def _load_source(self):
  82. if self.path is None and self.stack_path is None and self.host_scripts_dir is None:
  83. raise Exception("The attribute 'path' must be specified")
  84. paths = self.path.split('/')
  85. self.path_to_script = self.path
  86. # if the path doesn't exist and stacks dir is defined, try that
  87. if not os.path.exists(self.path_to_script) and self.stacks_dir is not None:
  88. self.path_to_script = os.path.join(self.stacks_dir, *paths)
  89. # if the path doesn't exist and common services dir is defined, try that
  90. if not os.path.exists(self.path_to_script) and self.common_services_dir is not None:
  91. self.path_to_script = os.path.join(self.common_services_dir, *paths)
  92. # if the path doesn't exist and the host script dir is defined, try that
  93. if not os.path.exists(self.path_to_script) and self.host_scripts_dir is not None:
  94. self.path_to_script = os.path.join(self.host_scripts_dir, *paths)
  95. # if the path can't be evaluated, throw exception
  96. if not os.path.exists(self.path_to_script) or not os.path.isfile(self.path_to_script):
  97. raise Exception(
  98. "Unable to find '{0}' as an absolute path or part of {1} or {2}".format(self.path,
  99. self.stacks_dir, self.host_scripts_dir))
  100. if logger.isEnabledFor(logging.DEBUG):
  101. logger.debug("Executing script check {0}".format(self.path_to_script))
  102. if (not self.path_to_script.endswith('.py')):
  103. logger.error("Unable to execute script {0}".format(self.path_to_script))
  104. return None
  105. return imp.load_source(self._find_value('name'), self.path_to_script)
  106. def _get_reporting_text(self, state):
  107. '''
  108. Always returns {0} since the result of the script alert is a rendered string.
  109. This will ensure that the base class takes the result string and just uses
  110. it directly.
  111. :param state: the state of the alert in uppercase (such as OK, WARNING, etc)
  112. :return: the parameterized text
  113. '''
  114. return '{0}'