Files
zaza-openstack-tests/zaza/openstack/charm_tests/masakari/tests.py
2019-07-22 10:20:26 +00:00

198 lines
7.4 KiB
Python

#!/usr/bin/env python3
# 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.
"""Encapsulate masakari testing."""
from datetime import datetime
import logging
import tenacity
import novaclient
import zaza.model
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.utilities.juju as juju_utils
import zaza.openstack.utilities.openstack as openstack_utils
import zaza.openstack.configure.guest
import zaza.openstack.configure.hacluster
import zaza.openstack.configure.masakari
class MasakariTest(test_utils.OpenStackBaseTest):
"""Encapsulate Masakari tests."""
@classmethod
def setUpClass(cls):
"""Run class setup for running tests."""
super(MasakariTest, cls).setUpClass()
cls.keystone_session = openstack_utils.get_overcloud_keystone_session()
cls.model_name = zaza.model.get_juju_model()
cls.nova_client = openstack_utils.get_nova_session_client(
cls.keystone_session)
@classmethod
def tearDown(cls):
"""Bring hypervisors and services back up."""
logging.info('Running teardown')
for unit in zaza.model.get_units('nova-compute',
model_name=cls.model_name):
zaza.openstack.configure.masakari.simulate_compute_host_recovery(
unit.entity_id,
model_name=cls.model_name)
openstack_utils.enable_all_nova_services(cls.nova_client)
zaza.openstack.configure.masakari.enable_hosts()
def ensure_guest(self, vm_name):
"""Return the existing guest or boot a new one.
:param vm_name: Name of guest to lookup
:type vm_name: str
:returns: Guest matching name.
:rtype: novaclient.v2.servers.Server
"""
try:
guest = self.nova_client.servers.find(name=vm_name)
logging.info('Found existing guest')
except novaclient.exceptions.NotFound:
logging.info('Launching new guest')
guest = zaza.openstack.configure.guest.launch_instance(
'bionic',
use_boot_volume=True,
meta={'HA_Enabled': 'True'},
vm_name=vm_name)
return guest
def get_guests_compute_info(self, vm_name):
"""Return the hostname & juju unit of compute host hosting vm.
:param vm_name: Name of guest to lookup
:type vm_name: str
:returns: Hypervisor name and juju unit name
:rtype: (str, str)
"""
current_hypervisor = openstack_utils.get_hypervisor_for_guest(
self.nova_client,
vm_name)
unit_name = juju_utils.get_unit_name_from_host_name(
current_hypervisor,
'nova-compute')
return current_hypervisor, unit_name
def get_guest_qemu_pid(self, compute_unit_name, vm_uuid, model_name=None):
"""Return the qemu pid of process running guest.
:param compute_unit_name: Juju unit name of hypervisor running guest
:type compute_unit_name: str
:param vm_uuid: Guests UUID
:type vm_uuid: str
:param model_name: Name of model running cloud.
:type model_name: str
:returns: PID of qemu process
:rtype: int
:raises: ValueError
"""
pid_find_cmd = 'pgrep -u libvirt-qemu -f {}'.format(vm_uuid)
out = zaza.model.run_on_unit(
compute_unit_name,
pid_find_cmd,
model_name=self.model_name)
return int(out['Stdout'].strip())
@tenacity.retry(wait=tenacity.wait_exponential(multiplier=2, max=60),
reraise=True, stop=tenacity.stop_after_attempt(5),
retry=tenacity.retry_if_exception_type(ValueError))
def wait_for_guest_pid(self, compute_unit_name, vm_uuid, model_name=None):
"""Wait for the qemu process running guest to appear & return its pid.
:param compute_unit_name: Juju unit name of hypervisor running guest
:type compute_unit_name: str
:param vm_uuid: Guests UUID
:type vm_uuid: str
:param model_name: Name of model running cloud.
:type model_name: str
:returns: PID of qemu process
:rtype: int
:raises: ValueError
"""
return self.get_guest_qemu_pid(
compute_unit_name,
vm_uuid,
model_name=self.model_name)
def test_instance_failover(self):
"""Test masakari managed guest migration."""
# Launch guest
self.assertTrue(
zaza.openstack.configure.hacluster.check_all_nodes_online(
'masakari'))
vm_name = 'zaza-test-instance-failover'
self.ensure_guest(vm_name)
# Locate hypervisor hosting guest and shut it down
current_hypervisor, unit_name = self.get_guests_compute_info(vm_name)
zaza.openstack.configure.masakari.simulate_compute_host_failure(
unit_name,
model_name=self.model_name)
# Wait for instance move
logging.info('Waiting for guest to move away from {}'.format(
current_hypervisor))
# wait_for_server_migration will throw an exception if migration fails
openstack_utils.wait_for_server_migration(
self.nova_client,
vm_name,
current_hypervisor)
# Bring things back
zaza.openstack.configure.masakari.simulate_compute_host_recovery(
unit_name,
model_name=self.model_name)
openstack_utils.enable_all_nova_services(self.nova_client)
zaza.openstack.configure.masakari.enable_hosts()
def test_instance_restart_on_fail(self):
"""Test singlee guest crash and recovery."""
vm_name = 'zaza-test-instance-failover'
vm = self.ensure_guest(vm_name)
_, unit_name = self.get_guests_compute_info(vm_name)
logging.info('{} is running on {}'.format(vm_name, unit_name))
guest_pid = self.get_guest_qemu_pid(
unit_name,
vm.id,
model_name=self.model_name)
logging.info('{} pid is {}'.format(vm_name, guest_pid))
inital_update_time = datetime.strptime(
vm.updated,
"%Y-%m-%dT%H:%M:%SZ")
logging.info('Simulating vm crash of {}'.format(vm_name))
zaza.openstack.configure.masakari.simulate_guest_crash(
guest_pid,
unit_name,
model_name=self.model_name)
logging.info('Waiting for {} to be updated and become active'.format(
vm_name))
openstack_utils.wait_for_server_update_and_active(
self.nova_client,
vm_name,
inital_update_time)
new_guest_pid = self.wait_for_guest_pid(
unit_name,
vm.id,
model_name=self.model_name)
logging.info('{} pid is now {}'.format(vm_name, guest_pid))
assert new_guest_pid and new_guest_pid != guest_pid, (
"Restart failed or never happened")