diff --git a/etc/vitrage/policy.json b/etc/vitrage/policy.json index 59f3d5cc1..a5d0b93bb 100644 --- a/etc/vitrage/policy.json +++ b/etc/vitrage/policy.json @@ -4,5 +4,6 @@ "list resources": "role:admin", "list alarms": "role:admin", "get rca": "role:admin", - "template validate": "role:admin" + "template validate": "role:admin", + "template list": "role:admin" } \ No newline at end of file diff --git a/vitrage/api/controllers/v1/template.py b/vitrage/api/controllers/v1/template.py index 5d85aae55..f9ac92945 100644 --- a/vitrage/api/controllers/v1/template.py +++ b/vitrage/api/controllers/v1/template.py @@ -27,6 +27,21 @@ LOG = log.getLogger(__name__) class TemplateController(RootRestController): + @pecan.expose('json') + def get_all(self): + + LOG.info(_LI('returns template list')) + + enforce("template list", + pecan.request.headers, + pecan.request.enforcer, + {}) + try: + return self._get_templates() + except Exception as e: + LOG.exception('failed to get template list %s', e) + abort(404, str(e)) + @pecan.expose('json') def post(self, **kwargs): @@ -45,6 +60,19 @@ class TemplateController(RootRestController): LOG.exception('failed to validate template(s) %s', e) abort(404, str(e)) + @staticmethod + def _get_templates(): + templates_json = pecan.request.client.call(pecan.request.context, + 'get_templates') + LOG.info(templates_json) + + try: + template_list = json.loads(templates_json)['templates_details'] + return template_list + except Exception as e: + LOG.exception('failed to get template list %s ', e) + abort(404, str(e)) + @staticmethod def _validate(templates): diff --git a/vitrage/api_handler/apis.py b/vitrage/api_handler/apis.py index 35592a487..02697fc77 100644 --- a/vitrage/api_handler/apis.py +++ b/vitrage/api_handler/apis.py @@ -23,6 +23,7 @@ from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE from vitrage.datasources.nova.zone import NOVA_ZONE_DATASOURCE from vitrage.datasources import OPENSTACK_CLUSTER +from vitrage.evaluator.template_fields import TemplateFields from vitrage.evaluator.template_validation.status_messages import status_msgs from vitrage.evaluator.template_validation.template_content_validator import \ content_validation @@ -180,8 +181,27 @@ class TemplateApis(object): FAILED_MSG = 'validation failed' OK_MSG = 'validation OK' + def __init__(self, templates): + self.templates = templates + + def get_templates(self, ctx): + LOG.debug("TemplateApis get_templates") + + templates_details = [] + for template in self.templates: + + template_metadata = template.data[TemplateFields.METADATA] + + templates_details.append({ + 'name': template_metadata[TemplateFields.NAME], + 'status': self._get_template_status(template.result), + 'status details': template.result.comment, + 'date': template.date.strftime('%Y-%m-%dT%H:%M:%SZ') + }) + return json.dumps({'templates_details': templates_details}) + def validate_template(self, ctx, templates): - LOG.debug("EntityGraphApis validate_template templates:" + LOG.debug("TemplateApis validate_template templates:" "%s", str(templates)) results = [] @@ -230,3 +250,11 @@ class TemplateApis(object): 'message': str(message), 'error code': status_code }) + + @staticmethod + def _get_template_status(result): + + if result.is_valid: + return 'pass' + else: + return 'failed' diff --git a/vitrage/api_handler/service.py b/vitrage/api_handler/service.py index 0ffb76853..45de82859 100644 --- a/vitrage/api_handler/service.py +++ b/vitrage/api_handler/service.py @@ -29,10 +29,11 @@ eventlet.monkey_patch() class VitrageApiHandlerService(os_service.Service): - def __init__(self, conf, e_graph): + def __init__(self, conf, e_graph, scenario_repo): super(VitrageApiHandlerService, self).__init__() self.conf = conf self.entity_graph = e_graph + self.scenario_repo = scenario_repo def start(self): LOG.info("Vitrage Api Handler Service - Starting...") @@ -44,7 +45,8 @@ class VitrageApiHandlerService(os_service.Service): target = oslo_messaging.Target(topic=self.conf.rpc_topic, server=rabbit_hosts) - endpoints = [EntityGraphApis(self.entity_graph), TemplateApis()] + endpoints = [EntityGraphApis(self.entity_graph), + TemplateApis(self.scenario_repo.templates)] server = vitrage_rpc.get_server(target, endpoints, transport) diff --git a/vitrage/cmd/graph.py b/vitrage/cmd/graph.py index 440595ad4..c9e97f26b 100644 --- a/vitrage/cmd/graph.py +++ b/vitrage/cmd/graph.py @@ -53,7 +53,7 @@ def main(): conf, mp_queue, evaluator_queue, evaluator, e_graph, init_status)) launcher.launch_service(api_handler_svc.VitrageApiHandlerService( - conf, e_graph)) + conf, e_graph, evaluator.scenario_repo)) datasources.launch() diff --git a/vitrage/evaluator/base.py b/vitrage/evaluator/base.py new file mode 100644 index 000000000..e7e284150 --- /dev/null +++ b/vitrage/evaluator/base.py @@ -0,0 +1,16 @@ +# Copyright 2016 - Nokia +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +from collections import namedtuple + +Template = namedtuple('Template', ['data', 'date', 'result']) diff --git a/vitrage/evaluator/scenario_evaluator.py b/vitrage/evaluator/scenario_evaluator.py index e24173949..1e93adc44 100644 --- a/vitrage/evaluator/scenario_evaluator.py +++ b/vitrage/evaluator/scenario_evaluator.py @@ -53,14 +53,22 @@ class ScenarioEvaluator(object): event_queue, enabled=False): self.conf = conf + self._scenario_repo = scenario_repo self._entity_graph = entity_graph self._graph_algs = create_algorithm(entity_graph) - self._scenario_repo = scenario_repo self._action_executor = ActionExecutor(event_queue) self._entity_graph.subscribe(self.process_event) self._action_tracker = ActionTracker(DatasourceInfoMapper(self.conf)) self.enabled = enabled + @property + def scenario_repo(self): + return self._scenario_repo + + @scenario_repo.setter + def scenario_repo(self, scenario_repo): + self._scenario_repo = scenario_repo + def process_event(self, before, current, is_vertex): """Notification of a change in the entity graph. diff --git a/vitrage/evaluator/scenario_repository.py b/vitrage/evaluator/scenario_repository.py index 2b9755c55..68e868121 100644 --- a/vitrage/evaluator/scenario_repository.py +++ b/vitrage/evaluator/scenario_repository.py @@ -16,10 +16,11 @@ from collections import namedtuple from oslo_log import log +from vitrage.common import datetime_utils from vitrage.common import file_utils +from vitrage.evaluator.base import Template from vitrage.evaluator.template_data import RELATIONSHIP from vitrage.evaluator.template_data import TemplateData -from vitrage.evaluator.template_fields import TemplateFields from vitrage.evaluator.template_validation.template_content_validator import \ content_validation from vitrage.evaluator.template_validation.template_syntax_validator import \ @@ -34,11 +35,19 @@ EdgeKeyScenario = namedtuple('EdgeKeyScenario', ['label', 'source', 'target']) class ScenarioRepository(object): def __init__(self, conf): - self.templates = defaultdict(list) + self._templates = [] self.relationship_scenarios = defaultdict(list) self.entity_scenarios = defaultdict(list) self._load_templates_files(conf) + @property + def templates(self): + return self._templates + + @templates.setter + def templates(self, templates): + self._templates = templates + def get_scenarios_by_vertex(self, vertex): entity_key = frozenset(vertex.properties.items()) @@ -67,20 +76,21 @@ class ScenarioRepository(object): def add_template(self, template_def): - syntax_validation_result = syntax_validation(template_def) - content_validation_result = content_validation(template_def) - if syntax_validation_result.is_valid and \ - content_validation_result.is_valid: - template_data = TemplateData(template_def) - self.templates[template_data.name] = template_data - self._add_template_scenarios(template_data) + current_time = datetime_utils.utcnow() + + result = syntax_validation(template_def) + if not result.is_valid: + LOG.info('Unable to load template: %s' % result.comment) else: - metadata = template_def.get(TemplateFields.METADATA, None) - if metadata: - template_name = metadata.get(TemplateFields.NAME, None) - LOG.info('Unable to load template: %s' % template_name) - else: - LOG.info('Unable to load template with invalid metadata') + result = content_validation(template_def) + if not result.is_valid: + LOG.info('Unable to load template: %s' % result.comment) + + self.templates.append(Template(template_def, current_time, result)) + + if result.is_valid: + template_data = TemplateData(template_def) + self._add_template_scenarios(template_data) def _load_templates_files(self, conf):