Removed Bundled intree vitrage-tempest-plugin from vitrage project
Depends-On: I5bafa207fdfdd07f3601e924764ee93c08512bf4 Change-Id: Iab7f60a8e8fb9443597cbe0067d9411d587002d3
This commit is contained in:
parent
8838ea134a
commit
027bc49a03
@ -28,6 +28,7 @@
|
||||
- openstack/python-vitrageclient
|
||||
- openstack/vitrage
|
||||
- openstack/vitrage-dashboard
|
||||
- openstack/vitrage-tempest-plugin
|
||||
irrelevant-files:
|
||||
- ^.*\.rst$
|
||||
- ^doc/.*$
|
||||
@ -46,6 +47,7 @@
|
||||
- openstack/python-vitrageclient
|
||||
- openstack/vitrage
|
||||
- openstack/vitrage-dashboard
|
||||
- openstack/vitrage-tempest-plugin
|
||||
irrelevant-files:
|
||||
- ^.*\.rst$
|
||||
- ^doc/.*$
|
||||
@ -64,6 +66,7 @@
|
||||
- openstack/python-vitrageclient
|
||||
- openstack/vitrage
|
||||
- openstack/vitrage-dashboard
|
||||
- openstack/vitrage-tempest-plugin
|
||||
irrelevant-files:
|
||||
- ^.*\.rst$
|
||||
- ^doc/.*$
|
||||
@ -82,6 +85,7 @@
|
||||
- openstack/python-vitrageclient
|
||||
- openstack/vitrage
|
||||
- openstack/vitrage-dashboard
|
||||
- openstack/vitrage-tempest-plugin
|
||||
irrelevant-files:
|
||||
- ^.*\.rst$
|
||||
- ^doc/.*$
|
||||
|
@ -28,22 +28,21 @@ if [ "$DEVSTACK_GATE_USE_PYTHON3" == "True" ]; then
|
||||
export PYTHON=python3
|
||||
fi
|
||||
|
||||
sudo cp $DEVSTACK_PATH/tempest/etc/logging.conf.sample $DEVSTACK_PATH/tempest/etc/logging.conf
|
||||
sudo cp -rf $DEVSTACK_PATH/tempest/etc/logging.conf.sample $DEVSTACK_PATH/tempest/etc/logging.conf
|
||||
|
||||
${PYTHON:-python} $DEVSTACK_PATH/vitrage/vitrage_tempest_tests/add_legacy_dir_templates.py
|
||||
${PYTHON:-python} $DEVSTACK_PATH/vitrage-tempest-plugin/vitrage_tempest_tests/add_legacy_dir_templates.py
|
||||
|
||||
# restart due to configuration files changes
|
||||
sudo systemctl restart devstack@vitrage-graph.service
|
||||
|
||||
# wait for 30 seconds
|
||||
# wait for 30 seconds (initialization might take time)
|
||||
sleep 30
|
||||
|
||||
|
||||
|
||||
cd $DEVSTACK_PATH/tempest/; sudo -E testr init
|
||||
cd $DEVSTACK_PATH/tempest/
|
||||
sudo -E testr init
|
||||
|
||||
echo "Listing existing Tempest tests"
|
||||
sudo -E testr list-tests vitrage_tempest_tests
|
||||
sudo -E testr list-tests vitrage_tempest_tests | grep -E "$TESTS" > /tmp/vitrage_tempest_tests.list
|
||||
sudo -E testr list-tests vitrage_tempest_tests | grep -E "$TESTS" | tee /tmp/vitrage_tempest_tests.list
|
||||
echo "Testing $1: $TESTS..."
|
||||
sudo -E testr run --subunit --load-list=/tmp/vitrage_tempest_tests.list | subunit-trace --fails
|
||||
|
@ -30,6 +30,7 @@
|
||||
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||
[[local|localrc]]
|
||||
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
|
||||
enable_plugin vitrage-tempest-plugin git://git.openstack.org/openstack/vitrage-tempest-plugin
|
||||
|
||||
# swift is not ready for python3 yet
|
||||
disable_service s-account
|
||||
@ -52,7 +53,9 @@
|
||||
export PROJECTS="openstack/mistral $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
|
||||
export ENABLED_SERVICES=tempest
|
||||
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
|
||||
|
||||
if [ "py27" == "py35" ] ; then
|
||||
export DEVSTACK_GATE_USE_PYTHON3=True
|
||||
|
@ -30,6 +30,7 @@
|
||||
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||
[[local|localrc]]
|
||||
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
|
||||
enable_plugin vitrage-tempest-plugin git://git.openstack.org/openstack/vitrage-tempest-plugin
|
||||
|
||||
# swift is not ready for python3 yet
|
||||
disable_service s-account
|
||||
@ -52,7 +53,9 @@
|
||||
export PROJECTS="openstack/mistral $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
|
||||
export ENABLED_SERVICES=tempest
|
||||
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
|
||||
|
||||
if [ "py35" == "py35" ] ; then
|
||||
export DEVSTACK_GATE_USE_PYTHON3=True
|
||||
|
@ -30,6 +30,7 @@
|
||||
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||
[[local|localrc]]
|
||||
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
|
||||
enable_plugin vitrage-tempest-plugin git://git.openstack.org/openstack/vitrage-tempest-plugin
|
||||
|
||||
# swift is not ready for python3 yet
|
||||
disable_service s-account
|
||||
@ -52,7 +53,9 @@
|
||||
export PROJECTS="openstack/mistral $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
|
||||
export ENABLED_SERVICES=tempest
|
||||
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
|
||||
|
||||
if [ "py27" == "py35" ] ; then
|
||||
export DEVSTACK_GATE_USE_PYTHON3=True
|
||||
|
@ -30,6 +30,7 @@
|
||||
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||
[[local|localrc]]
|
||||
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
|
||||
enable_plugin vitrage-tempest-plugin git://git.openstack.org/openstack/vitrage-tempest-plugin
|
||||
|
||||
# swift is not ready for python3 yet
|
||||
disable_service s-account
|
||||
@ -52,7 +53,9 @@
|
||||
export PROJECTS="openstack/mistral $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
||||
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
|
||||
export ENABLED_SERVICES=tempest
|
||||
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
|
||||
|
||||
if [ "py35" == "py35" ] ; then
|
||||
export DEVSTACK_GATE_USE_PYTHON3=True
|
||||
|
@ -44,9 +44,6 @@ oslo.config.opts =
|
||||
oslo.policy.policies =
|
||||
vitrage = vitrage.common.policies:list_rules
|
||||
|
||||
tempest.test_plugins =
|
||||
vitrage_tests = vitrage_tempest_tests.plugin:VitrageTempestPlugin
|
||||
|
||||
vitrage.storage =
|
||||
mysql = vitrage.storage.impl_sqlalchemy:Connection
|
||||
mysql+pymysql = vitrage.storage.impl_sqlalchemy:Connection
|
||||
@ -56,7 +53,6 @@ vitrage.storage =
|
||||
[files]
|
||||
packages =
|
||||
vitrage
|
||||
vitrage_tempest_tests
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
@ -25,7 +25,6 @@ oslo.i18n>=3.15.3 # Apache-2.0
|
||||
oslo.policy>=1.30.0 # Apache-2.0
|
||||
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
||||
requests-mock>=1.1.0 # Apache-2.0
|
||||
tempest>=17.1.0 # Apache-2.0
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
testscenarios>=0.4 # Apache-2.0/BSD
|
||||
testtools>=2.2.0 # MIT
|
||||
|
@ -11,6 +11,7 @@
|
||||
# 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 oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||
from vitrage.common.constants import EdgeLabel
|
||||
@ -25,6 +26,8 @@ from vitrage.datasources import transformer_base as tbase
|
||||
from vitrage.datasources.transformer_base import extract_field_value
|
||||
import vitrage.graph.utils as graph_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class InstanceTransformer(ResourceTransformerBase):
|
||||
|
||||
@ -99,12 +102,16 @@ class InstanceTransformer(ResourceTransformerBase):
|
||||
return [host_neighbor]
|
||||
|
||||
def _create_entity_key(self, event):
|
||||
LOG.debug('Creating key for instance event: %s', str(event))
|
||||
|
||||
instance_id = 'instance_id' if tbase.is_update_event(event) else 'id'
|
||||
key_fields = self._key_values(NOVA_INSTANCE_DATASOURCE,
|
||||
extract_field_value(event,
|
||||
instance_id))
|
||||
return tbase.build_key(key_fields)
|
||||
key = tbase.build_key(key_fields)
|
||||
LOG.debug('Created key: %s', key)
|
||||
|
||||
return key
|
||||
|
||||
def get_vitrage_type(self):
|
||||
return NOVA_INSTANCE_DATASOURCE
|
||||
|
@ -62,6 +62,9 @@ def mark_deleted(g, item):
|
||||
def delete_placeholder_vertex(g, vertex):
|
||||
"""Checks if it is a placeholder vertex, and if so deletes it """
|
||||
|
||||
LOG.debug('Asked to delete a placeholder vertex: %s with %d neighbors',
|
||||
str(vertex), len(g.get_edges(vertex.vertex_id)))
|
||||
|
||||
if not vertex[VProps.VITRAGE_IS_PLACEHOLDER]:
|
||||
return
|
||||
if not any(True for neighbor_edge in g.get_edges(vertex.vertex_id)
|
||||
@ -80,6 +83,10 @@ def find_neighbor_types(neighbors):
|
||||
|
||||
|
||||
def get_vertex_types(vertex):
|
||||
props = vertex.items()
|
||||
if VProps.VITRAGE_CATEGORY not in props:
|
||||
LOG.warning('no vitrage_category in vertex: %s', str(vertex))
|
||||
|
||||
vitrage_category = vertex[VProps.VITRAGE_CATEGORY]
|
||||
vitrage_type = vertex[VProps.VITRAGE_TYPE]
|
||||
return vitrage_category, vitrage_type
|
||||
|
@ -1,6 +0,0 @@
|
||||
==============================
|
||||
Tempest Integration of Vitrage
|
||||
==============================
|
||||
|
||||
This directory contains Tempest tests to cover the Vitrage project.
|
||||
|
@ -1,15 +0,0 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,39 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import sys
|
||||
|
||||
from vitrage import service
|
||||
from vitrage import storage
|
||||
from vitrage.tests.functional.test_configuration import TestConfiguration
|
||||
from vitrage_tempest_tests.tests.common import general_utils
|
||||
|
||||
files = ['corrupted_template.yaml', 'e2e_test_basic_actions.yaml',
|
||||
'e2e_test_overlapping_actions.yaml', 'v1_execute_mistral.yaml',
|
||||
'v2_execute_mistral.yaml', 'host_aodh_alarm_for_rca.yaml',
|
||||
'nagios_alarm_for_alarms.yaml'
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
resources_path = general_utils.tempest_resources_dir() + '/templates/api/'
|
||||
conf = service.prepare_service()
|
||||
db = storage.get_connection_from_config(conf)
|
||||
TestConfiguration._db = db
|
||||
for f in files:
|
||||
full_path = resources_path + f
|
||||
TestConfiguration.add_templates(full_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,39 +0,0 @@
|
||||
# Copyright 2015
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 oslo_config import cfg
|
||||
|
||||
service_option = cfg.BoolOpt("vitrage",
|
||||
default=True,
|
||||
help="Whether or not vitrage is expected to be "
|
||||
"available")
|
||||
|
||||
rca_service_group = cfg.OptGroup(name="root_cause_analysis_service",
|
||||
title="Root Cause Analysis Service Options")
|
||||
|
||||
RcaServiceGroup = [
|
||||
# RCA Service tempest configuration
|
||||
cfg.StrOpt("region",
|
||||
default="",
|
||||
help="The application_catalog region name to use. If empty, "
|
||||
"the value of identity.region is used instead. "
|
||||
"If no such region is found in the service catalog, "
|
||||
"the first found one is used."),
|
||||
|
||||
cfg.StrOpt("identity_version",
|
||||
default="v2",
|
||||
help="Default identity version for "
|
||||
"REST client authentication.")
|
||||
]
|
@ -1,43 +0,0 @@
|
||||
# Copyright 2015
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 os
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
from tempest.test_discover import plugins
|
||||
|
||||
from vitrage_tempest_tests import config as config_rca_service
|
||||
|
||||
|
||||
class VitrageTempestPlugin(plugins.TempestPlugin):
|
||||
def load_tests(self):
|
||||
base_path = os.path.split(os.path.dirname(
|
||||
os.path.abspath(__file__)))[0]
|
||||
test_dir = "vitrage_tempest_tests/tests"
|
||||
full_test_dir = os.path.join(base_path, test_dir)
|
||||
return full_test_dir, base_path
|
||||
|
||||
def register_opts(self, conf):
|
||||
conf.register_opt(config_rca_service.service_option,
|
||||
group='service_available')
|
||||
conf.register_group(config_rca_service.rca_service_group)
|
||||
conf.register_opts(config_rca_service.RcaServiceGroup,
|
||||
group='root_cause_analysis_service')
|
||||
|
||||
def get_opt_lists(self):
|
||||
return [(config_rca_service.rca_service_group.name,
|
||||
config_rca_service.RcaServiceGroup),
|
||||
('service_available', [config_rca_service.service_option])]
|
@ -1,15 +0,0 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,15 +0,0 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,15 +0,0 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,42 +0,0 @@
|
||||
# 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 vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
||||
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
|
||||
|
||||
TEMPLATES_RESOURCES_PATH = 'resources/templates/'
|
||||
TEMPLATES_SOURCES_PATH = '/etc/vitrage/templates/'
|
||||
|
||||
|
||||
class BaseAlarmsTest(BaseVitrageTempest):
|
||||
"""Topology test class for Vitrage API tests."""
|
||||
|
||||
def setUp(self):
|
||||
super(BaseAlarmsTest, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(BaseAlarmsTest, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseAlarmsTest, cls).setUpClass()
|
||||
|
||||
def _check_num_alarms(self, num_alarms=0, state=''):
|
||||
if len(TempestClients.aodh().alarm.list()) != num_alarms:
|
||||
return False
|
||||
|
||||
return all(alarm[AodhProps.STATE].upper() == state.upper()
|
||||
for alarm in TempestClients.aodh().alarm.list())
|
@ -1,96 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import json
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.datasources.aodh import AODH_DATASOURCE
|
||||
from vitrage_tempest_tests.tests.api.alarms.base import BaseAlarmsTest
|
||||
from vitrage_tempest_tests.tests.common import aodh_utils
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
import unittest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestAlarms(BaseAlarmsTest):
|
||||
"""Alarms test class for Vitrage API tests."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestAlarms, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestAlarms, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestAlarms, cls).setUpClass()
|
||||
|
||||
@unittest.skip("CLI tests are ineffective and not maintained")
|
||||
@utils.tempest_logger
|
||||
def test_compare_cli_vs_api_alarms(self):
|
||||
"""Wrapper that returns a test graph."""
|
||||
try:
|
||||
instances = nova_utils.create_instances(num_instances=1,
|
||||
set_public_network=True)
|
||||
self.assertNotEqual(len(instances), 0,
|
||||
'The instances list is empty')
|
||||
aodh_utils.create_aodh_alarm(
|
||||
resource_id=instances[0].id,
|
||||
name='tempest_aodh_test')
|
||||
|
||||
api_alarms = TempestClients.vitrage().alarm.list(vitrage_id='all',
|
||||
all_tenants=True)
|
||||
cli_alarms = utils.run_vitrage_command(
|
||||
'vitrage alarm list', self.conf)
|
||||
self._compare_alarms_lists(
|
||||
api_alarms, cli_alarms, AODH_DATASOURCE,
|
||||
instances[0].id)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
aodh_utils.delete_all_aodh_alarms()
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
def _compare_alarms_lists(self, api_alarms, cli_alarms,
|
||||
resource_type, resource_id):
|
||||
"""Validate alarm existence """
|
||||
self.assertNotEqual(len(api_alarms), 0,
|
||||
'The alarms list taken from api is empty')
|
||||
self.assertIsNotNone(cli_alarms,
|
||||
'The alarms list taken from cli is empty')
|
||||
|
||||
LOG.info("The alarms list taken from cli is : " +
|
||||
str(cli_alarms))
|
||||
LOG.info("The alarms list taken by api is : " +
|
||||
str(json.dumps(api_alarms)))
|
||||
|
||||
cli_items = cli_alarms.splitlines()
|
||||
|
||||
api_by_type = g_utils.all_matches(
|
||||
api_alarms, vitrage_type=resource_type)
|
||||
cli_by_type = cli_alarms.count(' ' + resource_type + ' ')
|
||||
|
||||
api_by_id = g_utils.all_matches(api_alarms, resource_id=resource_id)
|
||||
cli_by_id = cli_alarms.count(resource_id)
|
||||
|
||||
self.assertEqual(len(cli_items), len(api_alarms) + 4)
|
||||
self.assertEqual(cli_by_type, len(api_by_type))
|
||||
self.assertEqual(cli_by_id, len(api_by_id))
|
@ -1,15 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,54 +0,0 @@
|
||||
# Copyright 2017 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 datetime import datetime
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage_tempest_tests.tests.e2e.test_basic_actions import TestActionsBase
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseTestEvents(TestActionsBase):
|
||||
"""Test class for Vitrage event API"""
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseTestEvents, cls).setUpClass()
|
||||
|
||||
def _check_alarms(self):
|
||||
api_alarms = self.vitrage_client.alarm.list(vitrage_id='all',
|
||||
all_tenants=True)
|
||||
if api_alarms:
|
||||
return True, api_alarms
|
||||
return False, api_alarms
|
||||
|
||||
def _post_event(self, details):
|
||||
event_time = datetime.now()
|
||||
event_time_iso = event_time.isoformat()
|
||||
event_type = 'compute.host.down'
|
||||
self.vitrage_client.event.post(event_time_iso, event_type, details)
|
||||
|
||||
@staticmethod
|
||||
def _create_doctor_event_details(hostname, status):
|
||||
return {
|
||||
'hostname': hostname,
|
||||
'source': 'sample_monitor',
|
||||
'cause': 'another alarm',
|
||||
'severity': 'critical',
|
||||
'status': status,
|
||||
'monitor_id': 'sample monitor',
|
||||
'monitor_event_id': '456',
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
# Copyright 2017 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.
|
||||
|
||||
import six
|
||||
|
||||
from datetime import datetime
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import EventProperties as EventProps
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage_tempest_tests.tests.api.event.base import BaseTestEvents
|
||||
from vitrage_tempest_tests.tests.common.vitrage_utils import DOWN
|
||||
from vitrage_tempest_tests.tests.utils import wait_for_answer
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestEvents(BaseTestEvents):
|
||||
"""Test class for Vitrage event API"""
|
||||
|
||||
def test_send_doctor_event_without_resource_id(self):
|
||||
"""Sending an event in Doctor format should result in an alarm"""
|
||||
self._test_send_doctor_event(
|
||||
self._create_doctor_event_details('host123', DOWN))
|
||||
|
||||
def test_send_doctor_event_without_resource_id_v2(self):
|
||||
"""Sending an event in Doctor format should result in an alarm"""
|
||||
self._test_send_doctor_event(
|
||||
self._create_doctor_event_details('host457', DOWN))
|
||||
|
||||
def _test_send_doctor_event(self, details):
|
||||
try:
|
||||
# post an event to the message bus
|
||||
event_time = datetime.now()
|
||||
event_time_iso = event_time.isoformat()
|
||||
event_type = 'compute.host.down'
|
||||
self.vitrage_client.event.post(event_time_iso, event_type, details)
|
||||
api_alarms = wait_for_answer(2, 0.5, self._check_alarms)
|
||||
|
||||
# expect to get a 'host down alarm', generated by Doctor datasource
|
||||
self.assertIsNotNone(api_alarms, 'Expected host down alarm')
|
||||
self.assertEqual(1, len(api_alarms), 'Expected host down alarm')
|
||||
|
||||
alarm = api_alarms[0]
|
||||
event_time_tz = six.u(event_time.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
||||
self._check_alarm(alarm, event_time_tz, event_type, details)
|
||||
|
||||
event_time = datetime.now()
|
||||
event_time_iso = event_time.isoformat()
|
||||
details['status'] = 'up'
|
||||
self.vitrage_client.event.post(event_time_iso, event_type, details)
|
||||
|
||||
api_alarms = wait_for_answer(2, 0.5, self._check_alarms)
|
||||
self.assertIsNotNone(api_alarms, 'Expected host down alarm')
|
||||
self.assertEqual(0, len(api_alarms), 'Expected host down alarm')
|
||||
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
raise
|
||||
finally:
|
||||
LOG.warning('done')
|
||||
|
||||
def _check_alarm(self, alarm, event_time, event_type, details):
|
||||
self.assertEqual(EntityCategory.ALARM, alarm[VProps.VITRAGE_CATEGORY])
|
||||
self.assertEqual(event_type, alarm[VProps.NAME])
|
||||
self.assertEqual(event_time, alarm[EventProps.TIME])
|
||||
self.assertEqual(details['status'], alarm['status'])
|
||||
self.assertFalse(alarm[VProps.VITRAGE_IS_DELETED])
|
||||
self.assertFalse(alarm[VProps.VITRAGE_IS_PLACEHOLDER])
|
@ -1,15 +0,0 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,216 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import json
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import EdgeLabel
|
||||
from vitrage.common.constants import EdgeProperties
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources.aodh import AODH_DATASOURCE
|
||||
from vitrage.datasources import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
||||
from vitrage.entity_graph.mappings.operational_alarm_severity \
|
||||
import OperationalAlarmSeverity
|
||||
from vitrage.entity_graph.mappings.operational_resource_state \
|
||||
import OperationalResourceState
|
||||
from vitrage.evaluator.actions.evaluator_event_transformer \
|
||||
import VITRAGE_DATASOURCE
|
||||
from vitrage_tempest_tests.tests.api.alarms.base import BaseAlarmsTest
|
||||
from vitrage_tempest_tests.tests.common import aodh_utils
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.common import vitrage_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
RCA_ALARM_NAME = 'rca_test_host_alarm'
|
||||
VITRAGE_ALARM_NAME = 'instance_deduce'
|
||||
|
||||
|
||||
class BaseRcaTest(BaseAlarmsTest):
|
||||
|
||||
def setUp(self):
|
||||
super(BaseRcaTest, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(BaseRcaTest, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseRcaTest, cls).setUpClass()
|
||||
|
||||
def _clean_all(self):
|
||||
nova_utils.delete_all_instances()
|
||||
aodh_utils.delete_all_aodh_alarms()
|
||||
|
||||
def _create_alarm(self, resource_id, alarm_name, unic=False):
|
||||
aodh_utils.create_aodh_alarm(resource_id=resource_id,
|
||||
name=alarm_name,
|
||||
unic=unic)
|
||||
|
||||
list_alarms = self.vitrage_client.alarm.list(vitrage_id='all',
|
||||
all_tenants=True)
|
||||
expected_alarm = g_utils.all_matches(
|
||||
list_alarms,
|
||||
resource_id=resource_id,
|
||||
vitrage_type=AODH_DATASOURCE)
|
||||
if not expected_alarm:
|
||||
return None
|
||||
return expected_alarm[0]
|
||||
|
||||
def _compare_rca(self, api_rca, cli_rca):
|
||||
self.assertNotEqual(len(api_rca), 0, 'The rca taken from api is empty')
|
||||
self.assertIsNotNone(cli_rca, 'The rca taken from cli is empty')
|
||||
|
||||
LOG.info("The rca taken from cli is : " + str(cli_rca))
|
||||
LOG.info("The rca taken by api is : " + str(json.dumps(api_rca)))
|
||||
|
||||
parsed_rca = json.loads(cli_rca)
|
||||
sorted_cli_graph = self._clean_timestamps(sorted(parsed_rca.items()))
|
||||
sorted_api_graph = self._clean_timestamps(sorted(api_rca.items()))
|
||||
self.assertEqual(sorted_cli_graph, sorted_api_graph)
|
||||
|
||||
def _validate_rca(self, rca):
|
||||
self.assertNotEqual(len(rca), 0, 'The rca is empty')
|
||||
LOG.info("The rca alarms list is : " + str(json.dumps(rca)))
|
||||
|
||||
resource_alarm = g_utils.all_matches(
|
||||
rca,
|
||||
vitrage_type=AODH_DATASOURCE,
|
||||
name=RCA_ALARM_NAME)
|
||||
|
||||
deduce_alarms = g_utils.all_matches(
|
||||
rca,
|
||||
vitrage_type=VITRAGE_DATASOURCE,
|
||||
name=VITRAGE_ALARM_NAME,
|
||||
severity=OperationalAlarmSeverity.WARNING)
|
||||
|
||||
self.assertEqual(3, len(rca))
|
||||
self.assertEqual(1, len(resource_alarm))
|
||||
self.assertEqual(2, len(deduce_alarms))
|
||||
|
||||
def _validate_deduce_alarms(self, alarms, instances):
|
||||
"""Validate alarm existence """
|
||||
self.assertNotEqual(len(alarms), 0, 'The alarms list is empty')
|
||||
LOG.info("The alarms list is : " + str(json.dumps(alarms)))
|
||||
|
||||
# Find the vitrage_id of the deduced alarms using their original id.
|
||||
vitrage_resources = TempestClients.vitrage().resource.list(
|
||||
all_tenants=False)
|
||||
vitrage_instance_0_id = g_utils.first_match(vitrage_resources,
|
||||
id=instances[0].id)
|
||||
|
||||
vitrage_instance_1_id = g_utils.first_match(vitrage_resources,
|
||||
id=instances[1].id)
|
||||
|
||||
# Find the deduced alarms based on their properties
|
||||
deduce_alarms_1 = g_utils.all_matches(
|
||||
alarms,
|
||||
vitrage_type=VITRAGE_DATASOURCE,
|
||||
name=VITRAGE_ALARM_NAME,
|
||||
vitrage_resource_type=NOVA_INSTANCE_DATASOURCE,
|
||||
vitrage_resource_id=vitrage_instance_0_id[VProps.VITRAGE_ID])
|
||||
|
||||
deduce_alarms_2 = g_utils.all_matches(
|
||||
alarms,
|
||||
vitrage_type=VITRAGE_DATASOURCE,
|
||||
name=VITRAGE_ALARM_NAME,
|
||||
vitrage_resource_type=NOVA_INSTANCE_DATASOURCE,
|
||||
vitrage_resource_id=vitrage_instance_1_id[VProps.VITRAGE_ID])
|
||||
|
||||
self.assertEqual(3, len(alarms), "Expected 3 alarms - 1 on host and "
|
||||
"2 deduced")
|
||||
self.assertEqual(1, len(deduce_alarms_1), "Deduced alarm not found")
|
||||
self.assertEqual(1, len(deduce_alarms_2), "Deduced alarm not found")
|
||||
|
||||
def _validate_relationship(self, links, alarms):
|
||||
self.assertNotEqual(len(links), 0, 'The links list is empty')
|
||||
self.assertNotEqual(len(alarms), 0, 'The alarms list is empty')
|
||||
|
||||
flag = True
|
||||
for item in links:
|
||||
source_alarm_name = alarms[item['source']].get(VProps.NAME)
|
||||
target_alarm_name = alarms[item['target']].get(VProps.NAME)
|
||||
if item.get('key') != EdgeLabel.CAUSES \
|
||||
or item.get(EdgeProperties.RELATIONSHIP_TYPE) != EdgeLabel.CAUSES \
|
||||
or source_alarm_name != RCA_ALARM_NAME \
|
||||
or target_alarm_name != VITRAGE_ALARM_NAME:
|
||||
flag = False
|
||||
|
||||
self.assertEqual(3, len(alarms))
|
||||
self.assertTrue(flag)
|
||||
|
||||
def _validate_set_state(self, topology, instances):
|
||||
self.assertNotEqual(len(topology), 0, 'The topology graph is empty')
|
||||
host = g_utils.all_matches(
|
||||
topology,
|
||||
vitrage_type=NOVA_HOST_DATASOURCE,
|
||||
id=self._get_hostname(),
|
||||
vitrage_state=OperationalResourceState.ERROR,
|
||||
vitrage_aggregated_state=OperationalResourceState.ERROR)
|
||||
|
||||
vm1 = g_utils.all_matches(
|
||||
topology,
|
||||
vitrage_type=NOVA_INSTANCE_DATASOURCE,
|
||||
id=instances[0].id,
|
||||
vitrage_state=OperationalResourceState.SUBOPTIMAL,
|
||||
vitrage_aggregated_state=OperationalResourceState.SUBOPTIMAL)
|
||||
|
||||
vm2 = g_utils.all_matches(
|
||||
topology,
|
||||
vitrage_type=NOVA_INSTANCE_DATASOURCE,
|
||||
id=instances[1].id,
|
||||
vitrage_state=OperationalResourceState.SUBOPTIMAL,
|
||||
vitrage_aggregated_state=OperationalResourceState.SUBOPTIMAL)
|
||||
|
||||
self.assertEqual(1, len(host))
|
||||
self.assertEqual(1, len(vm1))
|
||||
self.assertEqual(1, len(vm2))
|
||||
|
||||
def _validate_notifier(self, alarms, vitrage_alarms):
|
||||
self.assertNotEqual(len(alarms), 0, 'The aodh alarms list is empty')
|
||||
self.assertNotEqual(len(vitrage_alarms), 0,
|
||||
'The vitrage alarms list is empty')
|
||||
|
||||
validation = 0
|
||||
for itemC in alarms:
|
||||
vitrage_id = filter(
|
||||
lambda item: item['field'] == VProps.VITRAGE_ID,
|
||||
itemC.event_rule['query'])
|
||||
for itemV in vitrage_alarms:
|
||||
if not vitrage_id:
|
||||
if itemC.name == itemV[VProps.NAME]:
|
||||
validation += 1
|
||||
break
|
||||
elif vitrage_id[0]['value'] == itemV[VProps.VITRAGE_ID]:
|
||||
validation += 1
|
||||
break
|
||||
|
||||
self.assertEqual(validation, len(vitrage_alarms))
|
||||
self.assertEqual(3, len(alarms))
|
||||
|
||||
def _get_hostname(self):
|
||||
host = vitrage_utils.get_first_host()
|
||||
return host.get(VProps.ID)
|
||||
|
||||
@staticmethod
|
||||
def _clean_timestamps(alist):
|
||||
try:
|
||||
del alist[5][1][0][VProps.VITRAGE_SAMPLE_TIMESTAMP]
|
||||
del alist[5][1][0][VProps.UPDATE_TIMESTAMP]
|
||||
except Exception:
|
||||
pass
|
||||
return alist
|
@ -1,177 +0,0 @@
|
||||
# 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 oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage_tempest_tests.tests.api.rca.base import BaseRcaTest
|
||||
from vitrage_tempest_tests.tests.api.rca.base import RCA_ALARM_NAME
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
import unittest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestRca(BaseRcaTest):
|
||||
"""RCA test class for Vitrage API tests."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestRca, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestRca, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestRca, cls).setUpClass()
|
||||
|
||||
@unittest.skip("CLI tests are ineffective and not maintained")
|
||||
@utils.tempest_logger
|
||||
def test_compare_cli_and_api(self):
|
||||
"""compare_cli_and_api test
|
||||
|
||||
There test validate correctness of rca of created
|
||||
aodh event alarms, and equals them with cli rca
|
||||
"""
|
||||
try:
|
||||
instances = nova_utils.create_instances(num_instances=1,
|
||||
set_public_network=True)
|
||||
self.assertNotEqual(len(instances), 0, 'Failed to create instance')
|
||||
|
||||
instance_alarm = self._create_alarm(
|
||||
resource_id=instances[0].id,
|
||||
alarm_name='instance_rca_alarm', unic=True)
|
||||
|
||||
vitrage_id = instance_alarm.get(VProps.VITRAGE_ID)
|
||||
api_rca = self.vitrage_client.rca.get(alarm_id=vitrage_id)
|
||||
cli_rca = utils.run_vitrage_command(
|
||||
'vitrage rca show ' + vitrage_id, self.conf)
|
||||
|
||||
self._compare_rca(api_rca, cli_rca)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._clean_all()
|
||||
|
||||
@unittest.skip("skipping test - test not working")
|
||||
@utils.tempest_logger
|
||||
# TODO(nivo): check why creation of alarm doesnt return the alarm
|
||||
def test_validate_rca(self):
|
||||
"""validate_rca test
|
||||
|
||||
There tests validates correctness of rca of created aodh
|
||||
event alarm and correctness of relationship between host alarm
|
||||
to instance alarms (created by special template file),
|
||||
source alarm - aodh alarm on host
|
||||
target alarms - 2 instance alarms (caused 2 created instance)
|
||||
"""
|
||||
try:
|
||||
nova_utils.create_instances(num_instances=2,
|
||||
set_public_network=True)
|
||||
host_alarm = self._create_alarm(
|
||||
resource_id=self._get_hostname(),
|
||||
alarm_name=RCA_ALARM_NAME)
|
||||
api_rca = self.vitrage_client.rca.get(
|
||||
alarm_id=host_alarm.get(VProps.VITRAGE_ID), all_tenants=True)
|
||||
|
||||
self._validate_rca(rca=api_rca['nodes'])
|
||||
self._validate_relationship(links=api_rca['links'],
|
||||
alarms=api_rca['nodes'])
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._clean_all()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_validate_deduce_alarms(self):
|
||||
"""validate_deduce_alarms test
|
||||
|
||||
There tests validates correctness of deduce alarms
|
||||
(created by special template file), and equals there
|
||||
resource_id with created instances id
|
||||
"""
|
||||
try:
|
||||
instances = nova_utils.create_instances(num_instances=2,
|
||||
set_public_network=True)
|
||||
self._create_alarm(
|
||||
resource_id=self._get_hostname(),
|
||||
alarm_name=RCA_ALARM_NAME)
|
||||
api_alarms = self.vitrage_client.alarm.list(vitrage_id='all',
|
||||
all_tenants=True)
|
||||
|
||||
self._validate_deduce_alarms(alarms=api_alarms,
|
||||
instances=instances)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._clean_all()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_validate_set_state(self):
|
||||
"""validate_set_state test
|
||||
|
||||
There tests validates correctness of topology resource
|
||||
state, after alarms creation (by special template file),
|
||||
source state - ERROR
|
||||
target state - SUBOPTIMAL (caused 2 created instance)
|
||||
"""
|
||||
try:
|
||||
instances = nova_utils.create_instances(num_instances=2,
|
||||
set_public_network=True)
|
||||
self._create_alarm(
|
||||
resource_id=self._get_hostname(),
|
||||
alarm_name=RCA_ALARM_NAME)
|
||||
topology = self.vitrage_client.topology.get(all_tenants=True)
|
||||
|
||||
self._validate_set_state(topology=topology['nodes'],
|
||||
instances=instances)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._clean_all()
|
||||
|
||||
@unittest.skip("aodh notifier is not supported")
|
||||
@utils.tempest_logger
|
||||
def test_validate_notifier(self):
|
||||
"""validate_notifier test
|
||||
|
||||
There tests validates work of aodh alarm notifier -
|
||||
all created vitrage alarms appears in ceilometer
|
||||
alarms-list.
|
||||
IMPORTANT: enable notifiers=aodh in vitrage.conf file
|
||||
"""
|
||||
try:
|
||||
nova_utils.create_instances(num_instances=2,
|
||||
set_public_network=True)
|
||||
self._create_alarm(
|
||||
resource_id=self._get_hostname(),
|
||||
alarm_name=RCA_ALARM_NAME)
|
||||
vitrage_alarms = TempestClients.vitrage().alarm.list(
|
||||
vitrage_id='all', all_tenants=True)
|
||||
aodh_alarms = TempestClients.aodh().alarm.list()
|
||||
|
||||
self._validate_notifier(alarms=aodh_alarms,
|
||||
vitrage_alarms=vitrage_alarms)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._clean_all()
|
@ -1,225 +0,0 @@
|
||||
# Copyright 2017 ZTE, 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.
|
||||
|
||||
import json
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
import unittest
|
||||
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources import CINDER_VOLUME_DATASOURCE
|
||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
||||
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
from vitrageclient.exceptions import ClientException
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestResource(BaseVitrageTempest):
|
||||
"""Test class for Vitrage resource API tests."""
|
||||
|
||||
properties = (VProps.VITRAGE_ID,
|
||||
VProps.VITRAGE_TYPE,
|
||||
VProps.ID,
|
||||
VProps.STATE,
|
||||
VProps.VITRAGE_AGGREGATED_STATE)
|
||||
|
||||
def setUp(self):
|
||||
super(TestResource, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestResource, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestResource, cls).setUpClass()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_compare_cli_vs_api_resource_list(self):
|
||||
"""resource list """
|
||||
try:
|
||||
instances = nova_utils.create_instances(num_instances=1,
|
||||
set_public_network=True)
|
||||
self.assertNotEqual(len(instances), 0,
|
||||
'The instances list is empty')
|
||||
api_resources = self.vitrage_client.resource.list(
|
||||
all_tenants=True)
|
||||
|
||||
LOG.info("api_resources = %s", api_resources)
|
||||
|
||||
cli_resources = utils.run_vitrage_command(
|
||||
'vitrage resource list --all -f json', self.conf)
|
||||
|
||||
self._compare_resources(api_resources, cli_resources)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_default_resource_list(self):
|
||||
"""resource list with default query
|
||||
|
||||
get the resources: network, instance, port
|
||||
"""
|
||||
try:
|
||||
instances = nova_utils.create_instances(num_instances=1,
|
||||
set_public_network=True)
|
||||
self.assertNotEqual(len(instances), 0,
|
||||
'The instances list is empty')
|
||||
resources = self.vitrage_client.resource.list(all_tenants=False)
|
||||
self.assertEqual(3, len(resources))
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_resource_list_with_all_tenants(self):
|
||||
"""resource list with all tenants
|
||||
|
||||
get the resources:
|
||||
|
||||
"""
|
||||
try:
|
||||
resources_before = self.vitrage_client.resource.list(
|
||||
all_tenants=True)
|
||||
instances = nova_utils.create_instances(num_instances=1,
|
||||
set_public_network=True)
|
||||
self.assertNotEqual(len(instances), 0,
|
||||
'The instances list is empty')
|
||||
resources = self.vitrage_client.resource.list(all_tenants=True)
|
||||
|
||||
self.assertEqual(len(resources_before) + 2, len(resources))
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_resource_list_with_existing_type(self):
|
||||
"""resource list with existing type
|
||||
|
||||
get the resource: one instance
|
||||
"""
|
||||
try:
|
||||
instances = nova_utils.create_instances(num_instances=1,
|
||||
set_public_network=True)
|
||||
self.assertNotEqual(len(instances), 0,
|
||||
'The instances list is empty')
|
||||
resources = self.vitrage_client.resource.list(
|
||||
resource_type=NOVA_INSTANCE_DATASOURCE,
|
||||
all_tenants=True)
|
||||
self.assertEqual(1, len(resources))
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_resource_list_with_no_existing_type(self):
|
||||
"""resource list with no existing type"""
|
||||
try:
|
||||
instances = nova_utils.create_instances(num_instances=1,
|
||||
set_public_network=True)
|
||||
self.assertNotEqual(len(instances), 0,
|
||||
'The instances list is empty')
|
||||
resources = self.vitrage_client.resource.list(
|
||||
resource_type=CINDER_VOLUME_DATASOURCE,
|
||||
all_tenants=True)
|
||||
self.assertEqual(0, len(resources))
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
@unittest.skip("CLI tests are ineffective and not maintained")
|
||||
def test_compare_resource_show(self):
|
||||
"""resource_show test"""
|
||||
resource_list = self.vitrage_client.resource.list(all_tenants=False)
|
||||
self.assertNotEqual(len(resource_list), 0)
|
||||
for resource in resource_list:
|
||||
api_resource_show = \
|
||||
self.vitrage_client.resource.get(resource[VProps.VITRAGE_ID])
|
||||
cli_resource_show = utils.run_vitrage_command(
|
||||
'vitrage resource show ' + resource[VProps.VITRAGE_ID],
|
||||
self.conf)
|
||||
|
||||
self._compare_resource_show(
|
||||
api_resource_show, cli_resource_show)
|
||||
|
||||
def test_resource_show_with_no_existing_resource(self):
|
||||
"""resource_show test no existing resource"""
|
||||
try:
|
||||
|
||||
self.assertRaises(ClientException,
|
||||
self.vitrage_client.resource.get(
|
||||
'test_for_no_existing'))
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
|
||||
finally:
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
def _compare_resources(self, api_resources, cli_resources):
|
||||
self.assertNotEqual(len(api_resources), 0,
|
||||
'The resources taken from rest api is empty')
|
||||
self.assertNotEqual(len(cli_resources), 0,
|
||||
'The resources taken from terminal is empty')
|
||||
|
||||
sorted_cli_resources = sorted(
|
||||
json.loads(cli_resources),
|
||||
key=lambda resource: resource["ID"])
|
||||
sorted_api_resources = sorted(
|
||||
api_resources,
|
||||
key=lambda resource: resource["vitrage_id"])
|
||||
|
||||
self.assertEqual(len(sorted_cli_resources),
|
||||
len(sorted_api_resources), 'cli = %s --> api = %s' %
|
||||
(sorted_cli_resources, sorted_api_resources))
|
||||
|
||||
for cli_resource, api_resource in \
|
||||
zip(sorted_cli_resources, sorted_api_resources):
|
||||
|
||||
self.assertEqual(
|
||||
cli_resource.get("ID").lower(),
|
||||
api_resource.get(VProps.VITRAGE_ID).lower())
|
||||
self.assertEqual(
|
||||
cli_resource.get("Type").lower(),
|
||||
api_resource.get(VProps.VITRAGE_TYPE).lower())
|
||||
self.assertEqual(
|
||||
cli_resource.get("Data Source ID").lower(),
|
||||
api_resource.get(VProps.ID).lower())
|
||||
self.assertEqual(
|
||||
cli_resource.get("State").lower(),
|
||||
api_resource.get(VProps.VITRAGE_OPERATIONAL_STATE).lower())
|
||||
|
||||
def _compare_resource_show(self, api_resource_show,
|
||||
cli_resource_show):
|
||||
self.assertIsNotNone(api_resource_show,
|
||||
'The resource show taken from rest api is empty')
|
||||
self.assertIsNotNone(cli_resource_show,
|
||||
'The resource show taken from terminal is empty')
|
||||
|
||||
for item in self.properties:
|
||||
self.assertEqual(api_resource_show.get(item),
|
||||
cli_resource_show.get(item))
|
@ -1,15 +0,0 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,181 +0,0 @@
|
||||
# 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.
|
||||
import json
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.exception import VitrageError
|
||||
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common import vitrage_utils
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseTemplateTest(BaseVitrageTempest):
|
||||
"""Template test class for Vitrage API tests."""
|
||||
|
||||
DEFAULT_PATH = '/etc/vitrage/templates/'
|
||||
TEST_PATH = '/opt/stack/vitrage/vitrage_tempest_tests/' \
|
||||
+ 'tests/resources/templates/api/'
|
||||
|
||||
NON_EXIST_FILE = 'non_exist_file.yaml'
|
||||
ERROR_FILE = 'corrupted_template.yaml'
|
||||
OK_FILE = 'nagios_alarm_for_alarms.yaml'
|
||||
|
||||
ERROR_STATUS = 'validation failed'
|
||||
OK_STATUS = 'validation OK'
|
||||
OK_MSG = 'Template validation is OK'
|
||||
|
||||
def setUp(self):
|
||||
super(BaseTemplateTest, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(BaseTemplateTest, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseTemplateTest, cls).setUpClass()
|
||||
|
||||
def _compare_template_lists(self, api_templates, cli_templates):
|
||||
self.assertNotEqual(len(api_templates), 0,
|
||||
'The template list taken from api is empty')
|
||||
self.assertIsNotNone(cli_templates,
|
||||
'The template list taken from cli is empty')
|
||||
|
||||
LOG.info("The template list taken from cli is : " +
|
||||
str(cli_templates))
|
||||
LOG.info("The template list taken by api is : " +
|
||||
str(json.dumps(api_templates)))
|
||||
|
||||
self._validate_templates_list_length(api_templates, cli_templates)
|
||||
self._validate_passed_templates_length(api_templates, cli_templates)
|
||||
self._compare_each_template_in_list(api_templates, cli_templates)
|
||||
self._validate_templates_existence_in_default_folder(api_templates)
|
||||
|
||||
def _compare_template_validations(self, api_templates, cli_templates):
|
||||
self.assertNotEqual(len(api_templates), 0,
|
||||
'The template validations taken from api is empty')
|
||||
self.assertIsNotNone(
|
||||
cli_templates, 'The template validations taken from cli is empty')
|
||||
|
||||
LOG.info("The template validations taken from cli is : " +
|
||||
str(cli_templates))
|
||||
LOG.info("The template validations taken by api is : " +
|
||||
str(json.dumps(api_templates)))
|
||||
|
||||
parsed_topology = json.loads(cli_templates)
|
||||
sorted_cli_templates = sorted(parsed_topology.items())
|
||||
sorted_api_templates = sorted(api_templates.items())
|
||||
self.assertEqual(sorted_api_templates, sorted_cli_templates)
|
||||
|
||||
def _validate_templates_list_length(self, api_templates, cli_templates):
|
||||
self.assertEqual(len(cli_templates.splitlines()),
|
||||
len(api_templates) + 4)
|
||||
|
||||
def _validate_passed_templates_length(self, api_templates, cli_templates):
|
||||
api_passes_templates = g_utils.all_matches(
|
||||
api_templates,
|
||||
**{'status details': self.OK_MSG})
|
||||
cli_passes_templates = cli_templates.count(' ' + self.OK_MSG + ' ')
|
||||
self.assertEqual(cli_passes_templates, len(api_passes_templates))
|
||||
|
||||
def _compare_each_template_in_list(self, api_templates, cli_templates):
|
||||
counter = 0
|
||||
for api_item in api_templates:
|
||||
for line in cli_templates.splitlines():
|
||||
name_start = line.count(' ' + api_item['name'] + ' ')
|
||||
status_start = line.count(' ' + api_item['status'] + ' ')
|
||||
if name_start > 0 and status_start > 0:
|
||||
counter += 1
|
||||
break
|
||||
self.assertEqual(counter, len(api_templates))
|
||||
|
||||
def _validate_templates_existence_in_default_folder(self, templates_list):
|
||||
counter = 0
|
||||
text_out = utils.get_from_terminal('ls ' + self.DEFAULT_PATH)
|
||||
for item in templates_list:
|
||||
name_start = text_out.count(' ' + item['name'] + ' ')
|
||||
if name_start > -1:
|
||||
counter += 1
|
||||
self.assertEqual(counter, len(templates_list))
|
||||
|
||||
def _run_default_template_validation(
|
||||
self, template, validation, path):
|
||||
self.assertNotEqual(len(validation), 0,
|
||||
'The template validation is empty')
|
||||
self.assertEqual(path, validation['file path'])
|
||||
self.assertEqual(0, validation['status code'])
|
||||
self.assertEqual(self.OK_STATUS, validation['status'])
|
||||
self.assertEqual(self.OK_MSG, validation['message'])
|
||||
self.assertEqual(validation['message'], template['status details'])
|
||||
|
||||
def _run_template_validation(
|
||||
self, validation, path, negative=False):
|
||||
self.assertIn(path, validation['file path'])
|
||||
|
||||
if negative:
|
||||
self.assertEqual(3, validation['status code'])
|
||||
self.assertEqual(self.ERROR_STATUS, validation['status'])
|
||||
self.assertNotEqual(validation['message'], self.OK_MSG)
|
||||
return
|
||||
|
||||
self.assertEqual(0, validation['status code'])
|
||||
self.assertEqual(self.OK_STATUS, validation['status'])
|
||||
self.assertEqual(self.OK_MSG, validation['message'])
|
||||
|
||||
def _compare_template_show(self, api_templates, cli_templates):
|
||||
self.assertNotEqual(len(api_templates), 0,
|
||||
'The template validations taken from api is empty')
|
||||
self.assertIsNotNone(
|
||||
cli_templates, 'The template validations taken from cli is empty')
|
||||
|
||||
LOG.info("The template validations taken from cli is : " +
|
||||
str(cli_templates))
|
||||
LOG.info("The template validations taken by api is : " +
|
||||
str(json.dumps(api_templates)))
|
||||
|
||||
parsed_topology = json.loads(cli_templates)
|
||||
sorted_cli_templates = sorted(parsed_topology.items())
|
||||
sorted_api_templates = sorted(api_templates.items())
|
||||
self.assertEqual(sorted_api_templates, sorted_cli_templates)
|
||||
|
||||
def _validate_template_structure(self, template_item, template_show):
|
||||
self.assertEqual(
|
||||
template_item['name'], template_show['metadata']['name'])
|
||||
template_content = utils.get_from_terminal(
|
||||
'cat ' + self.DEFAULT_PATH + template_item['name'] + '*')
|
||||
|
||||
entities = template_content.count('entity:')
|
||||
relationships = template_content.count('relationship:')
|
||||
scenarios = template_content.count('scenario:')
|
||||
|
||||
self.assertIn(
|
||||
template_show['metadata']['name'], template_content)
|
||||
self.assertEqual(
|
||||
entities, len(template_show['definitions']['entities']))
|
||||
self.assertEqual(
|
||||
relationships, len(template_show['definitions']['relationships']))
|
||||
self.assertEqual(
|
||||
scenarios, len(template_show['scenarios']))
|
||||
|
||||
def _rollback_to_default(self, templates):
|
||||
try:
|
||||
for t in templates:
|
||||
db_row = vitrage_utils.get_first_template(name=t)
|
||||
vitrage_utils.delete_template(db_row['uuid'])
|
||||
except Exception as e:
|
||||
raise VitrageError('Rollback to default failed %s', e)
|
@ -1,304 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import TemplateStatus
|
||||
from vitrage.common.constants import TemplateTypes as TTypes
|
||||
from vitrage.utils import file
|
||||
from vitrage_tempest_tests.tests.api.templates.base import BaseTemplateTest
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.common import vitrage_utils
|
||||
import vitrage_tempest_tests.tests.utils as utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
STANDARD_TEMPLATE = 'host_high_memory_usage_scenarios.yaml'
|
||||
EQUIVALENCE_TEMPLATE = 'basic_equivalence_templates.yaml'
|
||||
DEFINITION_TEMPLATE = 'basic_def_template.yaml'
|
||||
STANDARD_ERROR = 'corrupted_template.yaml'
|
||||
|
||||
FAKE_UUID = 'ade68276-0fe9-42cd-9ec2-e7f20470a771'
|
||||
|
||||
|
||||
class TestValidate(BaseTemplateTest):
|
||||
"""Template test class for Vitrage API tests."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestValidate, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestValidate, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestValidate, cls).setUpClass()
|
||||
|
||||
def test_templates_list(self):
|
||||
"""template_list test
|
||||
|
||||
There test validate correctness of template list,
|
||||
equals templates files existence with default folder
|
||||
and between cli via api ...
|
||||
"""
|
||||
api_template_list = self.vitrage_client.template.list()
|
||||
cli_template_list = utils.run_vitrage_command(
|
||||
'vitrage template list', self.conf)
|
||||
|
||||
self._compare_template_lists(api_template_list, cli_template_list)
|
||||
|
||||
def test_compare_templates_validation(self):
|
||||
"""template_validate test
|
||||
|
||||
There test validate correctness of template validation,
|
||||
equals templates files validation between cli via api
|
||||
"""
|
||||
path = self.DEFAULT_PATH
|
||||
api_template_validation = \
|
||||
self.vitrage_client.template.validate(path=path)
|
||||
cli_template_validation = utils.run_vitrage_command(
|
||||
'vitrage template validate --path ' + path, self.conf)
|
||||
|
||||
self._compare_template_validations(
|
||||
api_template_validation, cli_template_validation)
|
||||
|
||||
@unittest.skip("skipping test")
|
||||
# TODO(nivo): fix test - passes on machine but not at gate
|
||||
def test_templates_validate_default_templates(self):
|
||||
"""templates_validate test
|
||||
|
||||
There test validate correctness of list of uploaded template files
|
||||
(in /etc/vitrage/templates folder)
|
||||
"""
|
||||
path = self.DEFAULT_PATH
|
||||
validation = self.vitrage_client.template.validate(path=path)
|
||||
self.assertNotEqual(len(validation), 0)
|
||||
for item in validation['results']:
|
||||
self._run_template_validation(item, path)
|
||||
|
||||
def test_templates_validate_non_exist_template(self):
|
||||
"""templates_validate test
|
||||
|
||||
There negative test - validate error message
|
||||
in case of non-exist template file
|
||||
"""
|
||||
try:
|
||||
path = self.TEST_PATH + self.NON_EXIST_FILE
|
||||
validation = self.vitrage_client.template.validate(path=path)
|
||||
self.assertIsNone(validation)
|
||||
except Exception as up:
|
||||
self.assertEqual('No such file or directory', up.strerror)
|
||||
self.assertEqual(2, up.errno)
|
||||
|
||||
def test_templates_validate_corrupted_templates(self):
|
||||
"""templates_validate test
|
||||
|
||||
There negative test - validate correctness of error
|
||||
message in case of corrupted template file
|
||||
"""
|
||||
try:
|
||||
path = self.TEST_PATH + self.ERROR_FILE
|
||||
validation = self.vitrage_client.template.validate(path=path)
|
||||
self.assertEqual(1, len(validation['results']))
|
||||
self._run_template_validation(
|
||||
validation['results'][0], path, negative=True)
|
||||
except Exception:
|
||||
LOG.error('Failed to get validation of corrupted template file')
|
||||
|
||||
def test_templates_validate_correct_template(self):
|
||||
"""templates_validate test
|
||||
|
||||
There test validate correctness of template file
|
||||
"""
|
||||
try:
|
||||
path = self.TEST_PATH + self.OK_FILE
|
||||
validation = self.vitrage_client.template.validate(path=path)
|
||||
self.assertEqual(1, len(validation['results']))
|
||||
self._run_template_validation(
|
||||
validation['results'][0], path)
|
||||
except Exception:
|
||||
LOG.error('Failed to get validation of template file')
|
||||
|
||||
@unittest.skip("CLI tests are ineffective and not maintained")
|
||||
def test_compare_template_show(self):
|
||||
"""templates_show test
|
||||
|
||||
There test validate correctness of uploaded template files
|
||||
one by one with full details
|
||||
(in /etc/vitrage/templates folder)
|
||||
"""
|
||||
template_list = self.vitrage_client.template.list()
|
||||
self.assertNotEqual(len(template_list), 0)
|
||||
for item in template_list:
|
||||
api_template_show = self.vitrage_client.template.show(item['uuid'])
|
||||
cli_template_show = utils.run_vitrage_command(
|
||||
'vitrage template show ' + item['uuid'], self.conf)
|
||||
|
||||
self._compare_template_show(
|
||||
api_template_show, cli_template_show)
|
||||
self._validate_template_structure(item, api_template_show)
|
||||
|
||||
|
||||
class TemplatesDBTest(BaseTemplateTest):
|
||||
"""Template DB test class for vitrage API tests"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TemplatesDBTest, cls).setUpClass()
|
||||
cls.client = TempestClients.vitrage()
|
||||
|
||||
def test_template_add(self):
|
||||
"""template add test
|
||||
|
||||
test standard , definition and equivalence templates
|
||||
"""
|
||||
templates_names = list()
|
||||
try:
|
||||
# TODO(ikinory): add folder of templates
|
||||
# Add standard ,equivalence and definition templates
|
||||
templates_names = self._add_templates()
|
||||
vitrage_utils.add_template(STANDARD_TEMPLATE,
|
||||
template_type=TTypes.STANDARD)
|
||||
# assert standard template
|
||||
db_row = vitrage_utils.get_first_template(
|
||||
name='host_high_memory_usage_scenarios', type=TTypes.STANDARD)
|
||||
self.assertEqual(db_row['name'],
|
||||
'host_high_memory_usage_scenarios',
|
||||
'standard template not found in list')
|
||||
|
||||
# assert equivalence template
|
||||
db_row = vitrage_utils.get_first_template(
|
||||
name='entity equivalence example',
|
||||
type=TTypes.EQUIVALENCE)
|
||||
self.assertEqual(db_row['name'],
|
||||
'entity equivalence example',
|
||||
'equivalence template not found in list')
|
||||
|
||||
# assert definition template
|
||||
db_row = vitrage_utils.get_first_template(
|
||||
name='basic_def_template',
|
||||
type=TTypes.DEFINITION,
|
||||
status=TemplateStatus.ACTIVE)
|
||||
|
||||
self.assertEqual(db_row['name'],
|
||||
'basic_def_template',
|
||||
'definition template not found in list')
|
||||
|
||||
# assert corrupted template - validate failed
|
||||
db_row = vitrage_utils.get_first_template(
|
||||
name='corrupted_template',
|
||||
type=TTypes.STANDARD,
|
||||
status=TemplateStatus.ERROR)
|
||||
self.assertIsNotNone(
|
||||
db_row,
|
||||
'corrupted template template presented in list')
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default(templates_names)
|
||||
|
||||
def test_template_delete(self):
|
||||
try:
|
||||
|
||||
# add standard template
|
||||
vitrage_utils.add_template(STANDARD_TEMPLATE,
|
||||
template_type=TTypes.STANDARD)
|
||||
db_row = vitrage_utils.get_first_template(
|
||||
name='host_high_memory_usage_scenarios',
|
||||
type=TTypes.STANDARD,
|
||||
status=TemplateStatus.ACTIVE)
|
||||
self.assertIsNotNone(db_row,
|
||||
'Template should appear in templates list')
|
||||
|
||||
# delete template
|
||||
uuid = db_row['uuid']
|
||||
vitrage_utils.delete_template(uuid)
|
||||
db_row = vitrage_utils.get_first_template(
|
||||
name='host_high_memory_usage_scenarios', type=TTypes.STANDARD)
|
||||
self.assertIsNone(db_row, 'Template should not appear in list')
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
|
||||
def test_compare_cli_to_api(self):
|
||||
"""Compare between api template list
|
||||
|
||||
to cli template list
|
||||
compares each template in list
|
||||
"""
|
||||
templates_names = list()
|
||||
try:
|
||||
# Add standard ,equivalence and definition templates
|
||||
templates_names = self._add_templates()
|
||||
cli_templates_list = utils.run_vitrage_command(
|
||||
"vitrage template list", self.conf)
|
||||
api_templates_list = self.client.template.list()
|
||||
|
||||
self.assertNotEqual(len(api_templates_list), 0,
|
||||
'The template list taken from api is empty')
|
||||
self.assertIsNotNone(cli_templates_list,
|
||||
'The template list taken from cli is empty')
|
||||
self._validate_templates_list_length(api_templates_list,
|
||||
cli_templates_list)
|
||||
self._validate_passed_templates_length(api_templates_list,
|
||||
cli_templates_list)
|
||||
self._compare_each_template_in_list(api_templates_list,
|
||||
cli_templates_list)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default(templates_names)
|
||||
|
||||
def test_template_show(self):
|
||||
"""Compare template content from file to DB"""
|
||||
try:
|
||||
# add standard template
|
||||
template_path = \
|
||||
g_utils.tempest_resources_dir() + '/templates/api/'\
|
||||
+ STANDARD_TEMPLATE
|
||||
vitrage_utils.add_template(STANDARD_TEMPLATE,
|
||||
template_type=TTypes.STANDARD)
|
||||
db_row = vitrage_utils.get_first_template(
|
||||
name='host_high_memory_usage_scenarios',
|
||||
type=TTypes.STANDARD,
|
||||
status=TemplateStatus.ACTIVE)
|
||||
payload_from_db = self.client.template.show(db_row['uuid'])
|
||||
payload_from_file = file.load_yaml_file(template_path)
|
||||
self.assertEqual(payload_from_file, payload_from_db,
|
||||
"Template content doesn't match")
|
||||
vitrage_utils.delete_template(db_row['uuid'])
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
|
||||
def _add_templates(self):
|
||||
vitrage_utils.add_template(STANDARD_TEMPLATE,
|
||||
template_type=TTypes.STANDARD)
|
||||
vitrage_utils.add_template(EQUIVALENCE_TEMPLATE,
|
||||
template_type=TTypes.EQUIVALENCE)
|
||||
vitrage_utils.add_template(DEFINITION_TEMPLATE,
|
||||
template_type=TTypes.DEFINITION)
|
||||
vitrage_utils.add_template(STANDARD_ERROR,
|
||||
template_type=TTypes.STANDARD)
|
||||
return ['host_high_memory_usage_scenarios',
|
||||
'entity equivalence example',
|
||||
'basic_def_template',
|
||||
'corrupted_template']
|
@ -1,64 +0,0 @@
|
||||
# Copyright 2018 - 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 oslo_log import log as logging
|
||||
|
||||
from vitrage_tempest_tests.tests.api.templates.base import BaseTemplateTest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
EXECUTE_MISTRAL_TEMPLATE = 'v2_execute_mistral.yaml'
|
||||
EQUIVALENCE_TEMPLATE = 'v2_equivalence_templates.yaml'
|
||||
DEFINITION_TEMPLATE = 'v2_definition_template.yaml'
|
||||
NO_TYPE_TEMPLATE = 'v2_no_type_template.yaml'
|
||||
|
||||
FAKE_UUID = 'ade68276-0fe9-42cd-9ec2-e7f20470a771'
|
||||
|
||||
|
||||
class TestValidateV2(BaseTemplateTest):
|
||||
"""Template test class for Vitrage API tests."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestValidateV2, cls).setUpClass()
|
||||
|
||||
def test_templates_validate_no_type_templates(self):
|
||||
try:
|
||||
path = self.TEST_PATH + NO_TYPE_TEMPLATE
|
||||
validation = self.vitrage_client.template.validate(path=path)
|
||||
self.assertEqual(1, len(validation['results']))
|
||||
self._run_template_validation(
|
||||
validation['results'][0], path, negative=True)
|
||||
except Exception:
|
||||
LOG.error('Failed to get validation of corrupted template file')
|
||||
|
||||
def test_templates_validate_standard_template(self):
|
||||
try:
|
||||
path = self.TEST_PATH + EXECUTE_MISTRAL_TEMPLATE
|
||||
validation = self.vitrage_client.template.validate(path=path)
|
||||
self.assertEqual(1, len(validation['results']))
|
||||
self._run_template_validation(
|
||||
validation['results'][0], path)
|
||||
except Exception:
|
||||
LOG.error('Failed to get validation of standard template file')
|
||||
|
||||
def test_templates_validate_definition_template(self):
|
||||
try:
|
||||
path = self.TEST_PATH + DEFINITION_TEMPLATE
|
||||
validation = self.vitrage_client.template.validate(path=path)
|
||||
self.assertEqual(1, len(validation['results']))
|
||||
self._run_template_validation(
|
||||
validation['results'][0], path)
|
||||
except Exception:
|
||||
LOG.error('Failed to get validation of definition template file')
|
@ -1,15 +0,0 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,141 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
|
||||
from vitrage_tempest_tests.tests.base import LOG
|
||||
from vitrage_tempest_tests.tests.common import cinder_utils
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
|
||||
|
||||
class BaseTopologyTest(BaseVitrageTempest):
|
||||
"""Topology test class for Vitrage API tests."""
|
||||
|
||||
def setUp(self):
|
||||
super(BaseTopologyTest, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(BaseTopologyTest, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseTopologyTest, cls).setUpClass()
|
||||
|
||||
def _rollback_to_default(self):
|
||||
self._delete_entities()
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
root=None,
|
||||
all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data()
|
||||
num_default_entities = self.num_default_entities + \
|
||||
self.num_default_networks + self.num_default_ports
|
||||
num_default_edges = self.num_default_edges + self.num_default_ports
|
||||
try:
|
||||
self._validate_graph_correctness(graph,
|
||||
num_default_entities,
|
||||
num_default_edges,
|
||||
entities)
|
||||
except AssertionError as e:
|
||||
LOG.error(e)
|
||||
|
||||
def _create_entities(self, num_instances, num_volumes=0, end_sleep=3):
|
||||
resources = nova_utils.create_instances(num_instances)
|
||||
|
||||
self.assertNotEqual(len(resources), 0, 'The instances list is empty')
|
||||
if num_volumes > 0:
|
||||
cinder_utils.create_volume_and_attach('volume-1', 1,
|
||||
resources[0].id,
|
||||
'/tmp/vda')
|
||||
|
||||
# waiting until all the entities creation were processed by the
|
||||
# entity graph processor
|
||||
time.sleep(end_sleep)
|
||||
|
||||
@staticmethod
|
||||
def _delete_entities():
|
||||
cinder_utils.delete_all_volumes()
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
# waiting until all the entities deletion were processed by the
|
||||
# entity graph processor
|
||||
time.sleep(2)
|
||||
|
||||
def _compare_graphs(self, api_graph, cli_graph):
|
||||
"""Compare Graph object to graph form terminal """
|
||||
self.assertNotEqual(len(api_graph), 0,
|
||||
'The topology graph taken from rest api is empty')
|
||||
self.assertNotEqual(len(cli_graph), 0,
|
||||
'The topology graph taken from terminal is empty')
|
||||
|
||||
parsed_topology = json.loads(cli_graph)
|
||||
|
||||
sorted_cli_graph = sorted(parsed_topology.items())
|
||||
sorted_api_graph = sorted(api_graph.items())
|
||||
|
||||
for item in sorted_cli_graph[4][1]:
|
||||
item.pop(VProps.UPDATE_TIMESTAMP, None)
|
||||
|
||||
for item in sorted_api_graph[4][1]:
|
||||
item.pop(VProps.UPDATE_TIMESTAMP, None)
|
||||
|
||||
for item in sorted_cli_graph[4][1]:
|
||||
item.pop(VProps.VITRAGE_SAMPLE_TIMESTAMP, None)
|
||||
|
||||
for item in sorted_api_graph[4][1]:
|
||||
item.pop(VProps.VITRAGE_SAMPLE_TIMESTAMP, None)
|
||||
|
||||
self.assertEqual(sorted_cli_graph, sorted_api_graph)
|
||||
|
||||
@staticmethod
|
||||
def _graph_query():
|
||||
return '{"and": [{"==": {"vitrage_category": "RESOURCE"}},' \
|
||||
'{"==": {"vitrage_is_deleted": false}},' \
|
||||
'{"==": {"vitrage_is_placeholder": false}},' \
|
||||
'{"or": [{"==": {"vitrage_type": "openstack.cluster"}},' \
|
||||
'{"==": {"vitrage_type": "nova.instance"}},' \
|
||||
'{"==": {"vitrage_type": "nova.host"}},' \
|
||||
'{"==": {"vitrage_type": "nova.zone"}}]}]}'
|
||||
|
||||
@staticmethod
|
||||
def _tree_query():
|
||||
return '{"and": [{"==": {"vitrage_category": "RESOURCE"}},' \
|
||||
'{"==": {"vitrage_is_deleted": false}},' \
|
||||
'{"==": {"vitrage_is_placeholder": false}},' \
|
||||
'{"or": [{"==": {"vitrage_type": "openstack.cluster"}},' \
|
||||
'{"==": {"vitrage_type": "nova.host"}},' \
|
||||
'{"==": {"vitrage_type": "nova.zone"}}]}]}'
|
||||
|
||||
@staticmethod
|
||||
def _graph_no_match_query():
|
||||
return '{"and": [{"==": {"vitrage_category": "test"}},' \
|
||||
'{"==": {"vitrage_is_deleted": false}},' \
|
||||
'{"==": {"vitrage_is_placeholder": false}},' \
|
||||
'{"or": [{"==": {"vitrage_type": "openstack.cluster"}},' \
|
||||
'{"==": {"vitrage_type": "nova.instance"}},' \
|
||||
'{"==": {"vitrage_type": "nova.host"}},' \
|
||||
'{"==": {"vitrage_type": "nova.zone"}}]}]}'
|
||||
|
||||
@staticmethod
|
||||
def _tree_no_match_query():
|
||||
return '{"and": [{"==": {"vitrage_category": "test"}},' \
|
||||
'{"==": {"vitrage_is_deleted": false}},' \
|
||||
'{"==": {"vitrage_is_placeholder": false}},' \
|
||||
'{"or": [{"==": {"vitrage_type": "openstack.cluster"}},' \
|
||||
'{"==": {"vitrage_type": "nova.host"}},' \
|
||||
'{"==": {"vitrage_type": "nova.zone"}}]}]}'
|
@ -1,420 +0,0 @@
|
||||
# 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 oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources import OPENSTACK_CLUSTER
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
import vitrage_tempest_tests.tests.utils as utils
|
||||
from vitrageclient.exceptions import ClientException
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
NOVA_QUERY = '{"and": [{"==": {"vitrage_category": "RESOURCE"}},' \
|
||||
'{"==": {"vitrage_is_deleted": false}},' \
|
||||
'{"==": {"vitrage_is_placeholder": false}},' \
|
||||
'{"or": [{"==": {"vitrage_type": "openstack.cluster"}},' \
|
||||
'{"==": {"vitrage_type": "nova.instance"}},' \
|
||||
'{"==": {"vitrage_type": "nova.host"}},' \
|
||||
'{"==": {"vitrage_type": "nova.zone"}}]}]}'
|
||||
|
||||
|
||||
class TestTopology(BaseTopologyTest):
|
||||
"""Topology test class for Vitrage API tests."""
|
||||
|
||||
NUM_INSTANCE = 3
|
||||
NUM_VOLUME = 1
|
||||
|
||||
def setUp(self):
|
||||
super(TestTopology, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestTopology, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestTopology, cls).setUpClass()
|
||||
|
||||
def _get_root_vertex_id(self):
|
||||
items = self.vitrage_client.resource.list(
|
||||
resource_type=OPENSTACK_CLUSTER, all_tenants=True)
|
||||
return items[0][VProps.VITRAGE_ID]
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_compare_api_and_cli(self):
|
||||
"""compare_api_and_cli
|
||||
|
||||
This test validate correctness of topology graph:
|
||||
cli via api
|
||||
"""
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
cli_graph = utils.run_vitrage_command(
|
||||
'vitrage topology show --all-tenants',
|
||||
self.conf)
|
||||
|
||||
LOG.info('api-graph=%(api)s cli-graph=%(cli)s', {'api': api_graph,
|
||||
'cli': cli_graph})
|
||||
|
||||
self._compare_graphs(api_graph, cli_graph)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_default_graph(self):
|
||||
"""default_graph
|
||||
|
||||
This test validate correctness of default topology graph
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE,
|
||||
num_volumes=self.NUM_VOLUME)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=self.NUM_INSTANCE + 1,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=2 * self.NUM_INSTANCE + self.NUM_VOLUME,
|
||||
volume_entities=self.NUM_VOLUME,
|
||||
volume_edges=self.NUM_VOLUME)
|
||||
num_entities = self.num_default_entities + self.NUM_VOLUME + \
|
||||
2 * self.NUM_INSTANCE + self.num_default_networks + \
|
||||
self.num_default_ports
|
||||
num_edges = self.num_default_edges + 3 * self.NUM_INSTANCE + \
|
||||
self.NUM_VOLUME + self.num_default_ports
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_graph_with_query(self):
|
||||
"""graph_with_query
|
||||
|
||||
This test validate correctness of topology graph
|
||||
with query
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE,
|
||||
num_volumes=self.NUM_VOLUME)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
query=self._graph_query(),
|
||||
all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=self.NUM_INSTANCE + 1,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=self.NUM_INSTANCE)
|
||||
num_entities = self.num_default_entities + self.NUM_INSTANCE
|
||||
num_edges = self.num_default_edges + self.NUM_INSTANCE
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_nova_tree(self):
|
||||
"""nova_tree
|
||||
|
||||
This test validate correctness of topology tree
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE,
|
||||
num_volumes=self.NUM_VOLUME)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
graph_type='tree', query=NOVA_QUERY, all_tenants=True)
|
||||
graph = self._create_graph_from_tree_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=self.NUM_INSTANCE + 1,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=self.NUM_INSTANCE)
|
||||
num_entities = self.num_default_entities + self.NUM_INSTANCE
|
||||
num_edges = self.num_default_edges + self.NUM_INSTANCE
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_tree_with_query(self):
|
||||
"""tree_with_query
|
||||
|
||||
This test validate correctness of topology tree
|
||||
with query
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
graph_type='tree', query=self._tree_query(), all_tenants=True)
|
||||
graph = self._create_graph_from_tree_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1, host_edges=1)
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
self.num_default_entities,
|
||||
self.num_default_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_tree_with_depth_exclude_instance(self):
|
||||
"""tree_with_query
|
||||
|
||||
This test validate correctness of topology tree
|
||||
with query
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
limit=2, graph_type='tree', query=NOVA_QUERY, all_tenants=True)
|
||||
graph = self._create_graph_from_tree_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1, host_edges=1)
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
self.num_default_entities,
|
||||
self.num_default_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_tree_with_depth_include_instance(self):
|
||||
"""tree_with_query
|
||||
|
||||
This test validate correctness of topology tree
|
||||
with query
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
limit=3, graph_type='tree', query=NOVA_QUERY, all_tenants=True)
|
||||
graph = self._create_graph_from_tree_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=self.NUM_INSTANCE + 1,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=self.NUM_INSTANCE)
|
||||
num_entities = self.num_default_entities + self.NUM_INSTANCE
|
||||
num_edges = self.num_default_edges + self.NUM_INSTANCE
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@unittest.skip("skipping test - not working")
|
||||
@utils.tempest_logger
|
||||
def test_graph_with_root_and_depth_exclude_instance(self):
|
||||
"""tree_with_query
|
||||
|
||||
This test validate correctness of topology graph
|
||||
with root and depth exclude instance
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
limit=2,
|
||||
root=self._get_root_vertex_id(),
|
||||
all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1, host_edges=1)
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
self.num_default_entities,
|
||||
self.num_default_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@unittest.skip("skipping test - not working")
|
||||
@utils.tempest_logger
|
||||
def test_graph_with_root_and_depth_include_instance(self):
|
||||
"""graph_with_root_and_depth_include_instance
|
||||
|
||||
This test validate correctness of topology graph
|
||||
with root and depth include instance
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
limit=3,
|
||||
root=self._get_root_vertex_id(),
|
||||
all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=self.NUM_INSTANCE + 1,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=self.NUM_INSTANCE)
|
||||
num_entities = self.num_default_entities + self.NUM_INSTANCE
|
||||
num_edges = self.num_default_edges + self.NUM_INSTANCE
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_graph_with_depth_and_no_root(self):
|
||||
"""graph_with_depth_and_no_root
|
||||
|
||||
This test validate correctness of topology
|
||||
graph with depth and without root
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE,
|
||||
num_volumes=self.NUM_VOLUME)
|
||||
|
||||
# Calculate expected results
|
||||
self.vitrage_client.topology.get(
|
||||
limit=2,
|
||||
root=None,
|
||||
all_tenants=True)
|
||||
except ClientException as e:
|
||||
self.assertEqual(403, e.code)
|
||||
self.assertEqual(
|
||||
"Graph-type 'graph' requires a 'root' with 'depth'",
|
||||
str(e.message))
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_graph_with_no_match_query(self):
|
||||
"""graph_with_no_match_query
|
||||
|
||||
This test validate correctness of topology graph
|
||||
with no match query
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE,
|
||||
num_volumes=self.NUM_VOLUME)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
query=self._graph_no_match_query(), all_tenants=True)
|
||||
|
||||
# Test Assertions
|
||||
self.assertEqual(
|
||||
0,
|
||||
len(api_graph['nodes']), 'num of vertex node')
|
||||
self.assertEqual(
|
||||
0,
|
||||
len(api_graph['links']), 'num of edges')
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_tree_with_no_match_query(self):
|
||||
"""tree_with_no_match_query
|
||||
|
||||
This test validate correctness of topology tree
|
||||
with no match query
|
||||
"""
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(
|
||||
graph_type='tree',
|
||||
query=self._tree_no_match_query(),
|
||||
all_tenants=True)
|
||||
|
||||
# Test Assertions
|
||||
self.assertEqual({}, api_graph)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
@ -1,15 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,149 +0,0 @@
|
||||
# Copyright 2017 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 oslo_log import log as logging
|
||||
|
||||
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrageclient.exceptions import ClientException
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
URL = 'url'
|
||||
REGEX_FILTER = 'regex_filter'
|
||||
HEADERS = 'headers'
|
||||
HEADERS_PROPS = '{"content": "application/json"}'
|
||||
REGEX_PROPS = '{"name": "e2e.*"}'
|
||||
|
||||
|
||||
class TestWebhook(BaseVitrageTempest):
|
||||
"""Webhook test class for Vitrage API tests."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestWebhook, cls).setUpClass()
|
||||
cls.pre_test_webhook_count = \
|
||||
len(TempestClients.vitrage().webhook.list())
|
||||
|
||||
def test_add_webhook(self):
|
||||
|
||||
webhooks = TempestClients.vitrage().webhook.list()
|
||||
self.assertEqual(self.pre_test_webhook_count,
|
||||
len(webhooks),
|
||||
'Amount of webhooks should be the same as '
|
||||
'before the test')
|
||||
|
||||
created_webhook = TempestClients.vitrage().webhook.add(
|
||||
url="https://www.test.com",
|
||||
regex_filter=REGEX_PROPS,
|
||||
headers=HEADERS_PROPS
|
||||
)
|
||||
|
||||
self.assertIsNone(created_webhook.get('ERROR'), 'webhook not '
|
||||
'created')
|
||||
self.assertEqual(created_webhook[HEADERS],
|
||||
HEADERS_PROPS,
|
||||
'headers not created correctly')
|
||||
self.assertEqual(created_webhook[REGEX_FILTER],
|
||||
REGEX_PROPS,
|
||||
'regex not created correctly')
|
||||
self.assertEqual(created_webhook[URL],
|
||||
"https://www.test.com",
|
||||
'URL not created correctly')
|
||||
|
||||
webhooks = TempestClients.vitrage().webhook.list()
|
||||
|
||||
self.assertEqual(self.pre_test_webhook_count + 1, len(webhooks))
|
||||
TempestClients.vitrage().webhook.delete(
|
||||
created_webhook['id'])
|
||||
|
||||
def test_delete_webhook(self):
|
||||
webhooks = TempestClients.vitrage().webhook.list()
|
||||
self.assertEqual(self.pre_test_webhook_count,
|
||||
len(webhooks),
|
||||
'Amount of webhooks should be the same as '
|
||||
'before the test')
|
||||
|
||||
created_webhook = TempestClients.vitrage().webhook.add(
|
||||
url="https://www.test.com",
|
||||
regex_filter=REGEX_PROPS,
|
||||
headers=HEADERS_PROPS
|
||||
)
|
||||
|
||||
created_webhook = TempestClients.vitrage().webhook.delete(
|
||||
id=created_webhook['id'])
|
||||
self.assertIsNotNone(created_webhook.get('SUCCESS'),
|
||||
'failed to delete')
|
||||
self.assertEqual(self.pre_test_webhook_count, len(webhooks),
|
||||
'No webhooks should exist after deletion')
|
||||
|
||||
def test_delete_non_existing_webhook(self):
|
||||
self.assertRaises(ClientException,
|
||||
TempestClients.vitrage().webhook.delete,
|
||||
('non existant'))
|
||||
|
||||
def test_list_webhook(self):
|
||||
|
||||
webhooks = TempestClients.vitrage().webhook.list()
|
||||
self.assertEqual(self.pre_test_webhook_count,
|
||||
len(webhooks),
|
||||
'Amount of webhooks should be the same as '
|
||||
'before the test')
|
||||
|
||||
created_webhook = TempestClients.vitrage().webhook.add(
|
||||
url="https://www.test.com",
|
||||
regex_filter=REGEX_PROPS,
|
||||
headers=HEADERS_PROPS
|
||||
)
|
||||
|
||||
webhooks = TempestClients.vitrage().webhook.list()
|
||||
self.assertEqual(self.pre_test_webhook_count + 1, len(webhooks))
|
||||
self.assertEqual(created_webhook[HEADERS], webhooks[0][HEADERS])
|
||||
self.assertEqual(created_webhook['id'], webhooks[0]['id'])
|
||||
self.assertEqual(created_webhook[REGEX_FILTER],
|
||||
webhooks[0][REGEX_FILTER])
|
||||
|
||||
TempestClients.vitrage().webhook.delete(
|
||||
created_webhook['id'])
|
||||
|
||||
def test_show_webhook(self):
|
||||
webhooks = TempestClients.vitrage().webhook.list()
|
||||
self.assertEqual(self.pre_test_webhook_count,
|
||||
len(webhooks),
|
||||
'Amount of webhooks should be the same as '
|
||||
'before the test')
|
||||
|
||||
created_webhook = TempestClients.vitrage().webhook.add(
|
||||
url="https://www.test.com",
|
||||
regex_filter=REGEX_PROPS,
|
||||
headers=HEADERS_PROPS
|
||||
)
|
||||
|
||||
show_webhook = TempestClients.vitrage().webhook.show(
|
||||
created_webhook['id']
|
||||
)
|
||||
|
||||
self.assertIsNotNone(show_webhook, 'webhook not listed')
|
||||
self.assertEqual(created_webhook[HEADERS],
|
||||
show_webhook[HEADERS],
|
||||
'headers mismatch')
|
||||
self.assertEqual(created_webhook[REGEX_FILTER],
|
||||
show_webhook[REGEX_FILTER],
|
||||
'regex mismatch')
|
||||
self.assertEqual(created_webhook[URL],
|
||||
show_webhook[URL],
|
||||
'URL mismatch')
|
||||
|
||||
TempestClients.vitrage().webhook.delete(
|
||||
created_webhook['id'])
|
@ -1,258 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import six
|
||||
import traceback
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslotest import base
|
||||
|
||||
from vitrage.common.constants import EdgeProperties
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources.aodh import AODH_DATASOURCE
|
||||
from vitrage.datasources.cinder.volume import CINDER_VOLUME_DATASOURCE
|
||||
from vitrage.datasources.heat.stack import HEAT_STACK_DATASOURCE
|
||||
from vitrage.datasources.neutron.network import NEUTRON_NETWORK_DATASOURCE
|
||||
from vitrage.datasources.neutron.port import NEUTRON_PORT_DATASOURCE
|
||||
from vitrage.datasources import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
||||
from vitrage.datasources import NOVA_ZONE_DATASOURCE
|
||||
from vitrage.datasources import OPENSTACK_CLUSTER
|
||||
from vitrage.datasources.static_physical import SWITCH
|
||||
from vitrage.graph.driver.networkx_graph import NXGraph
|
||||
from vitrage.graph import Edge
|
||||
from vitrage.graph import Vertex
|
||||
from vitrage import service
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
import warnings
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
if six.PY2:
|
||||
class ResourceWarning(Warning):
|
||||
pass
|
||||
|
||||
|
||||
class BaseVitrageTempest(base.BaseTestCase):
|
||||
"""Base test class for All Vitrage tests."""
|
||||
|
||||
NUM_VERTICES_PER_TYPE = 'num_vertices'
|
||||
NUM_EDGES_PER_TYPE = 'num_edges_per_type'
|
||||
|
||||
def setUp(self):
|
||||
super(BaseVitrageTempest, self).setUp()
|
||||
warnings.filterwarnings(action="ignore",
|
||||
message="unclosed",
|
||||
category=ResourceWarning)
|
||||
|
||||
def tearDown(self):
|
||||
super(BaseVitrageTempest, self).tearDown()
|
||||
warnings.filterwarnings(action="ignore",
|
||||
message="unclosed",
|
||||
category=ResourceWarning)
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseVitrageTempest, cls).setUpClass()
|
||||
warnings.filterwarnings(action="ignore",
|
||||
message="unclosed",
|
||||
category=ResourceWarning)
|
||||
cls.conf = service.prepare_service([])
|
||||
TempestClients.class_init(cls.conf)
|
||||
cls.vitrage_client = TempestClients.vitrage()
|
||||
|
||||
cls.num_default_networks = \
|
||||
len(TempestClients.neutron().list_networks()['networks'])
|
||||
cls.num_default_ports = 0
|
||||
cls.num_default_entities = 3
|
||||
cls.num_default_edges = 2
|
||||
|
||||
def _create_graph_from_graph_dictionary(self, api_graph):
|
||||
self.assertIsNotNone(api_graph)
|
||||
graph = NXGraph()
|
||||
|
||||
nodes = api_graph['nodes']
|
||||
for i in range(len(nodes)):
|
||||
graph.add_vertex(Vertex(str(i), nodes[i]))
|
||||
|
||||
edges = api_graph['links']
|
||||
for i in range(len(edges)):
|
||||
graph.add_edge(Edge(str(edges[i]['source']),
|
||||
str(edges[i]['target']),
|
||||
edges[i][EdgeProperties.RELATIONSHIP_TYPE]))
|
||||
|
||||
return graph
|
||||
|
||||
def _create_graph_from_tree_dictionary(self,
|
||||
api_graph,
|
||||
graph=None,
|
||||
ancestor=None):
|
||||
children = []
|
||||
graph = NXGraph() if not graph else graph
|
||||
|
||||
if 'children' in api_graph:
|
||||
children = api_graph.copy()['children']
|
||||
del api_graph['children']
|
||||
|
||||
vertex = Vertex(api_graph[VProps.VITRAGE_ID], api_graph)
|
||||
graph.add_vertex(vertex)
|
||||
if ancestor:
|
||||
graph.add_edge(Edge(ancestor[VProps.VITRAGE_ID],
|
||||
vertex[VProps.VITRAGE_ID],
|
||||
'label'))
|
||||
|
||||
for entity in children:
|
||||
self._create_graph_from_tree_dictionary(entity, graph, vertex)
|
||||
|
||||
return graph
|
||||
|
||||
def _entities_validation_data(self, **kwargs):
|
||||
validation_data = []
|
||||
|
||||
# openstack.cluster
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: OPENSTACK_CLUSTER,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('cluster_entities', 1),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('cluster_edges', 1)}
|
||||
validation_data.append(props)
|
||||
|
||||
# nova.zone
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: NOVA_ZONE_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('zone_entities', 1),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('zone_edges', 2)}
|
||||
validation_data.append(props)
|
||||
|
||||
# nova.host
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('host_entities', 1),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('host_edges', 1)}
|
||||
validation_data.append(props)
|
||||
|
||||
# nova.instance
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get(
|
||||
'instance_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get(
|
||||
'instance_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# cinder.volume
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: CINDER_VOLUME_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get(
|
||||
'volume_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get(
|
||||
'volume_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# switch
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: SWITCH,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get(
|
||||
'switch_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get(
|
||||
'switch_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# aodh
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
|
||||
VProps.VITRAGE_TYPE: AODH_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get(
|
||||
'aodh_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get(
|
||||
'aodh_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# neutron.network
|
||||
if kwargs.get('network_entities') is not None:
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: NEUTRON_NETWORK_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get(
|
||||
'network_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get(
|
||||
'network_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# neutron.port
|
||||
if kwargs.get('port_entities') is not None:
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: NEUTRON_PORT_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get(
|
||||
'port_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get(
|
||||
'port_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# heat.stack
|
||||
props = {VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.VITRAGE_TYPE: HEAT_STACK_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get(
|
||||
'stack_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get(
|
||||
'stack_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
return validation_data
|
||||
|
||||
def _validate_graph_correctness(self,
|
||||
graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities):
|
||||
self.assertIsNotNone(graph)
|
||||
self.assertIsNotNone(entities)
|
||||
|
||||
for entity in entities:
|
||||
query = {
|
||||
VProps.VITRAGE_CATEGORY: entity[VProps.VITRAGE_CATEGORY],
|
||||
VProps.VITRAGE_TYPE: entity[VProps.VITRAGE_TYPE],
|
||||
VProps.VITRAGE_IS_DELETED: False,
|
||||
VProps.VITRAGE_IS_PLACEHOLDER: False
|
||||
}
|
||||
vertices = graph.get_vertices(vertex_attr_filter=query)
|
||||
self.assertEqual(entity[self.NUM_VERTICES_PER_TYPE],
|
||||
len(vertices),
|
||||
'%s%s' % ('Num vertices is incorrect for: ',
|
||||
entity[VProps.VITRAGE_TYPE]))
|
||||
|
||||
entity_num_edges = sum([len(graph.get_edges(vertex.vertex_id))
|
||||
for vertex in vertices])
|
||||
self.assertEqual(entity[self.NUM_EDGES_PER_TYPE],
|
||||
entity_num_edges,
|
||||
'%s%s' % ('Num edges is incorrect for: ',
|
||||
entity[VProps.VITRAGE_TYPE]))
|
||||
|
||||
self.assertEqual(num_entities, graph.num_vertices())
|
||||
self.assertEqual(num_edges, graph.num_edges())
|
||||
|
||||
@staticmethod
|
||||
def _get_value(item, key):
|
||||
return utils.uni2str(item[key])
|
||||
|
||||
def _print_entity_graph(self):
|
||||
api_graph = TempestClients.vitrage().topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
LOG.info('Entity Graph: \n%s', graph.json_output_graph())
|
||||
|
||||
def _handle_exception(self, exception):
|
||||
traceback.print_exc()
|
||||
LOG.exception(exception)
|
||||
self._print_entity_graph()
|
@ -1,15 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,55 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import random
|
||||
import time
|
||||
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
|
||||
|
||||
def create_aodh_alarm(resource_id=None, name=None, unic=True):
|
||||
if not name:
|
||||
name = '%s-%s' % ('test_', random.randrange(0, 100000, 1))
|
||||
elif unic:
|
||||
name = '%s-%s' % (name, random.randrange(0, 100000, 1))
|
||||
|
||||
aodh_request = _aodh_request(resource_id=resource_id, name=name)
|
||||
TempestClients.aodh().alarm.create(aodh_request)
|
||||
time.sleep(45)
|
||||
|
||||
|
||||
def delete_all_aodh_alarms():
|
||||
alarms = TempestClients.aodh().alarm.list()
|
||||
for alarm in alarms:
|
||||
TempestClients.aodh().alarm.delete(alarm[AodhProps.ALARM_ID])
|
||||
time.sleep(120)
|
||||
|
||||
|
||||
def _aodh_request(resource_id=None, name=None):
|
||||
query = []
|
||||
if resource_id:
|
||||
query = [
|
||||
dict(
|
||||
field=u'traits.resource_id',
|
||||
type='',
|
||||
op=u'eq',
|
||||
value=resource_id)
|
||||
]
|
||||
|
||||
return dict(
|
||||
name=name,
|
||||
description=u'test alarm',
|
||||
event_rule=dict(query=query),
|
||||
severity=u'low',
|
||||
state=u'alarm',
|
||||
type=u'event')
|
@ -1,54 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import random
|
||||
import time
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
|
||||
|
||||
def create_ceilometer_alarm(resource_id=None, name=None, unic=True):
|
||||
if not name:
|
||||
name = '%s-%s' % ('test_', random.randrange(0, 100000, 1))
|
||||
elif unic:
|
||||
name = '%s-%s' % (name, random.randrange(0, 100000, 1))
|
||||
|
||||
aodh_request = _aodh_request(resource_id=resource_id, name=name)
|
||||
TempestClients.ceilometer().alarms.create(**aodh_request)
|
||||
time.sleep(45)
|
||||
|
||||
|
||||
def delete_all_ceilometer_alarms():
|
||||
alarms = TempestClients.ceilometer().alarms.list()
|
||||
for alarm in alarms:
|
||||
TempestClients.ceilometer().alarms.delete(alarm.alarm_id)
|
||||
time.sleep(120)
|
||||
|
||||
|
||||
def _aodh_request(resource_id=None, name=None):
|
||||
query = []
|
||||
if resource_id:
|
||||
query = [
|
||||
dict(
|
||||
field=u'traits.resource_id',
|
||||
type='',
|
||||
op=u'eq',
|
||||
value=resource_id)
|
||||
]
|
||||
|
||||
return dict(
|
||||
name=name,
|
||||
description=u'test alarm',
|
||||
event_rule=dict(query=query),
|
||||
severity='low',
|
||||
state='alarm',
|
||||
type=u'event')
|
@ -1,49 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import time
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.utils import wait_for_status
|
||||
|
||||
|
||||
def create_volume_and_attach(name, size, instance_id, mount_point):
|
||||
volume = TempestClients.cinder().volumes.create(name=name,
|
||||
size=size)
|
||||
time.sleep(2)
|
||||
TempestClients.cinder().volumes.attach(volume=volume,
|
||||
instance_uuid=instance_id,
|
||||
mountpoint=mount_point)
|
||||
wait_for_status(30, _check_num_volumes, num_volumes=1, state='in-use')
|
||||
time.sleep(2)
|
||||
return volume
|
||||
|
||||
|
||||
def delete_all_volumes():
|
||||
volumes = TempestClients.cinder().volumes.list()
|
||||
for volume in volumes:
|
||||
try:
|
||||
TempestClients.cinder().volumes.detach(volume)
|
||||
TempestClients.cinder().volumes.force_delete(volume)
|
||||
except Exception:
|
||||
TempestClients.cinder().volumes.force_delete(volume)
|
||||
wait_for_status(30, _check_num_volumes, num_volumes=0)
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
def _check_num_volumes(num_volumes=0, state=''):
|
||||
if len(TempestClients.cinder().volumes.list()) != num_volumes:
|
||||
return False
|
||||
|
||||
return all(volume.__dict__['status'].upper() == state.upper() and
|
||||
len(volume.__dict__['attachments']) == 1
|
||||
for volume in TempestClients.cinder().volumes.list())
|
@ -1,44 +0,0 @@
|
||||
# Copyright 2017 - 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 os import path
|
||||
import six
|
||||
|
||||
|
||||
def first_match(list_of_dicts, **kwargs):
|
||||
subset_dict = _remove_none_values(**kwargs)
|
||||
for d in list_of_dicts:
|
||||
if is_subset(subset_dict, d):
|
||||
return d
|
||||
|
||||
|
||||
def all_matches(list_of_dicts, **kwargs):
|
||||
subset_dict = _remove_none_values(**kwargs)
|
||||
return [d for d in list_of_dicts if is_subset(subset_dict, d)]
|
||||
|
||||
|
||||
def is_subset(subset, full):
|
||||
if not subset:
|
||||
return True
|
||||
full_dict = full
|
||||
if type(full) is not dict:
|
||||
full_dict = full.__dict__
|
||||
return six.viewitems(subset) <= six.viewitems(full_dict)
|
||||
|
||||
|
||||
def _remove_none_values(**kwargs):
|
||||
return {k: v for k, v in kwargs.items() if v is not None}
|
||||
|
||||
|
||||
def tempest_resources_dir():
|
||||
return path.join(path.dirname(path.dirname(__file__)), 'resources')
|
@ -1,18 +0,0 @@
|
||||
# Copyright 2017 - 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 vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
|
||||
|
||||
def get_first_image():
|
||||
return TempestClients.glance().images.list().next()
|
@ -1,61 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import time
|
||||
|
||||
from heatclient.common import http
|
||||
from heatclient.common import template_utils
|
||||
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.utils import wait_for_status
|
||||
|
||||
|
||||
def create_stacks(num_stacks, nested, template_file):
|
||||
tpl_files, template = template_utils.process_template_path(
|
||||
template_file,
|
||||
object_request=http.authenticated_fetcher(TempestClients.heat()))
|
||||
|
||||
for i in range(num_stacks):
|
||||
stack_name = 'stack_%s' % i + ('_nested' if nested else '')
|
||||
TempestClients.heat().stacks.create(stack_name=stack_name,
|
||||
template=template,
|
||||
files=tpl_files,
|
||||
parameters={})
|
||||
wait_for_status(45,
|
||||
_check_num_stacks,
|
||||
num_stacks=num_stacks,
|
||||
state='CREATE_COMPLETE')
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
def delete_all_stacks():
|
||||
stacks = TempestClients.heat().stacks.list()
|
||||
for stack in stacks:
|
||||
try:
|
||||
TempestClients.heat().stacks.delete(stack.to_dict()['id'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
wait_for_status(30, _check_num_stacks, num_stacks=0)
|
||||
time.sleep(4)
|
||||
|
||||
|
||||
def _check_num_stacks(num_stacks, state=''):
|
||||
stacks_list = \
|
||||
[stack.to_dict() for stack in TempestClients.heat().stacks.list()
|
||||
if 'FAILED' not in stack.to_dict()['stack_status']]
|
||||
if len(stacks_list) != num_stacks:
|
||||
return False
|
||||
|
||||
return all(stack['stack_status'].upper() == state.upper()
|
||||
for stack in stacks_list)
|
@ -1,20 +0,0 @@
|
||||
# Copyright 2017 - 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 vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
|
||||
|
||||
def get_public_network():
|
||||
nets = TempestClients.neutron().list_networks()
|
||||
return g_utils.first_match(nets['networks'], name='public')
|
@ -1,67 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import time
|
||||
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common import glance_utils
|
||||
from vitrage_tempest_tests.tests.common import neutron_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.utils import wait_for_status
|
||||
|
||||
|
||||
def create_instances(num_instances=1, set_public_network=False, name='vm'):
|
||||
nics = []
|
||||
flavor = get_first_flavor()
|
||||
image = glance_utils.get_first_image()
|
||||
if set_public_network:
|
||||
public_net = neutron_utils.get_public_network()
|
||||
if public_net:
|
||||
nics = [{'net-id': public_net['id']}]
|
||||
|
||||
resources = [TempestClients.nova().servers.create(
|
||||
name='%s-%s' % (name, index),
|
||||
flavor=flavor,
|
||||
image=image,
|
||||
nics=nics) for index in range(num_instances)]
|
||||
wait_for_status(30, _check_num_instances, num_instances=num_instances,
|
||||
state='active')
|
||||
time.sleep(2)
|
||||
return resources
|
||||
|
||||
|
||||
def delete_all_instances(**kwargs):
|
||||
instances = TempestClients.nova().servers.list()
|
||||
instances_to_delete = g_utils.all_matches(instances, **kwargs)
|
||||
for item in instances_to_delete:
|
||||
try:
|
||||
TempestClients.nova().servers.force_delete(item)
|
||||
except Exception:
|
||||
pass
|
||||
wait_for_status(
|
||||
30,
|
||||
_check_num_instances,
|
||||
num_instances=len(instances) - len(instances_to_delete))
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
def get_first_flavor():
|
||||
return TempestClients.nova().flavors.list()[0]
|
||||
|
||||
|
||||
def _check_num_instances(num_instances=0, state=''):
|
||||
if len(TempestClients.nova().servers.list()) != num_instances:
|
||||
return False
|
||||
|
||||
return all(instance.__dict__['status'].upper() == state.upper()
|
||||
for instance in TempestClients.nova().servers.list())
|
@ -1,123 +0,0 @@
|
||||
# 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 vitrage import keystone_client
|
||||
from vitrage import os_clients
|
||||
from vitrageclient import client as vc
|
||||
|
||||
|
||||
class TempestClients(object):
|
||||
@classmethod
|
||||
def class_init(cls, conf):
|
||||
cls._conf = conf
|
||||
cls._vitrage = None
|
||||
cls._ceilometer = None
|
||||
cls._nova = None
|
||||
cls._cinder = None
|
||||
cls._glance = None
|
||||
cls._neutron = None
|
||||
cls._heat = None
|
||||
cls._mistral = None
|
||||
cls._aodh = None
|
||||
|
||||
@classmethod
|
||||
def vitrage(cls):
|
||||
"""vitrage client
|
||||
|
||||
:rtype: vitrageclient.v1.client.Client
|
||||
"""
|
||||
if not cls._vitrage:
|
||||
cls._vitrage = vc.Client(
|
||||
'1', session=keystone_client.get_session(cls._conf))
|
||||
return cls._vitrage
|
||||
|
||||
@classmethod
|
||||
def ceilometer(cls):
|
||||
"""ceilometer client
|
||||
|
||||
:rtype: ceilometerclient.v2.client.Client
|
||||
"""
|
||||
if not cls._ceilometer:
|
||||
cls._ceilometer = os_clients.ceilometer_client(cls._conf)
|
||||
return cls._ceilometer
|
||||
|
||||
@classmethod
|
||||
def nova(cls):
|
||||
"""nova client
|
||||
|
||||
:rtype: novaclient.v2.client.Client
|
||||
"""
|
||||
if not cls._nova:
|
||||
cls._nova = os_clients.nova_client(cls._conf)
|
||||
return cls._nova
|
||||
|
||||
@classmethod
|
||||
def cinder(cls):
|
||||
"""cinder client
|
||||
|
||||
:rtype: cinderclient.v2.client.Client
|
||||
"""
|
||||
if not cls._cinder:
|
||||
cls._cinder = os_clients.cinder_client(cls._conf)
|
||||
return cls._cinder
|
||||
|
||||
@classmethod
|
||||
def glance(cls):
|
||||
"""glance client
|
||||
|
||||
:rtype: glanceclient.v2.client.Client
|
||||
"""
|
||||
if not cls._glance:
|
||||
cls._glance = os_clients.glance_client(cls._conf)
|
||||
return cls._glance
|
||||
|
||||
@classmethod
|
||||
def neutron(cls):
|
||||
"""neutron client
|
||||
|
||||
:rtype: neutronclient.v2_0.client.Client
|
||||
"""
|
||||
if not cls._neutron:
|
||||
cls._neutron = os_clients.neutron_client(cls._conf)
|
||||
return cls._neutron
|
||||
|
||||
@classmethod
|
||||
def heat(cls):
|
||||
"""heat client
|
||||
|
||||
:rtype: heatclient.v1.client.Client
|
||||
"""
|
||||
if not cls._heat:
|
||||
cls._heat = os_clients.heat_client(cls._conf)
|
||||
return cls._heat
|
||||
|
||||
@classmethod
|
||||
def mistral(cls):
|
||||
"""mistral client
|
||||
|
||||
:rtype: mistralclient.v2.client.Client
|
||||
"""
|
||||
if not cls._mistral:
|
||||
cls._mistral = os_clients.mistral_client(cls._conf)
|
||||
return cls._mistral
|
||||
|
||||
@classmethod
|
||||
def aodh(cls):
|
||||
"""aodh client
|
||||
|
||||
:rtype: aodhclient.v2.client.Client
|
||||
"""
|
||||
if not cls._aodh:
|
||||
cls._aodh = os_clients.aodh_client(cls._conf)
|
||||
return cls._aodh
|
@ -1,87 +0,0 @@
|
||||
# Copyright 2017 - 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 datetime import datetime
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import TemplateStatus
|
||||
from vitrage.common.constants import TemplateTypes
|
||||
from vitrage.datasources import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.utils import wait_for_status
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
DOWN = 'down'
|
||||
UP = 'up'
|
||||
|
||||
|
||||
def generate_fake_host_alarm(hostname, event_type, enabled=True):
|
||||
details = {
|
||||
'hostname': hostname,
|
||||
'source': 'fake_tempest_monitor',
|
||||
'cause': 'another alarm',
|
||||
'severity': 'critical',
|
||||
'status': DOWN if enabled else UP,
|
||||
'monitor_id': 'fake tempest monitor id',
|
||||
'monitor_event_id': '111',
|
||||
}
|
||||
event_time = datetime.now()
|
||||
event_time_iso = event_time.isoformat()
|
||||
TempestClients.vitrage().event.post(event_time_iso, event_type, details)
|
||||
|
||||
|
||||
def get_first_host(**kwargs):
|
||||
try:
|
||||
hosts = TempestClients.vitrage().resource.list(
|
||||
NOVA_HOST_DATASOURCE, all_tenants=True)
|
||||
except Exception as e:
|
||||
LOG.exception("get_first_host failed with %s", e)
|
||||
hosts = TempestClients.vitrage().resource.list(
|
||||
NOVA_HOST_DATASOURCE, all_tenants=True)
|
||||
return g_utils.first_match(hosts, **kwargs)
|
||||
|
||||
|
||||
def get_first_instance(**kwargs):
|
||||
instances = TempestClients.vitrage().resource.list(
|
||||
NOVA_INSTANCE_DATASOURCE, all_tenants=True)
|
||||
return g_utils.first_match(instances, **kwargs)
|
||||
|
||||
|
||||
def add_template(filename='',
|
||||
folder='templates/api',
|
||||
template_type=TemplateTypes.STANDARD):
|
||||
full_path = g_utils.tempest_resources_dir() + '/' + folder + '/' + filename
|
||||
t = TempestClients.vitrage().template.add(full_path, template_type)
|
||||
if t and t[0]:
|
||||
wait_for_status(
|
||||
10,
|
||||
get_first_template,
|
||||
uuid=t[0]['uuid'], status=TemplateStatus.ACTIVE)
|
||||
return t[0]
|
||||
return None
|
||||
|
||||
|
||||
def get_first_template(**kwargs):
|
||||
templates = TempestClients.vitrage().template.list()
|
||||
return g_utils.first_match(templates, **kwargs)
|
||||
|
||||
|
||||
def delete_template(uuid):
|
||||
TempestClients.vitrage().template.delete(uuid)
|
||||
wait_for_status(
|
||||
10,
|
||||
lambda _id: True if not get_first_template(uuid=_id) else False,
|
||||
_id=uuid)
|
@ -1,14 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
__author__ = 'stack'
|
@ -1,137 +0,0 @@
|
||||
# Copyright 2017 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.
|
||||
|
||||
import datetime
|
||||
import six
|
||||
|
||||
from oslo_log import log as logging
|
||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||
from vitrage.datasources import NEUTRON_PORT_DATASOURCE
|
||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
||||
from vitrage import storage
|
||||
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
INSTANCE_NAME = 'test-persistor-vm'
|
||||
|
||||
INSTANCE_CREATE_EVENT = {
|
||||
DSProps.ENTITY_TYPE: NOVA_INSTANCE_DATASOURCE,
|
||||
DSProps.EVENT_TYPE: 'compute.instance.create.end',
|
||||
'hostname': INSTANCE_NAME + '-0'
|
||||
}
|
||||
|
||||
PORT_CREATE_EVENT = {
|
||||
DSProps.ENTITY_TYPE: NEUTRON_PORT_DATASOURCE,
|
||||
DSProps.EVENT_TYPE: 'port.create.end',
|
||||
}
|
||||
|
||||
PORT_UPDATE_EVENT = {
|
||||
DSProps.ENTITY_TYPE: NEUTRON_PORT_DATASOURCE,
|
||||
DSProps.EVENT_TYPE: 'port.update.end',
|
||||
}
|
||||
|
||||
|
||||
def get_first_match(events, event):
|
||||
for curr_event in events:
|
||||
if six.viewitems(event) <= six.viewitems(curr_event.payload):
|
||||
return curr_event
|
||||
|
||||
|
||||
class TestEvents(BaseVitrageTempest):
|
||||
"""Test class for Vitrage persisror service"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestEvents, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestEvents, self).tearDown()
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestEvents, cls).setUpClass()
|
||||
cls.db_connection = storage.get_connection_from_config(cls.conf)
|
||||
|
||||
def test_create_instance(self):
|
||||
"""This function validates creating instance events.
|
||||
|
||||
Create instance generates three ordered events.
|
||||
1. neutron port is created.
|
||||
2. the port is updated to the created instance.
|
||||
3. nova instance is created with the given hostname.
|
||||
"""
|
||||
try:
|
||||
|
||||
# Action
|
||||
time_before_action = datetime.datetime.utcnow()
|
||||
nova_utils.create_instances(num_instances=1,
|
||||
name=INSTANCE_NAME,
|
||||
set_public_network=True)
|
||||
|
||||
writen_events = self._load_db_events(time_before_action)
|
||||
|
||||
port_create_event = get_first_match(writen_events,
|
||||
PORT_CREATE_EVENT)
|
||||
|
||||
self.assertIsNotNone(port_create_event,
|
||||
"port.create.end event is not writen to db")
|
||||
|
||||
port_update_event = get_first_match(writen_events,
|
||||
PORT_UPDATE_EVENT)
|
||||
|
||||
self.assertIsNotNone(port_update_event,
|
||||
"port.update.end event is not writen to db")
|
||||
|
||||
instance_create_event = get_first_match(writen_events,
|
||||
INSTANCE_CREATE_EVENT)
|
||||
|
||||
self.assertIsNotNone(instance_create_event,
|
||||
"compute.instance.create.end event is not "
|
||||
"writen to db")
|
||||
|
||||
# Check correct timestamp order
|
||||
events_timestamp_list = \
|
||||
[port_create_event.collector_timestamp,
|
||||
port_update_event.collector_timestamp,
|
||||
instance_create_event.collector_timestamp]
|
||||
|
||||
self.assertEqual(sorted(events_timestamp_list),
|
||||
events_timestamp_list,
|
||||
"Events Timestamp order is wrong")
|
||||
|
||||
# Check correct event_id order
|
||||
events_id_list = \
|
||||
[port_create_event.event_id,
|
||||
port_update_event.event_id,
|
||||
instance_create_event.event_id]
|
||||
|
||||
self.assertEqual(sorted(events_id_list),
|
||||
events_id_list,
|
||||
"Events id order is wrong")
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
|
||||
finally:
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
def _load_db_events(self, time_before_action):
|
||||
writen_events = self.db_connection.events.query(
|
||||
gt_collector_timestamp=time_before_action)
|
||||
|
||||
return writen_events
|
@ -1,15 +0,0 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,107 +0,0 @@
|
||||
# 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 oslo_log import log as logging
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
from vitrage_tempest_tests.tests.api.alarms.base import BaseAlarmsTest
|
||||
from vitrage_tempest_tests.tests.common import aodh_utils
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestAodhAlarm(BaseAlarmsTest):
|
||||
NUM_INSTANCE = 1
|
||||
NUM_ALARM = 1
|
||||
|
||||
def setUp(self):
|
||||
super(TestAodhAlarm, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestAodhAlarm, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestAodhAlarm, cls).setUpClass()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_alarm_with_resource_id(self):
|
||||
try:
|
||||
# Action
|
||||
nova_utils.create_instances(num_instances=self.NUM_INSTANCE)
|
||||
aodh_utils.create_aodh_alarm(
|
||||
self._find_instance_resource_id())
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=1 + self.NUM_INSTANCE,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=2 * self.NUM_INSTANCE + self.NUM_ALARM,
|
||||
aodh_entities=self.NUM_ALARM,
|
||||
aodh_edges=self.NUM_ALARM)
|
||||
num_entities = self.num_default_entities + \
|
||||
2 * self.NUM_INSTANCE + self.NUM_ALARM + \
|
||||
self.num_default_networks + self.num_default_ports
|
||||
num_edges = self.num_default_edges + 3 * self.NUM_INSTANCE + \
|
||||
self.NUM_ALARM + self.num_default_ports
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
aodh_utils.delete_all_aodh_alarms()
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_alarm_without_resource_id(self):
|
||||
try:
|
||||
# Action
|
||||
aodh_utils.create_aodh_alarm()
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=1,
|
||||
aodh_entities=self.NUM_ALARM,
|
||||
aodh_edges=0)
|
||||
num_entities = self.num_default_entities + self.NUM_ALARM + \
|
||||
self.num_default_networks + self.num_default_ports
|
||||
num_edges = self.num_default_edges + self.num_default_ports
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
aodh_utils.delete_all_aodh_alarms()
|
||||
|
||||
def _find_instance_resource_id(self):
|
||||
servers = TempestClients.nova().servers.list()
|
||||
return servers[0].id
|
@ -1,68 +0,0 @@
|
||||
# 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 oslo_log import log as logging
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestCinderVolume(BaseTopologyTest):
|
||||
NUM_INSTANCE = 3
|
||||
NUM_VOLUME = 1
|
||||
|
||||
def setUp(self):
|
||||
super(TestCinderVolume, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestCinderVolume, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestCinderVolume, cls).setUpClass()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_volume(self):
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE,
|
||||
num_volumes=self.NUM_VOLUME)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=self.NUM_INSTANCE + 1,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=2 * self.NUM_INSTANCE + self.NUM_VOLUME,
|
||||
volume_entities=self.NUM_VOLUME,
|
||||
volume_edges=self.NUM_VOLUME)
|
||||
num_entities = self.num_default_entities + self.NUM_VOLUME + \
|
||||
2 * self.NUM_INSTANCE + self.num_default_ports + \
|
||||
self.num_default_networks
|
||||
num_edges = self.num_default_edges + 3 * self.NUM_INSTANCE + \
|
||||
self.NUM_VOLUME + self.num_default_ports
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
@ -1,86 +0,0 @@
|
||||
# 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 oslo_log import log as logging
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
from vitrage_tempest_tests.tests.common.general_utils\
|
||||
import tempest_resources_dir
|
||||
from vitrage_tempest_tests.tests.common import heat_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestHeatStack(BaseTopologyTest):
|
||||
NUM_STACKS = 1
|
||||
|
||||
def setUp(self):
|
||||
super(TestHeatStack, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestHeatStack, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestHeatStack, cls).setUpClass()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_nested_heat_stack(self):
|
||||
self._test_heat_stack(nested=True,
|
||||
tmpl_file='heat_nested_template.yaml')
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_heat_stack(self):
|
||||
self._test_heat_stack(nested=False, tmpl_file='heat_template.yaml')
|
||||
|
||||
def _test_heat_stack(self, nested, tmpl_file):
|
||||
"""heat stack test
|
||||
|
||||
This test validate correctness topology graph with heat stack module
|
||||
"""
|
||||
template_file = tempest_resources_dir() + '/heat/' + tmpl_file
|
||||
try:
|
||||
# Action
|
||||
heat_utils.create_stacks(self.NUM_STACKS, nested, template_file)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=1 + self.NUM_STACKS,
|
||||
instance_entities=self.NUM_STACKS,
|
||||
instance_edges=3 * self.NUM_STACKS,
|
||||
network_entities=self.num_default_networks,
|
||||
network_edges=self.num_default_ports + self.NUM_STACKS,
|
||||
port_entities=self.num_default_ports + self.NUM_STACKS,
|
||||
port_edges=self.num_default_ports + 2 * self.NUM_STACKS,
|
||||
stack_entities=self.NUM_STACKS,
|
||||
stack_edges=self.NUM_STACKS)
|
||||
num_entities = self.num_default_entities + 3 * self.NUM_STACKS + \
|
||||
self.num_default_networks + self.num_default_ports
|
||||
num_edges = self.num_default_edges + 4 * self.NUM_STACKS + \
|
||||
self.num_default_ports
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
heat_utils.delete_all_stacks()
|
@ -1,110 +0,0 @@
|
||||
# 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 oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestNeutron(BaseTopologyTest):
|
||||
NUM_INSTANCE = 3
|
||||
|
||||
def setUp(self):
|
||||
super(TestNeutron, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestNeutron, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestNeutron, cls).setUpClass()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_neutron(self):
|
||||
"""neutron test
|
||||
|
||||
This test validate correctness topology graph with neutron module
|
||||
"""
|
||||
|
||||
try:
|
||||
# Action
|
||||
nova_utils.create_instances(num_instances=self.NUM_INSTANCE,
|
||||
set_public_network=True)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=1 + self.NUM_INSTANCE,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=2 * self.NUM_INSTANCE,
|
||||
network_entities=self.num_default_networks,
|
||||
network_edges=self.num_default_ports + self.NUM_INSTANCE,
|
||||
port_entities=self.num_default_ports + self.NUM_INSTANCE,
|
||||
port_edges=self.num_default_ports + 2 * self.NUM_INSTANCE)
|
||||
num_entities = self.num_default_entities + \
|
||||
2 * self.NUM_INSTANCE + \
|
||||
self.num_default_networks + self.num_default_ports
|
||||
num_edges = self.num_default_edges + 3 * self.NUM_INSTANCE + \
|
||||
self.num_default_ports
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
nova_utils.delete_all_instances()
|
||||
|
||||
@staticmethod
|
||||
def _get_network_name(instance, networks):
|
||||
for network in networks:
|
||||
try:
|
||||
if len(instance.networks[network[VProps.NAME]]) > 0:
|
||||
return network[VProps.NAME]
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _port_to_inst_edges(instances, network_name, ports):
|
||||
counter = 0
|
||||
for vm in instances:
|
||||
for port in ports:
|
||||
ips_number = 0
|
||||
for vm_ip in vm.addresses[network_name]:
|
||||
for port_ip in port['fixed_ips']:
|
||||
if vm_ip['addr'] == port_ip['ip_address']:
|
||||
ips_number += 1
|
||||
break
|
||||
if ips_number == len(vm.addresses[network_name]):
|
||||
counter += 1
|
||||
break
|
||||
return counter
|
||||
|
||||
def _port_to_network_edges(self, networks, ports):
|
||||
counter = 0
|
||||
for net in networks:
|
||||
counter += len(g_utils.all_matches(ports, network_id=net['id']))
|
||||
return counter
|
@ -1,64 +0,0 @@
|
||||
# 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 oslo_log import log as logging
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestNova(BaseTopologyTest):
|
||||
NUM_INSTANCE = 3
|
||||
|
||||
def setUp(self):
|
||||
super(TestNova, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestNova, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestNova, cls).setUpClass()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_nova_entities(self):
|
||||
try:
|
||||
# Action
|
||||
self._create_entities(num_instances=self.NUM_INSTANCE)
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=1 + self.NUM_INSTANCE,
|
||||
instance_entities=self.NUM_INSTANCE,
|
||||
instance_edges=2 * self.NUM_INSTANCE)
|
||||
num_entities = self.num_default_entities + \
|
||||
2 * self.NUM_INSTANCE + \
|
||||
self.num_default_networks + self.num_default_ports
|
||||
num_edges = self.num_default_edges + 3 * self.NUM_INSTANCE + \
|
||||
self.num_default_ports
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default()
|
@ -1,98 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import socket
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
|
||||
from vitrage_tempest_tests.tests.common.general_utils \
|
||||
import tempest_resources_dir
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestStaticPhysical(BaseVitrageTempest):
|
||||
NUM_SWITCH = 2
|
||||
|
||||
def setUp(self):
|
||||
super(TestStaticPhysical, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestStaticPhysical, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestStaticPhysical, cls).setUpClass()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_switches(self):
|
||||
try:
|
||||
# Action
|
||||
self._create_switches()
|
||||
|
||||
# Calculate expected results
|
||||
api_graph = self.vitrage_client.topology.get(all_tenants=True)
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1,
|
||||
host_edges=1 + self.NUM_SWITCH,
|
||||
switch_entities=self.NUM_SWITCH,
|
||||
switch_edges=self.NUM_SWITCH)
|
||||
num_entities = self.num_default_entities + self.NUM_SWITCH + \
|
||||
self.num_default_networks + self.num_default_ports
|
||||
num_edges = self.num_default_edges + self.NUM_SWITCH + \
|
||||
self.num_default_ports
|
||||
|
||||
# Test Assertions
|
||||
self._validate_graph_correctness(graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._delete_switches()
|
||||
|
||||
@staticmethod
|
||||
def _create_switches():
|
||||
hostname = socket.gethostname()
|
||||
|
||||
# template file
|
||||
resources_path = tempest_resources_dir() + '/static_physical/'
|
||||
file_path = resources_path + '/static_physical_configuration.yaml'
|
||||
with open(file_path, 'r') as f:
|
||||
template_data = f.read()
|
||||
template_data = template_data.replace('tmp-devstack', hostname)
|
||||
|
||||
# new file
|
||||
new_file = open(
|
||||
'/etc/vitrage/static_datasources/'
|
||||
'static_physical_configuration.yaml', 'w')
|
||||
new_file.write(template_data)
|
||||
new_file.close()
|
||||
|
||||
time.sleep(25)
|
||||
|
||||
@staticmethod
|
||||
def _delete_switches():
|
||||
path = '/etc/vitrage/static_datasources/' \
|
||||
'static_physical_configuration.yaml'
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
time.sleep(25)
|
@ -1,15 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,80 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.common import vitrage_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestActionsBase(BaseVitrageTempest):
|
||||
def setUp(self):
|
||||
super(TestActionsBase, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestActionsBase, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestActionsBase, cls).setUpClass()
|
||||
host = vitrage_utils.get_first_host()
|
||||
if not host:
|
||||
raise Exception("No host found")
|
||||
if not host.get(VProps.VITRAGE_AGGREGATED_STATE) == 'AVAILABLE':
|
||||
raise Exception("Host is not running %s", str(host))
|
||||
cls.orig_host = host
|
||||
|
||||
def _trigger_do_action(self, trigger_name):
|
||||
vitrage_utils.generate_fake_host_alarm(
|
||||
self.orig_host.get('name'),
|
||||
enabled=True,
|
||||
event_type=trigger_name
|
||||
)
|
||||
time.sleep(2)
|
||||
|
||||
def _trigger_undo_action(self, trigger_name):
|
||||
vitrage_utils.generate_fake_host_alarm(
|
||||
self.orig_host.get('name'),
|
||||
enabled=False,
|
||||
event_type=trigger_name
|
||||
)
|
||||
time.sleep(2)
|
||||
|
||||
def _check_deduced(self, deduced_count, deduced_props, resource_id):
|
||||
alarms = TempestClients.vitrage().alarm.list(
|
||||
vitrage_id=resource_id,
|
||||
all_tenants=True)
|
||||
deduces = g_utils.all_matches(alarms, **deduced_props)
|
||||
self.assertEqual(
|
||||
deduced_count,
|
||||
len(deduces),
|
||||
'Expected %s deduces\n - \n%s\n - \n%s' %
|
||||
(str(deduced_count), str(alarms), str(deduces)))
|
||||
|
||||
def _check_rca(self, rca, expected_alarms, inspected):
|
||||
self.assertEqual(len(expected_alarms), len(rca['nodes']))
|
||||
for expected_alarm in expected_alarms:
|
||||
self.assertIsNotNone(
|
||||
g_utils.first_match(rca['nodes'], **expected_alarm),
|
||||
'expected_alarm is not in the rca %s' % str(expected_alarm))
|
||||
rca_inspected = rca['nodes'][rca['inspected_index']]
|
||||
self.assertTrue(g_utils.is_subset(inspected, rca_inspected),
|
||||
'Invalid inspected item \n%s\n%s' %
|
||||
(str(rca_inspected), str(inspected)))
|
@ -1,203 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources.doctor import DOCTOR_DATASOURCE
|
||||
from vitrage.evaluator.actions.evaluator_event_transformer import \
|
||||
VITRAGE_DATASOURCE
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common import nova_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.common import vitrage_utils
|
||||
from vitrage_tempest_tests.tests.e2e.test_actions_base import TestActionsBase
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
TRIGGER_ALARM_1 = 'e2e.test_basic_actions.trigger.alarm1'
|
||||
TRIGGER_ALARM_2 = 'e2e.test_basic_actions.trigger.alarm2'
|
||||
TRIGGER_ALARM_3 = 'e2e.test_basic_actions.trigger.alarm3'
|
||||
TRIGGER_ALARM_4 = 'e2e.test_basic_actions.trigger.alarm4'
|
||||
DEDUCED = 'e2e.test_basic_actions.deduced.alarm'
|
||||
|
||||
TRIGGER_ALARM_2_PROPS = {
|
||||
VProps.NAME: TRIGGER_ALARM_2,
|
||||
VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
|
||||
VProps.VITRAGE_TYPE: DOCTOR_DATASOURCE,
|
||||
}
|
||||
|
||||
DEDUCED_PROPS = {
|
||||
VProps.NAME: DEDUCED,
|
||||
VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
|
||||
VProps.VITRAGE_TYPE: VITRAGE_DATASOURCE,
|
||||
}
|
||||
|
||||
|
||||
class TestBasicActions(TestActionsBase):
|
||||
def setUp(self):
|
||||
super(TestBasicActions, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestBasicActions, self).tearDown()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_action_set_state_host(self):
|
||||
try:
|
||||
|
||||
# Do
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
curr_host = vitrage_utils.get_first_host()
|
||||
self.assertEqual(
|
||||
'ERROR',
|
||||
curr_host.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
'state should change after set_state action')
|
||||
|
||||
# Undo
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
curr_host = vitrage_utils.get_first_host()
|
||||
self.assertEqual(
|
||||
self.orig_host.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
curr_host.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
'state should change after undo set_state action')
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_action_set_state_instance(self):
|
||||
|
||||
vm_id = ""
|
||||
try:
|
||||
vm_id = nova_utils.create_instances(set_public_network=True)[0].id
|
||||
|
||||
# Do
|
||||
orig_instance = vitrage_utils.get_first_instance(id=vm_id)
|
||||
self._trigger_do_action(TRIGGER_ALARM_3)
|
||||
curr_instance = vitrage_utils.get_first_instance(id=vm_id)
|
||||
self.assertEqual(
|
||||
'ERROR',
|
||||
curr_instance.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
'state should change after set_state action')
|
||||
|
||||
# Undo
|
||||
self._trigger_undo_action(TRIGGER_ALARM_3)
|
||||
curr_instance = vitrage_utils.get_first_instance(id=vm_id)
|
||||
self.assertEqual(
|
||||
orig_instance.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
curr_instance.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
'state should change after undo set_state action')
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_3)
|
||||
nova_utils.delete_all_instances(id=vm_id)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_action_mark_down_host(self):
|
||||
try:
|
||||
host_name = self.orig_host.get(VProps.NAME)
|
||||
|
||||
# Do
|
||||
self._trigger_do_action(TRIGGER_ALARM_4)
|
||||
nova_service = TempestClients.nova().services.list(
|
||||
host=host_name, binary='nova-compute')[0]
|
||||
self.assertEqual("down", str(nova_service.state))
|
||||
|
||||
# Undo
|
||||
self._trigger_undo_action(TRIGGER_ALARM_4)
|
||||
nova_service = TempestClients.nova().services.list(
|
||||
host=host_name, binary='nova-compute')[0]
|
||||
self.assertEqual("up", str(nova_service.state))
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_4)
|
||||
# nova.host datasource may take up to snapshot_intreval to update
|
||||
time.sleep(130)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_action_mark_down_instance(self):
|
||||
vm_id = ""
|
||||
try:
|
||||
vm_id = nova_utils.create_instances(set_public_network=True)[0].id
|
||||
# Do
|
||||
self._trigger_do_action(TRIGGER_ALARM_3)
|
||||
nova_instance = TempestClients.nova().servers.get(vm_id)
|
||||
self.assertEqual("ERROR", str(nova_instance.status))
|
||||
|
||||
# Undo
|
||||
self._trigger_undo_action(TRIGGER_ALARM_3)
|
||||
nova_instance = TempestClients.nova().servers.get(vm_id)
|
||||
self.assertEqual("ACTIVE", str(nova_instance.status))
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
pass
|
||||
self._trigger_undo_action(TRIGGER_ALARM_3)
|
||||
nova_utils.delete_all_instances(id=vm_id)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_action_deduce_alarm(self):
|
||||
try:
|
||||
host_id = self.orig_host.get(VProps.VITRAGE_ID)
|
||||
|
||||
# Do
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
self._check_deduced(1, DEDUCED_PROPS, host_id)
|
||||
|
||||
# Undo
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
self._check_deduced(0, DEDUCED_PROPS, host_id)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_action_add_causal_relationship(self):
|
||||
try:
|
||||
# Do
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
alarms = TempestClients.vitrage().alarm.list(
|
||||
vitrage_id=self.orig_host.get(VProps.VITRAGE_ID),
|
||||
all_tenants=True)
|
||||
self.assertTrue(len(alarms) >= 2, 'alarms %s' % str(alarms))
|
||||
|
||||
deduced = g_utils.first_match(alarms, **DEDUCED_PROPS)
|
||||
trigger = g_utils.first_match(alarms, **TRIGGER_ALARM_2_PROPS)
|
||||
|
||||
# Get Rca for the deduced
|
||||
rca = TempestClients.vitrage().rca.get(
|
||||
deduced[VProps.VITRAGE_ID], all_tenants=True)
|
||||
self._check_rca(rca, [deduced, trigger], DEDUCED_PROPS)
|
||||
|
||||
# Get Rca for the trigger
|
||||
rca = TempestClients.vitrage().rca.get(
|
||||
trigger[VProps.VITRAGE_ID], all_tenants=True)
|
||||
self._check_rca(rca, [deduced, trigger], TRIGGER_ALARM_2_PROPS)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
@ -1,189 +0,0 @@
|
||||
# Copyright 2017 - 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 oslo_log import log as logging
|
||||
import time
|
||||
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.evaluator.actions.evaluator_event_transformer import \
|
||||
VITRAGE_DATASOURCE
|
||||
from vitrage_tempest_tests.tests.common import vitrage_utils as v_util
|
||||
from vitrage_tempest_tests.tests.e2e.test_actions_base import TestActionsBase
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
TRIGGER_ALARM_1 = 'e2e.test_template_actions.trigger.alarm1'
|
||||
DEDUCED = 'e2e.test_template_actions.deduced.alarm'
|
||||
|
||||
TRIGGER_ALARM_2 = 'e2e.test_template_actions.trigger.alarm2'
|
||||
DEDUCED_2 = 'e2e.test_template_actions.deduced.alarm2'
|
||||
|
||||
TEST_TEMPLATE = 'e2e_test_template_actions.yaml'
|
||||
TEST_TEMPLATE_2 = 'e2e_test_template_actions_2.yaml'
|
||||
|
||||
INFILE_NAME = 'e2e_test_template_actions'
|
||||
INFILE_NAME_2 = 'e2e_test_template_actions_2'
|
||||
|
||||
|
||||
FOLDER_PATH = 'templates/api/e2e_test_template'
|
||||
|
||||
DEDUCED_PROPS = {
|
||||
VProps.NAME: DEDUCED,
|
||||
VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
|
||||
VProps.VITRAGE_TYPE: VITRAGE_DATASOURCE,
|
||||
}
|
||||
|
||||
DEDUCED_PROPS_2 = {
|
||||
VProps.NAME: DEDUCED_2,
|
||||
VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
|
||||
VProps.VITRAGE_TYPE: VITRAGE_DATASOURCE,
|
||||
}
|
||||
|
||||
|
||||
class TestTemplateActions(TestActionsBase):
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
super(TestTemplateActions, self).__init__(*args, **kwds)
|
||||
self.added_template = None
|
||||
|
||||
def setUp(self):
|
||||
super(TestTemplateActions, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestTemplateActions, self).tearDown()
|
||||
time.sleep(10)
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
if self.added_template is not None:
|
||||
v_util.delete_template(self.added_template['uuid'])
|
||||
self.added_template = None
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_evaluator_reload_with_new_template(self):
|
||||
"""Test reload new template e2e
|
||||
|
||||
1. raise trigger alarm (template is not loaded yet)
|
||||
2. add the relevant template
|
||||
3. check action is executed
|
||||
This checks that the evaluators are reloaded and run on all existing
|
||||
vertices.
|
||||
"""
|
||||
try:
|
||||
host_id = self.orig_host.get(VProps.VITRAGE_ID)
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
self.added_template = v_util.add_template(TEST_TEMPLATE,
|
||||
folder=FOLDER_PATH)
|
||||
self._check_deduced(1, DEDUCED_PROPS, host_id)
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_evaluator_reload_with_existing_template(self):
|
||||
"""Test reload new template e2e
|
||||
|
||||
1.add the relevant template
|
||||
2.raise trigger alarm.
|
||||
3. check action is executed
|
||||
This checks that new workers execute new template
|
||||
"""
|
||||
try:
|
||||
host_id = self.orig_host.get(VProps.VITRAGE_ID)
|
||||
self.added_template = v_util.add_template(TEST_TEMPLATE,
|
||||
folder=FOLDER_PATH)
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
self._check_deduced(1, DEDUCED_PROPS, host_id)
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_evaluator_reload_with_new_template_v2(self):
|
||||
"""Test reload new template e2e v2
|
||||
|
||||
1. raise trigger alarm
|
||||
2. add the relevant template
|
||||
3. delete the template.
|
||||
4. check action - should be not active.
|
||||
This checks that the evaluators are reloaded and run on all existing
|
||||
vertices.
|
||||
Checks temporary worker that was added to delete template.
|
||||
"""
|
||||
try:
|
||||
host_id = self.orig_host.get(VProps.VITRAGE_ID)
|
||||
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
self.added_template = v_util.add_template(TEST_TEMPLATE,
|
||||
folder=FOLDER_PATH)
|
||||
self._check_deduced(1, DEDUCED_PROPS, host_id)
|
||||
v_util.delete_template(self.added_template['uuid'])
|
||||
self.added_template = None
|
||||
self._check_deduced(0, DEDUCED_PROPS, host_id)
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_evaluator_reload_with_existing_template_v2(self):
|
||||
"""Test reload new template e2e v2
|
||||
|
||||
1.add the relevant template
|
||||
2.delete the template
|
||||
2.raise trigger alarm.
|
||||
3. check no deduced alarm
|
||||
This checks that template deleted properly and no action executed.
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
host_id = self.orig_host.get(VProps.VITRAGE_ID)
|
||||
self.added_template = v_util.add_template(TEST_TEMPLATE,
|
||||
folder=FOLDER_PATH)
|
||||
v_util.delete_template(self.added_template['uuid'])
|
||||
self.added_template = None
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
self._check_deduced(0, DEDUCED_PROPS, host_id)
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_evaluator_reload_with_multiple_new_template(self):
|
||||
"""Test reload new template e2e
|
||||
|
||||
1. raise trigger alarm (template is not loaded yet)
|
||||
2. add 2 new templates.
|
||||
3. check both actions are executed
|
||||
This checks that the evaluators are reloaded for both templates
|
||||
and run on all existing vertices.
|
||||
"""
|
||||
try:
|
||||
host_id = self.orig_host.get(VProps.VITRAGE_ID)
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
v_util.add_template(folder=FOLDER_PATH)
|
||||
self.added_template = v_util.get_first_template(name=INFILE_NAME)
|
||||
second_template = v_util.get_first_template(name=INFILE_NAME_2)
|
||||
self._check_deduced(1, DEDUCED_PROPS, host_id)
|
||||
self._check_deduced(1, DEDUCED_PROPS_2, host_id)
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
if second_template:
|
||||
v_util.delete_template(second_template['uuid'])
|
@ -1,271 +0,0 @@
|
||||
# Copyright 2017 - 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 oslo_log import log as logging
|
||||
import requests
|
||||
from six.moves import BaseHTTPServer
|
||||
import socket
|
||||
from threading import Thread
|
||||
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.e2e.test_actions_base import TestActionsBase
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
TRIGGER_ALARM_1 = 'e2e.test_webhook.alarm1'
|
||||
TRIGGER_ALARM_2 = 'e2e.test_webhook.alarm2'
|
||||
TRIGGER_ALARM_WITH_DEDUCED = 'e2e.test_webhook.alarm_with_deduced'
|
||||
URL = 'url'
|
||||
REGEX_FILTER = 'regex_filter'
|
||||
HEADERS = 'headers'
|
||||
HEADERS_PROPS = '{"content": "application/json"}'
|
||||
NAME_FILTER = '{"name": "e2e.*"}'
|
||||
NAME_FILTER_FOR_DEDUCED = '{"name": "e2e.test_webhook.deduced"}'
|
||||
TYPE_FILTER = '{"vitrage_type": "doctor"}'
|
||||
FILTER_NO_MATCH = '{"name": "NO MATCH"}'
|
||||
|
||||
|
||||
class TestWebhook(TestActionsBase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestWebhook, cls).setUpClass()
|
||||
# Configure mock server.
|
||||
cls.mock_server_port = _get_free_port()
|
||||
cls.mock_server = MockHTTPServer(('localhost', cls.mock_server_port),
|
||||
MockServerRequestHandler)
|
||||
|
||||
# Start running mock server in a separate thread.
|
||||
cls.mock_server_thread = Thread(target=cls.mock_server.serve_forever)
|
||||
cls.mock_server_thread.setDaemon(True)
|
||||
cls.mock_server_thread.start()
|
||||
cls.URL_PROPS = 'http://localhost:%s/' % cls.mock_server_port
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_webhook_basic_event(self):
|
||||
|
||||
try:
|
||||
|
||||
# Add webhook with filter matching alarm
|
||||
TempestClients.vitrage().webhook.add(
|
||||
url=self.URL_PROPS,
|
||||
regex_filter=NAME_FILTER,
|
||||
headers=HEADERS_PROPS
|
||||
)
|
||||
|
||||
# Raise alarm
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
|
||||
# Check event received
|
||||
self.assertEqual(1, len(self.mock_server.requests),
|
||||
'Wrong number of notifications for raise alarm')
|
||||
|
||||
# Undo
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
|
||||
# Check event undo received
|
||||
self.assertEqual(2, len(self.mock_server.requests),
|
||||
'Wrong number of notifications for clear alarm')
|
||||
|
||||
finally:
|
||||
self._delete_webhooks()
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
self.mock_server.reset_requests_list()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_webhook_with_no_filter(self):
|
||||
"""Test to see that a webhook with no filter receives all
|
||||
|
||||
notifications
|
||||
"""
|
||||
|
||||
try:
|
||||
|
||||
# Add webhook
|
||||
TempestClients.vitrage().webhook.add(
|
||||
url=self.URL_PROPS,
|
||||
regex_filter=NAME_FILTER,
|
||||
)
|
||||
|
||||
# Raise alarm
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
|
||||
# Check event received
|
||||
self.assertEqual(1, len(self.mock_server.requests),
|
||||
'Wrong number of notifications for raise alarm')
|
||||
|
||||
# Raise another alarm
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
|
||||
# Check second event received
|
||||
self.assertEqual(2, len(self.mock_server.requests),
|
||||
'Wrong number of notifications for clear alarm')
|
||||
|
||||
finally:
|
||||
self._delete_webhooks()
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
self.mock_server.reset_requests_list()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_webhook_with_no_match(self):
|
||||
"""Test to check that filters with no match do not send event """
|
||||
|
||||
try:
|
||||
|
||||
# Add webhook
|
||||
TempestClients.vitrage().webhook.add(
|
||||
url=self.URL_PROPS,
|
||||
regex_filter=FILTER_NO_MATCH,
|
||||
)
|
||||
|
||||
# Raise alarm
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
|
||||
# Check event not received
|
||||
self.assertEqual(0, len(self.mock_server.requests),
|
||||
'event should not have passed filter')
|
||||
|
||||
# Raise another alarm
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
|
||||
# Check second event not received
|
||||
self.assertEqual(0, len(self.mock_server.requests),
|
||||
'event should not have passed filter')
|
||||
|
||||
finally:
|
||||
self._delete_webhooks()
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
self.mock_server.reset_requests_list()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_multiple_webhooks(self):
|
||||
"""Test to check filter by type and by ID (with 2 different
|
||||
|
||||
webhooks)
|
||||
"""
|
||||
|
||||
host_id = self.orig_host[VProps.VITRAGE_ID]
|
||||
ID_FILTER = '{"%s": "%s"}' % (VProps.VITRAGE_RESOURCE_ID, host_id)
|
||||
|
||||
try:
|
||||
|
||||
# Add webhook
|
||||
TempestClients.vitrage().webhook.add(
|
||||
url=self.URL_PROPS,
|
||||
regex_filter=TYPE_FILTER,
|
||||
)
|
||||
|
||||
TempestClients.vitrage().webhook.add(
|
||||
url=self.URL_PROPS,
|
||||
regex_filter=ID_FILTER,
|
||||
)
|
||||
|
||||
# Raise alarm
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
|
||||
# Check event received
|
||||
self.assertEqual(2, len(self.mock_server.requests),
|
||||
'event not posted to all webhooks')
|
||||
|
||||
# Raise another alarm
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
|
||||
# Check second event received
|
||||
self.assertEqual(4, len(self.mock_server.requests),
|
||||
'event not posted to all webhooks')
|
||||
|
||||
finally:
|
||||
self._delete_webhooks()
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
self.mock_server.reset_requests_list()
|
||||
|
||||
# Will be un-commented-out in the next change
|
||||
#
|
||||
# @utils.tempest_logger
|
||||
# def test_webhook_for_deduced_alarm(self):
|
||||
#
|
||||
# try:
|
||||
#
|
||||
# # Add webhook with filter for the deduced alarm
|
||||
# TempestClients.vitrage().webhook.add(
|
||||
# url=self.URL_PROPS,
|
||||
# regex_filter=NAME_FILTER_FOR_DEDUCED,
|
||||
# headers=HEADERS_PROPS
|
||||
# )
|
||||
#
|
||||
# # Raise the trigger alarm
|
||||
# self._trigger_do_action(TRIGGER_ALARM_WITH_DEDUCED)
|
||||
#
|
||||
# # Check event received - expected one for the deduced alarm
|
||||
# # (the trigger alarm does not pass the filter). This test verifies
|
||||
# # that the webhook is called only once for the deduced alarm.
|
||||
# self.assertEqual(1, len(self.mock_server.requests),
|
||||
# 'Wrong number of notifications for deduced alarm')
|
||||
#
|
||||
# # Undo
|
||||
# self._trigger_undo_action(TRIGGER_ALARM_WITH_DEDUCED)
|
||||
#
|
||||
# # Check event undo received
|
||||
# self.assertEqual(2, len(self.mock_server.requests),
|
||||
# 'Wrong number of notifications for clear deduced '
|
||||
# 'alarm')
|
||||
#
|
||||
# finally:
|
||||
# self._delete_webhooks()
|
||||
# self._trigger_undo_action(TRIGGER_ALARM_WITH_DEDUCED)
|
||||
# self.mock_server.reset_requests_list()
|
||||
|
||||
def _delete_webhooks(self):
|
||||
webhooks = TempestClients.vitrage().webhook.list()
|
||||
for webhook in webhooks:
|
||||
TempestClients.vitrage().webhook.delete(webhook['id'])
|
||||
|
||||
|
||||
def _get_free_port():
|
||||
s = socket.socket(socket.AF_INET, type=socket.SOCK_STREAM)
|
||||
s.bind(('localhost', 0))
|
||||
address, port = s.getsockname()
|
||||
s.close()
|
||||
return port
|
||||
|
||||
|
||||
class MockHTTPServer(BaseHTTPServer.HTTPServer):
|
||||
|
||||
def __init__(self, server, handler):
|
||||
BaseHTTPServer.HTTPServer.__init__(self, server, handler)
|
||||
self.requests = []
|
||||
|
||||
def process_request(self, request, client_address):
|
||||
self.requests.append(request)
|
||||
LOG.info('received request: %s', str(request))
|
||||
BaseHTTPServer.HTTPServer.process_request(
|
||||
self, client_address=client_address, request=request)
|
||||
|
||||
def reset_requests_list(self):
|
||||
self.requests = []
|
||||
|
||||
|
||||
class MockServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
||||
def do_POST(self):
|
||||
|
||||
# Process a HTTP Post request and return status code 200
|
||||
self.send_response(requests.codes.ok)
|
||||
self.end_headers()
|
||||
return
|
@ -1,241 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources.doctor import DOCTOR_DATASOURCE
|
||||
from vitrage.evaluator.actions.evaluator_event_transformer import \
|
||||
VITRAGE_DATASOURCE
|
||||
from vitrage_tempest_tests.tests.common import general_utils as g_utils
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests.common import vitrage_utils
|
||||
from vitrage_tempest_tests.tests.e2e.test_actions_base import TestActionsBase
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
TRIGGER_ALARM_1 = 'e2e.test_overlapping_actions.trigger.alarm1'
|
||||
TRIGGER_ALARM_2 = 'e2e.test_overlapping_actions.trigger.alarm2'
|
||||
TRIGGER_ALARM_3 = 'e2e.test_overlapping_actions.trigger.alarm3'
|
||||
TRIGGER_ALARM_4 = 'e2e.test_overlapping_actions.trigger.alarm4'
|
||||
DEDUCED = 'e2e.test_overlapping_actions.deduced.alarm'
|
||||
|
||||
TRIGGER_ALARM_1_PROPS = {
|
||||
VProps.NAME: TRIGGER_ALARM_1,
|
||||
VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
|
||||
VProps.VITRAGE_TYPE: DOCTOR_DATASOURCE,
|
||||
}
|
||||
|
||||
TRIGGER_ALARM_2_PROPS = {
|
||||
VProps.NAME: TRIGGER_ALARM_2,
|
||||
VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
|
||||
VProps.VITRAGE_TYPE: DOCTOR_DATASOURCE,
|
||||
}
|
||||
|
||||
DEDUCED_PROPS = {
|
||||
VProps.NAME: DEDUCED,
|
||||
VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
|
||||
VProps.VITRAGE_TYPE: VITRAGE_DATASOURCE,
|
||||
}
|
||||
|
||||
|
||||
class TestOverlappingActions(TestActionsBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOverlappingActions, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestOverlappingActions, self).tearDown()
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_overlapping_action_set_state(self):
|
||||
try:
|
||||
# Do - first
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
curr_host = vitrage_utils.get_first_host()
|
||||
self.assertEqual(
|
||||
'ERROR',
|
||||
curr_host.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
'state should change after set_state action')
|
||||
|
||||
# Do - second
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
curr_host = vitrage_utils.get_first_host()
|
||||
self.assertEqual(
|
||||
'ERROR',
|
||||
curr_host.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
'state should remain unchanged')
|
||||
|
||||
# Undo - first
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
curr_host = vitrage_utils.get_first_host()
|
||||
self.assertEqual(
|
||||
'ERROR',
|
||||
curr_host.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
'state should remain unchanged')
|
||||
|
||||
# Undo - second
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
curr_host = vitrage_utils.get_first_host()
|
||||
self.assertEqual(
|
||||
self.orig_host.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
curr_host.get(VProps.VITRAGE_AGGREGATED_STATE),
|
||||
'state should change after undo set_state action')
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_overlapping_action_mark_down(self):
|
||||
try:
|
||||
host_name = self.orig_host.get(VProps.NAME)
|
||||
|
||||
# Do - first
|
||||
self._trigger_do_action(TRIGGER_ALARM_3)
|
||||
nova_service = TempestClients.nova().services.list(
|
||||
host=host_name, binary='nova-compute')[0]
|
||||
self.assertEqual("down", str(nova_service.state))
|
||||
|
||||
# Do - second
|
||||
self._trigger_do_action(TRIGGER_ALARM_4)
|
||||
nova_service = TempestClients.nova().services.list(
|
||||
host=host_name, binary='nova-compute')[0]
|
||||
self.assertEqual("down", str(nova_service.state))
|
||||
|
||||
# Undo - first
|
||||
self._trigger_undo_action(TRIGGER_ALARM_3)
|
||||
nova_service = TempestClients.nova().services.list(
|
||||
host=host_name, binary='nova-compute')[0]
|
||||
self.assertEqual("down", str(nova_service.state))
|
||||
|
||||
# Undo - second
|
||||
self._trigger_undo_action(TRIGGER_ALARM_4)
|
||||
nova_service = TempestClients.nova().services.list(
|
||||
host=host_name, binary='nova-compute')[0]
|
||||
self.assertEqual("up", str(nova_service.state))
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_3)
|
||||
self._trigger_undo_action(TRIGGER_ALARM_4)
|
||||
# nova.host datasource may take up to snapshot_intreval to update
|
||||
time.sleep(130)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_overlapping_action_deduce_alarm(self):
|
||||
try:
|
||||
host_id = self.orig_host.get(VProps.VITRAGE_ID)
|
||||
|
||||
# Do - first
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
self._check_deduced(1, DEDUCED_PROPS, host_id)
|
||||
|
||||
# Do - second
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
self._check_deduced(1, DEDUCED_PROPS, host_id)
|
||||
|
||||
# Undo - first
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
self._check_deduced(1, DEDUCED_PROPS, host_id)
|
||||
|
||||
# Undo - second
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
self._check_deduced(0, DEDUCED_PROPS, host_id)
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_overlapping_action_add_causal_relationship(self):
|
||||
try:
|
||||
# ---- Do first & second ----
|
||||
self._trigger_do_action(TRIGGER_ALARM_1)
|
||||
self._trigger_do_action(TRIGGER_ALARM_2)
|
||||
alarms = TempestClients.vitrage().alarm.list(
|
||||
vitrage_id=self.orig_host.get(VProps.VITRAGE_ID),
|
||||
all_tenants=True)
|
||||
|
||||
deduced = g_utils.first_match(alarms, **DEDUCED_PROPS)
|
||||
trigger1 = g_utils.first_match(alarms, **TRIGGER_ALARM_1_PROPS)
|
||||
trigger2 = g_utils.first_match(alarms, **TRIGGER_ALARM_2_PROPS)
|
||||
|
||||
# Get Rca for the deduced
|
||||
rca = TempestClients.vitrage().rca.get(
|
||||
deduced[VProps.VITRAGE_ID], all_tenants=True)
|
||||
self._check_rca(rca, [deduced, trigger1, trigger2], DEDUCED_PROPS)
|
||||
|
||||
# Get Rca for trigger 1
|
||||
rca = TempestClients.vitrage().rca.get(
|
||||
trigger1[VProps.VITRAGE_ID], all_tenants=True)
|
||||
self._check_rca(rca, [deduced, trigger1], TRIGGER_ALARM_1_PROPS)
|
||||
|
||||
# Get Rca for trigger 2
|
||||
rca = TempestClients.vitrage().rca.get(
|
||||
trigger2[VProps.VITRAGE_ID], all_tenants=True)
|
||||
self._check_rca(rca, [deduced, trigger2], TRIGGER_ALARM_2_PROPS)
|
||||
|
||||
# ---- Undo - first ----
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
alarms = TempestClients.vitrage().alarm.list(
|
||||
vitrage_id=self.orig_host.get(VProps.VITRAGE_ID),
|
||||
all_tenants=True)
|
||||
|
||||
deduced = g_utils.first_match(alarms, **DEDUCED_PROPS)
|
||||
trigger2 = g_utils.first_match(alarms, **TRIGGER_ALARM_2_PROPS)
|
||||
|
||||
# Get Rca for the deduced
|
||||
rca = TempestClients.vitrage().rca.get(
|
||||
deduced[VProps.VITRAGE_ID], all_tenants=True)
|
||||
self._check_rca(rca, [deduced, trigger2], DEDUCED_PROPS)
|
||||
|
||||
# Get Rca for trigger 2
|
||||
rca = TempestClients.vitrage().rca.get(
|
||||
trigger2[VProps.VITRAGE_ID], all_tenants=True)
|
||||
self._check_rca(rca, [deduced, trigger2], TRIGGER_ALARM_2_PROPS)
|
||||
|
||||
# ---- Undo - second ----
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
||||
alarms = TempestClients.vitrage().alarm.list(
|
||||
vitrage_id=self.orig_host.get(VProps.VITRAGE_ID),
|
||||
all_tenants=True)
|
||||
self.assertEqual(
|
||||
0,
|
||||
len(g_utils.all_matches(alarms, **TRIGGER_ALARM_1_PROPS)),
|
||||
'trigger alarm 1 should have been removed')
|
||||
self.assertEqual(
|
||||
0,
|
||||
len(g_utils.all_matches(alarms, **TRIGGER_ALARM_2_PROPS)),
|
||||
'trigger alarm 2 should have been removed')
|
||||
self.assertEqual(
|
||||
0,
|
||||
len(g_utils.all_matches(alarms, **DEDUCED_PROPS)),
|
||||
'deduced alarm should have been removed')
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._trigger_undo_action(TRIGGER_ALARM_1)
|
||||
self._trigger_undo_action(TRIGGER_ALARM_2)
|
@ -1,15 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
|
||||
__author__ = 'stack'
|
@ -1,181 +0,0 @@
|
||||
# Copyright 2017 - 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.
|
||||
|
||||
import json
|
||||
from oslo_log import log as logging
|
||||
from testtools.matchers import HasLength
|
||||
|
||||
from vitrage import os_clients
|
||||
from vitrage_tempest_tests.tests.api.event.base import BaseTestEvents
|
||||
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
|
||||
from vitrage_tempest_tests.tests import utils
|
||||
from vitrage_tempest_tests.tests.utils import wait_for_status
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
WF_NAME = 'wf_for_tempest_test_1234'
|
||||
|
||||
WF_DEFINITION = """
|
||||
---
|
||||
version: '2.0'
|
||||
|
||||
wf_for_tempest_test_1234:
|
||||
type: direct
|
||||
input:
|
||||
- farewell
|
||||
|
||||
tasks:
|
||||
goodbye:
|
||||
action: std.echo output="<% $.farewell %>, Tempest Test!"
|
||||
"""
|
||||
|
||||
|
||||
class TestMistralNotifier(BaseTestEvents):
|
||||
|
||||
TRIGGER_ALARM_1 = "notifiers.mistral.trigger.alarm.1"
|
||||
TRIGGER_ALARM_2 = "notifiers.mistral.trigger.alarm.2"
|
||||
TRIGGER_ALARM_FOR_FUNCTION = "notifiers.mistral.trigger.alarm.for.function"
|
||||
|
||||
def setUp(self):
|
||||
super(TestMistralNotifier, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestMistralNotifier, self).tearDown()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestMistralNotifier, cls).setUpClass()
|
||||
cls.mistral_client = os_clients.mistral_client(cls.conf)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_execute_mistral_v1(self):
|
||||
self._do_test_execute_mistral(self.TRIGGER_ALARM_1)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_execute_mistral_v2(self):
|
||||
self._do_test_execute_mistral(self.TRIGGER_ALARM_2)
|
||||
|
||||
@utils.tempest_logger
|
||||
def test_execute_mistral_with_function(self):
|
||||
# Execute the basic test
|
||||
self._do_test_execute_mistral(self.TRIGGER_ALARM_FOR_FUNCTION)
|
||||
|
||||
# Make sure that the workflow execution was done with the correct input
|
||||
# (can be checked even if the Vitrage alarm is already down)
|
||||
executions = self.mistral_client.executions.list()
|
||||
|
||||
last_execution = executions[0]
|
||||
for execution in executions:
|
||||
if execution.updated_at > last_execution.updated_at:
|
||||
last_execution = execution
|
||||
|
||||
execution_input_str = last_execution.input
|
||||
self.assertIsNotNone(execution_input_str,
|
||||
'The last execution had no input')
|
||||
self.assertIn('farewell', execution_input_str,
|
||||
'No \'farewell\' key in the last execution input')
|
||||
|
||||
execution_input = json.loads(execution_input_str)
|
||||
|
||||
farewell_value = execution_input['farewell']
|
||||
self.assertIsNotNone(farewell_value, '\'farewell\' input parameter is '
|
||||
'None in last workflow execution')
|
||||
|
||||
self.assertEqual(self.TRIGGER_ALARM_FOR_FUNCTION, farewell_value,
|
||||
'\'farewell\' input parameter does not match the'
|
||||
'alarm name')
|
||||
|
||||
def _do_test_execute_mistral(self, trigger_alarm):
|
||||
workflows = self.mistral_client.workflows.list()
|
||||
self.assertIsNotNone(workflows, 'Failed to get the list of workflows')
|
||||
num_workflows = len(workflows)
|
||||
|
||||
executions = self.mistral_client.executions.list()
|
||||
self.assertIsNotNone(executions,
|
||||
'Failed to get the list of workflow executions')
|
||||
num_executions = len(executions)
|
||||
|
||||
alarms = utils.wait_for_answer(2, 0.5, self._check_alarms)
|
||||
self.assertIsNotNone(alarms, 'Failed to get the list of alarms')
|
||||
num_alarms = len(alarms)
|
||||
|
||||
try:
|
||||
# Create a Mistral workflow
|
||||
self.mistral_client.workflows.create(WF_DEFINITION)
|
||||
|
||||
# Validate the workflow creation
|
||||
workflows = self.mistral_client.workflows.list()
|
||||
self.assertIsNotNone(workflows,
|
||||
'Failed to get the list of workflows')
|
||||
self.assertThat(workflows, HasLength(num_workflows + 1),
|
||||
'Mistral workflow was not created')
|
||||
|
||||
# Trigger an alarm. According to v1_execute_mistral.yaml template,
|
||||
# the alarm should cause execution of the workflow
|
||||
self._trigger_do_action(trigger_alarm)
|
||||
|
||||
# Wait for the alarm to be raised
|
||||
self.assertTrue(wait_for_status(
|
||||
10,
|
||||
self._check_num_vitrage_alarms,
|
||||
num_alarms=num_alarms + 1),
|
||||
'Trigger alarm was not raised')
|
||||
|
||||
# Wait for the Mistral workflow execution
|
||||
self.assertTrue(wait_for_status(
|
||||
20,
|
||||
self._check_mistral_workflow_execution,
|
||||
num_executions=num_executions + 1),
|
||||
'Mistral workflow was not executed')
|
||||
|
||||
except Exception as e:
|
||||
self._handle_exception(e)
|
||||
raise
|
||||
finally:
|
||||
self._rollback_to_default(WF_NAME, num_workflows,
|
||||
trigger_alarm, num_alarms)
|
||||
pass
|
||||
|
||||
def _rollback_to_default(self, workflow_name, num_workflows,
|
||||
trigger_alarm, num_alarms):
|
||||
# Delete the workflow
|
||||
self.mistral_client.workflows.delete(workflow_name)
|
||||
|
||||
workflows = self.mistral_client.workflows.list()
|
||||
self.assertIsNotNone(workflows, 'Failed to get the list of workflows')
|
||||
self.assertThat(workflows, HasLength(num_workflows),
|
||||
'Failed to remove the test workflow')
|
||||
|
||||
# Clear the trigger alarm and wait it to be deleted
|
||||
self._trigger_undo_action(trigger_alarm)
|
||||
|
||||
self.assertTrue(wait_for_status(
|
||||
10,
|
||||
self._check_num_vitrage_alarms,
|
||||
num_alarms=num_alarms),
|
||||
'Vitrage trigger alarm was not deleted')
|
||||
|
||||
@staticmethod
|
||||
def _check_num_vitrage_alarms(num_alarms):
|
||||
vitrage_alarms = TempestClients.vitrage().alarm.list(vitrage_id='all',
|
||||
all_tenants=True)
|
||||
if len(vitrage_alarms) == num_alarms:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _check_mistral_workflow_execution(self, num_executions):
|
||||
if len(self.mistral_client.executions.list()) == num_executions:
|
||||
return True
|
||||
return False
|
@ -1,12 +0,0 @@
|
||||
heat_template_version: 2013-05-23
|
||||
|
||||
description: |
|
||||
The heat template is used to demo
|
||||
|
||||
resources:
|
||||
rg:
|
||||
type: OS::Heat::ResourceGroup
|
||||
properties:
|
||||
count: 1
|
||||
resource_def:
|
||||
type: server.yaml
|
@ -1,24 +0,0 @@
|
||||
heat_template_version: 2013-05-23
|
||||
|
||||
description: |
|
||||
The heat template is used to demo
|
||||
|
||||
parameters:
|
||||
image:
|
||||
type: string
|
||||
default: cirros-0.3.5-x86_64-disk
|
||||
network:
|
||||
type: string
|
||||
default: public
|
||||
flavor:
|
||||
type: string
|
||||
default: m1.small
|
||||
|
||||
resources:
|
||||
server_2:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
image: { get_param: image }
|
||||
flavor: { get_param: flavor }
|
||||
networks:
|
||||
- network: { get_param: network }
|
@ -1,24 +0,0 @@
|
||||
heat_template_version: 2013-05-23
|
||||
|
||||
description: |
|
||||
The heat template is used to demo
|
||||
|
||||
parameters:
|
||||
image:
|
||||
type: string
|
||||
default: cirros-0.3.5-x86_64-disk
|
||||
network:
|
||||
type: string
|
||||
default: public
|
||||
flavor:
|
||||
type: string
|
||||
default: m1.small
|
||||
|
||||
resources:
|
||||
server_2:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
image: { get_param: image }
|
||||
flavor: { get_param: flavor }
|
||||
networks:
|
||||
- network: { get_param: network }
|
@ -1,19 +0,0 @@
|
||||
entities:
|
||||
- type: switch
|
||||
name: switch-1
|
||||
id: 12345
|
||||
state: available
|
||||
relationships:
|
||||
- type: nova.host
|
||||
name: tmp-devstack
|
||||
id: tmp-devstack
|
||||
relation_type: attached
|
||||
- type: switch
|
||||
name: switch-2
|
||||
id: 23456
|
||||
state: available
|
||||
relationships:
|
||||
- type: nova.host
|
||||
name: tmp-devstack
|
||||
id: tmp-devstack
|
||||
relation_type: attached
|
@ -1,22 +0,0 @@
|
||||
metadata:
|
||||
#a basic def_template file
|
||||
name: basic_def_template
|
||||
description: basic def_template for general tests
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: nagios
|
||||
name: host_problem
|
||||
template_id: alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: resource
|
||||
relationships:
|
||||
- relationship:
|
||||
source: alarm
|
||||
target: resource
|
||||
relationship_type: on
|
||||
template_id : alarm_on_host
|
||||
|
@ -1,21 +0,0 @@
|
||||
metadata:
|
||||
name: entity equivalence example
|
||||
equivalences:
|
||||
- equivalence:
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: nagios
|
||||
name: cpu_high
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: cpu_high
|
||||
- equivalence:
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: nagios
|
||||
name: mem_low
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: mem_low
|
@ -1,27 +0,0 @@
|
||||
metadata:
|
||||
name: corrupted_template
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.instance
|
||||
template_id: instance
|
||||
relationships:
|
||||
- relationship:
|
||||
source: host
|
||||
target: instance
|
||||
relationship_type: contains
|
||||
template_id: host_contains_instance
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: alarm_on_host and host_contains_instance and alarm_on_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: host_alarm
|
||||
target: instance_alarm
|
@ -1,113 +0,0 @@
|
||||
metadata:
|
||||
name: e2e_test_basic_actions
|
||||
description: this template includes vitrage basic actions
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_basic_actions.trigger.alarm1
|
||||
template_id: trigger_alarm_1
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_basic_actions.trigger.alarm2
|
||||
template_id: trigger_alarm_2
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_basic_actions.trigger.alarm3
|
||||
template_id: trigger_alarm_3
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_basic_actions.trigger.alarm4
|
||||
template_id: trigger_alarm_4
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: e2e.test_basic_actions.deduced.alarm
|
||||
template_id: deduced_alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.instance
|
||||
template_id: instance
|
||||
relationships:
|
||||
- relationship:
|
||||
source: trigger_alarm_1
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_1_on_host
|
||||
- relationship:
|
||||
source: trigger_alarm_2
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_2_on_host
|
||||
- relationship:
|
||||
source: trigger_alarm_3
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_3_on_host
|
||||
- relationship:
|
||||
source: trigger_alarm_4
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_4_on_host
|
||||
- relationship:
|
||||
source: deduced_alarm
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : deduced_alarm_on_host
|
||||
- relationship:
|
||||
source: host
|
||||
target: instance
|
||||
relationship_type: contains
|
||||
template_id: host_contains_instance
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: trigger_alarm_1_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
state: ERROR
|
||||
- scenario:
|
||||
condition: trigger_alarm_4_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: mark_down
|
||||
action_target:
|
||||
target: host
|
||||
- scenario:
|
||||
condition: trigger_alarm_2_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
alarm_name: e2e.test_basic_actions.deduced.alarm
|
||||
severity: WARNING
|
||||
- scenario:
|
||||
condition: trigger_alarm_2_on_host and deduced_alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: trigger_alarm_2
|
||||
target: deduced_alarm
|
||||
- scenario:
|
||||
condition: trigger_alarm_3_on_host and host_contains_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: instance
|
||||
properties:
|
||||
state: ERROR
|
||||
- action:
|
||||
action_type: mark_down
|
||||
action_target:
|
||||
target: instance
|
@ -1,131 +0,0 @@
|
||||
metadata:
|
||||
name: e2e_test_overlapping_actions
|
||||
description: this template includes vitrage basic actions
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_overlapping_actions.trigger.alarm1
|
||||
template_id: trigger_alarm_1
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_overlapping_actions.trigger.alarm2
|
||||
template_id: trigger_alarm_2
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_overlapping_actions.trigger.alarm3
|
||||
template_id: trigger_alarm_3
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_overlapping_actions.trigger.alarm4
|
||||
template_id: trigger_alarm_4
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: e2e.test_overlapping_actions.deduced.alarm
|
||||
template_id: deduced_alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
relationships:
|
||||
- relationship:
|
||||
source: trigger_alarm_1
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_1_on_host
|
||||
- relationship:
|
||||
source: trigger_alarm_2
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_2_on_host
|
||||
- relationship:
|
||||
source: trigger_alarm_3
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_3_on_host
|
||||
- relationship:
|
||||
source: trigger_alarm_4
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_4_on_host
|
||||
- relationship:
|
||||
source: deduced_alarm
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : deduced_alarm_on_host
|
||||
scenarios:
|
||||
|
||||
# First part - trigger_alarm_1_on_host or trigger_alarm_3_on_host:
|
||||
|
||||
- scenario:
|
||||
condition: trigger_alarm_1_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
state: ERROR
|
||||
- scenario:
|
||||
condition: trigger_alarm_3_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: mark_down
|
||||
action_target:
|
||||
target: host
|
||||
- scenario:
|
||||
condition: trigger_alarm_1_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
alarm_name: e2e.test_overlapping_actions.deduced.alarm
|
||||
severity: WARNING
|
||||
- scenario:
|
||||
condition: trigger_alarm_1_on_host and deduced_alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: trigger_alarm_1
|
||||
target: deduced_alarm
|
||||
|
||||
# Second part - trigger_alarm_2_on_host or trigger_alarm_4_on_host:
|
||||
|
||||
- scenario:
|
||||
condition: trigger_alarm_2_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
state: ERROR
|
||||
- scenario:
|
||||
condition: trigger_alarm_4_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: mark_down
|
||||
action_target:
|
||||
target: host
|
||||
- scenario:
|
||||
condition: trigger_alarm_2_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
alarm_name: e2e.test_overlapping_actions.deduced.alarm
|
||||
severity: WARNING
|
||||
- scenario:
|
||||
condition: trigger_alarm_2_on_host and deduced_alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: trigger_alarm_2
|
||||
target: deduced_alarm
|
@ -1,66 +0,0 @@
|
||||
metadata:
|
||||
name: e2e_test_template_actions
|
||||
description: this template includes vitrage basic actions
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_template_actions.trigger.alarm1
|
||||
template_id: trigger_alarm_1
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: e2e.test_template_actions.deduced.alarm
|
||||
template_id: deduced_alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.instance
|
||||
template_id: instance
|
||||
relationships:
|
||||
- relationship:
|
||||
source: trigger_alarm_1
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_1_on_host
|
||||
- relationship:
|
||||
source: deduced_alarm
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : deduced_alarm_on_host
|
||||
- relationship:
|
||||
source: host
|
||||
target: instance
|
||||
relationship_type: contains
|
||||
template_id: host_contains_instance
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: trigger_alarm_1_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
state: ERROR
|
||||
- scenario:
|
||||
condition: trigger_alarm_1_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
alarm_name: e2e.test_template_actions.deduced.alarm
|
||||
severity: WARNING
|
||||
- scenario:
|
||||
condition: trigger_alarm_1_on_host and deduced_alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: trigger_alarm_1
|
||||
target: deduced_alarm
|
@ -1,66 +0,0 @@
|
||||
metadata:
|
||||
name: e2e_test_template_actions_2
|
||||
description: this template includes vitrage basic actions
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_template_actions.trigger.alarm2
|
||||
template_id: trigger_alarm_2
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: e2e.test_template_actions.deduced.alarm2
|
||||
template_id: deduced_alarm_2
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.instance
|
||||
template_id: instance
|
||||
relationships:
|
||||
- relationship:
|
||||
source: trigger_alarm_2
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : trigger_alarm_2_on_host
|
||||
- relationship:
|
||||
source: deduced_alarm_2
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : deduced_alarm_2_on_host
|
||||
- relationship:
|
||||
source: host
|
||||
target: instance
|
||||
relationship_type: contains
|
||||
template_id: host_contains_instance
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: trigger_alarm_2_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
state: ERROR
|
||||
- scenario:
|
||||
condition: trigger_alarm_2_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
alarm_name: e2e.test_template_actions.deduced.alarm2
|
||||
severity: WARNING
|
||||
- scenario:
|
||||
condition: trigger_alarm_2_on_host and deduced_alarm_2_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: trigger_alarm_2
|
||||
target: deduced_alarm_2
|
@ -1,29 +0,0 @@
|
||||
metadata:
|
||||
name: e2e_webhook
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: e2e.test_webhook.alarm_with_deduced
|
||||
template_id: host_alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
relationships:
|
||||
- relationship:
|
||||
source: host_alarm
|
||||
target: host
|
||||
relationship_type: on
|
||||
template_id : alarm_on_host
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
alarm_name: e2e.test_webhook.deduced
|
||||
severity: WARNING
|
@ -1,12 +0,0 @@
|
||||
metadata:
|
||||
name: zabbix_host_equivalence
|
||||
equivalences:
|
||||
- equivalence:
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: nagios
|
||||
name: host_problem
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: zabbix
|
||||
name: host_problem
|
@ -1,72 +0,0 @@
|
||||
metadata:
|
||||
name: host_aodh_alarm
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: aodh
|
||||
name: 'rca_test_host_alarm'
|
||||
template_id: host_alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.instance
|
||||
template_id: instance
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: instance_deduce
|
||||
template_id: instance_alarm
|
||||
relationships:
|
||||
- relationship:
|
||||
source: host_alarm
|
||||
target: host
|
||||
relationship_type: on
|
||||
template_id : alarm_on_host
|
||||
- relationship:
|
||||
source: instance_alarm
|
||||
target: instance
|
||||
relationship_type: on
|
||||
template_id : alarm_on_instance
|
||||
- relationship:
|
||||
source: host
|
||||
target: instance
|
||||
relationship_type: contains
|
||||
template_id: host_contains_instance
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
state: ERROR
|
||||
- scenario:
|
||||
condition: alarm_on_host and host_contains_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: instance
|
||||
properties:
|
||||
alarm_name: instance_deduce
|
||||
severity: WARNING
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: instance
|
||||
properties:
|
||||
state: SUBOPTIMAL
|
||||
- scenario:
|
||||
condition: alarm_on_host and host_contains_instance and alarm_on_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: host_alarm
|
||||
target: instance_alarm
|
@ -1,73 +0,0 @@
|
||||
metadata:
|
||||
name: host_high_memory_usage_scenarios
|
||||
description: scenarios triggered by high memory usage on physical host
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: zabbix
|
||||
rawtext: Lack of available memory on server {HOST.NAME}
|
||||
template_id: lack_of_available_memory_alarm
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: Instance memory performance degraded
|
||||
template_id: instance_memory_performance_degraded_alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.instance
|
||||
template_id: instance
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
relationships:
|
||||
- relationship:
|
||||
source: lack_of_available_memory_alarm
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : lack_of_available_memory_alarm_on_host
|
||||
- relationship:
|
||||
source: host
|
||||
relationship_type: contains
|
||||
target: instance
|
||||
template_id : host_contains_instance
|
||||
- relationship:
|
||||
source: instance_memory_performance_degraded_alarm
|
||||
relationship_type: on
|
||||
target: instance
|
||||
template_id : memory_performance_degraded_alarm_on_instance
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: lack_of_available_memory_alarm_on_host and host_contains_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: instance
|
||||
properties:
|
||||
alarm_name: Instance memory performance degraded
|
||||
severity: warning
|
||||
- scenario:
|
||||
condition: lack_of_available_memory_alarm_on_host and host_contains_instance and memory_performance_degraded_alarm_on_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: lack_of_available_memory_alarm
|
||||
target: instance_memory_performance_degraded_alarm
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: instance
|
||||
properties:
|
||||
state: SUBOPTIMAL
|
||||
- scenario:
|
||||
condition: lack_of_available_memory_alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
state: SUBOPTIMAL
|
@ -1,57 +0,0 @@
|
||||
metadata:
|
||||
name: first_deduced_alarm_ever_nagios
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: Uptime
|
||||
template_id: alarm_1
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.instance
|
||||
template_id: instance
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: another_nagios_alarm
|
||||
template_id: alarm_2
|
||||
relationships:
|
||||
- relationship:
|
||||
source: alarm_1
|
||||
target: host
|
||||
relationship_type: on
|
||||
template_id : alarm_on_host
|
||||
- relationship:
|
||||
source: alarm_2
|
||||
target: instance
|
||||
relationship_type: on
|
||||
template_id : alarm_on_instance
|
||||
- relationship:
|
||||
source: host
|
||||
target: instance
|
||||
relationship_type: contains
|
||||
template_id: host_contains_instance
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: alarm_on_host and host_contains_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: instance
|
||||
properties:
|
||||
alarm_name: another_nagios_alarm
|
||||
severity: warning
|
||||
- scenario:
|
||||
condition: alarm_on_host and alarm_on_instance and host_contains_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: alarm_1
|
||||
target: alarm_2
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
metadata:
|
||||
version: 1
|
||||
name: v1_execute_mistral
|
||||
description: execute mistral
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: notifiers.mistral.trigger.alarm.1
|
||||
template_id: alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
relationships:
|
||||
- relationship:
|
||||
source: alarm
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : alarm_on_host
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: execute_mistral
|
||||
properties:
|
||||
workflow: wf_for_tempest_test_1234
|
||||
farewell: Hello and Goodbye
|
@ -1,30 +0,0 @@
|
||||
metadata:
|
||||
version: 2
|
||||
name: v2_definition
|
||||
description: v2 definition template
|
||||
type: definition
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: notifiers.mistral.trigger.alarm.2
|
||||
template_id: alarm_2
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: notifiers.mistral.trigger.alarm.for.function
|
||||
template_id: alarm_for_func
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
relationships:
|
||||
- relationship:
|
||||
source: alarm_2
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : alarm_2_on_host
|
||||
- relationship:
|
||||
source: alarm_for_func
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : alarm_for_func_on_host
|
@ -1,14 +0,0 @@
|
||||
metadata:
|
||||
name: v2_equivalence
|
||||
version: 2
|
||||
type: equivalence
|
||||
equivalences:
|
||||
- equivalence:
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: nagios
|
||||
name: host_problem
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: zabbix
|
||||
name: host_problem
|
@ -1,49 +0,0 @@
|
||||
metadata:
|
||||
version: 2
|
||||
name: v2_execute_mistral
|
||||
description: execute mistral
|
||||
type: standard
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: notifiers.mistral.trigger.alarm.2
|
||||
template_id: alarm_2
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: notifiers.mistral.trigger.alarm.for.function
|
||||
template_id: alarm_for_func
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
relationships:
|
||||
- relationship:
|
||||
source: alarm_2
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : alarm_2_on_host
|
||||
- relationship:
|
||||
source: alarm_for_func
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : alarm_for_func_on_host
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: alarm_2_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: execute_mistral
|
||||
properties:
|
||||
workflow: wf_for_tempest_test_1234
|
||||
input:
|
||||
farewell: Hello and Goodbye
|
||||
- scenario:
|
||||
condition: alarm_for_func_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: execute_mistral
|
||||
properties:
|
||||
workflow: wf_for_tempest_test_1234
|
||||
input:
|
||||
farewell: get_attr(alarm_for_func,name)
|
@ -1,21 +0,0 @@
|
||||
metadata:
|
||||
version: 2
|
||||
name: v2_no_type
|
||||
description: invalid v2 template - with no type
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: invalid.template.alarm
|
||||
template_id: alarm
|
||||
relationships:
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: alarm
|
||||
actions:
|
||||
- action:
|
||||
action_type: execute_mistral
|
||||
properties:
|
||||
workflow: wf_for_tempest_test_1234
|
||||
input:
|
||||
farewell: Hello and Goodbye
|
@ -1,171 +0,0 @@
|
||||
# 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 functools import wraps
|
||||
|
||||
import socket
|
||||
import time
|
||||
|
||||
from oslo_config.cfg import NoSuchOptError
|
||||
from oslo_log import log as logging
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_from_terminal(command):
|
||||
proc = os.popen(command)
|
||||
text_out = proc.read()
|
||||
proc.close()
|
||||
return text_out
|
||||
|
||||
|
||||
def run_vitrage_command(command, conf):
|
||||
# AUTH_URL
|
||||
local_ip = socket.gethostbyname(socket.gethostname())
|
||||
auth_url = get_property_value('OS_AUTH_URL', 'auth_url',
|
||||
'http://%s:5000/v2.0' % local_ip, conf)
|
||||
auth_url_param = '--os-auth-url ' + auth_url
|
||||
|
||||
# USERNAME
|
||||
user = get_property_value('OS_USERNAME', 'username',
|
||||
'admin', conf)
|
||||
user_param = '--os-user-name ' + user
|
||||
|
||||
# PASSWORD
|
||||
password = get_property_value('OS_PASSWORD', 'password',
|
||||
'secretadmin', conf)
|
||||
password_param = '--os-password ' + password
|
||||
|
||||
# PROJECT_NAME
|
||||
project_name = get_property_value('OS_TENANT_NAME', 'project_name',
|
||||
'admin', conf)
|
||||
project_name_param = '--os-project-name ' + project_name
|
||||
|
||||
# USER_DOMAIN_ID
|
||||
user_domain_id = get_property_value('OS_USER_DOMAIN_ID',
|
||||
'user_domain_id',
|
||||
'default', conf)
|
||||
user_domain_id_param = '--os-user-domain-id ' + user_domain_id
|
||||
|
||||
# PROJECT_DOMAIN_ID
|
||||
project_domain_id = get_property_value('OS_PROJECT_DOMAIN_ID',
|
||||
'project_domain_id',
|
||||
'default', conf)
|
||||
project_domain_id_par = '--os-project-domain-id ' + project_domain_id
|
||||
|
||||
full_command = '%s %s %s %s %s %s %s' % (command, user_param,
|
||||
password_param,
|
||||
project_name_param,
|
||||
auth_url_param,
|
||||
user_domain_id_param,
|
||||
project_domain_id_par)
|
||||
|
||||
LOG.info('Full command: %s', full_command)
|
||||
|
||||
child = subprocess.Popen(full_command,
|
||||
shell=True,
|
||||
executable="/bin/bash",
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
stdout, stderr = child.communicate()
|
||||
if stderr:
|
||||
LOG.error('error from command %(command)s = %(error)s',
|
||||
{'error': stderr, 'command': full_command})
|
||||
|
||||
output = stdout.decode('utf-8')
|
||||
|
||||
LOG.info('cli stdout: %s', output)
|
||||
|
||||
if child.returncode:
|
||||
LOG.error('process return code is not 0 : return code = %d',
|
||||
child.returncode)
|
||||
return output
|
||||
|
||||
|
||||
def get_property_value(environment_name, conf_name, default_value, conf):
|
||||
if os.environ.get(environment_name):
|
||||
return os.environ[environment_name]
|
||||
|
||||
try:
|
||||
return conf.service_credentials[conf_name]
|
||||
except NoSuchOptError:
|
||||
LOG.debug("Configuration doesn't exist: service_credentials.%s",
|
||||
conf_name)
|
||||
|
||||
return default_value
|
||||
|
||||
|
||||
def run_from_terminal(command):
|
||||
proc = os.popen(command)
|
||||
proc.close()
|
||||
|
||||
|
||||
def change_terminal_dir(path):
|
||||
os.chdir(path)
|
||||
LOG.debug("The path is : " + path)
|
||||
|
||||
|
||||
def get_regex_result(pattern, text):
|
||||
p = re.compile(pattern)
|
||||
m = p.search(text)
|
||||
if m:
|
||||
LOG.debug("The regex value is " + m.group(1))
|
||||
return m.group(1)
|
||||
return None
|
||||
|
||||
|
||||
def uni2str(text):
|
||||
return text.encode('ascii', 'ignore')
|
||||
|
||||
|
||||
def tempest_logger(func):
|
||||
func_name = func.__name__
|
||||
|
||||
@wraps(func)
|
||||
def func_name_print_func(*args, **kwargs):
|
||||
LOG.info('Test Start: ' + func_name)
|
||||
result = func(*args, **kwargs)
|
||||
LOG.info('Test End: ' + func_name)
|
||||
return result
|
||||
|
||||
return func_name_print_func
|
||||
|
||||
|
||||
def wait_for_answer(max_waiting, time_between_attempts, func, **kwargs):
|
||||
"""time_between_attempts should be in range of 0 to 1"""
|
||||
status, res = False, None
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < max_waiting:
|
||||
time.sleep(time_between_attempts)
|
||||
status, res = func(**kwargs)
|
||||
if status:
|
||||
return res
|
||||
LOG.info("wait for answer- False")
|
||||
return res
|
||||
|
||||
|
||||
def wait_for_status(max_waiting, func, **kwargs):
|
||||
count = 0
|
||||
while count < max_waiting:
|
||||
if func(**kwargs):
|
||||
return True
|
||||
count += 1
|
||||
time.sleep(2)
|
||||
LOG.error("wait_for_status - False")
|
||||
return False
|
Loading…
Reference in New Issue
Block a user