template validate API controller and API handler

Change-Id: I1fd681e14eb544e7eddfe17c51c70485c05f041c
This commit is contained in:
liathartal 2016-06-05 08:37:23 +00:00
parent 9a7fbdb4d7
commit 81e232a1af
11 changed files with 115 additions and 28 deletions

View File

@ -3,5 +3,6 @@
"get resource": "role:admin", "get resource": "role:admin",
"list resources": "role:admin", "list resources": "role:admin",
"list alarms": "role:admin", "list alarms": "role:admin",
"get rca": "role:admin" "get rca": "role:admin",
"template validate": "role:admin"
} }

View File

@ -38,20 +38,20 @@ class AlarmsController(RootRestController):
enforce("list alarms", pecan.request.headers, enforce("list alarms", pecan.request.headers,
pecan.request.enforcer, {}) pecan.request.enforcer, {})
LOG.info(_LI('received list alarms with vitrage id %s') % LOG.info(_LI('returns list alarms with vitrage id %s') %
vitrage_id) vitrage_id)
try: try:
if pecan.request.cfg.api.use_mock_file: if pecan.request.cfg.api.use_mock_file:
return self.get_mock_data('alarms.sample.json') return self.get_mock_data('alarms.sample.json')
else: else:
return self.get_alarms(vitrage_id) return self._get_alarms(vitrage_id)
except Exception as e: except Exception as e:
LOG.exception('failed to get alarms %s', e) LOG.exception('failed to get alarms %s', e)
abort(404, str(e)) abort(404, str(e))
@staticmethod @staticmethod
def get_alarms(vitrage_id=None): def _get_alarms(vitrage_id=None):
alarms_json = pecan.request.client.call(pecan.request.context, alarms_json = pecan.request.client.call(pecan.request.context,
'get_alarms', 'get_alarms',
arg=vitrage_id) arg=vitrage_id)

View File

@ -13,6 +13,7 @@
from vitrage.api.controllers.v1 import alarms from vitrage.api.controllers.v1 import alarms
from vitrage.api.controllers.v1 import rca from vitrage.api.controllers.v1 import rca
from vitrage.api.controllers.v1 import resource from vitrage.api.controllers.v1 import resource
from vitrage.api.controllers.v1 import template
from vitrage.api.controllers.v1 import topology from vitrage.api.controllers.v1 import topology
@ -21,3 +22,4 @@ class V1Controller(object):
resources = resource.ResourcesController() resources = resource.ResourcesController()
alarms = alarms.AlarmsController() alarms = alarms.AlarmsController()
rca = rca.RCAController() rca = rca.RCAController()
template = template.TemplateController()

View File

@ -0,0 +1,58 @@
# Copyright 2016 - Nokia Corporation
#
# 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.
import json
import pecan
from oslo_log import log
from pecan.core import abort
from vitrage.api.controllers.rest import RootRestController
from vitrage.api.policy import enforce
from vitrage.i18n import _LI
LOG = log.getLogger(__name__)
class TemplateController(RootRestController):
@pecan.expose('json')
def post(self, **kwargs):
LOG.info(_LI('validate template. args: %s') % kwargs)
enforce("template validate",
pecan.request.headers,
pecan.request.enforcer,
{})
template_def = kwargs['template_def']
try:
return self._validate(template_def)
except Exception as e:
LOG.exception('failed to validate template(s) %s', e)
abort(404, str(e))
@staticmethod
def _validate(template_def):
result_json = pecan.request.client.call(pecan.request.context,
'validate_template',
template_def=template_def)
try:
return json.loads(result_json)
except Exception as e:
LOG.exception('failed to open file %s ', e)
abort(404, str(e))

View File

@ -1,4 +1,4 @@
# Copyright 2016 - Alcatel-Lucent # Copyright 2016 - Nokia Corporation
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain

View File

