Removed Bundled intree vitrage-tempest-plugin from vitrage project

Depends-On: I5bafa207fdfdd07f3601e924764ee93c08512bf4
Change-Id: Iab7f60a8e8fb9443597cbe0067d9411d587002d3
This commit is contained in:
Chandan Kumar 2017-12-17 13:10:42 +05:30 committed by Eyal
parent 8838ea134a
commit 027bc49a03
89 changed files with 37 additions and 6253 deletions

View File

@ -28,6 +28,7 @@
- openstack/python-vitrageclient
- openstack/vitrage
- openstack/vitrage-dashboard
- openstack/vitrage-tempest-plugin
irrelevant-files:
- ^.*\.rst$
- ^doc/.*$
@ -46,6 +47,7 @@
- openstack/python-vitrageclient
- openstack/vitrage
- openstack/vitrage-dashboard
- openstack/vitrage-tempest-plugin
irrelevant-files:
- ^.*\.rst$
- ^doc/.*$
@ -64,6 +66,7 @@
- openstack/python-vitrageclient
- openstack/vitrage
- openstack/vitrage-dashboard
- openstack/vitrage-tempest-plugin
irrelevant-files:
- ^.*\.rst$
- ^doc/.*$
@ -82,6 +85,7 @@
- openstack/python-vitrageclient
- openstack/vitrage
- openstack/vitrage-dashboard
- openstack/vitrage-tempest-plugin
irrelevant-files:
- ^.*\.rst$
- ^doc/.*$

View File

@ -28,22 +28,21 @@ if [ "$DEVSTACK_GATE_USE_PYTHON3" == "True" ]; then
export PYTHON=python3
fi
sudo cp $DEVSTACK_PATH/tempest/etc/logging.conf.sample $DEVSTACK_PATH/tempest/etc/logging.conf
sudo cp -rf $DEVSTACK_PATH/tempest/etc/logging.conf.sample $DEVSTACK_PATH/tempest/etc/logging.conf
${PYTHON:-python} $DEVSTACK_PATH/vitrage/vitrage_tempest_tests/add_legacy_dir_templates.py
${PYTHON:-python} $DEVSTACK_PATH/vitrage-tempest-plugin/vitrage_tempest_tests/add_legacy_dir_templates.py
# restart due to configuration files changes
sudo systemctl restart devstack@vitrage-graph.service
# wait for 30 seconds
# wait for 30 seconds (initialization might take time)
sleep 30
cd $DEVSTACK_PATH/tempest/; sudo -E testr init
cd $DEVSTACK_PATH/tempest/
sudo -E testr init
echo "Listing existing Tempest tests"
sudo -E testr list-tests vitrage_tempest_tests
sudo -E testr list-tests vitrage_tempest_tests | grep -E "$TESTS" > /tmp/vitrage_tempest_tests.list
sudo -E testr list-tests vitrage_tempest_tests | grep -E "$TESTS" | tee /tmp/vitrage_tempest_tests.list
echo "Testing $1: $TESTS..."
sudo -E testr run --subunit --load-list=/tmp/vitrage_tempest_tests.list | subunit-trace --fails

View File

@ -30,6 +30,7 @@
cat << 'EOF' >>"/tmp/dg-local.conf"
[[local|localrc]]
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
enable_plugin vitrage-tempest-plugin git://git.openstack.org/openstack/vitrage-tempest-plugin
# swift is not ready for python3 yet
disable_service s-account
@ -52,7 +53,9 @@
export PROJECTS="openstack/mistral $PROJECTS"
export PROJECTS="openstack/vitrage $PROJECTS"
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
export ENABLED_SERVICES=tempest
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
if [ "py27" == "py35" ] ; then
export DEVSTACK_GATE_USE_PYTHON3=True

View File

@ -30,6 +30,7 @@
cat << 'EOF' >>"/tmp/dg-local.conf"
[[local|localrc]]
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
enable_plugin vitrage-tempest-plugin git://git.openstack.org/openstack/vitrage-tempest-plugin
# swift is not ready for python3 yet
disable_service s-account
@ -52,7 +53,9 @@
export PROJECTS="openstack/mistral $PROJECTS"
export PROJECTS="openstack/vitrage $PROJECTS"
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
export ENABLED_SERVICES=tempest
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
if [ "py35" == "py35" ] ; then
export DEVSTACK_GATE_USE_PYTHON3=True

View File

@ -30,6 +30,7 @@
cat << 'EOF' >>"/tmp/dg-local.conf"
[[local|localrc]]
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
enable_plugin vitrage-tempest-plugin git://git.openstack.org/openstack/vitrage-tempest-plugin
# swift is not ready for python3 yet
disable_service s-account
@ -52,7 +53,9 @@
export PROJECTS="openstack/mistral $PROJECTS"
export PROJECTS="openstack/vitrage $PROJECTS"
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
export ENABLED_SERVICES=tempest
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
if [ "py27" == "py35" ] ; then
export DEVSTACK_GATE_USE_PYTHON3=True

