Merge branch 'master' into lourot/bug/1877076
This commit is contained in:
@@ -29,6 +29,7 @@ python-ceilometerclient
|
||||
python-cinderclient
|
||||
python-glanceclient
|
||||
python-heatclient
|
||||
python-ironicclient
|
||||
python-keystoneclient
|
||||
python-manilaclient
|
||||
python-neutronclient
|
||||
|
||||
@@ -44,6 +44,7 @@ install_require = [
|
||||
'python-barbicanclient>=4.0.1,<5.0.0',
|
||||
'python-designateclient>=1.5,<3.0.0',
|
||||
'python-heatclient<2.0.0',
|
||||
'python-ironicclient',
|
||||
'python-glanceclient<3.0.0',
|
||||
'python-keystoneclient<3.22.0',
|
||||
'python-manilaclient<2.0.0',
|
||||
|
||||
@@ -42,7 +42,7 @@ class TestTempestSetup(unittest.TestCase):
|
||||
'TEST_GATEWAY': 'test',
|
||||
'TEST_CIDR_EXT': 'test',
|
||||
'TEST_FIP_RANGE': 'test',
|
||||
'TEST_NAMESERVER': 'test',
|
||||
'TEST_NAME_SERVER': 'test',
|
||||
'TEST_CIDR_PRIV': 'test',
|
||||
}
|
||||
tempest_setup.add_environment_var_config(ctxt, ['neutron'])
|
||||
@@ -55,7 +55,7 @@ class TestTempestSetup(unittest.TestCase):
|
||||
ctxt = {}
|
||||
get_deployment_context.return_value = {
|
||||
'TEST_GATEWAY': 'test',
|
||||
'TEST_NAMESERVER': 'test',
|
||||
'TEST_NAME_SERVER': 'test',
|
||||
'TEST_CIDR_PRIV': 'test',
|
||||
}
|
||||
with self.assertRaises(Exception) as context:
|
||||
|
||||
@@ -504,7 +504,7 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
|
||||
glance_mock.images.upload.assert_called_once_with(
|
||||
'9d1125af',
|
||||
f(),
|
||||
)
|
||||
backend=None)
|
||||
self.resource_reaches_status.assert_called_once_with(
|
||||
glance_mock.images,
|
||||
'9d1125af',
|
||||
@@ -529,7 +529,11 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
|
||||
self.upload_image_to_glance.assert_called_once_with(
|
||||
glance_mock,
|
||||
'wibbly/c.img',
|
||||
'bob')
|
||||
'bob',
|
||||
backend=None,
|
||||
disk_format='qcow2',
|
||||
visibility='public',
|
||||
container_format='bare')
|
||||
|
||||
def test_create_image_pass_directory(self):
|
||||
glance_mock = mock.MagicMock()
|
||||
@@ -549,7 +553,11 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
|
||||
self.upload_image_to_glance.assert_called_once_with(
|
||||
glance_mock,
|
||||
'tests/c.img',
|
||||
'bob')
|
||||
'bob',
|
||||
backend=None,
|
||||
disk_format='qcow2',
|
||||
visibility='public',
|
||||
container_format='bare')
|
||||
self.gettempdir.assert_not_called()
|
||||
|
||||
def test_create_ssh_key(self):
|
||||
|
||||
@@ -32,8 +32,37 @@ def basic_setup():
|
||||
"""
|
||||
|
||||
|
||||
def _get_default_glance_client():
|
||||
"""Create default Glance client using overcloud credentials."""
|
||||
keystone_session = openstack_utils.get_overcloud_keystone_session()
|
||||
glance_client = openstack_utils.get_glance_session_client(keystone_session)
|
||||
return glance_client
|
||||
|
||||
|
||||
def get_stores_info(glance_client=None):
|
||||
"""Retrieve glance backing store info.
|
||||
|
||||
:param glance_client: Authenticated glanceclient
|
||||
:type glance_client: glanceclient.Client
|
||||
"""
|
||||
glance_client = glance_client or _get_default_glance_client()
|
||||
stores = glance_client.images.get_stores_info().get("stores", [])
|
||||
return stores
|
||||
|
||||
|
||||
def get_store_ids(glance_client=None):
|
||||
"""Retrieve glance backing store ids.
|
||||
|
||||
:param glance_client: Authenticated glanceclient
|
||||
:type glance_client: glanceclient.Client
|
||||
"""
|
||||
stores = get_stores_info(glance_client)
|
||||
return [store["id"] for store in stores]
|
||||
|
||||
|
||||
def add_image(image_url, glance_client=None, image_name=None, tags=[],
|
||||
properties=None):
|
||||
properties=None, backend=None, disk_format='qcow2',
|
||||
visibility='public', container_format='bare'):
|
||||
"""Retrieve image from ``image_url`` and add it to glance.
|
||||
|
||||
:param image_url: Retrievable URL with image data
|
||||
@@ -47,10 +76,14 @@ def add_image(image_url, glance_client=None, image_name=None, tags=[],
|
||||
:param properties: Properties to add to image
|
||||
:type properties: dict
|
||||
"""
|
||||
if not glance_client:
|
||||
keystone_session = openstack_utils.get_overcloud_keystone_session()
|
||||
glance_client = openstack_utils.get_glance_session_client(
|
||||
keystone_session)
|
||||
glance_client = glance_client or _get_default_glance_client()
|
||||
if backend is not None:
|
||||
stores = get_store_ids(glance_client)
|
||||
if backend not in stores:
|
||||
raise ValueError("Invalid backend: %(backend)s "
|
||||
"(available: %(available)s)" % {
|
||||
"backend": backend,
|
||||
"available": ", ".join(stores)})
|
||||
if image_name:
|
||||
image = openstack_utils.get_images_by_name(
|
||||
glance_client, image_name)
|
||||
@@ -65,7 +98,11 @@ def add_image(image_url, glance_client=None, image_name=None, tags=[],
|
||||
image_url,
|
||||
image_name,
|
||||
tags=tags,
|
||||
properties=properties)
|
||||
properties=properties,
|
||||
backend=backend,
|
||||
disk_format=disk_format,
|
||||
visibility=visibility,
|
||||
container_format=container_format)
|
||||
|
||||
|
||||
def add_cirros_image(glance_client=None, image_name=None):
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Copyright 2020 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.
|
||||
|
||||
"""Collection of code for setting up and testing ironic."""
|
||||
@@ -0,0 +1,184 @@
|
||||
# Copyright 2020 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 configuring ironic."""
|
||||
|
||||
import copy
|
||||
import os
|
||||
import tenacity
|
||||
|
||||
import zaza.openstack.charm_tests.glance.setup as glance_setup
|
||||
import zaza.openstack.utilities.openstack as openstack_utils
|
||||
from zaza.openstack.utilities import (
|
||||
cli as cli_utils,
|
||||
)
|
||||
import zaza.model as zaza_model
|
||||
|
||||
|
||||
FLAVORS = {
|
||||
'bm1.small': {
|
||||
'flavorid': 2,
|
||||
'ram': 2048,
|
||||
'disk': 20,
|
||||
'vcpus': 1,
|
||||
'properties': {
|
||||
"resources:CUSTOM_BAREMETAL1_SMALL": 1,
|
||||
},
|
||||
},
|
||||
'bm1.medium': {
|
||||
'flavorid': 3,
|
||||
'ram': 4096,
|
||||
'disk': 40,
|
||||
'vcpus': 2,
|
||||
'properties': {
|
||||
"resources:CUSTOM_BAREMETAL1_MEDIUM": 1,
|
||||
},
|
||||
},
|
||||
'bm1.large': {
|
||||
'flavorid': 4,
|
||||
'ram': 8192,
|
||||
'disk': 40,
|
||||
'vcpus': 4,
|
||||
'properties': {
|
||||
"resources:CUSTOM_BAREMETAL1_LARGE": 1,
|
||||
},
|
||||
},
|
||||
'bm1.tempest': {
|
||||
'flavorid': 6,
|
||||
'ram': 256,
|
||||
'disk': 1,
|
||||
'vcpus': 1,
|
||||
'properties': {
|
||||
"resources:CUSTOM_BAREMETAL1_TEMPEST": 1,
|
||||
},
|
||||
},
|
||||
'bm2.tempest': {
|
||||
'flavorid': 7,
|
||||
'ram': 512,
|
||||
'disk': 1,
|
||||
'vcpus': 1,
|
||||
'properties': {
|
||||
"resources:CUSTOM_BAREMETAL2_TEMPEST": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _add_image(url, image_name, backend="swift",
|
||||
disk_format="raw", container_format="bare"):
|
||||
for attempt in tenacity.Retrying(
|
||||
stop=tenacity.stop_after_attempt(3),
|
||||
reraise=True):
|
||||
with attempt:
|
||||
glance_setup.add_image(
|
||||
url,
|
||||
image_name=image_name,
|
||||
backend=backend,
|
||||
disk_format=disk_format,
|
||||
container_format=container_format)
|
||||
|
||||
|
||||
def add_ironic_deployment_image(initrd_url=None, kernel_url=None):
|
||||
"""Add Ironic deploy images to glance.
|
||||
|
||||
:param initrd_url: URL where the ari image resides
|
||||
:type initrd_url: str
|
||||
:param kernel_url: URL where the aki image resides
|
||||
:type kernel_url: str
|
||||
"""
|
||||
base_name = 'ironic-deploy'
|
||||
initrd_name = "{}-initrd".format(base_name)
|
||||
vmlinuz_name = "{}-vmlinuz".format(base_name)
|
||||
if not initrd_url:
|
||||
initrd_url = os.environ.get('TEST_IRONIC_DEPLOY_INITRD', None)
|
||||
if not kernel_url:
|
||||
kernel_url = os.environ.get('TEST_IRONIC_DEPLOY_VMLINUZ', None)
|
||||
if not all([initrd_url, kernel_url]):
|
||||
raise ValueError("Missing required deployment image URLs")
|
||||
|
||||
_add_image(
|
||||
initrd_url,
|
||||
initrd_name,
|
||||
backend="swift",
|
||||
disk_format="ari",
|
||||
container_format="ari")
|
||||
|
||||
_add_image(
|
||||
kernel_url,
|
||||
vmlinuz_name,
|
||||
backend="swift",
|
||||
disk_format="aki",
|
||||
container_format="aki")
|
||||
|
||||
|
||||
def add_ironic_os_image(image_url=None):
|
||||
"""Upload the operating system images built for bare metal deployments.
|
||||
|
||||
:param image_url: URL where the image resides
|
||||
:type image_url: str
|
||||
"""
|
||||
image_url = image_url or os.environ.get(
|
||||
'TEST_IRONIC_RAW_BM_IMAGE', None)
|
||||
image_name = "baremetal-ubuntu-image"
|
||||
if image_url is None:
|
||||
raise ValueError("Missing image_url")
|
||||
|
||||
_add_image(
|
||||
image_url,
|
||||
image_name,
|
||||
backend="swift",
|
||||
disk_format="raw",
|
||||
container_format="bare")
|
||||
|
||||
|
||||
def set_temp_url_secret():
|
||||
"""Run the set-temp-url-secret on the ironic-conductor leader.
|
||||
|
||||
This is needed if direct boot method is enabled.
|
||||
"""
|
||||
zaza_model.run_action_on_leader(
|
||||
'ironic-conductor',
|
||||
'set-temp-url-secret',
|
||||
action_params={})
|
||||
|
||||
|
||||
def create_bm_flavors(nova_client=None):
|
||||
"""Create baremetal flavors.
|
||||
|
||||
:param nova_client: Authenticated nova client
|
||||
:type nova_client: novaclient.v2.client.Client
|
||||
"""
|
||||
if not nova_client:
|
||||
keystone_session = openstack_utils.get_overcloud_keystone_session()
|
||||
nova_client = openstack_utils.get_nova_session_client(
|
||||
keystone_session)
|
||||
cli_utils.setup_logging()
|
||||
names = [flavor.name for flavor in nova_client.flavors.list()]
|
||||
# Disable scheduling based on standard flavor properties
|
||||
default_properties = {
|
||||
"resources:VCPU": 0,
|
||||
"resources:MEMORY_MB": 0,
|
||||
"resources:DISK_GB": 0,
|
||||
}
|
||||
for flavor in FLAVORS.keys():
|
||||
if flavor not in names:
|
||||
properties = copy.deepcopy(default_properties)
|
||||
properties.update(FLAVORS[flavor]["properties"])
|
||||
bm_flavor = nova_client.flavors.create(
|
||||
name=flavor,
|
||||
ram=FLAVORS[flavor]['ram'],
|
||||
vcpus=FLAVORS[flavor]['vcpus'],
|
||||
disk=FLAVORS[flavor]['disk'],
|
||||
flavorid=FLAVORS[flavor]['flavorid'])
|
||||
bm_flavor.set_keys(properties)
|
||||
@@ -0,0 +1,83 @@
|
||||
# Copyright 2020 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 ironic testing."""
|
||||
|
||||
import logging
|
||||
|
||||
import ironicclient.client as ironic_client
|
||||
import zaza.openstack.charm_tests.test_utils as test_utils
|
||||
import zaza.openstack.utilities.openstack as openstack_utils
|
||||
|
||||
|
||||
def _get_ironic_client(ironic_api_version="1.58"):
|
||||
keystone_session = openstack_utils.get_overcloud_keystone_session()
|
||||
ironic = ironic_client.Client(1, session=keystone_session,
|
||||
os_ironic_api_version=ironic_api_version)
|
||||
return ironic
|
||||
|
||||
|
||||
class IronicTest(test_utils.OpenStackBaseTest):
|
||||
"""Run Ironic specific tests."""
|
||||
|
||||
_SERVICES = ['ironic-api']
|
||||
|
||||
def test_110_catalog_endpoints(self):
|
||||
"""Verify that the endpoints are present in the catalog."""
|
||||
overcloud_auth = openstack_utils.get_overcloud_auth()
|
||||
keystone_client = openstack_utils.get_keystone_client(
|
||||
overcloud_auth)
|
||||
actual_endpoints = keystone_client.service_catalog.get_endpoints()
|
||||
actual_interfaces = [endpoint['interface'] for endpoint in
|
||||
actual_endpoints["baremetal"]]
|
||||
for expected_interface in ('internal', 'admin', 'public'):
|
||||
assert(expected_interface in actual_interfaces)
|
||||
|
||||
def test_400_api_connection(self):
|
||||
"""Simple api calls to check service is up and responding."""
|
||||
ironic = _get_ironic_client()
|
||||
|
||||
logging.info('listing conductors')
|
||||
conductors = ironic.conductor.list()
|
||||
assert(len(conductors) > 0)
|
||||
|
||||
# By default, only IPMI HW type is enabled. iDrac and Redfish
|
||||
# can optionally be enabled
|
||||
drivers = ironic.driver.list()
|
||||
driver_names = [drv.name for drv in drivers]
|
||||
|
||||
expected = ['intel-ipmi', 'ipmi']
|
||||
for exp in expected:
|
||||
assert(exp in driver_names)
|
||||
assert(len(driver_names) == 2)
|
||||
|
||||
def test_900_restart_on_config_change(self):
|
||||
"""Checking restart happens on config change.
|
||||
|
||||
Change debug mode and assert that change propagates to the correct
|
||||
file and that services are restarted as a result
|
||||
"""
|
||||
self.restart_on_changed_debug_oslo_config_file(
|
||||
'/etc/ironic/ironic.conf', self._SERVICES)
|
||||
|
||||
def test_910_pause_resume(self):
|
||||
"""Run pause and resume tests.
|
||||
|
||||
Pause service and check services are stopped then resume and check
|
||||
they are started
|
||||
"""
|
||||
logging.info('Skipping pause resume test LP: #1886202...')
|
||||
return
|
||||
with self.pause_resume(self._SERVICES):
|
||||
logging.info("Testing pause resume")
|
||||
@@ -38,31 +38,34 @@ class BaseGuestCreateTest(unittest.TestCase):
|
||||
zaza.openstack.configure.guest.launch_instance(instance_key)
|
||||
|
||||
|
||||
class CirrosGuestCreateTest(BaseGuestCreateTest):
|
||||
class CirrosGuestCreateTest(test_utils.OpenStackBaseTest):
|
||||
"""Tests to launch a cirros image."""
|
||||
|
||||
def test_launch_small_instance(self):
|
||||
"""Launch a cirros instance and test connectivity."""
|
||||
zaza.openstack.configure.guest.launch_instance(
|
||||
glance_setup.CIRROS_IMAGE_NAME)
|
||||
self.RESOURCE_PREFIX = 'zaza-nova'
|
||||
self.launch_guest(
|
||||
'cirros', instance_key=glance_setup.CIRROS_IMAGE_NAME)
|
||||
|
||||
|
||||
class LTSGuestCreateTest(BaseGuestCreateTest):
|
||||
class LTSGuestCreateTest(test_utils.OpenStackBaseTest):
|
||||
"""Tests to launch a LTS image."""
|
||||
|
||||
def test_launch_small_instance(self):
|
||||
"""Launch a Bionic instance and test connectivity."""
|
||||
zaza.openstack.configure.guest.launch_instance(
|
||||
glance_setup.LTS_IMAGE_NAME)
|
||||
self.RESOURCE_PREFIX = 'zaza-nova'
|
||||
self.launch_guest(
|
||||
'ubuntu', instance_key=glance_setup.LTS_IMAGE_NAME)
|
||||
|
||||
|
||||
class LTSGuestCreateVolumeBackedTest(BaseGuestCreateTest):
|
||||
class LTSGuestCreateVolumeBackedTest(test_utils.OpenStackBaseTest):
|
||||
"""Tests to launch a LTS image."""
|
||||
|
||||
def test_launch_small_instance(self):
|
||||
"""Launch a Bionic instance and test connectivity."""
|
||||
zaza.openstack.configure.guest.launch_instance(
|
||||
glance_setup.LTS_IMAGE_NAME,
|
||||
self.RESOURCE_PREFIX = 'zaza-nova'
|
||||
self.launch_guest(
|
||||
'volume-backed-ubuntu', instance_key=glance_setup.LTS_IMAGE_NAME,
|
||||
use_boot_volume=True)
|
||||
|
||||
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
"""Encapsulate OVN testing."""
|
||||
|
||||
import logging
|
||||
import tenacity
|
||||
|
||||
import juju
|
||||
|
||||
import tenacity
|
||||
|
||||
import zaza
|
||||
|
||||
import zaza.model
|
||||
import zaza.openstack.charm_tests.test_utils as test_utils
|
||||
import zaza.openstack.utilities.generic as generic_utils
|
||||
import zaza.openstack.utilities.openstack as openstack_utils
|
||||
@@ -36,10 +39,19 @@ class BaseCharmOperationTest(test_utils.BaseCharmTest):
|
||||
"""Run class setup for OVN charm operation tests."""
|
||||
super(BaseCharmOperationTest, cls).setUpClass()
|
||||
cls.services = ['NotImplemented'] # This must be overridden
|
||||
cls.nrpe_checks = ['NotImplemented'] # This must be overridden
|
||||
cls.current_release = openstack_utils.get_os_release(
|
||||
openstack_utils.get_current_os_release_pair(
|
||||
cls.release_application or cls.application_name))
|
||||
|
||||
@tenacity.retry(
|
||||
retry=tenacity.retry_if_result(lambda ret: ret is not None),
|
||||
# sleep for 2mins to allow 1min cron job to run...
|
||||
wait=tenacity.wait_fixed(120),
|
||||
stop=tenacity.stop_after_attempt(2))
|
||||
def _retry_check_commands_on_units(self, cmds, units):
|
||||
return generic_utils.check_commands_on_units(cmds, units)
|
||||
|
||||
def test_pause_resume(self):
|
||||
"""Run pause and resume tests.
|
||||
|
||||
@@ -50,6 +62,20 @@ class BaseCharmOperationTest(test_utils.BaseCharmTest):
|
||||
logging.info('Testing pause resume (services="{}")'
|
||||
.format(self.services))
|
||||
|
||||
def test_nrpe_configured(self):
|
||||
"""Confirm that the NRPE service check files are created."""
|
||||
units = zaza.model.get_units(self.application_name)
|
||||
cmds = []
|
||||
for check_name in self.nrpe_checks:
|
||||
cmds.append(
|
||||
'egrep -oh /usr/local.* /etc/nagios/nrpe.d/'
|
||||
'check_{}.cfg'.format(check_name)
|
||||
)
|
||||
ret = self._retry_check_commands_on_units(cmds, units)
|
||||
if ret:
|
||||
logging.info(ret)
|
||||
self.assertIsNone(ret, msg=ret)
|
||||
|
||||
|
||||
class CentralCharmOperationTest(BaseCharmOperationTest):
|
||||
"""OVN Central Charm operation tests."""
|
||||
@@ -62,6 +88,22 @@ class CentralCharmOperationTest(BaseCharmOperationTest):
|
||||
'ovn-northd',
|
||||
'ovsdb-server',
|
||||
]
|
||||
source = zaza.model.get_application_config(
|
||||
cls.application_name)['source']['value']
|
||||
logging.info(source)
|
||||
if 'train' in source:
|
||||
cls.nrpe_checks = [
|
||||
'ovn-northd',
|
||||
'ovn-nb-ovsdb',
|
||||
'ovn-sb-ovsdb',
|
||||
]
|
||||
else:
|
||||
# Ussuri or later (distro or cloudarchive)
|
||||
cls.nrpe_checks = [
|
||||
'ovn-northd',
|
||||
'ovn-ovsdb-server-sb',
|
||||
'ovn-ovsdb-server-nb',
|
||||
]
|
||||
|
||||
|
||||
class ChassisCharmOperationTest(BaseCharmOperationTest):
|
||||
@@ -76,6 +118,26 @@ class ChassisCharmOperationTest(BaseCharmOperationTest):
|
||||
cls.services = [
|
||||
'ovn-controller',
|
||||
]
|
||||
if cls.application_name == 'ovn-chassis':
|
||||
principal_app_name = 'magpie'
|
||||
else:
|
||||
principal_app_name = cls.application_name
|
||||
source = zaza.model.get_application_config(
|
||||
principal_app_name)['source']['value']
|
||||
logging.info(source)
|
||||
if 'train' in source:
|
||||
cls.nrpe_checks = [
|
||||
'ovn-host',
|
||||
'ovs-vswitchd',
|
||||
'ovsdb-server',
|
||||
]
|
||||
else:
|
||||
# Ussuri or later (distro or cloudarchive)
|
||||
cls.nrpe_checks = [
|
||||
'ovn-controller',
|
||||
'ovsdb-server',
|
||||
'ovs-vswitchd',
|
||||
]
|
||||
|
||||
|
||||
class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
|
||||
@@ -26,10 +26,12 @@ import zaza.openstack.charm_tests.glance.setup as glance_setup
|
||||
|
||||
SETUP_ENV_VARS = {
|
||||
'neutron': ['TEST_GATEWAY', 'TEST_CIDR_EXT', 'TEST_FIP_RANGE',
|
||||
'TEST_NAMESERVER', 'TEST_CIDR_PRIV'],
|
||||
'TEST_NAME_SERVER', 'TEST_CIDR_PRIV'],
|
||||
'swift': ['TEST_SWIFT_IP'],
|
||||
}
|
||||
|
||||
IGNORABLE_VARS = ['TEST_CIDR_PRIV']
|
||||
|
||||
TEMPEST_FLAVOR_NAME = 'm1.tempest'
|
||||
TEMPEST_ALT_FLAVOR_NAME = 'm2.tempest'
|
||||
TEMPEST_SVC_LIST = ['ceilometer', 'cinder', 'glance', 'heat', 'horizon',
|
||||
@@ -198,7 +200,8 @@ def add_environment_var_config(ctxt, services):
|
||||
if value:
|
||||
ctxt[var.lower()] = value
|
||||
else:
|
||||
missing_vars.append(var)
|
||||
if var not in IGNORABLE_VARS:
|
||||
missing_vars.append(var)
|
||||
if missing_vars:
|
||||
raise ValueError(
|
||||
("Environment variables [{}] must all be set to run this"
|
||||
|
||||
@@ -52,9 +52,11 @@ http_image = http://{{ test_swift_ip }}:80/swift/v1/images/cirros-0.3.4-x86_64-u
|
||||
|
||||
{% if 'neutron' in enabled_services %}
|
||||
[network]
|
||||
{% if test_cidr_priv %}
|
||||
project_network_cidr = {{ test_cidr_priv }}
|
||||
{% endif %}
|
||||
public_network_id = {{ ext_net }}
|
||||
dns_servers = {{ test_nameserver }}
|
||||
dns_servers = {{ test_name_server }}
|
||||
project_networks_reachable = false
|
||||
|
||||
[network-feature-enabled]
|
||||
|
||||
@@ -54,9 +54,11 @@ http_image = http://{{ test_swift_ip }}:80/swift/v1/images/cirros-0.3.4-x86_64-u
|
||||
|
||||
{% if 'neutron' in enabled_services %}
|
||||
[network]
|
||||
{% if test_cidr_priv %}
|
||||
project_network_cidr = {{ test_cidr_priv }}
|
||||
{% endif %}
|
||||
public_network_id = {{ ext_net }}
|
||||
dns_servers = {{ test_nameserver }}
|
||||
dns_servers = {{ test_name_server }}
|
||||
project_networks_reachable = false
|
||||
floating_network_name = {{ ext_net }}
|
||||
|
||||
|
||||
@@ -127,10 +127,28 @@ class BaseCharmTest(unittest.TestCase):
|
||||
else:
|
||||
cls.model_name = model.get_juju_model()
|
||||
cls.test_config = lifecycle_utils.get_charm_config(fatal=False)
|
||||
|
||||
if application_name:
|
||||
cls.application_name = application_name
|
||||
else:
|
||||
cls.application_name = cls.test_config['charm_name']
|
||||
charm_under_test_name = cls.test_config['charm_name']
|
||||
deployed_app_names = model.sync_deployed(model_name=cls.model_name)
|
||||
if charm_under_test_name in deployed_app_names:
|
||||
# There is an application named like the charm under test.
|
||||
# Let's consider it the application under test:
|
||||
cls.application_name = charm_under_test_name
|
||||
else:
|
||||
# Let's search for any application whose name starts with the
|
||||
# name of the charm under test and assume it's the application
|
||||
# under test:
|
||||
for app_name in deployed_app_names:
|
||||
if app_name.startswith(charm_under_test_name):
|
||||
cls.application_name = app_name
|
||||
break
|
||||
else:
|
||||
logging.warning('Could not find application under test')
|
||||
return
|
||||
|
||||
cls.lead_unit = model.get_lead_unit_name(
|
||||
cls.application_name,
|
||||
model_name=cls.model_name)
|
||||
@@ -526,7 +544,8 @@ class OpenStackBaseTest(BaseCharmTest):
|
||||
# Test did not define self.RESOURCE_PREFIX, ignore.
|
||||
pass
|
||||
|
||||
def launch_guest(self, guest_name, userdata=None):
|
||||
def launch_guest(self, guest_name, userdata=None, use_boot_volume=False,
|
||||
instance_key=None):
|
||||
"""Launch two guests to use in tests.
|
||||
|
||||
Note that it is up to the caller to have set the RESOURCE_PREFIX class
|
||||
@@ -539,25 +558,38 @@ class OpenStackBaseTest(BaseCharmTest):
|
||||
:type guest_name: str
|
||||
:param userdata: Userdata to attach to instance
|
||||
:type userdata: Optional[str]
|
||||
:param use_boot_volume: Whether to boot guest from a shared volume.
|
||||
:type use_boot_volume: boolean
|
||||
:param instance_key: Key to collect associated config data with.
|
||||
:type instance_key: Optional[str]
|
||||
:returns: Nova instance objects
|
||||
:rtype: Server
|
||||
"""
|
||||
instance_key = instance_key or glance_setup.LTS_IMAGE_NAME
|
||||
instance_name = '{}-{}'.format(self.RESOURCE_PREFIX, guest_name)
|
||||
|
||||
instance = self.retrieve_guest(instance_name)
|
||||
if instance:
|
||||
logging.info('Removing already existing instance ({}) with '
|
||||
'requested name ({})'
|
||||
.format(instance.id, instance_name))
|
||||
openstack_utils.delete_resource(
|
||||
self.nova_client.servers,
|
||||
instance.id,
|
||||
msg="server")
|
||||
for attempt in tenacity.Retrying(
|
||||
stop=tenacity.stop_after_attempt(3),
|
||||
wait=tenacity.wait_exponential(
|
||||
multiplier=1, min=2, max=10)):
|
||||
with attempt:
|
||||
old_instance_with_same_name = self.retrieve_guest(
|
||||
instance_name)
|
||||
if old_instance_with_same_name:
|
||||
logging.info(
|
||||
'Removing already existing instance ({}) with '
|
||||
'requested name ({})'
|
||||
.format(old_instance_with_same_name.id, instance_name))
|
||||
openstack_utils.delete_resource(
|
||||
self.nova_client.servers,
|
||||
old_instance_with_same_name.id,
|
||||
msg="server")
|
||||
|
||||
return configure_guest.launch_instance(
|
||||
glance_setup.LTS_IMAGE_NAME,
|
||||
vm_name=instance_name,
|
||||
userdata=userdata)
|
||||
return configure_guest.launch_instance(
|
||||
instance_key,
|
||||
vm_name=instance_name,
|
||||
use_boot_volume=use_boot_volume,
|
||||
userdata=userdata)
|
||||
|
||||
def launch_guests(self, userdata=None):
|
||||
"""Launch two guests to use in tests.
|
||||
@@ -572,15 +604,10 @@ class OpenStackBaseTest(BaseCharmTest):
|
||||
"""
|
||||
launched_instances = []
|
||||
for guest_number in range(1, 2+1):
|
||||
for attempt in tenacity.Retrying(
|
||||
stop=tenacity.stop_after_attempt(3),
|
||||
wait=tenacity.wait_exponential(
|
||||
multiplier=1, min=2, max=10)):
|
||||
with attempt:
|
||||
launched_instances.append(
|
||||
self.launch_guest(
|
||||
guest_name='ins-{}'.format(guest_number),
|
||||
userdata=userdata))
|
||||
launched_instances.append(
|
||||
self.launch_guest(
|
||||
guest_name='ins-{}'.format(guest_number),
|
||||
userdata=userdata))
|
||||
return launched_instances
|
||||
|
||||
def retrieve_guest(self, guest_name):
|
||||
|
||||
@@ -123,6 +123,10 @@ CHARM_TYPES = {
|
||||
'pkg': 'ceph-common',
|
||||
'origin_setting': 'source'
|
||||
},
|
||||
'placement': {
|
||||
'pkg': 'placement-common',
|
||||
'origin_setting': 'openstack-origin'
|
||||
},
|
||||
}
|
||||
|
||||
# Older tests use the order the services appear in the list to imply
|
||||
@@ -143,6 +147,7 @@ UPGRADE_SERVICES = [
|
||||
'type': CHARM_TYPES['openstack-dashboard']},
|
||||
{'name': 'ovn-central', 'type': CHARM_TYPES['ovn-central']},
|
||||
{'name': 'ceph-mon', 'type': CHARM_TYPES['ceph-mon']},
|
||||
{'name': 'placement', 'type': CHARM_TYPES['placement']},
|
||||
]
|
||||
|
||||
|
||||
@@ -2059,7 +2064,8 @@ def delete_volume_backup(cinder, vol_backup_id):
|
||||
|
||||
|
||||
def upload_image_to_glance(glance, local_path, image_name, disk_format='qcow2',
|
||||
visibility='public', container_format='bare'):
|
||||
visibility='public', container_format='bare',
|
||||
backend=None):
|
||||
"""Upload the given image to glance and apply the given label.
|
||||
|
||||
:param glance: Authenticated glanceclient
|
||||
@@ -2085,7 +2091,7 @@ def upload_image_to_glance(glance, local_path, image_name, disk_format='qcow2',
|
||||
disk_format=disk_format,
|
||||
visibility=visibility,
|
||||
container_format=container_format)
|
||||
glance.images.upload(image.id, open(local_path, 'rb'))
|
||||
glance.images.upload(image.id, open(local_path, 'rb'), backend=backend)
|
||||
|
||||
resource_reaches_status(
|
||||
glance.images,
|
||||
@@ -2097,7 +2103,8 @@ def upload_image_to_glance(glance, local_path, image_name, disk_format='qcow2',
|
||||
|
||||
|
||||
def create_image(glance, image_url, image_name, image_cache_dir=None, tags=[],
|
||||
properties=None):
|
||||
properties=None, backend=None, disk_format='qcow2',
|
||||
visibility='public', container_format='bare'):
|
||||
"""Download the image and upload it to glance.
|
||||
|
||||
Download an image from image_url and upload it to glance labelling
|
||||
@@ -2131,7 +2138,10 @@ def create_image(glance, image_url, image_name, image_cache_dir=None, tags=[],
|
||||
if not os.path.exists(local_path):
|
||||
download_image(image_url, local_path)
|
||||
|
||||
image = upload_image_to_glance(glance, local_path, image_name)
|
||||
image = upload_image_to_glance(
|
||||
glance, local_path, image_name, backend=backend,
|
||||
disk_format=disk_format, visibility=visibility,
|
||||
container_format=container_format)
|
||||
for tag in tags:
|
||||
result = glance.image_tags.update(image.id, tag)
|
||||
logging.debug(
|
||||
|
||||
Reference in New Issue
Block a user