@ -23,6 +23,8 @@ from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE
from vitrage.datasources.nova.zone import NOVA_ZONE_DATASOURCE from vitrage.datasources.nova.zone import NOVA_ZONE_DATASOURCE
from vitrage.datasources import OPENSTACK_CLUSTER from vitrage.datasources import OPENSTACK_CLUSTER
from vitrage.evaluator.template_validation.template_syntax_validator import \
syntax_validation
from vitrage.graph import create_algorithm from vitrage.graph import create_algorithm
from vitrage.graph import Direction from vitrage.graph import Direction
@ -112,7 +114,7 @@ class EntityGraphApis(object):
root_id=root, root_id=root,
depth=depth) depth=depth)
return found_graph.output_graph() return found_graph.json_output_graph()
def get_rca(self, ctx, root): def get_rca(self, ctx, root):
LOG.debug("EntityGraphApis get_rca root:%s", str(root)) LOG.debug("EntityGraphApis get_rca root:%s", str(root))
@ -128,7 +130,7 @@ class EntityGraphApis(object):
direction=Direction.OUT) direction=Direction.OUT)
unified_graph = found_graph_in unified_graph = found_graph_in
unified_graph.union(found_graph_out) unified_graph.union(found_graph_out)
json_graph = unified_graph.output_graph( json_graph = unified_graph.json_output_graph(
inspected_index=self._find_rca_index(unified_graph, root)) inspected_index=self._find_rca_index(unified_graph, root))
return json_graph return json_graph
@ -168,3 +170,26 @@ class EntityGraphApis(object):
if vertex == root: if vertex == root:
return root_index return root_index
return 0 return 0
class TemplateApis(object):
def validate_template(self, ctx, template_def):
LOG.debug("EntityGraphApis validate_template template definition:"
"%s", str(template_def))
result = syntax_validation(template_def)
if not result.is_valid:
return self._extract_json_result('validation failed', result)
return self._extract_json_result('validation OK', result)
@staticmethod
def _extract_json_result(status, result):
return json.dumps({
'status': status,
'description': result.description,
'message': str(result.comment)
})

View File

@ -17,7 +17,8 @@ from oslo_log import log
import oslo_messaging import oslo_messaging
from oslo_service import service as os_service from oslo_service import service as os_service
from vitrage.entity_graph.api_handler.entity_graph_api import EntityGraphApis from vitrage.api_handler.entity_graph_api import EntityGraphApis
from vitrage.api_handler.entity_graph_api import TemplateApis
from vitrage import messaging from vitrage import messaging
from vitrage import rpc as vitrage_rpc from vitrage import rpc as vitrage_rpc
@ -43,7 +44,7 @@ class VitrageApiHandlerService(os_service.Service):
target = oslo_messaging.Target(topic=self.conf.rpc_topic, target = oslo_messaging.Target(topic=self.conf.rpc_topic,
server=rabbit_hosts) server=rabbit_hosts)
endpoints = [EntityGraphApis(self.entity_graph), ] endpoints = [EntityGraphApis(self.entity_graph), TemplateApis()]
server = vitrage_rpc.get_server(target, endpoints, transport) server = vitrage_rpc.get_server(target, endpoints, transport)

View File

@ -19,10 +19,10 @@ import sys
from oslo_service import service as os_service from oslo_service import service as os_service
from vitrage.api_handler import service as api_handler_svc
from vitrage.common.constants import EntityCategory from vitrage.common.constants import EntityCategory
from vitrage.datasources import launcher as datasource_launcher from vitrage.datasources import launcher as datasource_launcher
from vitrage.datasources import OPENSTACK_CLUSTER from vitrage.datasources import OPENSTACK_CLUSTER
from vitrage.entity_graph.api_handler import service as api_handler_svc
from vitrage.entity_graph.consistency import service as consistency_svc from vitrage.entity_graph.consistency import service as consistency_svc
from vitrage.entity_graph.initialization_status import InitializationStatus from vitrage.entity_graph.initialization_status import InitializationStatus
from vitrage.entity_graph.processor import entity_graph from vitrage.entity_graph.processor import entity_graph

View File

