Add basic classes and structure for tests

Add basic bvt tests for influxdb_grafana.
Add helpers modules.

Change-Id: I698661a478674b7810f688433000ca39cdf35f3c
This commit is contained in:
Rodion Promyshlennikov 2016-05-04 16:06:48 +03:00
parent 924505b3a4
commit 8c13244e25
12 changed files with 615 additions and 1 deletions

View File

@ -0,0 +1,94 @@
# Copyright 2016 Mirantis, Inc.
#
# 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 abc
from fuelweb_test.tests import base_test_case
import six
from stacklight_tests.helpers import checkers
from stacklight_tests.helpers import helpers
from stacklight_tests.helpers import remote_ops
from stacklight_tests.helpers import ui_tester
from stacklight_tests import settings
@six.add_metaclass(abc.ABCMeta)
class PluginApi(object):
"""Common test class to operate with StackLight plugin."""
def __init__(self):
self.test = base_test_case.TestBasic()
self.env = self.test.env
self.settings = self.get_plugin_settings()
self.helpers = helpers.PluginHelper(self.env)
self.checkers = checkers
self.remote_ops = remote_ops
self.ui_tester = ui_tester.UITester()
def __getattr__(self, item):
return getattr(self.test, item)
@property
def base_nodes(self):
base_nodes = {
'slave-01': ['controller'],
'slave-02': ['compute', 'cinder'],
'slave-03': self.settings.role_name,
}
return base_nodes
@property
def full_ha_nodes(self):
full_ha_nodes = {
'slave-01': ['controller'],
'slave-02': ['controller'],
'slave-03': ['controller'],
'slave-04': ['compute', 'cinder'],
'slave-05': ['compute', 'cinder'],
'slave-06': ['compute', 'cinder'],
'slave-07': self.settings.role_name,
'slave-08': self.settings.role_name,
'slave-09': self.settings.role_name,
}
return full_ha_nodes
def create_cluster(self, cluster_settings=None,
mode=settings.DEPLOYMENT_MODE):
return helpers.create_cluster(
self.env,
name=self.__class__.__name__,
cluster_settings=cluster_settings,
mode=mode,
)
@abc.abstractmethod
def get_plugin_settings(self):
pass
@abc.abstractmethod
def prepare_plugin(self):
pass
@abc.abstractmethod
def activate_plugin(self):
pass
@abc.abstractmethod
def get_plugin_vip(self):
pass
@abc.abstractmethod
def check_plugin_online(self):
pass

View File

@ -0,0 +1,24 @@
# Copyright 2016 Mirantis, Inc.
#
# 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 proboscis import asserts
import requests
def check_http_get_response(url, expected_code=200, msg=None, **kwargs):
msg = msg or "%s responded with {0}, expected {1}" % url
r = requests.get(url, **kwargs)
asserts.assert_equal(
r.status_code, expected_code, msg.format(r.status_code, expected_code))
return r

View File

