Re-enable and fix amulet tests

* Re-enable amulet tests which were disabled in error by the a
  previous commit.
* Charmhelper sync to pickup cinder v2+ compat fixes in amulet
  helper utils
* Add thin-provisioning-tools to packages as cinder now creates
  thin lvm volumes by default and needs that pkg
* General v2 compat fixes in amulet tests

Change-Id: Ice227870c8a705d550107de280ebd65fdff31544
This commit is contained in:
Liam Young 2017-11-07 20:23:26 +00:00
parent 209341a601
commit 1609a71ce1
7 changed files with 159 additions and 27 deletions

View File

@ -30,6 +30,7 @@ import yaml
from charmhelpers.core.hookenv import (
config,
hook_name,
local_unit,
log,
relation_ids,
@ -302,7 +303,12 @@ class NRPE(object):
"command": nrpecheck.command,
}
service('restart', 'nagios-nrpe-server')
# update-status hooks are configured to firing every 5 minutes by
# default. When nagios-nrpe-server is restarted, the nagios server
# reports checks failing causing unneccessary alerts. Let's not restart
# on update-status hooks.
if not hook_name() == 'update-status':
service('restart', 'nagios-nrpe-server')
monitor_ids = relation_ids("local-monitors") + \
relation_ids("nrpe-external-master")

View File