View File

@ -30,6 +30,7 @@
cat << 'EOF' >>"/tmp/dg-local.conf"
[[local|localrc]]
enable_plugin vitrage git://git.openstack.org/openstack/vitrage
enable_plugin vitrage-tempest-plugin git://git.openstack.org/openstack/vitrage-tempest-plugin
# swift is not ready for python3 yet
disable_service s-account
@ -52,7 +53,9 @@
export PROJECTS="openstack/mistral $PROJECTS"
export PROJECTS="openstack/vitrage $PROJECTS"
export PROJECTS="openstack/vitrage-dashboard $PROJECTS"
export PROJECTS="openstack/vitrage-tempest-plugin $PROJECTS"
export ENABLED_SERVICES=tempest
export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
if [ "py35" == "py35" ] ; then
export DEVSTACK_GATE_USE_PYTHON3=True

View File

@ -44,9 +44,6 @@ oslo.config.opts =
oslo.policy.policies =
vitrage = vitrage.common.policies:list_rules
tempest.test_plugins =
vitrage_tests = vitrage_tempest_tests.plugin:VitrageTempestPlugin
vitrage.storage =
mysql = vitrage.storage.impl_sqlalchemy:Connection
mysql+pymysql = vitrage.storage.impl_sqlalchemy:Connection
@ -56,7 +53,6 @@ vitrage.storage =
[files]
packages =
vitrage
vitrage_tempest_tests
[build_sphinx]
source-dir = doc/source

View File

@ -25,7 +25,6 @@ oslo.i18n>=3.15.3 # Apache-2.0
oslo.policy>=1.30.0 # Apache-2.0
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
requests-mock>=1.1.0 # Apache-2.0
tempest>=17.1.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=2.2.0 # MIT

View File

@ -11,6 +11,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging
from vitrage.common.constants import DatasourceProperties as DSProps
from vitrage.common.constants import EdgeLabel
@ -25,6 +26,8 @@ from vitrage.datasources import transformer_base as tbase
from vitrage.datasources.transformer_base import extract_field_value
import vitrage.graph.utils as graph_utils
LOG = logging.getLogger(__name__)
class InstanceTransformer(ResourceTransformerBase):
@ -99,12 +102,16 @@ class InstanceTransformer(ResourceTransformerBase):
return [host_neighbor]
def _create_entity_key(self, event):
LOG.debug('Creating key for instance event: %s', str(event))
instance_id = 'instance_id' if tbase.is_update_event(event) else 'id'
key_fields = self._key_values(NOVA_INSTANCE_DATASOURCE,
extract_field_value(event,
instance_id))
return tbase.build_key(key_fields)
key = tbase.build_key(key_fields)
LOG.debug('Created key: %s', key)
return key
def get_vitrage_type(self):
return NOVA_INSTANCE_DATASOURCE

View File

@ -62,6 +62,9 @@ def mark_deleted(g, item):
def delete_placeholder_vertex(g, vertex):
"""Checks if it is a placeholder vertex, and if so deletes it """
LOG.debug('Asked to delete a placeholder vertex: %s with %d neighbors',
str(vertex), len(g.get_edges(vertex.vertex_id)))
if not vertex[VProps.VITRAGE_IS_PLACEHOLDER]:
return
if not any(True for neighbor_edge in g.get_edges(vertex.vertex_id)
@ -80,6 +83,10 @@ def find_neighbor_types(neighbors):
def get_vertex_types(vertex):
props = vertex.items()
if VProps.VITRAGE_CATEGORY not in props:
LOG.warning('no vitrage_category in vertex: %s', str(vertex))
vitrage_category = vertex[VProps.VITRAGE_CATEGORY]
vitrage_type = vertex[VProps.VITRAGE_TYPE]
return vitrage_category, vitrage_type

View File

@ -1,6 +0,0 @@
==============================
Tempest Integration of Vitrage
==============================
This directory contains Tempest tests to cover the Vitrage project.

View 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'

View File

@ -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())

View File

@ -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.")
]

View File

@ -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])]

View 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'

View 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'

View 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'

View File

@ -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())

View File

@ -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))

View File

@ -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'

View File

@ -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',
}

View File

@ -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])

View 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'

View File

@ -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

View File

@ -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()

View File

@ -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))

View 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'

View File

@ -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)

View File

@ -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']

View File

@ -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')

View 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'

View File

@ -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"}}]}]}'

View File

@ -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()

View File

@ -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'

View File

@ -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'])

View File

@ -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()

View File

@ -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'

View File

@ -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')

View File

@ -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')

View File

@ -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())

View File

@ -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')

View File

@ -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()

View File

@ -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)

View File

@ -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')

View File

@ -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())

View File

@ -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

View File

@ -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)

View File

@ -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'

View File

@ -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

View 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'

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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'

View File

@ -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)))

View File

@ -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)

View File

@ -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'])

View File

@ -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

View File

@ -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)

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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 }

View File

@ -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 }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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