@ -0,0 +1,88 @@
# Copyright 2016 Mirantis, Inc.
#
# 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 urllib2
from fuelweb_test import logger
from proboscis import asserts
from stacklight_tests import settings
def create_cluster(
env, name, cluster_settings=None, mode=settings.DEPLOYMENT_MODE):
return env.fuel_web.create_cluster(
name=name, settings=cluster_settings, mode=mode)
class PluginHelper(object):
"""Class for common help functions."""
def __init__(self, env):
self.env = env
self.fuel_web = self.env.fuel_web
self._cluster_id = None
@property
def cluster_id(self):
if self._cluster_id is None:
try:
self._cluster_id = self.fuel_web.get_last_created_cluster()
except urllib2.URLError:
raise EnvironmentError("No cluster was created.")
return self._cluster_id
@cluster_id.setter
def cluster_id(self, value):
self._cluster_id = value
def prepare_plugin(self, plugin_path):
"""Upload and install plugin by path."""
self.env.admin_actions.upload_plugin(plugin=plugin_path)
self.env.admin_actions.install_plugin(
plugin_file_name=os.path.basename(plugin_path))
def activate_plugin(self, name, version, options):
"""Activate and check exist plugin."""
msg = "Plugin couldn't be enabled. Check plugin version. Test aborted"
asserts.assert_true(
self.fuel_web.check_plugin_exists(self.cluster_id, name),
msg)
self.fuel_web.update_plugin_settings(
self.cluster_id, name, version, options)
def get_plugin_vip(self, vip_name):
"""Get plugin IP."""
networks = self.fuel_web.client.get_networks(self.cluster_id)
vip = networks.get('vips').get(vip_name, {}).get('ipaddr', None)
asserts.assert_is_not_none(
vip, "Failed to get the IP of {} server".format(vip_name))
logger.debug("Check that {} is ready".format(vip_name))
return vip
def get_all_ready_nodes(self):
return [node for node in
self.fuel_web.client.list_cluster_nodes(self.cluster_id)
if node["status"] == "ready"]
def deploy_cluster(self, nodes_roles):
"""Method to deploy cluster with provided node roles."""
self.fuel_web.update_nodes(self.cluster_id, nodes_roles)
self.fuel_web.deploy_cluster_wait(self.cluster_id)
def run_ostf(self, *args, **kwargs):
kwargs.update({"cluster_id": self.cluster_id})
self.fuel_web.run_ostf(*args, **kwargs)

View File

@ -0,0 +1,38 @@
# Copyright 2016 Mirantis, Inc.
#
# 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.
def get_all_bridged_interfaces_for_node(remote, excluded_criteria=None):
# TODO(rpromyshlennikov): do filtration on python side
excluded_criteria_cmd = (
" | grep -v '%s'" % excluded_criteria
if excluded_criteria else "")
cmd = "brctl show | awk '/br-/{{print $1}}'{excluded}".format(
excluded=excluded_criteria_cmd)
interfaces = remote.check_call(cmd)["stdout"]
return [iface.strip() for iface in interfaces]
def switch_interface(remote, interface, method="up"):
cmd = "if{method} {interface}".format(method=method,
interface=interface)
remote.check_call(cmd)
def simulate_network_interrupt_on_node(remote):
cmd = (
"(/sbin/iptables -I INPUT -j DROP "
"&& sleep 30 "
"&& /sbin/iptables -D INPUT -j DROP) 2>&1>/dev/null &")
remote.execute(cmd)

View File

@ -0,0 +1,18 @@
# Copyright 2016 Mirantis, Inc.
#
# 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.
class UITester(object):
# NOTE(rpromyshlennikov): to prepare to move UI test
pass

View File

@ -0,0 +1,109 @@
# Copyright 2016 Mirantis, Inc.
#
# 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 devops.helpers import helpers as devops_helpers
from fuelweb_test import logger
from proboscis import asserts
import requests
from stacklight_tests import base_test
from stacklight_tests.influxdb_grafana import plugin_settings
class InfluxdbPluginApi(base_test.PluginApi):
def get_plugin_settings(self):
return plugin_settings
def prepare_plugin(self):
self.helpers.prepare_plugin(self.settings.plugin_path)
def activate_plugin(self):
self.helpers.activate_plugin(
self.settings.name, self.settings.version, self.settings.options)
def get_plugin_vip(self):
return self.helpers.get_plugin_vip(self.settings.vip_name)
def make_request_to_influx(self,
db=plugin_settings.influxdb_db_name,
user=plugin_settings.influxdb_rootuser,
password=plugin_settings.influxdb_rootpass,
query="",
expected_code=200):
influxdb_vip = self.get_plugin_vip()
params = {
"db": db,
"u": user,
"p": password,
"q": query,
}
msg = "InfluxDB responded with {0}, expected {1}"
r = self.checkers.check_http_get_response(
self.settings.influxdb_url.format(influxdb_vip),
expected_code=expected_code, msg=msg, params=params)
return r
def check_plugin_online(self):
self.make_request_to_influx(query="show measurements")
logger.debug("Check that the Grafana server is running")
msg = "Grafana server responded with {0}, expected {1}"
self.checkers.check_http_get_response(
self.settings.grafana_url.format(
self.settings.grafana_user, self.settings.grafana_pass,
self.get_plugin_vip()),
msg=msg
)
def check_influxdb_nodes_count(self, nodes_count=1):
response = self.make_request_to_influx(
user=self.settings.influxdb_rootuser,
password=self.settings.influxdb_rootpass,
query="show servers")
nodes_count_responsed = len(
response.json()["results"][0]["series"][0]["values"])
msg = "InfluxDB nodes count expected, received instead: {}".format(
nodes_count_responsed)
asserts.assert_equal(nodes_count, nodes_count_responsed, msg)
def get_influxdb_master_node(self):
influx_master_node = self.helpers.get_master_node_by_role(
self.settings.role_name)
return influx_master_node
def wait_for_rotation_influx_master(self,
old_master, timeout=5 * 60):
logger.info('Wait a influxDB master node rotation')
msg = "Failed influxDB master rotation from {0}".format(old_master)
devops_helpers.wait(
lambda: old_master != self.get_influxdb_master_node()['fqdn'],
timeout=timeout, timeout_msg=msg)
def wait_plugin_online(self, timeout=5 * 60):
def check_availability():
try:
self.check_plugin_online()
return True
except (AssertionError, requests.ConnectionError):
return False
logger.info('Wait a plugin become online')
msg = "Plugin has not become online after waiting period"
devops_helpers.wait(
check_availability, timeout=timeout, timeout_msg=msg)