@ -628,6 +628,18 @@ class OpenStackAmuletUtils(AmuletUtils):
_keypair = nova.keypairs.create(name=keypair_name)
return _keypair
def _get_cinder_obj_name(self, cinder_object):
"""Retrieve name of cinder object.
:param cinder_object: cinder snapshot or volume object
:returns: str cinder object name
"""
# v1 objects store name in 'display_name' attr but v2+ use 'name'
try:
return cinder_object.display_name
except AttributeError:
return cinder_object.name
def create_cinder_volume(self, cinder, vol_name="demo-vol", vol_size=1,
img_id=None, src_vol_id=None, snap_id=None):
"""Create cinder volume, optionally from a glance image, OR
@ -678,6 +690,13 @@ class OpenStackAmuletUtils(AmuletUtils):
source_volid=src_vol_id,
snapshot_id=snap_id)
vol_id = vol_new.id
except TypeError:
vol_new = cinder.volumes.create(name=vol_name,
imageRef=img_id,
size=vol_size,
source_volid=src_vol_id,
snapshot_id=snap_id)
vol_id = vol_new.id
except Exception as e:
msg = 'Failed to create volume: {}'.format(e)
amulet.raise_status(amulet.FAIL, msg=msg)
@ -692,7 +711,7 @@ class OpenStackAmuletUtils(AmuletUtils):
# Re-validate new volume
self.log.debug('Validating volume attributes...')
val_vol_name = cinder.volumes.get(vol_id).display_name
val_vol_name = self._get_cinder_obj_name(cinder.volumes.get(vol_id))
val_vol_boot = cinder.volumes.get(vol_id).bootable
val_vol_stat = cinder.volumes.get(vol_id).status
val_vol_size = cinder.volumes.get(vol_id).size

View File

@ -22,6 +22,7 @@ from __future__ import print_function
import copy
from distutils.version import LooseVersion
from functools import wraps
from collections import namedtuple
import glob
import os
import json
@ -1164,3 +1165,42 @@ def meter_info():
"""Get the meter status information, if running in the meter-status-changed
hook."""
return os.environ.get('JUJU_METER_INFO')
def iter_units_for_relation_name(relation_name):
"""Iterate through all units in a relation
Generator that iterates through all the units in a relation and yields
a named tuple with rid and unit field names.
Usage:
data = [(u.rid, u.unit)
for u in iter_units_for_relation_name(relation_name)]
:param relation_name: string relation name
:yield: Named Tuple with rid and unit field names
"""
RelatedUnit = namedtuple('RelatedUnit', 'rid, unit')
for rid in relation_ids(relation_name):
for unit in related_units(rid):
yield RelatedUnit(rid, unit)
def ingress_address(rid=None, unit=None):
"""
Retrieve the ingress-address from a relation when available. Otherwise,
return the private-address. This function is to be used on the consuming
side of the relation.
Usage:
addresses = [ingress_address(rid=u.rid, unit=u.unit)
for u in iter_units_for_relation_name(relation_name)]
:param rid: string relation id
:param unit: string unit name
:side effect: calls relation_get
:return: string IP address
"""
settings = relation_get(rid=rid, unit=unit)
return (settings.get('ingress-address') or
settings.get('private-address'))

View File

@ -130,6 +130,7 @@ COMMON_PACKAGES = [
'python-mysqldb',
'python-psycopg2',
'qemu-utils',
'thin-provisioning-tools',
]
API_PACKAGES = ['cinder-api']

View File

@ -248,6 +248,10 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
snap_new = self.cinder.volume_snapshots.create(
volume_id=vol_id, display_name=name)
snap_id = snap_new.id
except TypeError:
snap_new = self.cinder.volume_snapshots.create(
volume_id=vol_id, name=name)
snap_id = snap_new.id
except Exception as e:
msg = 'Failed to snapshot the volume: {}'.format(e)
amulet.raise_status(amulet.FAIL, msg=msg)
@ -264,7 +268,8 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
# Validate snapshot
u.log.debug('Validating snapshot attributes...')
snap_name = self.cinder.volume_snapshots.get(snap_id).display_name
snap_name = u._get_cinder_obj_name(
self.cinder.volume_snapshots.get(snap_id))
snap_stat = self.cinder.volume_snapshots.get(snap_id).status
snap_vol_id = self.cinder.volume_snapshots.get(snap_id).volume_id
msg_attr = ('Snapshot attributes - name:{} status:{} '
@ -284,7 +289,9 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
cinder volumes and snapshots that exist."""
u.log.debug('Checking cinder volumes against lvm volumes...')
# Inspect
cmd = 'sudo lvs | grep cinder-volumes | awk \'{ print $1 }\''
cmd = ('sudo lvs | grep -E \'^\s*(volume|_snap)\' | '
'grep cinder-volumes | awk \'{ print $1 }\'')
output, code = self.cinder_sentry.run(cmd)
u.log.debug('{} `{}` returned '
'{}'.format(self.cinder_sentry.info['unit_name'],
@ -311,7 +318,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
for vol_this in vol_list:
try:
vol_id = vol_this.id
vol_name = vol_this.display_name
vol_name = u._get_cinder_obj_name(vol_this)
lv_id = 'volume-{}'.format(vol_id)
_index = lv_id_list.index(lv_id)
u.log.info('Volume ({}) correlates to lv '
@ -326,7 +333,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
return None
def HOLDtest_100_services(self):
def test_100_services(self):
"""Verify that the expected services are running on the
cinder unit."""
services = {
@ -339,13 +346,13 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
if self._get_openstack_release() < self.xenial_ocata:
services[self.cinder_sentry].append('cinder-api')
def HOLDtest_110_memcache(self):
def test_110_memcache(self):
u.validate_memcache(self.cinder_sentry,
'/etc/cinder/cinder.conf',
self._get_openstack_release(),
earliest_release=self.trusty_mitaka)
def HOLDtest_110_users(self):
def test_110_users(self):
"""Verify expected users."""
u.log.debug('Checking keystone users...')
if self._get_openstack_release() < self.xenial_pike:
@ -379,7 +386,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
if ret:
amulet.raise_status(amulet.FAIL, msg=ret)
def HOLDtest_112_service_catalog(self):
def test_112_service_catalog(self):
"""Verify that the service catalog endpoint data"""
u.log.debug('Checking keystone service catalog...')
endpoint_vol = {'adminURL': u.valid_url,
@ -410,7 +417,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
if ret:
amulet.raise_status(amulet.FAIL, msg=ret)
def HOLDtest_114_cinder_endpoint(self):
def test_114_cinder_endpoint(self):
"""Verify the cinder endpoint data."""
u.log.debug('Checking cinder endpoint...')
endpoints = self.keystone.endpoints.list()
@ -428,7 +435,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
amulet.raise_status(amulet.FAIL,
msg='cinder endpoint: {}'.format(ret))
def HOLDtest_202_cinder_glance_image_service_relation(self):
def test_202_cinder_glance_image_service_relation(self):
"""Verify the cinder:glance image-service relation data"""
u.log.debug('Checking cinder:glance image-service relation data...')
unit = self.cinder_sentry
@ -439,7 +446,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
msg = u.relation_error('cinder image-service', ret)
amulet.raise_status(amulet.FAIL, msg=msg)
def HOLDtest_203_glance_cinder_image_service_relation(self):
def test_203_glance_cinder_image_service_relation(self):
"""Verify the glance:cinder image-service relation data"""
u.log.debug('Checking glance:cinder image-service relation data...')
unit = self.glance_sentry
@ -453,7 +460,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
msg = u.relation_error('glance image-service', ret)
amulet.raise_status(amulet.FAIL, msg=msg)
def HOLDtest_204_mysql_cinder_db_relation(self):
def test_204_mysql_cinder_db_relation(self):
"""Verify the mysql:glance shared-db relation data"""
u.log.debug('Checking mysql:cinder db relation data...')
unit = self.pxc_sentry
@ -467,7 +474,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
msg = u.relation_error('mysql shared-db', ret)
amulet.raise_status(amulet.FAIL, msg=msg)
def HOLDtest_205_cinder_mysql_db_relation(self):
def test_205_cinder_mysql_db_relation(self):
"""Verify the cinder:mysql shared-db relation data"""
u.log.debug('Checking cinder:mysql db relation data...')
unit = self.cinder_sentry
@ -483,7 +490,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
msg = u.relation_error('cinder shared-db', ret)
amulet.raise_status(amulet.FAIL, msg=msg)
def HOLDtest_206_keystone_cinder_id_relation(self):
def test_206_keystone_cinder_id_relation(self):
"""Verify the keystone:cinder identity-service relation data"""
u.log.debug('Checking keystone:cinder id relation data...')
unit = self.keystone_sentry
@ -515,7 +522,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
msg = u.relation_error('identity-service cinder', ret)
amulet.raise_status(amulet.FAIL, msg=msg)
def HOLDtest_207_cinder_keystone_id_relation(self):
def test_207_cinder_keystone_id_relation(self):
"""Verify the cinder:keystone identity-service relation data"""
u.log.debug('Checking cinder:keystone id relation data...')
unit = self.cinder_sentry
@ -529,7 +536,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
msg = u.relation_error('cinder identity-service', ret)
amulet.raise_status(amulet.FAIL, msg=msg)
def HOLDtest_208_rabbitmq_cinder_amqp_relation(self):
def test_208_rabbitmq_cinder_amqp_relation(self):
"""Verify the rabbitmq-server:cinder amqp relation data"""
u.log.debug('Checking rmq:cinder amqp relation data...')
unit = self.rabbitmq_sentry
@ -544,7 +551,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
msg = u.relation_error('amqp cinder', ret)
amulet.raise_status(amulet.FAIL, msg=msg)
def HOLDtest_209_cinder_rabbitmq_amqp_relation(self):
def test_209_cinder_rabbitmq_amqp_relation(self):
"""Verify the cinder:rabbitmq-server amqp relation data"""
u.log.debug('Checking cinder:rmq amqp relation data...')
unit = self.cinder_sentry
@ -559,7 +566,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
msg = u.relation_error('cinder amqp', ret)
amulet.raise_status(amulet.FAIL, msg=msg)
def HOLDtest_300_cinder_config(self):
def test_300_cinder_config(self):
"""Verify the data in the cinder.conf file."""
u.log.debug('Checking cinder config file data...')
unit = self.cinder_sentry
@ -652,7 +659,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
message = "cinder config error: {}".format(ret)
amulet.raise_status(amulet.FAIL, msg=message)
def HOLDtest_301_cinder_logging_config(self):
def test_301_cinder_logging_config(self):
"""Verify the data in the cinder logging conf file."""
u.log.debug('Checking cinder logging config file data...')
unit = self.cinder_sentry
@ -679,7 +686,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
message = "cinder logging config error: {}".format(ret)
amulet.raise_status(amulet.FAIL, msg=message)
def HOLDtest_303_cinder_rootwrap_config(self):
def test_303_cinder_rootwrap_config(self):
"""Inspect select config pairs in rootwrap.conf."""
u.log.debug('Checking cinder rootwrap config file data...')
unit = self.cinder_sentry
@ -703,14 +710,14 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
u.log.debug('Cinder api check (volumes.list): {}'.format(check))
assert(check == [])
def HOLDtest_401_create_delete_volume(self):
def test_401_create_delete_volume(self):
"""Create a cinder volume and delete it."""
u.log.debug('Creating, checking and deleting cinder volume...')
vol_new = u.create_cinder_volume(self.cinder)
vol_id = vol_new.id
u.delete_resource(self.cinder.volumes, vol_id, msg="cinder volume")
def HOLDtest_402_create_delete_volume_from_image(self):
def test_402_create_delete_volume_from_image(self):
"""Create a cinder volume from a glance image, and delete it."""
u.log.debug('Creating, checking and deleting cinder volume'
'from glance image...')
@ -723,7 +730,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
u.delete_resource(self.glance.images, img_id, msg="glance image")
u.delete_resource(self.cinder.volumes, vol_id, msg="cinder volume")
def HOLDtest_403_volume_snap_clone_extend_inspect(self):
def test_403_volume_snap_clone_extend_inspect(self):
"""Create a cinder volume, clone it, extend its size, create a
snapshot of the volume, create a volume from a snapshot, check
status of each, inspect underlying lvm, then delete the resources."""
@ -772,7 +779,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
u.log.debug('Deleting volume {}...'.format(vol.id))
u.delete_resource(self.cinder.volumes, vol.id, msg="cinder volume")
def HOLDtest_900_restart_on_config_change(self):
def test_900_restart_on_config_change(self):
"""Verify that the specified services are restarted when the
config is changed."""
@ -816,7 +823,7 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
self.d.configure(juju_service, set_default)
def HOLDtest_910_pause_and_resume(self):
def test_910_pause_and_resume(self):
"""The services can be paused and resumed. """
u.log.debug('Checking pause and resume actions...')
unit = self.d.sentry['cinder'][0]

View File

@ -628,6 +628,18 @@ class OpenStackAmuletUtils(AmuletUtils):
_keypair = nova.keypairs.create(name=keypair_name)
return _keypair
def _get_cinder_obj_name(self, cinder_object):
"""Retrieve name of cinder object.
:param cinder_object: cinder snapshot or volume object
:returns: str cinder object name
"""
# v1 objects store name in 'display_name' attr but v2+ use 'name'
try:
return cinder_object.display_name
except AttributeError:
return cinder_object.name
def create_cinder_volume(self, cinder, vol_name="demo-vol", vol_size=1,
img_id=None, src_vol_id=None, snap_id=None):
"""Create cinder volume, optionally from a glance image, OR
@ -678,6 +690,13 @@ class OpenStackAmuletUtils(AmuletUtils):
source_volid=src_vol_id,
snapshot_id=snap_id)
vol_id = vol_new.id
except TypeError:
vol_new = cinder.volumes.create(name=vol_name,
imageRef=img_id,
size=vol_size,
source_volid=src_vol_id,
snapshot_id=snap_id)
vol_id = vol_new.id
except Exception as e:
msg = 'Failed to create volume: {}'.format(e)
amulet.raise_status(amulet.FAIL, msg=msg)
@ -692,7 +711,7 @@ class OpenStackAmuletUtils(AmuletUtils):
# Re-validate new volume
self.log.debug('Validating volume attributes...')
val_vol_name = cinder.volumes.get(vol_id).display_name
val_vol_name = self._get_cinder_obj_name(cinder.volumes.get(vol_id))
val_vol_boot = cinder.volumes.get(vol_id).bootable
val_vol_stat = cinder.volumes.get(vol_id).status
val_vol_size = cinder.volumes.get(vol_id).size

View File

@ -22,6 +22,7 @@ from __future__ import print_function
import copy
from distutils.version import LooseVersion
from functools import wraps
from collections import namedtuple
import glob
import os
import json
@ -1164,3 +1165,42 @@ def meter_info():
"""Get the meter status information, if running in the meter-status-changed
hook."""
return os.environ.get('JUJU_METER_INFO')
def iter_units_for_relation_name(relation_name):
"""Iterate through all units in a relation
Generator that iterates through all the units in a relation and yields
a named tuple with rid and unit field names.
Usage:
data = [(u.rid, u.unit)
for u in iter_units_for_relation_name(relation_name)]
:param relation_name: string relation name
:yield: Named Tuple with rid and unit field names
"""
RelatedUnit = namedtuple('RelatedUnit', 'rid, unit')
for rid in relation_ids(relation_name):
for unit in related_units(rid):
yield RelatedUnit(rid, unit)
def ingress_address(rid=None, unit=None):
"""
Retrieve the ingress-address from a relation when available. Otherwise,
return the private-address. This function is to be used on the consuming
side of the relation.
Usage:
addresses = [ingress_address(rid=u.rid, unit=u.unit)
for u in iter_units_for_relation_name(relation_name)]
:param rid: string relation id
:param unit: string unit name
:side effect: calls relation_get
:return: string IP address
"""
settings = relation_get(rid=rid, unit=unit)
return (settings.get('ingress-address') or
settings.get('private-address'))