Add comments to the common code

This change also removes some methods that weren't needed.

Change-Id: Iafa215d7c9418b0e3b82b7ff9a4919ee6c5ac6a7
This commit is contained in:
Simon Pasquier 2016-05-19 14:25:02 +02:00
parent 40e9aeae69
commit 41596d7062
4 changed files with 113 additions and 54 deletions

View File

@ -21,12 +21,11 @@ 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."""
"""Base class to manage StackLight plugins with Fuel."""
def __init__(self):
self.test = base_test_case.TestBasic()
@ -42,16 +41,17 @@ class PluginApi(object):
@property
def base_nodes(self):
base_nodes = {
"""Return a dict mapping nodes to Fuel roles without HA."""
return {
'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 = {
"""Return a dict mapping nodes to Fuel roles with HA."""
return {
'slave-01': ['controller'],
'slave-02': ['controller'],
'slave-03': ['controller'],
@ -62,33 +62,48 @@ class PluginApi(object):
'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,
)
def create_cluster(self, name=None, settings=None):
"""Create a cluster.
:param name: name of the cluster (default: class's name).
:type name: str
:param settings: optional dict containing the cluster's configuration.
:type settings: dict
:returns: the cluster's id
:rtype: str
"""
return self.env.fuel_web.create_cluster(
name=self.__class__.__name__,
settings=settings,
mode='ha_compact')
@abc.abstractmethod
def get_plugin_settings(self):
"""Return a dict with the default plugin's settings.
"""
pass
@abc.abstractmethod
def prepare_plugin(self):
"""Upload and install the plugin on the Fuel master node.
"""
pass
@abc.abstractmethod
def activate_plugin(self):
"""Enable and configure the plugin in the environment.
"""
pass
@abc.abstractmethod
def get_plugin_vip(self):
"""Get the VIP address associated to the plugin (if any).
"""
pass
@abc.abstractmethod
def check_plugin_online(self):
"""Check that the plugin works properly.
"""
pass

View File

@ -20,7 +20,7 @@ def check_http_get_response(url, expected_code=200, msg=None, **kwargs):
"""Perform a HTTP GET request and assert that the HTTP server replies with
the expected code.
:param url: the request URL
:param url: the requested URL
:type url: str
:param expected_code: the expected HTTP response code. Defaults to 200
:type expected_code: int

View File

@ -22,18 +22,10 @@ from fuelweb_test.helpers import checkers
from fuelweb_test import logger
from proboscis import asserts
from stacklight_tests import settings
PACKAGE_VERSION_RE = re.compile(r'(\d+\.\d+\.\d+)')
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)
def get_plugin_version(filename):
"""Extract the plugin version from the package filename.
@ -106,21 +98,36 @@ class PluginHelper(object):
self.fuel_web.deploy_cluster_wait(self.cluster_id)
def run_ostf(self, *args, **kwargs):
"""Run the OpenStack health checks."""
self.fuel_web.run_ostf(self.cluster_id, *args, **kwargs)
def run_single_ostf(self, test_sets, test_name, *args, **kwargs):
"""Run a subset of the OpenStack health checks."""
self.fuel_web.run_single_ostf_test(self.cluster_id, test_sets,
test_name, *args, **kwargs)
def verify_service(self, ip, service_name, count):
"""Check that a process is running on a host.
:param ip: IP address of the host.
:type ip: str
:param service_name: the process name to match.
:type service_name: str
:param count: the number of processes to match.
:type count: int
"""
with self.env.d_env.get_ssh_to_remote(ip) as remote:
checkers.verify_service(remote, service_name, count)
def add_node_to_cluster(self, node, redeploy=True, check_services=False):
"""Method to add node to cluster
:param node: node to add to cluster
:param redeploy: redeploy or just update settings
:param check_services: run OSTF after redeploy or not
"""Add nodes to the cluster.
:param node: list of nodes with their roles.
:type: node: dict
:param redeploy: whether to redeploy the cluster (default: True).
:type redeploy: boolean
:param check_services: run OSTF after redeploy (default: False).
:type check_services: boolean
"""
self.fuel_web.update_nodes(
self.cluster_id,
@ -132,11 +139,15 @@ class PluginHelper(object):
def remove_node_from_cluster(self, node, redeploy=True,
check_services=False):
"""Method to remove node to cluster
:param node: node to add to cluster
:param redeploy: redeploy or just update settings
:param check_services: run OSTF after redeploy or not
"""
"""Remove nodes from the cluster.
:param node: list of nodes to remove from the cluster.
:type node: dict
:param redeploy: whether to redeploy the cluster (default: True).
:type redeploy: boolean
:param check_services: run OSTF after redeploy (default: False).
:type check_services: boolean
"""
self.fuel_web.update_nodes(
self.cluster_id,
node,
@ -147,6 +158,8 @@ class PluginHelper(object):
check_services=check_services)
def get_master_node_by_role(self, role_name, excluded_nodes_fqdns=()):
"""Return the node running as the Designated Controller (DC).
"""
nodes = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, role_name)
nodes = [node for node in nodes
@ -159,6 +172,8 @@ class PluginHelper(object):
return node
def hard_shutdown_node(self, fqdn):
"""Power off a node.
"""
devops_node = self.fuel_web.get_devops_node_by_nailgun_fqdn(
fqdn)
msg = 'Node {0} has not become offline after hard shutdown'.format(
@ -169,42 +184,44 @@ class PluginHelper(object):
helpers.wait(lambda: not self.fuel_web.get_nailgun_node_by_devops_node(
devops_node)['online'], timeout=60 * 5, timeout_msg=msg)
@staticmethod
def block_network_by_interface(interface):
if interface.network.is_blocked:
raise Exception('Network {0} is blocked'.format(interface))
else:
interface.network.block()
@staticmethod
def unblock_network_by_interface(interface):
if interface.network.is_blocked:
interface.network.unblock()
else:
raise Exception(
'Network {0} was not blocked'.format(interface))
def emulate_whole_network_disaster(self, delay_before_recover=5 * 60,
wait_become_online=True):
"""Simulate a full network outage for all nodes.
:param delay_before_recover: outage interval in seconds (default: 300).
:type delay_before_recover: int
:param wait_become_online: whether to wait for nodes to be back online.
:type wait_become_online: bool
"""
nodes = [node for node in self.env.d_env.get_nodes()
if node.driver.node_active(node)]
networks_interfaces = nodes[1].interfaces
for interface in networks_interfaces:
self.block_network_by_interface(interface)
interface.network.block()
time.sleep(delay_before_recover)
for interface in networks_interfaces:
self.unblock_network_by_interface(interface)
interface.network.unblock()
if wait_become_online:
self.fuel_web.wait_nodes_get_online_state(nodes[1:])
def uninstall_plugin(self, plugin_name, plugin_version, exit_code=0,
msg=None):
"""Remove a plugin.
:param plugin_name: plugin's name.
:type plugin_name: str
:param plugin_version: plugin's version.
:type plugin_version: str
:param exit_code: expected exit code.
:type exit_code: int
:param msg: message in case of error.
:type msg: str
"""
msg = msg or "Plugin {0} deletion failed: exit code is {1}"
with self.env.d_env.get_admin_remote() as remote:
exec_res = remote.execute("fuel plugins --remove"

View File

@ -14,6 +14,15 @@
def get_all_bridged_interfaces_for_node(remote, excluded_criteria=None):
"""Return all network bridges for a node.
:param remote: SSH connection to the node.
:type remote: SSHClient
:param excluded_criteria: regular expression to filter out items
:type excluded_criteria: str
:returns: list of interfaces
:rtype: list
"""
# TODO(rpromyshlennikov): do filtration on python side
excluded_criteria_cmd = (
" | grep -v '%s'" % excluded_criteria
@ -24,15 +33,33 @@ def get_all_bridged_interfaces_for_node(remote, excluded_criteria=None):
return [iface.strip() for iface in interfaces]
def switch_interface(remote, interface, method="up"):
def switch_interface(remote, interface, up=True):
"""Turn a network interface up or down.
:param remote: SSH connection to the node.
:type remote: SSHClient
:param interface: interface name.
:type interface: str
:param up: whether the interface should be turned up (default: True).
:type up: boolean
"""
method = 'up' if up else 'down'
cmd = "if{method} {interface}".format(method=method,
interface=interface)
remote.check_call(cmd)
def simulate_network_interrupt_on_node(remote):
def simulate_network_interrupt_on_node(remote, interval=30):
"""Simulate a network outage on a node.
:param remote: SSH connection to the node.
:type remote: SSHClient
:param interval: outage duration in seconds (default: 30).
:type interval: int
"""
cmd = (
"(/sbin/iptables -I INPUT -j DROP "
"&& sleep 30 "
"&& /sbin/iptables -D INPUT -j DROP) 2>&1>/dev/null &")
"(/sbin/iptables -I INPUT -j DROP && "
"sleep {interval} && "
"/sbin/iptables -D INPUT -j DROP) 2>&1>/dev/null &".format(
interval=interval))
remote.execute(cmd)