View File

@ -0,0 +1,50 @@
# Copyright 2016 Mirantis, Inc.
#
# 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 stacklight_tests import settings
name = 'influxdb_grafana'
version = '0.9.0'
role_name = ['influxdb_grafana']
vip_name = 'influxdb'
plugin_path = settings.INFLUXDB_GRAFANA_PLUGIN_PATH
influxdb_db_name = "lma"
influxdb_user = 'influxdb'
influxdb_pass = 'influxdbpass'
influxdb_rootuser = 'root'
influxdb_rootpass = 'r00tme'
influxdb_url = "http://{0}:8086/query"
grafana_user = 'grafana'
grafana_pass = 'grafanapass'
grafana_url = "http://{0}:{1}@{2}:8000/api/org"
mysql_mode = 'local'
mysql_dbname = 'grafanalma'
mysql_user = 'grafanalma'
mysql_pass = 'mysqlpass'
options = {
'influxdb_rootpass/value': influxdb_rootpass,
'influxdb_username/value': influxdb_user,
'influxdb_userpass/value': influxdb_pass,
'grafana_username/value': grafana_user,
'grafana_userpass/value': grafana_pass,
'mysql_mode/value': mysql_mode,
'mysql_dbname/value': mysql_dbname,
'mysql_username/value': mysql_user,
'mysql_password/value': mysql_pass,
}

View File

