OpenStack RCA (Root Cause Analysis) Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

datasource_info_mapper.py 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. # Copyright 2016 - Nokia
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. # not use this file except in compliance with the License. You may obtain
  5. # a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations
  13. # under the License.
  14. import os
  15. from oslo_config import cfg
  16. from oslo_log import log
  17. from vitrage.common.constants import EntityCategory
  18. from vitrage.common.constants import VertexProperties as VProps
  19. from vitrage.entity_graph.mappings.alarm_handler import AlarmHandler
  20. from vitrage.entity_graph.mappings.resource_handler import \
  21. ResourceHandler
  22. from vitrage.utils import file as file_utils
  23. CONF = cfg.CONF
  24. LOG = log.getLogger(__name__)
  25. DEFAULT_INFO_MAPPER = 'default'
  26. class DatasourceInfoMapper(object):
  27. OPERATIONAL_VALUES = 'operational_values'
  28. PRIORITY_VALUES = 'priority_values'
  29. UNDEFINED_DATASOURCE = 'undefined datasource'
  30. def __init__(self):
  31. self.category_normalizer = self._init_category_normalizer()
  32. self.datasources_value_confs = self._load_value_configurations()
  33. def vitrage_operational_value(self, vitrage_type, value):
  34. return self._get_value_data(vitrage_type,
  35. value,
  36. self.OPERATIONAL_VALUES)
  37. def value_priority(self, vitrage_type, value):
  38. return self._get_value_data(vitrage_type,
  39. value,
  40. self.PRIORITY_VALUES)
  41. def vitrage_aggregate_values(self, new_vertex, graph_vertex):
  42. LOG.debug('new_vertex: %s', new_vertex)
  43. LOG.debug('graph_vertex: %s', graph_vertex)
  44. vitrage_type = new_vertex[VProps.VITRAGE_TYPE] if \
  45. VProps.VITRAGE_TYPE in new_vertex.properties else \
  46. graph_vertex[VProps.VITRAGE_TYPE]
  47. vitrage_category = new_vertex[VProps.VITRAGE_CATEGORY] if \
  48. VProps.VITRAGE_CATEGORY in new_vertex.properties else \
  49. graph_vertex[VProps.VITRAGE_CATEGORY]
  50. if vitrage_type in self.datasources_value_confs or \
  51. vitrage_type not in CONF.datasources.types:
  52. value_properties = \
  53. self.category_normalizer[vitrage_category].value_properties()
  54. vitrage_operational_value, vitrage_aggregated_value, value_priority = \
  55. self._find_operational_value_and_priority(new_vertex,
  56. graph_vertex,
  57. value_properties[0],
  58. vitrage_type)
  59. value_properties.pop(0)
  60. for property_ in value_properties:
  61. t_operational_value, t_aggregated_value, t_value_priority = \
  62. self._find_operational_value_and_priority(new_vertex,
  63. graph_vertex,
  64. property_,
  65. vitrage_type)
  66. if t_value_priority > value_priority:
  67. vitrage_operational_value = t_operational_value
  68. vitrage_aggregated_value = t_aggregated_value
  69. value_priority = t_value_priority
  70. self.category_normalizer[vitrage_category].set_aggregated_value(
  71. new_vertex, vitrage_aggregated_value)
  72. self.category_normalizer[vitrage_category].set_operational_value(
  73. new_vertex, vitrage_operational_value)
  74. else:
  75. self.category_normalizer[vitrage_category].set_aggregated_value(
  76. new_vertex, self.UNDEFINED_DATASOURCE)
  77. self.category_normalizer[vitrage_category].set_operational_value(
  78. new_vertex, self.UNDEFINED_DATASOURCE)
  79. def get_datasource_priorities(self, vitrage_type=None):
  80. if vitrage_type:
  81. datasource_info = self.datasources_value_confs[vitrage_type]
  82. return datasource_info[self.PRIORITY_VALUES]
  83. else:
  84. priorities_dict = \
  85. {key: self.datasources_value_confs[key][self.PRIORITY_VALUES]
  86. for key in self.datasources_value_confs.keys()}
  87. return priorities_dict
  88. @staticmethod
  89. def _init_category_normalizer():
  90. return {
  91. EntityCategory.RESOURCE: ResourceHandler(),
  92. EntityCategory.ALARM: AlarmHandler()
  93. }
  94. def _load_value_configurations(self):
  95. valid_datasources_conf = {}
  96. erroneous_datasources_conf = []
  97. files = file_utils.list_files(
  98. CONF.entity_graph.datasources_values_dir, '.yaml')
  99. for file_name in files:
  100. try:
  101. full_path = CONF.entity_graph.datasources_values_dir \
  102. + '/' + file_name
  103. operational_values, priority_values = \
  104. self._retrieve_values_and_priorities_from_file(full_path)
  105. valid_datasources_conf[os.path.splitext(file_name)[0]] = {
  106. self.OPERATIONAL_VALUES: operational_values,
  107. self.PRIORITY_VALUES: priority_values
  108. }
  109. except Exception:
  110. datasource = os.path.splitext(file_name)[0]
  111. erroneous_datasources_conf.append(datasource)
  112. LOG.exception('Erroneous data source is %s', datasource)
  113. self._check_value_confs_exists(
  114. [key for key in valid_datasources_conf.keys()],
  115. erroneous_datasources_conf)
  116. return valid_datasources_conf
  117. def _retrieve_values_and_priorities_from_file(self, full_path):
  118. values = {}
  119. priorities = {}
  120. config = file_utils.load_yaml_file(full_path, with_exception=True)
  121. vitrage_category = config['category']
  122. for item in config['values']:
  123. aggregated_values = item['aggregated values']
  124. priority_value = int(aggregated_values['priority'])
  125. # original to operational value
  126. for value_map in aggregated_values['original values']:
  127. name = value_map['name']
  128. operational_value = value_map['operational_value']
  129. values[name.upper()] = operational_value
  130. priorities[name.upper()] = priority_value
  131. self._check_validity(vitrage_category, values, priorities, full_path)
  132. self._add_default_values(values, priorities, vitrage_category)
  133. return values, priorities
  134. def _add_default_values(self, values, priorities, category):
  135. default_values = self.category_normalizer[category].default_values()
  136. for original_val, operational_val, priority_val in default_values:
  137. values[original_val] = operational_val
  138. priorities[original_val] = priority_val
  139. def _check_validity(self, category, values, priorities, full_path):
  140. # check that all the operational values exists
  141. state_class_instance = \
  142. self.category_normalizer[category].get_value_class_instance()
  143. operational_values = DatasourceInfoMapper.\
  144. _get_all_local_variables_of_class(state_class_instance)
  145. for operational_value in values.values():
  146. if operational_value not in operational_values:
  147. raise ValueError('operational value %s for %s is not in %s',
  148. operational_value, full_path,
  149. state_class_instance.__class__.__name__)
  150. def _get_value_data(self, vitrage_type, value, data_type):
  151. try:
  152. upper_value = value if not value else value.upper()
  153. if vitrage_type in self.datasources_value_confs:
  154. values_conf = self.datasources_value_confs[
  155. vitrage_type][data_type]
  156. return values_conf[upper_value] if upper_value in values_conf \
  157. else values_conf[None]
  158. else:
  159. values_conf = self.datasources_value_confs[
  160. DEFAULT_INFO_MAPPER][data_type]
  161. return values_conf[upper_value] if upper_value in values_conf \
  162. else values_conf[None]
  163. except Exception:
  164. LOG.error('Exception in datasource: %s', vitrage_type)
  165. raise
  166. def _find_operational_value_and_priority(self,
  167. new_vertex,
  168. graph_vertex,
  169. property_,
  170. vitrage_type):
  171. state = self._get_updated_property(new_vertex,
  172. graph_vertex,
  173. property_)
  174. upper_state = state if not state else state.upper()
  175. vitrage_operational_state = self.vitrage_operational_value(
  176. vitrage_type, upper_state)
  177. value_priority = self.value_priority(vitrage_type,
  178. upper_state)
  179. return vitrage_operational_state, upper_state, value_priority
  180. @staticmethod
  181. def _get_all_local_variables_of_class(class_instance):
  182. return [getattr(class_instance, attr) for attr in dir(class_instance)
  183. if not callable(attr) and not attr.startswith("__")]
  184. def _check_value_confs_exists(self,
  185. ok_datasources,
  186. error_datasources):
  187. datasource_types = CONF.datasources.types
  188. datasources_with_state_conf = ok_datasources + error_datasources
  189. for datasource_type in datasource_types:
  190. if datasource_type not in datasources_with_state_conf:
  191. LOG.info("No state configuration file for: %s",
  192. datasource_type)
  193. @staticmethod
  194. def _get_updated_property(new_vertex, graph_vertex, prop):
  195. if new_vertex and prop in new_vertex.properties:
  196. return new_vertex[prop]
  197. elif graph_vertex and prop in graph_vertex.properties:
  198. return graph_vertex[prop]
  199. return None