Merge "[Verify] Adding creation of network resources to Tempest context"

This commit is contained in:
Jenkins 2015-11-16 12:57:59 +00:00 committed by Gerrit Code Review
commit 9faaabe8fc
3 changed files with 279 additions and 78 deletions

View File

@ -11,6 +11,7 @@ image_ref =
image_ref_alt =
flavor_ref =
flavor_ref_alt =
fixed_network_name =
ssh_user = cirros
image_ssh_user = cirros
image_alt_ssh_user = cirros

View File

@ -28,6 +28,7 @@ from rally.common import log as logging
from rally.common import objects
from rally import exceptions
from rally import osclients
from rally.plugins.openstack.wrappers import network
LOG = logging.getLogger(__name__)
@ -85,7 +86,6 @@ class TempestConfig(object):
self.endpoint = db.deployment_get(deployment)["admin"]
self.clients = osclients.Clients(objects.Endpoint(**self.endpoint))
self.keystone = self.clients.verified_keystone()
self.available_services = self.clients.services().values()
self.data_dir = _create_or_get_data_dir()
@ -256,22 +256,37 @@ class TempestResourcesContext(object):
def __init__(self, deployment, conf_path):
endpoint = db.deployment_get(deployment)["admin"]
self.clients = osclients.Clients(objects.Endpoint(**endpoint))
self.keystone = self.clients.verified_keystone()
self.available_services = self.clients.services().values()
self.conf_path = conf_path
self.conf = configparser.ConfigParser()
self.conf.read(conf_path)
def __enter__(self):
self._created_roles = []
self._created_images = []
self._created_flavors = []
self._created_networks = []
def __enter__(self):
self._create_tempest_roles()
self._configure_option("image_ref", self._create_image)
self._configure_option("image_ref_alt", self._create_image)
self._configure_option("flavor_ref", self._create_flavor, 64)
self._configure_option("flavor_ref_alt", self._create_flavor, 128)
if "neutron" in self.available_services:
neutronclient = self.clients.neutron()
if neutronclient.list_networks(shared=True)["networks"]:
# If the OpenStack cloud has some shared networks, we will
# create our own shared network and specify its name in the
# Tempest config file. Such approach will allow us to avoid
# failures of Tempest tests with error "Multiple possible
# networks found". Otherwise the default behavior defined in
# Tempest will be used and Tempest itself will manage network
# resources.
LOG.debug("Shared networks found. "
"'fixed_network_name' option should be configured")
self._configure_option("fixed_network_name",
self._create_network_resources)
_write_config(self.conf_path, self.conf)
@ -279,27 +294,33 @@ class TempestResourcesContext(object):
self._cleanup_roles()
self._cleanup_resource("image", self._created_images)
self._cleanup_resource("flavor", self._created_flavors)
if "neutron" in self.available_services:
self._cleanup_network_resources()
_write_config(self.conf_path, self.conf)
def _create_tempest_roles(self):
keystoneclient = self.clients.verified_keystone()
roles = [CONF.role.swift_operator_role,
CONF.role.swift_reseller_admin_role,
CONF.role.heat_stack_owner_role,
CONF.role.heat_stack_user_role]
existing_roles = set(role.name for role in self.keystone.roles.list())
existing_roles = set(role.name for role in keystoneclient.roles.list())
for role in roles:
if role not in existing_roles:
LOG.debug("Creating role '%s'" % role)
self._created_roles.append(self.keystone.roles.create(role))
self._created_roles.append(keystoneclient.roles.create(role))
def _configure_option(self, option, create_method, *args, **kwargs):
option_value = self.conf.get("compute", option)
if not option_value:
LOG.debug("Option '%s' is not configured" % option)
resource = create_method(*args, **kwargs)
self.conf.set("compute", option, resource.id)
res_id = resource["name"] if "network" in option else resource.id
self.conf.set("compute", option, res_id)
LOG.debug("Option '{opt}' is configured. {opt} = {resource_id}"
.format(opt=option, resource_id=resource.id))
.format(opt=option, resource_id=res_id))
else:
LOG.debug("Option '{opt}' was configured manually "
"in Tempest config file. {opt} = {opt_val}"
@ -335,6 +356,16 @@ class TempestResourcesContext(object):
return flavor
def _create_network_resources(self):
neutron_wrapper = network.NeutronWrapper(self.clients, task=None)
LOG.debug("Creating network resources: network, subnet, router")
net = neutron_wrapper.create_network(
self.clients.keystone().tenant_id, subnets_num=1,
add_router=True, network_create_args={"shared": True})
self._created_networks.append(net)
return net
def _cleanup_roles(self):
for role in self._created_roles:
LOG.debug("Deleting role '%s'" % role.name)
@ -349,4 +380,15 @@ class TempestResourcesContext(object):
self.conf.set("compute", "%s_ref_alt" % resource_type, "")
res.delete()
_write_config(self.conf_path, self.conf)
def _cleanup_network_resources(self):
neutron_wrapper = network.NeutronWrapper(self.clients, task=None)
for net in self._created_networks:
LOG.debug("Deleting network resources: router, subnet, network")
neutron_wrapper.delete_network(net)
self._remove_opt_value_from_config(net["name"])
def _remove_opt_value_from_config(self, opt_value):
for option, value in self.conf.items("compute"):
if opt_value == value:
LOG.debug("Removing '%s' from Tempest config file" % opt_value)
self.conf.set("compute", option, "")

View File

@ -18,6 +18,7 @@ import os
import mock
from oslo_config import cfg
import requests
from six.moves.urllib import parse
from rally import exceptions
from rally.verification.tempest import config
@ -27,7 +28,7 @@ from tests.unit import test
CONF = cfg.CONF
class ConfigTestCase(test.TestCase):
class TempestConfigTestCase(test.TestCase):
@mock.patch("rally.common.objects.deploy.db.deployment_get")
@mock.patch("rally.osclients.Clients.services",
@ -37,7 +38,7 @@ class ConfigTestCase(test.TestCase):
return_value=True)
def setUp(self, mock_isfile, mock_clients_verified_keystone,
mock_clients_services, mock_deployment_get):
super(ConfigTestCase, self).setUp()
super(TempestConfigTestCase, self).setUp()
self.endpoint = {
"username": "test",
@ -52,23 +53,12 @@ class ConfigTestCase(test.TestCase):
self.deployment = "fake_deployment"
self.conf_generator = config.TempestConfig(self.deployment)
self.conf_generator.clients.services = mock_clients_services
self.context = config.TempestResourcesContext(self.deployment,
"/path/to/fake/conf")
self.context.conf.add_section("compute")
keystone_patcher = mock.patch(
"rally.osclients.Keystone._create_keystone_client")
keystone_patcher.start()
self.addCleanup(keystone_patcher.stop)
@staticmethod
def _remove_default_section(items):
# Getting items from config parser by specified section name
# returns also values from DEFAULT section
defaults = (("log_file", "tempest.log"), ("debug", "True"),
("use_stderr", "False"))
return [item for item in items if item not in defaults]
@mock.patch("rally.verification.tempest.config.requests")
@mock.patch("rally.verification.tempest.config.os.rename")
@mock.patch("six.moves.builtins.open", side_effect=mock.mock_open(),
@ -82,6 +72,12 @@ class ConfigTestCase(test.TestCase):
mock_requests.get.assert_called_once_with(CONF.image.cirros_img_url,
stream=True)
@mock.patch("rally.verification.tempest.config.requests.get")
def test__download_cirros_image_connection_error(self, mock_requests_get):
mock_requests_get.side_effect = requests.ConnectionError()
self.assertRaises(exceptions.TempestConfigCreationFailure,
self.conf_generator._download_cirros_image)
@mock.patch("rally.verification.tempest.config.requests")
def test__download_cirros_image_notfound(self, mock_requests):
mock_result = mock.MagicMock()
@ -90,6 +86,14 @@ class ConfigTestCase(test.TestCase):
self.assertRaises(exceptions.TempestConfigCreationFailure,
self.conf_generator._download_cirros_image)
@mock.patch("rally.verification.tempest.config.requests")
def test__download_cirros_image_code_not_200_and_404(self, mock_requests):
mock_result = mock.MagicMock()
mock_result.status_code = 500
mock_requests.get.return_value = mock_result
self.assertRaises(exceptions.TempestConfigCreationFailure,
self.conf_generator._download_cirros_image)
def test__get_service_url(self):
service = "test_service"
service_type = "test_service_type"
@ -118,9 +122,8 @@ class ConfigTestCase(test.TestCase):
("s3_url", url),
("http_socket_timeout", "30"),
("s3_materials_path", s3_materials_path))
results = self._remove_default_section(
self.conf_generator.conf.items("boto"))
self.assertEqual(sorted(expected), sorted(results))
result = self.conf_generator.conf.items("boto")
self.assertIn(sorted(expected)[0], sorted(result))
def test__configure_default(self):
self.conf_generator._configure_default()
@ -129,6 +132,13 @@ class ConfigTestCase(test.TestCase):
results = self.conf_generator.conf.items("DEFAULT")
self.assertEqual(sorted(expected), sorted(results))
def test__configure_dashboard(self):
self.conf_generator._configure_dashboard()
url = "http://%s/" % parse.urlparse(self.endpoint["auth_url"]).hostname
expected = (("dashboard_url", url),)
result = self.conf_generator.conf.items("dashboard")
self.assertIn(sorted(expected)[0], sorted(result))
def test__configure_identity(self):
self.conf_generator._configure_identity()
expected = (
@ -141,52 +151,12 @@ class ConfigTestCase(test.TestCase):
("admin_domain_name", self.endpoint["admin_domain_name"]),
("uri", self.endpoint["auth_url"]),
("uri_v3", self.endpoint["auth_url"].replace("/v2.0/", "/v3")))
results = self._remove_default_section(
self.conf_generator.conf.items("identity"))
self.assertEqual(sorted(expected), sorted(results))
def test__configure_option_flavor(self):
mock_novaclient = mock.MagicMock()
mock_novaclient.flavors.create.side_effect = [
fakes.FakeFlavor(id="id1"), fakes.FakeFlavor(id="id2")]
mock_nova = mock.MagicMock()
mock_nova.client.Client.return_value = mock_novaclient
self.context.conf.set("compute", "flavor_ref", "")
self.context.conf.set("compute", "flavor_ref_alt", "")
with mock.patch.dict("sys.modules", {"novaclient": mock_nova}):
self.context._configure_option("flavor_ref",
mock_novaclient.flavors.create, 64)
self.context._configure_option("flavor_ref_alt",
mock_novaclient.flavors.create, 128)
self.assertEqual(mock_novaclient.flavors.create.call_count, 2)
expected = ("id1", "id2")
results = (self.context.conf.get("compute", "flavor_ref"),
self.context.conf.get("compute", "flavor_ref_alt"))
self.assertEqual(sorted(expected), sorted(results))
@mock.patch("six.moves.builtins.open")
def test__configure_option_image(self, mock_open):
mock_glanceclient = mock.MagicMock()
mock_glanceclient.images.create.side_effect = [
fakes.FakeImage(id="id1"), fakes.FakeImage(id="id2")]
mock_glance = mock.MagicMock()
mock_glance.Client.return_value = mock_glanceclient
self.context.conf.set("compute", "image_ref", "")
self.context.conf.set("compute", "image_ref_alt", "")
with mock.patch.dict("sys.modules", {"glanceclient": mock_glance}):
self.context._configure_option("image_ref",
mock_glanceclient.images.create)
self.context._configure_option("image_ref_alt",
mock_glanceclient.images.create)
self.assertEqual(mock_glanceclient.images.create.call_count, 2)
expected = ("id1", "id2")
results = (self.context.conf.get("compute", "image_ref"),
self.context.conf.get("compute", "image_ref_alt"))
self.assertEqual(sorted(expected), sorted(results))
result = self.conf_generator.conf.items("identity")
self.assertIn(sorted(expected)[0], sorted(result))
def test__configure_network_if_neutron(self):
fake_neutronclient = mock.MagicMock()
fake_neutronclient.list_networks.return_value = {
mock_neutronclient = mock.MagicMock()
mock_neutronclient.list_networks.return_value = {
"networks": [
{
"status": "ACTIVE",
@ -196,15 +166,14 @@ class ConfigTestCase(test.TestCase):
]
}
mock_neutron = mock.MagicMock()
mock_neutron.client.Client.return_value = fake_neutronclient
mock_neutron.client.Client.return_value = mock_neutronclient
with mock.patch.dict("sys.modules", {"neutronclient.neutron":
mock_neutron}):
self.conf_generator.available_services = ["neutron"]
self.conf_generator._configure_network()
expected = (("public_network_id", "test_id"),)
results = self._remove_default_section(
self.conf_generator.conf.items("network"))
self.assertEqual(sorted(expected), sorted(results))
result = self.conf_generator.conf.items("network")
self.assertIn(sorted(expected)[0], sorted(result))
def test__configure_network_if_nova(self):
self.conf_generator.available_services = ["nova"]
@ -223,6 +192,25 @@ class ConfigTestCase(test.TestCase):
self.conf_generator.conf.get(
"compute", "network_for_ssh"))
def test__configure_network_feature_enabled(self):
mock_neutronclient = mock.MagicMock()
mock_neutronclient.list_ext.return_value = {
"extensions": [
{"alias": "dvr"},
{"alias": "extra_dhcp_opt"},
{"alias": "extraroute"}
]
}
mock_neutron = mock.MagicMock()
mock_neutron.client.Client.return_value = mock_neutronclient
with mock.patch.dict("sys.modules",
{"neutronclient.neutron": mock_neutron}):
self.conf_generator.available_services = ["neutron"]
self.conf_generator._configure_network_feature_enabled()
expected = (("api_extensions", "dvr,extra_dhcp_opt,extraroute"),)
result = self.conf_generator.conf.items("network-feature-enabled")
self.assertIn(sorted(expected)[0], sorted(result))
@mock.patch("rally.verification.tempest.config.os.path.exists",
return_value=False)
@mock.patch("rally.verification.tempest.config.os.makedirs")
@ -232,9 +220,24 @@ class ConfigTestCase(test.TestCase):
self.conf_generator.data_dir, "lock_files_%s" % self.deployment)
mock_makedirs.assert_called_once_with(lock_path)
expected = (("lock_path", lock_path),)
results = self._remove_default_section(
self.conf_generator.conf.items("oslo_concurrency"))
self.assertEqual(sorted(expected), sorted(results))
result = self.conf_generator.conf.items("oslo_concurrency")
self.assertIn(sorted(expected)[0], sorted(result))
def test__configure_object_storage(self):
self.conf_generator._configure_object_storage()
expected = (
("operator_role", CONF.role.swift_operator_role),
("reseller_admin_role", CONF.role.swift_reseller_admin_role))
result = self.conf_generator.conf.items("object-storage")
self.assertIn(sorted(expected)[0], sorted(result))
def test__configure_scenario(self):
self.conf_generator._configure_scenario()
expected = (
("img_dir", self.conf_generator.data_dir),
("img_file", config.IMAGE_NAME))
result = self.conf_generator.conf.items("scenario")
self.assertIn(sorted(expected)[0], sorted(result))
@mock.patch("rally.verification.tempest.config.requests")
def test__configure_service_available(self, mock_requests):
@ -254,9 +257,8 @@ class ConfigTestCase(test.TestCase):
("cinder", "True"), ("nova", "True"),
("glance", "True"), ("horizon", "False"),
("sahara", "True"))
options = self._remove_default_section(
self.conf_generator.conf.items("service_available"))
self.assertEqual(sorted(expected), sorted(options))
result = self.conf_generator.conf.items("service_available")
self.assertIn(sorted(expected)[0], sorted(result))
@mock.patch("rally.verification.tempest.config.requests")
def test__configure_service_available_horizon(self, mock_requests):
@ -290,6 +292,17 @@ class ConfigTestCase(test.TestCase):
self.conf_generator.conf.get("validation",
"connect_method"))
@mock.patch("rally.verification.tempest.config._write_config")
@mock.patch("inspect.getmembers")
def test_generate(self, mock_inspect_getmembers, mock__write_config):
configure_something_method = mock.MagicMock()
mock_inspect_getmembers.return_value = [("_configure_something",
configure_something_method)]
self.conf_generator.generate("/path/to/fake/conf")
self.assertEqual(configure_something_method.call_count, 1)
self.assertEqual(mock__write_config.call_count, 1)
@mock.patch("six.moves.builtins.open",
side_effect=mock.mock_open(), create=True)
def test__write_config(self, mock_open):
@ -298,3 +311,148 @@ class ConfigTestCase(test.TestCase):
config._write_config(conf_path, conf_data)
mock_open.assert_called_once_with(conf_path, "w+")
conf_data.write.assert_called_once_with(mock_open.side_effect())
class TempestResourcesContextTestCase(test.TestCase):
@mock.patch("rally.common.objects.deploy.db.deployment_get")
@mock.patch("rally.osclients.Clients.services",
return_value={"test_service_type": "test_service"})
@mock.patch("rally.osclients.Clients.verified_keystone")
def setUp(self, mock_clients_verified_keystone,
mock_clients_services, mock_deployment_get):
super(TempestResourcesContextTestCase, self).setUp()
endpoint = {
"username": "test",
"tenant_name": "test",
"password": "test",
"auth_url": "http://test/v2.0/",
"permission": "admin",
"admin_domain_name": "Default"
}
mock_deployment_get.return_value = {"admin": endpoint}
self.context = config.TempestResourcesContext("fake_deployment",
"/fake/path/to/config")
self.context.clients = mock.MagicMock()
self.context.conf.add_section("compute")
keystone_patcher = mock.patch(
"rally.osclients.Keystone._create_keystone_client")
keystone_patcher.start()
self.addCleanup(keystone_patcher.stop)
@mock.patch("rally.plugins.openstack.wrappers."
"network.NeutronWrapper.create_network")
@mock.patch("six.moves.builtins.open", side_effect=mock.mock_open())
def test_options_configured_manually(
self, mock_open, mock_neutron_wrapper_create_network):
self.context.available_services = ["glance", "nova", "neutron"]
self.context.conf.set("compute", "image_ref", "id1")
self.context.conf.set("compute", "image_ref_alt", "id2")
self.context.conf.set("compute", "flavor_ref", "id3")
self.context.conf.set("compute", "flavor_ref_alt", "id4")
self.context.conf.set("compute", "fixed_network_name", "name1")
self.context.__enter__()
glanceclient = self.context.clients.glance()
novaclient = self.context.clients.nova()
self.assertEqual(glanceclient.images.create.call_count, 0)
self.assertEqual(novaclient.flavors.create.call_count, 0)
self.assertEqual(mock_neutron_wrapper_create_network.call_count, 0)
def test__create_tempest_roles(self):
role1 = CONF.role.swift_operator_role
role2 = CONF.role.swift_reseller_admin_role
role3 = CONF.role.heat_stack_owner_role
role4 = CONF.role.heat_stack_user_role
client = self.context.clients.verified_keystone()
client.roles.list.return_value = [fakes.FakeRole(name=role1),
fakes.FakeRole(name=role2)]
client.roles.create.side_effect = [fakes.FakeFlavor(name=role3),
fakes.FakeFlavor(name=role4)]
self.context._create_tempest_roles()
self.assertEqual(client.roles.create.call_count, 2)
created_roles = [role.name for role in self.context._created_roles]
self.assertIn(role3, created_roles)
self.assertIn(role4, created_roles)
# We can choose any option to test the '_configure_option' method. So let's
# configure the 'flavor_ref' option.
def test__configure_option(self):
create_method = mock.MagicMock()
create_method.side_effect = [fakes.FakeFlavor(id="id1")]
self.context.conf.set("compute", "flavor_ref", "")
self.context._configure_option("flavor_ref", create_method, 64)
self.assertEqual(create_method.call_count, 1)
result = self.context.conf.get("compute", "flavor_ref")
self.assertEqual("id1", result)
@mock.patch("six.moves.builtins.open")
def test__create_image(self, mock_open):
client = self.context.clients.glance()
client.images.create.side_effect = [fakes.FakeImage(id="id1")]
image = self.context._create_image()
self.assertEqual("id1", image.id)
self.assertEqual("id1", self.context._created_images[0].id)
def test__create_flavor(self):
client = self.context.clients.nova()
client.flavors.create.side_effect = [fakes.FakeFlavor(id="id1")]
flavor = self.context._create_flavor(64)
self.assertEqual("id1", flavor.id)
self.assertEqual("id1", self.context._created_flavors[0].id)
@mock.patch("rally.plugins.openstack.wrappers."
"network.NeutronWrapper.create_network")
def test__create_network_resources(
self, mock_neutron_wrapper_create_network):
mock_neutron_wrapper_create_network.side_effect = [
fakes.FakeNetwork(id="id1")]
network = self.context._create_network_resources()
self.assertEqual("id1", network.id)
self.assertEqual("id1", self.context._created_networks[0].id)
def test__cleanup_roles(self):
self.context._created_roles = [mock.MagicMock(), mock.MagicMock()]
self.context._cleanup_roles()
for role in self.context._created_roles:
self.assertEqual(role.delete.call_count, 1)
def test__cleanup_resource(self):
created_flavors = [mock.MagicMock(id="id1"), mock.MagicMock(id="id2")]
self.context.conf.set("compute", "flavor_ref", "id1")
self.context.conf.set("compute", "flavor_ref_alt", "id2")
self.context._cleanup_resource("flavor", created_flavors)
for flavor in self.context._created_flavors:
self.assertEqual(flavor.delete.call_count, 1)
self.assertEqual("", self.context.conf.get("compute", "flavor_ref"))
self.assertEqual("", self.context.conf.get("compute",
"flavor_ref_alt"))
@mock.patch("rally.plugins.openstack.wrappers."
"network.NeutronWrapper.delete_network")
def test__cleanup_network_resources(
self, mock_neutron_wrapper_delete_network):
self.context._created_networks = [{"name": "net-12345"}]
self.context.conf.set("compute", "fixed_network_name", "net-12345")
self.context._cleanup_network_resources()
self.assertEqual(mock_neutron_wrapper_delete_network.call_count, 1)
self.assertEqual("", self.context.conf.get("compute",
"fixed_network_name"))