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/python-vitrageclient
|
||||||
- openstack/vitrage
|
- openstack/vitrage
|
||||||
- openstack/vitrage-dashboard
|
- openstack/vitrage-dashboard
|
||||||
|
- openstack/vitrage-tempest-plugin
|
||||||
irrelevant-files:
|
irrelevant-files:
|
||||||
- ^.*\.rst$
|
- ^.*\.rst$
|
||||||
- ^doc/.*$
|
- ^doc/.*$
|
||||||
@ -46,6 +47,7 @@
|
|||||||
- openstack/python-vitrageclient
|
- openstack/python-vitrageclient
|
||||||
- openstack/vitrage
|
- openstack/vitrage
|
||||||
- openstack/vitrage-dashboard
|
- openstack/vitrage-dashboard
|
||||||
|
- openstack/vitrage-tempest-plugin
|
||||||
irrelevant-files:
|
irrelevant-files:
|
||||||
- ^.*\.rst$
|
- ^.*\.rst$
|
||||||
- ^doc/.*$
|
- ^doc/.*$
|
||||||
@ -64,6 +66,7 @@
|
|||||||
- openstack/python-vitrageclient
|
- openstack/python-vitrageclient
|
||||||
- openstack/vitrage
|
- openstack/vitrage
|
||||||
- openstack/vitrage-dashboard
|
- openstack/vitrage-dashboard
|
||||||
|
- openstack/vitrage-tempest-plugin
|
||||||
irrelevant-files:
|
irrelevant-files:
|
||||||
- ^.*\.rst$
|
- ^.*\.rst$
|
||||||
- ^doc/.*$
|
- ^doc/.*$
|
||||||
@ -82,6 +85,7 @@
|
|||||||
- openstack/python-vitrageclient
|
- openstack/python-vitrageclient
|
||||||
- openstack/vitrage
|
- openstack/vitrage
|
||||||
- openstack/vitrage-dashboard
|
- openstack/vitrage-dashboard
|
||||||
|
- openstack/vitrage-tempest-plugin
|
||||||
irrelevant-files:
|
irrelevant-files:
|
||||||
- ^.*\.rst$
|
- ^.*\.rst$
|
||||||
- ^doc/.*$
|
- ^doc/.*$
|
||||||
|
@ -28,22 +28,21 @@ if [ "$DEVSTACK_GATE_USE_PYTHON3" == "True" ]; then
|
|||||||
export PYTHON=python3
|
export PYTHON=python3
|
||||||
fi
|
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
|
# restart due to configuration files changes
|
||||||
sudo systemctl restart devstack@vitrage-graph.service
|
sudo systemctl restart devstack@vitrage-graph.service
|
||||||
|
|
||||||
# wait for 30 seconds
|
# wait for 30 seconds (initialization might take time)
|
||||||
sleep 30
|
sleep 30
|
||||||
|
|
||||||
|
|
||||||
|
cd $DEVSTACK_PATH/tempest/
|
||||||
cd $DEVSTACK_PATH/tempest/; sudo -E testr init
|
sudo -E testr init
|
||||||
|
|
||||||
echo "Listing existing Tempest tests"
|
echo "Listing existing Tempest tests"
|
||||||
sudo -E testr list-tests vitrage_tempest_tests
|
sudo -E testr list-tests vitrage_tempest_tests | grep -E "$TESTS" | tee /tmp/vitrage_tempest_tests.list
|
||||||
sudo -E testr list-tests vitrage_tempest_tests | grep -E "$TESTS" > /tmp/vitrage_tempest_tests.list
|
|
||||||
echo "Testing $1: $TESTS..."
|
echo "Testing $1: $TESTS..."
|
||||||
sudo -E testr run --subunit --load-list=/tmp/vitrage_tempest_tests.list | subunit-trace --fails
|
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"
|
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||||
[[local|localrc]]
|
[[local|localrc]]
|
||||||
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
|
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
|
# swift is not ready for python3 yet
|
||||||
disable_service s-account
|
disable_service s-account
|
||||||
@ -52,7 +53,9 @@
|
|||||||
export PROJECTS="openstack/mistral $PROJECTS"
|
export PROJECTS="openstack/mistral $PROJECTS"
|
||||||
export PROJECTS="openstack/vitrage $PROJECTS"
|
export PROJECTS="openstack/vitrage $PROJECTS"
|
||||||
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
||||||
|
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
|
||||||
export ENABLED_SERVICES=tempest
|
export ENABLED_SERVICES=tempest
|
||||||
|
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
|
||||||
|
|
||||||
if [ "py27" == "py35" ] ; then
|
if [ "py27" == "py35" ] ; then
|
||||||
export DEVSTACK_GATE_USE_PYTHON3=True
|
export DEVSTACK_GATE_USE_PYTHON3=True
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
cat << 'EOF' >>"/tmp/dg-local.conf"
|
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||||
[[local|localrc]]
|
[[local|localrc]]
|
||||||
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
|
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
|
# swift is not ready for python3 yet
|
||||||
disable_service s-account
|
disable_service s-account
|
||||||
@ -52,7 +53,9 @@
|
|||||||
export PROJECTS="openstack/mistral $PROJECTS"
|
export PROJECTS="openstack/mistral $PROJECTS"
|
||||||
export PROJECTS="openstack/vitrage $PROJECTS"
|
export PROJECTS="openstack/vitrage $PROJECTS"
|
||||||
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
||||||
|
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
|
||||||
export ENABLED_SERVICES=tempest
|
export ENABLED_SERVICES=tempest
|
||||||
|
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
|
||||||
|
|
||||||
if [ "py35" == "py35" ] ; then
|
if [ "py35" == "py35" ] ; then
|
||||||
export DEVSTACK_GATE_USE_PYTHON3=True
|
export DEVSTACK_GATE_USE_PYTHON3=True
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
cat << 'EOF' >>"/tmp/dg-local.conf"
|
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||||
[[local|localrc]]
|
[[local|localrc]]
|
||||||
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
|
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
|
# swift is not ready for python3 yet
|
||||||
disable_service s-account
|
disable_service s-account
|
||||||
@ -52,7 +53,9 @@
|
|||||||
export PROJECTS="openstack/mistral $PROJECTS"
|
export PROJECTS="openstack/mistral $PROJECTS"
|
||||||
export PROJECTS="openstack/vitrage $PROJECTS"
|
export PROJECTS="openstack/vitrage $PROJECTS"
|
||||||
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
||||||
|
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
|
||||||
export ENABLED_SERVICES=tempest
|
export ENABLED_SERVICES=tempest
|
||||||
|
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
|
||||||
|
|
||||||
if [ "py27" == "py35" ] ; then
|
if [ "py27" == "py35" ] ; then
|
||||||
export DEVSTACK_GATE_USE_PYTHON3=True
|
export DEVSTACK_GATE_USE_PYTHON3=True
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
cat << 'EOF' >>"/tmp/dg-local.conf"
|
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||||
[[local|localrc]]
|
[[local|localrc]]
|
||||||
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
|
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
|
# swift is not ready for python3 yet
|
||||||
disable_service s-account
|
disable_service s-account
|
||||||
@ -52,7 +53,9 @@
|
|||||||
export PROJECTS="openstack/mistral $PROJECTS"
|
export PROJECTS="openstack/mistral $PROJECTS"
|
||||||
export PROJECTS="openstack/vitrage $PROJECTS"
|
export PROJECTS="openstack/vitrage $PROJECTS"
|
||||||
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
|
||||||
|
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
|
||||||
export ENABLED_SERVICES=tempest
|
export ENABLED_SERVICES=tempest
|
||||||
|
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
|
||||||
|
|
||||||
if [ "py35" == "py35" ] ; then
|
if [ "py35" == "py35" ] ; then
|
||||||
export DEVSTACK_GATE_USE_PYTHON3=True
|
export DEVSTACK_GATE_USE_PYTHON3=True
|
||||||
|
@ -44,9 +44,6 @@ oslo.config.opts =
|
|||||||
oslo.policy.policies =
|
oslo.policy.policies =
|
||||||
vitrage = vitrage.common.policies:list_rules
|
vitrage = vitrage.common.policies:list_rules
|
||||||
|
|
||||||
tempest.test_plugins =
|
|
||||||
vitrage_tests = vitrage_tempest_tests.plugin:VitrageTempestPlugin
|
|
||||||
|
|
||||||
vitrage.storage =
|
vitrage.storage =
|
||||||
mysql = vitrage.storage.impl_sqlalchemy:Connection
|
mysql = vitrage.storage.impl_sqlalchemy:Connection
|
||||||
mysql+pymysql = vitrage.storage.impl_sqlalchemy:Connection
|
mysql+pymysql = vitrage.storage.impl_sqlalchemy:Connection
|
||||||
@ -56,7 +53,6 @@ vitrage.storage =
|
|||||||
[files]
|
[files]
|
||||||
packages =
|
packages =
|
||||||
vitrage
|
vitrage
|
||||||
vitrage_tempest_tests
|
|
||||||
|
|
||||||
[build_sphinx]
|
[build_sphinx]
|
||||||
source-dir = doc/source
|
source-dir = doc/source
|
||||||
|
@ -25,7 +25,6 @@ oslo.i18n>=3.15.3 # Apache-2.0
|
|||||||
oslo.policy>=1.30.0 # 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
|
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
||||||
requests-mock>=1.1.0 # Apache-2.0
|
requests-mock>=1.1.0 # Apache-2.0
|
||||||
tempest>=17.1.0 # Apache-2.0
|
|
||||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||||
testscenarios>=0.4 # Apache-2.0/BSD
|
testscenarios>=0.4 # Apache-2.0/BSD
|
||||||
testtools>=2.2.0 # MIT
|
testtools>=2.2.0 # MIT
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||||
from vitrage.common.constants import EdgeLabel
|
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
|
from vitrage.datasources.transformer_base import extract_field_value
|
||||||
import vitrage.graph.utils as graph_utils
|
import vitrage.graph.utils as graph_utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class InstanceTransformer(ResourceTransformerBase):
|
class InstanceTransformer(ResourceTransformerBase):
|
||||||
|
|
||||||
@ -99,12 +102,16 @@ class InstanceTransformer(ResourceTransformerBase):
|
|||||||
return [host_neighbor]
|
return [host_neighbor]
|
||||||
|
|
||||||
def _create_entity_key(self, event):
|
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'
|
instance_id = 'instance_id' if tbase.is_update_event(event) else 'id'
|
||||||
key_fields = self._key_values(NOVA_INSTANCE_DATASOURCE,
|
key_fields = self._key_values(NOVA_INSTANCE_DATASOURCE,
|
||||||
extract_field_value(event,
|
extract_field_value(event,
|
||||||
instance_id))
|
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):
|
def get_vitrage_type(self):
|
||||||
return NOVA_INSTANCE_DATASOURCE
|
return NOVA_INSTANCE_DATASOURCE
|
||||||
|
@ -62,6 +62,9 @@ def mark_deleted(g, item):
|
|||||||
def delete_placeholder_vertex(g, vertex):
|
def delete_placeholder_vertex(g, vertex):
|
||||||
"""Checks if it is a placeholder vertex, and if so deletes it """
|
"""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]:
|
if not vertex[VProps.VITRAGE_IS_PLACEHOLDER]:
|
||||||
return
|
return
|
||||||
if not any(True for neighbor_edge in g.get_edges(vertex.vertex_id)
|
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):
|
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_category = vertex[VProps.VITRAGE_CATEGORY]
|
||||||
vitrage_type = vertex[VProps.VITRAGE_TYPE]
|
vitrage_type = vertex[VProps.VITRAGE_TYPE]
|
||||||
return vitrage_category, 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…
x
Reference in New Issue
Block a user