@ -18,49 +18,49 @@ from vitrage.evaluator.actions.base import action_types
error_msgs = { error_msgs = {
# General 1-19 # General 1-19
1: '"template_id" field contains incorrect string value.', 1: 'template_id field contains incorrect string value.',
2: 'Duplicate template_id definition.', 2: 'Duplicate template_id definition.',
3: '"template_id" does not appear in the definition block.', 3: 'template_id does not appear in the definition block.',
# definitions section 20-39 # definitions section 20-39
20: 'definitions section must contain "entities" field.', 20: 'definitions section must contain entities field.',
21: '"definitions" section is a mandatory section.', 21: 'definitions section is a mandatory section.',
# Entities syntax error messages 40-59 # Entities syntax error messages 40-59
41: 'Entity definition must contain "template_id" field.', 41: 'Entity definition must contain template_id field.',
42: 'Entity definition must contain "category" field.', 42: 'Entity definition must contain category field.',
43: 'At least one entity must be defined.', 43: 'At least one entity must be defined.',
45: 'Invalid entity category. Category must be from types: ' 45: 'Invalid entity category. Category must be from types: '
'%s' % entities_categories, '%s' % entities_categories,
46: 'Entity field is required.', 46: 'Entity field is required.',
# metadata section syntax error messages 60-79 # metadata section syntax error messages 60-79
60: 'metadata section must contain "id" field.', 60: 'metadata section must contain id field.',
62: '"metadata" is a mandatory section.', 62: 'metadata is a mandatory section.',
# scenarios section 80-99 # scenarios section 80-99
80: '"scenarios" is a mandatory section].', 80: 'scenarios is a mandatory section].',
81: 'At least one scenario must be defined.', 81: 'At least one scenario must be defined.',
82: 'scenario field is required.', 82: 'scenario field is required.',
83: 'Entity definition must contain "condition" field.', 83: 'Entity definition must contain condition field.',
84: 'Entity definition must contain "actions" field.', 84: 'Entity definition must contain actions field.',
85: 'Failed to convert condition.', 85: 'Failed to convert condition.',
# relationships syntax error messages 100-119 # relationships syntax error messages 100-119
100: 'Invalid relation type. Relation type must be from types: ' 100: 'Invalid relation type. Relation type must be from types: '
'%s' % edge_labels, '%s' % edge_labels,
101: 'Relationship field is required.', 101: 'Relationship field is required.',
102: 'Relationship definition must contain "source" field.', 102: 'Relationship definition must contain source field.',
103: 'Relationship definition must contain "target" field.', 103: 'Relationship definition must contain target field.',
104: 'Relationship definition must contain "template_id" field.', 104: 'Relationship definition must contain template_id field.',
# actions syntax error messages 120-139 # actions syntax error messages 120-139
120: 'Invalid action type. Action type must be from types: ' 120: 'Invalid action type. Action type must be from types: '
'%s' % action_types, '%s' % action_types,
121: 'At least one action must be defined.', 121: 'At least one action must be defined.',
122: 'Action field is required.', 122: 'Action field is required.',
123: 'Relationship definition must contain "action_type" field.', 123: 'Relationship definition must contain action_type field.',
124: 'Relationship definition must contain "action_target" field.', 124: 'Relationship definition must contain action_target field.',
125: 'raise_alarm action must contain alarm_name field in properties ' 125: 'raise_alarm action must contain alarm_name field in properties '
'block.', 'block.',
126: 'raise_alarm action must contain severity field in properties block.', 126: 'raise_alarm action must contain severity field in properties block.',

View File

@ -323,7 +323,7 @@ class Graph(object):
pass pass
@abc.abstractmethod @abc.abstractmethod
def output_graph(self, **kwargs): def json_output_graph(self, **kwargs):
pass pass
@abc.abstractmethod @abc.abstractmethod

View File

@ -260,7 +260,7 @@ class NXGraph(Graph):
nodes.append((node_id_to_test, node_data)) nodes.append((node_id_to_test, node_data))
return nodes, edges_filtered2 return nodes, edges_filtered2
def output_graph(self, **kwargs): def json_output_graph(self, **kwargs):
node_link_data = json_graph.node_link_data(self._g) node_link_data = json_graph.node_link_data(self._g)
node_link_data.update(kwargs) node_link_data.update(kwargs)