script_alert.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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. logger = logging.getLogger()
  24. class ScriptAlert(BaseAlert):
  25. def __init__(self, alert_meta, alert_source_meta, config):
  26. """ ScriptAlert reporting structure is output from the script itself """
  27. alert_source_meta['reporting'] = {
  28. 'ok': { 'text': '{0}' },
  29. 'warning': { 'text': '{0}' },
  30. 'critical': { 'text': '{0}' },
  31. 'unknown': { 'text': '{0}' }
  32. }
  33. super(ScriptAlert, self).__init__(alert_meta, alert_source_meta)
  34. self.config = config
  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. self.parameters = {}
  41. if 'path' in alert_source_meta:
  42. self.path = alert_source_meta['path']
  43. if 'common_services_directory' in alert_source_meta:
  44. self.common_services_dir = alert_source_meta['common_services_directory']
  45. if 'stacks_directory' in alert_source_meta:
  46. self.stacks_dir = alert_source_meta['stacks_directory']
  47. if 'host_scripts_directory' in alert_source_meta:
  48. self.host_scripts_dir = alert_source_meta['host_scripts_directory']
  49. # convert a list of script parameters, like timeouts, into a dictionary
  50. # so the the scripts can easily lookup the data
  51. if 'parameters' in alert_source_meta:
  52. parameters = alert_source_meta['parameters']
  53. for parameter in parameters:
  54. if 'name' not in parameter or 'value' not in parameter:
  55. continue
  56. # create the dictionary value
  57. parameter_name = parameter['name']
  58. parameter_value = parameter['value']
  59. self.parameters[parameter_name] = parameter_value
  60. def _collect(self):
  61. cmd_module = self._load_source()
  62. if cmd_module is not None:
  63. configurations = {}
  64. try:
  65. tokens = cmd_module.get_tokens()
  66. if tokens is not None:
  67. # for each token, if there is a value, store in; otherwise don't store
  68. # a key with a value of None
  69. for token in tokens:
  70. value = self._get_configuration_value(token)
  71. if value is not None:
  72. configurations[token] = value
  73. except AttributeError:
  74. # it's OK if the module doesn't have get_tokens() ; no tokens will
  75. # be passed in so hopefully the script doesn't need any
  76. logger.debug("The script {0} does not have a get_tokens() function".format(str(cmd_module)))
  77. # try to get basedir for scripts
  78. # it's needed for server side scripts to properly use resource management
  79. matchObj = re.match( r'((.*)services\/(.*)\/package\/)', self.path_to_script)
  80. if matchObj:
  81. basedir = matchObj.group(1)
  82. with Environment(basedir, tmp_dir=self.config.get('agent', 'tmp_dir')) as env:
  83. return cmd_module.execute(configurations, self.parameters, self.host_name)
  84. else:
  85. return cmd_module.execute(configurations, self.parameters, self.host_name)
  86. else:
  87. return (self.RESULT_UNKNOWN, ["Unable to execute script {0}".format(self.path)])
  88. def _load_source(self):
  89. if self.path is None and self.stack_path is None and self.host_scripts_dir is None:
  90. raise Exception("The attribute 'path' must be specified")
  91. paths = self.path.split('/')
  92. self.path_to_script = self.path
  93. # if the path doesn't exist and stacks dir is defined, try that
  94. if not os.path.exists(self.path_to_script) and self.stacks_dir is not None:
  95. self.path_to_script = os.path.join(self.stacks_dir, *paths)
  96. # if the path doesn't exist and common services dir is defined, try that
  97. if not os.path.exists(self.path_to_script) and self.common_services_dir is not None:
  98. self.path_to_script = os.path.join(self.common_services_dir, *paths)
  99. # if the path doesn't exist and the host script dir is defined, try that
  100. if not os.path.exists(self.path_to_script) and self.host_scripts_dir is not None:
  101. self.path_to_script = os.path.join(self.host_scripts_dir, *paths)
  102. # if the path can't be evaluated, throw exception
  103. if not os.path.exists(self.path_to_script) or not os.path.isfile(self.path_to_script):
  104. raise Exception(
  105. "Unable to find '{0}' as an absolute path or part of {1} or {2}".format(self.path,
  106. self.stacks_dir, self.host_scripts_dir))
  107. if logger.isEnabledFor(logging.DEBUG):
  108. logger.debug("[Alert][{0}] Executing script check {1}".format(
  109. self.get_name(), self.path_to_script))
  110. if (not self.path_to_script.endswith('.py')):
  111. logger.error("[Alert][{0}] Unable to execute script {1}".format(
  112. self.get_name(), self.path_to_script))
  113. return None
  114. return imp.load_source(self._get_alert_meta_value_safely('name'), self.path_to_script)
  115. def _get_reporting_text(self, state):
  116. '''
  117. Always returns {0} since the result of the script alert is a rendered string.
  118. This will ensure that the base class takes the result string and just uses
  119. it directly.
  120. :param state: the state of the alert in uppercase (such as OK, WARNING, etc)
  121. :return: the parameterized text
  122. '''
  123. return '{0}'