Add masakari test support

Add support for testing masakari.
This commit is contained in:
Liam Young
2019-03-05 12:55:49 +00:00
parent d10ef061a9
commit 3efdbe4995
3 changed files with 213 additions and 1 deletions

View File

@@ -0,0 +1,22 @@
# Copyright 2019 Canonical Ltd.
#
# 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.
"""Code for setting up masakari tests."""
import zaza.configure.masakari
def create_segments():
"""Create simple segment setup."""
zaza.configure.masakari.create_segments()

169
zaza/configure/masakari.py Normal file
View File

@@ -0,0 +1,169 @@
# Copyright 2019 Canonical Ltd.
#
# 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.
"""Configure and manage masakari.
Functions for managing masakari resources and simulating compute node loss
and recovery.
"""
import logging
import zaza.model
import zaza.utilities.openstack as openstack_utils
ROUND_ROBIN = 'round-robin'
def roundrobin_assign_hosts_to_segments(nova_client, masakari_client):
"""Assign hypervisors to segments in a round-robin fashion.
:param nova_client: Authenticated nova client
:type nova_client: novaclient.Client
:param masakari_client: Authenticated masakari client
:type masakari_client: openstack.instance_ha.v1._proxy.Proxy
"""
hypervisors = nova_client.hypervisors.list()
segment_ids = [s.uuid for s in masakari_client.segments()]
segment_ids = segment_ids * len(hypervisors)
for hypervisor in hypervisors:
target_segment = segment_ids.pop()
hostname = hypervisor.hypervisor_hostname.split('.')[0]
logging.info('Adding {} to segment {}'.format(hostname,
target_segment))
masakari_client.create_host(
name=hostname,
segment_id=target_segment,
recovery_method='auto',
control_attributes='SSH',
type='COMPUTE')
HOST_ASSIGNMENT_METHODS = {
ROUND_ROBIN: roundrobin_assign_hosts_to_segments
}
def create_segments(segment_number=1, host_assignment_method=None):
"""Create a masakari segment and populate it with hypervisors.
:param segment_number: Number of segments to create
:type segment_number: int
:param host_assignment_method: Method to use to assign hypervisors to
segments
:type host_assignment_method: f()
"""
host_assignment_method = host_assignment_method or ROUND_ROBIN
keystone_session = openstack_utils.get_overcloud_keystone_session()
nova_client = openstack_utils.get_nova_session_client(keystone_session)
masakari_client = openstack_utils.get_masakari_session_client(
keystone_session)
for segment_number in range(0, segment_number):
segment_name = 'seg{}'.format(segment_number)
logging.info('Creating segment {}'.format(segment_name))
masakari_client.create_segment(
name=segment_name,
recovery_method='auto',
service_type='COMPUTE')
HOST_ASSIGNMENT_METHODS[host_assignment_method](
nova_client,
masakari_client)
def enable_hosts(masakari_client=None):
"""Enable all hypervisors within masakari.
Enable all hosts across all segments within masakari. This does not
enable the hypervisor from a nova POV.
:param masakari_client: Authenticated masakari client
:type masakari_client: openstack.instance_ha.v1._proxy.Proxy
"""
if not masakari_client:
keystone_session = openstack_utils.get_overcloud_keystone_session()
masakari_client = openstack_utils.get_masakari_session_client(
keystone_session)
for segment in masakari_client.segments():
for host in masakari_client.hosts(segment_id=segment.uuid):
if host.on_maintenance:
logging.info("Removing maintenance mode from masakari "
"host {}".format(host.uuid))
masakari_client.update_host(
host.uuid,
segment_id=segment.uuid,
**{'on_maintenance': False})
def _svc_control(unit_name, action, services, model_name):
"""Enable/Disable services on a unit.
This is a simplistic method for controlling services, hence its private.
:param unit_name: Juju name of unit (app/n)
:type unit_name: str
:param action: systemctl action to perform on unit (start/stop etc)
:type action: str
:param services: List of services to perform action against
:type services: []
:param model_name: Name of model unit_name resides in.
:type model_name: str
"""
logging.info('{} {} on {}'.format(action.title(), services, unit_name))
cmds = []
for svc in services:
cmds.append("systemctl {} {}".format(action, svc))
zaza.model.run_on_unit(
unit_name, command=';'.join(cmds),
model_name=model_name)
def simulate_compute_host_failure(unit_name, model_name):
"""Simulate compute node failure from a masakari and nova POV.
Masakari uses corosync/pacemaker to detect failure and nova check
nova-compute. Shutting down these services causes masakari and nova to
mark them as down.
:param unit_name: Juju name of unit (app/n)
:type unit_name: str
:param model_name: Name of model unit_name resides in.
:type model_name: str
"""
logging.info('Simulating failure of compute node {}'.format(unit_name))
_svc_control(
unit_name,
'stop',
['corosync', 'pacemaker', 'nova-compute'],
model_name)
def simulate_compute_host_recovery(unit_name, model_name):
"""Simulate compute node recovery from a masakari and nova POV.
Masakari uses corosync/pacemaker to detect failure and nova check
nova-compute. Starting these services is a prerequisite to marking
them as recovered.
:param unit_name: Juju name of unit (app/n)
:type unit_name: str
:param model_name: Name of model unit_name resides in.
:type model_name: str
"""
logging.info('Simulating recovery of compute node {}'.format(unit_name))
_svc_control(
unit_name,
'start',
['corosync', 'pacemaker', 'nova-compute'],
model_name)

View File

@@ -23,6 +23,8 @@ from .os_versions import (
OPENSTACK_RELEASES_PAIRS,
)
from openstack import connection
from cinderclient import client as cinderclient
from glanceclient import Client as GlanceClient
@@ -215,7 +217,7 @@ def get_swift_session_client(session):
def get_octavia_session_client(session, service_type='load-balancer',
interface='internal'):
"""Return neutronclient authenticated by keystone session.
"""Return octavia client authenticated by keystone session.
:param session: Keystone session object
:type session: keystoneauth1.session.Session object
@@ -251,6 +253,25 @@ def get_cinder_session_client(session, version=2):
return cinderclient.Client(session=session, version=version)
def get_masakari_session_client(session, interface='internal',
region_name='RegionOne'):
"""Return masakari client authenticated by keystone session.
:param session: Keystone session object
:type session: keystoneauth1.session.Session object
:param interface: Interface to look for in catalog
:type interface: str
:param region_name: Region name to use in catalogue lookup
:type region_name: str
:returns: Authenticated masakari client
:rtype: openstack.instance_ha.v1._proxy.Proxy
"""
conn = connection.Connection(session=session,
interface=interface,
region_name=region_name)
return conn.instance_ha
def get_keystone_scope():
"""Return Keystone scope based on OpenStack release of the overcloud.