@ -0,0 +1,124 @@
# Copyright 2016 Mirantis, Inc.
#
# 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 fuelweb_test.helpers.decorators import log_snapshot_after_test
from fuelweb_test.tests import base_test_case
from proboscis import test
from stacklight_tests.influxdb_grafana import api
@test(groups=["plugins"])
class TestInfluxdbPlugin(api.InfluxdbPluginApi):
"""Class for smoke testing the InfluxDB-Grafana plugin."""
@test(depends_on=[base_test_case.SetupEnvironment.prepare_slaves_3],
groups=["install_influxdb_grafana", "install",
"influxdb_grafana", "smoke"])
@log_snapshot_after_test
def install_influxdb_grafana_plugin(self):
"""Install InfluxDB-Grafana plugin and check it exists
Scenario:
1. Upload plugin to the master node
2. Install plugin
3. Create cluster
4. Check that plugin exists
Duration 20m
"""
self.env.revert_snapshot("ready_with_3_slaves")
self.prepare_plugin()
self.create_cluster()
self.activate_plugin()
@test(depends_on=[base_test_case.SetupEnvironment.prepare_slaves_3],
groups=["deploy_influxdb_grafana", "deploy",
"influxdb_grafana", "smoke"])
@log_snapshot_after_test
def deploy_influxdb_grafana_plugin(self):
"""Deploy a cluster with the InfluxDB-Grafana plugin
Scenario:
1. Upload plugin to the master node
2. Install plugin
3. Create cluster
4. Add 1 node with controller role
5. Add 1 node with compute and cinder roles
6. Add 1 node with influxdb_grafana role
7. Deploy the cluster
8. Check that plugin is working
9. Run OSTF
Duration 60m
Snapshot deploy_influxdb_grafana_plugin
"""
self.check_run("deploy_influxdb_grafana_plugin")
self.env.revert_snapshot("ready_with_3_slaves")
self.prepare_plugin()
self.create_cluster()
self.activate_plugin()
self.helpers.deploy_cluster(self.base_nodes)
self.check_plugin_online()
self.helpers.run_ostf()
self.env.make_snapshot("deploy_influxdb_grafana_plugin", is_make=True)
@test(depends_on=[base_test_case.SetupEnvironment.prepare_slaves_9],
groups=["deploy_ha_influxdb_grafana", "deploy", "deploy_ha"
"influxdb_grafana", "smoke"])
@log_snapshot_after_test
def deploy_ha_influxdb_grafana_plugin(self):
"""Deploy a cluster with the InfluxDB-Grafana plugin in HA mode
Scenario:
1. Upload plugin to the master node
2. Install plugin
3. Create cluster
4. Add 3 nodes with controller role
5. Add 3 nodes with compute and cinder roles
6. Add 3 nodes with influxdb_grafana role
7. Deploy the cluster
8. Check that plugin is working
9. Run OSTF
Duration 120m
Snapshot deploy_ha_influxdb_grafana_plugin
"""
self.check_run("deploy_ha_influxdb_grafana_plugin")
self.env.revert_snapshot("ready_with_9_slaves")
self.prepare_plugin()
self.create_cluster()
self.activate_plugin()
self.helpers.deploy_cluster(self.full_ha_nodes)
self.check_plugin_online()
self.helpers.run_ostf()
self.env.make_snapshot("deploy_ha_influxdb_grafana_plugin",
is_make=True)

View File

@ -0,0 +1,8 @@
from fuelweb_test.settings import * # noqa
LMA_COLLECTOR_PLUGIN_PATH = os.environ.get('LMA_COLLECTOR_PLUGIN_PATH')
LMA_INFRA_ALERTING_PLUGIN_PATH = os.environ.get(
'LMA_INFRA_ALERTING_PLUGIN_PATH')
ELASTICSEARCH_KIBANA_PLUGIN_PATH = os.environ.get(
'ELASTICSEARCH_KIBANA_PLUGIN_PATH')
INFLUXDB_GRAFANA_PLUGIN_PATH = os.environ.get('INFLUXDB_GRAFANA_PLUGIN_PATH')

View File

@ -0,0 +1,40 @@
# Copyright 2016 Mirantis, Inc.
#
# 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 stacklight_tests import base_test
from stacklight_tests.influxdb_grafana import api as influx_grafana_api
class Collector(base_test.PluginApi):
def __init__(self):
super(Collector, self).__init__()
self.plugins = [influx_grafana_api.InfluxdbPluginApi()]
def get_plugin_settings(self):
pass
def prepare_plugin(self):
for plugin in self.plugins:
plugin.prepare_plugin()
def activate_plugin(self):
for plugin in self.plugins:
plugin.activate_plugin()
def get_plugin_vip(self):
pass
def check_plugin_online(self):
for plugin in self.plugins:
plugin.check_plugin_online()

View File

@ -0,0 +1,21 @@
# Copyright 2016 Mirantis, Inc.
#
# 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 stacklight_tests.influxdb_grafana import (
plugin_settings as influxdb_grafana_settings)
name = 'toolchain'
version = '0.9.0'
# NOTE(rpromyshlennikov): use list(set(plugin1.role_name + plugin2.role_name))
role_name = influxdb_grafana_settings.role_name

View File

@ -10,7 +10,7 @@ distribute = false
[flake8]
filename=*.py
ignore = H703
ignore = H405, H703
show-source = true
exclude = .venv,.git,.tox,dist,doc,*egg,*lib/python*,build,releasenotes,tmp,utils/fuel-qa-builder/venv*
max-complexity=25