Add Magnum tests (#515)

- Add Heat domain-setup action as a setup configuration option which can be used in other charms
  - test_100_domain_setup is being deprecated if the new configuration option is being used
- Add Magnum tests
  - test create magnum cluster template
  - test create magnum cluster
  - test config changes
  - test pause and resume
- TEST_MAGNUM_QCOW2_IMAGE_URL environment variable is required in the CI
  - The value of this variable should be a link to a fedora-coreos QCOW2 image
This commit is contained in:
Oprin Marius
2022-07-05 14:06:02 +03:00
committed by GitHub
parent 31d806c731
commit 243435883f
8 changed files with 287 additions and 0 deletions

View File

@@ -36,6 +36,7 @@ python-glanceclient
python-heatclient
python-ironicclient
python-keystoneclient
python-magnumclient
python-manilaclient
python-neutronclient
python-novaclient

View File

@@ -53,6 +53,7 @@ install_require = [
'python-ironicclient',
'python-glanceclient<3.0.0',
'python-keystoneclient<3.22.0',
'python-magnumclient',
'python-manilaclient<2.0.0',
'python-novaclient<16.0.0',
'python-neutronclient<7.0.0',

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python3
#
# Copyright 2021 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 heat."""
import logging
import zaza.model
def domain_setup(application_name='heat'):
"""Run required action for a working Heat application."""
# Action is REQUIRED to run for a functioning heat deployment
logging.info('Running domain-setup action on heat unit...')
zaza.model.block_until_wl_status_info_starts_with(application_name,
"Unit is ready")
zaza.model.run_action_on_leader(application_name, "domain-setup")
zaza.model.block_until_wl_status_info_starts_with(application_name,
"Unit is ready")

View File

@@ -62,6 +62,8 @@ class HeatBasicDeployment(test_utils.OpenStackBaseTest):
services = ['heat-api', 'heat-api-cfn', 'heat-engine']
return services
# TODO: Deprecate this function
# domain-setup action has been added as a setup configuration option
def test_100_domain_setup(self):
"""Run required action for a working Heat unit."""
# Action is REQUIRED to run for a functioning heat deployment

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env python3
# Copyright 2021 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 magnum."""

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python3
#
# Copyright 2021 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 magnum."""
import logging
import os
import tenacity
import zaza.model
import zaza.openstack.utilities.openstack as openstack_utils
IMAGE_NAME = 'fedora-coreos'
def domain_setup(application_name='magnum'):
"""Run required action for a working Magnum application."""
# Action is REQUIRED to run for a functioning magnum deployment
logging.info('Running domain-setup action on magnum unit...')
zaza.model.block_until_wl_status_info_starts_with(application_name,
"Unit is ready")
zaza.model.run_action_on_leader(application_name, "domain-setup")
zaza.model.block_until_wl_status_info_starts_with(application_name,
"Unit is ready")
def add_image(image_url=None):
"""Upload Magnum image.
Upload the operating system images built for Kubernetes deployments.
Fedora CoreOS image was tested by Magnum team.
:param image_url: URL where the image resides
:type image_url: str
"""
image_url = image_url or os.environ.get(
'TEST_MAGNUM_QCOW2_IMAGE_URL', None)
if image_url is None:
raise ValueError("Missing image_url")
for attempt in tenacity.Retrying(
stop=tenacity.stop_after_attempt(3),
reraise=True):
with attempt:
keystone_session = openstack_utils.get_overcloud_keystone_session()
glance_client = openstack_utils.get_glance_session_client(
keystone_session)
image_properties = {
'os_distro': IMAGE_NAME
}
openstack_utils.create_image(glance_client, image_url, IMAGE_NAME,
properties=image_properties)

View File

@@ -0,0 +1,157 @@
#!/usr/bin/env python3
#
# Copyright 2021 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 magnum testing."""
import logging
import urllib
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.utilities.openstack as openstack_utils
import zaza.openstack.utilities.generic as generic_utils
from zaza.openstack.charm_tests.magnum.setup import IMAGE_NAME
# Resource and name constants
CLUSTER_NAME = 'test-kubernetes'
TEMPLATE_NAME = 'test-kubernetes-template'
FLAVOR_NAME = 'm1.small'
class MagnumBasicDeployment(test_utils.OpenStackBaseTest):
"""Encapsulate Magnum tests."""
@classmethod
def setUpClass(cls):
"""Run class setup for running magnum tests."""
super(MagnumBasicDeployment, cls).setUpClass()
cls.keystone_session = openstack_utils.get_overcloud_keystone_session()
cls.magnum_client = openstack_utils.get_magnum_session_client(
cls.keystone_session)
cls.glance_client = openstack_utils.get_glance_session_client(
cls.keystone_session)
@property
def services(self):
"""Return a list services for the selected OpenStack release.
:returns: List of services
:rtype: [str]
"""
services = ['magnum-api', 'magnum-conductor']
return services
def test_410_magnum_cluster_create_delete(self):
"""Create cluster, confirm nova compute resource, delete cluster."""
# Verify new image name
images_list = list(self.glance_client.images.list())
self.assertEqual(images_list[0].name, IMAGE_NAME,
"Magnum image not found")
# Create magnum template
template_fields = {
'name': TEMPLATE_NAME,
'image_id': IMAGE_NAME,
'external_network_id': 'ext_net',
'dns_nameserver': '1.1.1.1',
'master_flavor_id': FLAVOR_NAME,
'flavor_id': FLAVOR_NAME,
'coe': 'kubernetes'
}
logging.info('Creating magnum cluster template...')
template = self.magnum_client.cluster_templates.create(
**template_fields)
logging.info('Cluster template data: {}'.format(template))
# Create a magnum cluster from a magnum template, verify its status
logging.info('Creating magnum cluster...')
# Create the cluster
cluster_fields = {
'name': CLUSTER_NAME,
'cluster_template_id': template.uuid,
'master_count': 1,
'node_count': 1,
'keypair': 'zaza'
}
cluster = self.magnum_client.clusters.create(**cluster_fields)
logging.info('Cluster data: {}'.format(cluster))
# Confirm stack reaches COMPLETE status.
openstack_utils.resource_reaches_status(
self.magnum_client.clusters,
cluster.uuid,
expected_status="CREATE_COMPLETE",
msg="Cluster status wait",
stop_after_attempt=20,
wait_iteration_max_time=600,
wait_exponential_multiplier=2)
# List cluster
clusters = list(self.magnum_client.clusters.list())
logging.info('All clusters: {}'.format(clusters))
# Get cluster information
cluster = self.magnum_client.clusters.get(CLUSTER_NAME)
# Check Kubernetes api address
api_address = urllib.parse.urlparse(cluster.api_address)
api_status = generic_utils.is_port_open(api_address.port,
api_address.hostname)
self.assertTrue(api_status, 'Kubernetes API is unavailable')
# Delete cluster
logging.info('Deleting magnum cluster...')
openstack_utils.delete_resource(self.magnum_client.clusters,
CLUSTER_NAME, msg="magnum cluster")
# Delete template
logging.info('Deleting magnum cluster template...')
openstack_utils.delete_resource(self.magnum_client.cluster_templates,
TEMPLATE_NAME,
msg="magnum cluster template")
def test_900_magnum_restart_on_config_change(self):
"""Verify the specified services are restarted when config changes."""
logging.info('Testing restart on configuration change')
# Expected default and alternate values
set_default = {'cert-manager-type': 'barbican'}
set_alternate = {'cert-manager-type': 'x509keypair'}
# Config file affected by juju set config change
conf_file = '/etc/magnum/magnum.conf'
# Make config change, check for service restarts
logging.info('Making configuration change')
self.restart_on_changed(
conf_file,
set_default,
set_alternate,
None,
None,
self.services)
def test_910_pause_and_resume(self):
"""Run services pause and resume tests."""
logging.info('Checking pause and resume actions...')
logging.info('Skipping pause resume test LP: #1886202...')
return
with self.pause_resume(self.services):
logging.info("Testing pause resume")

View File

@@ -50,6 +50,7 @@ from openstack import connection
from aodhclient.v2 import client as aodh_client
from cinderclient import client as cinderclient
from heatclient import client as heatclient
from magnumclient import client as magnumclient
from glanceclient import Client as GlanceClient
from designateclient.client import Client as DesignateClient
@@ -407,6 +408,19 @@ def get_heat_session_client(session, version=1):
return heatclient.Client(session=session, version=version)
def get_magnum_session_client(session, version='1'):
"""Return magnumclient authenticated by keystone session.
:param session: Keystone session object
:type session: keystoneauth1.session.Session object
:param version: Magnum API version
:type version: string
:returns: Authenticated magnumclient
:rtype: magnumclient.Client object
"""
return magnumclient.Client(version, session=session)
def get_cinder_session_client(session, version=3):
"""Return cinderclient authenticated by keystone session.