Files
zaza-openstack-tests/zaza/openstack/charm_tests/glance_simplestreams_sync/tests.py
David Ames 14a6f06586 Fix glance simplestreams sync test races
We expect at least three images. Avoid various race conditions by
retrying using tenacity.
2020-04-22 17:32:33 +00:00

125 lines
4.9 KiB
Python

# 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 glance-simplestreams-sync testing."""
import json
import logging
import requests
import tenacity
import zaza.model as zaza_model
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.utilities.openstack as openstack_utils
@tenacity.retry(
retry=tenacity.retry_if_result(lambda images: len(images) < 3),
wait=tenacity.wait_fixed(6), # interval between retries
stop=tenacity.stop_after_attempt(100)) # retry times
def retry_image_sync(glance_client):
"""Wait for image sync with retry."""
# convert generator to list
return list(glance_client.images.list())
@tenacity.retry(
retry=tenacity.retry_if_exception_type(json.decoder.JSONDecodeError),
wait=tenacity.wait_fixed(10), reraise=True,
stop=tenacity.stop_after_attempt(10))
def get_product_streams(url):
"""Get product streams json data with retry."""
# There is a race between the images being available in glance and any
# metadata being written. Use tenacity to avoid this race.
client = requests.session()
json_data = client.get(url).text
return json.loads(json_data)
class GlanceSimpleStreamsSyncTest(test_utils.OpenStackBaseTest):
"""Glance Simple Streams Sync Test."""
@classmethod
def setUpClass(cls):
"""Run class setup for running glance simple streams sync tests."""
super(GlanceSimpleStreamsSyncTest, cls).setUpClass()
# dict of OS_* env vars
overcloud_auth = openstack_utils.get_overcloud_auth()
cls.keystone_client = openstack_utils.get_keystone_client(
overcloud_auth)
cls.glance_client = openstack_utils.get_glance_session_client(
cls.keystone_session)
def test_010_wait_for_image_sync(self):
"""Wait for images to be synced. Expect at least three."""
self.assertTrue(retry_image_sync(self.glance_client))
def test_050_gss_permissions_regression_check_lp1611987(self):
"""Assert the intended file permissions on gss config files.
refer: https://bugs.launchpad.net/bugs/1611987
"""
file_paths = [
'/etc/glance-simplestreams-sync/identity.yaml',
'/etc/glance-simplestreams-sync/mirrors.yaml',
'/var/log/glance-simplestreams-sync.log',
]
expected_perms = '640'
application = 'glance-simplestreams-sync'
for unit in zaza_model.get_units(application):
for file_path in file_paths:
cmd = 'stat -c %a {}'.format(file_path)
result = zaza_model.run_on_unit(unit.name, cmd, timeout=30)
# {'Code': '', 'Stderr': '', 'Stdout': '644\n'}
perms = result.get('Stdout', '').strip()
self.assertEqual(perms, expected_perms)
logging.debug(
'Permissions on {}: {}'.format(file_path, perms))
def test_110_local_product_stream(self):
"""Verify that the local product stream is accessible and has data."""
logging.debug('Checking local product streams...')
expected_images = [
'com.ubuntu.cloud:server:14.04:amd64',
'com.ubuntu.cloud:server:16.04:amd64',
'com.ubuntu.cloud:server:18.04:amd64',
]
uri = "streams/v1/auto.sync.json"
key = "url"
xenial_pike = openstack_utils.get_os_release('xenial_pike')
if openstack_utils.get_os_release() <= xenial_pike:
key = "publicURL"
catalog = self.keystone_client.service_catalog.get_endpoints()
ps_interface = catalog["product-streams"][0][key]
url = "{}/{}".format(ps_interface, uri)
# There is a race between the images being available in glance and the
# metadata being written for each image. Use tenacity to avoid this
# race and make the test idempotent.
@tenacity.retry(
retry=tenacity.retry_if_exception_type(AssertionError),
wait=tenacity.wait_fixed(10), reraise=True,
stop=tenacity.stop_after_attempt(10))
def _check_local_product_streams(url, expected_images):
product_streams = get_product_streams(url)
images = product_streams["products"]
for image in expected_images:
self.assertIn(image, images)
_check_local_product_streams(url, expected_images)
logging.debug("Local product stream successful")