template validate API controller and API handler
Change-Id: I1fd681e14eb544e7eddfe17c51c70485c05f041c
This commit is contained in:
parent
9a7fbdb4d7
commit
81e232a1af
@ -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"
|
||||||
}
|
}
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
58
vitrage/api/controllers/v1/template.py
Normal file
58
vitrage/api/controllers/v1/template.py
Normal 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))
|
@ -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
|
@ -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)
|
||||||
|
})
|
@ -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)
|
||||||
|
|
@ -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
|
||||||
|
@ -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.',
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user