[wrappers] Move wrappers under plugins.openstack

Change-Id: I23cb04aea14e59d388ca8b34811f260ede79e116
Implements: blueprint split-plugins
This commit is contained in:
Yair Fried 2015-06-02 16:04:59 +03:00
parent c4666d5eef
commit 1e160f3fa1
10 changed files with 1330 additions and 5 deletions

View File

@ -16,8 +16,8 @@
from oslo_utils import uuidutils as uid from oslo_utils import uuidutils as uid
from rally.benchmark.scenarios import base from rally.benchmark.scenarios import base
from rally.benchmark.wrappers import network as network_wrapper
from rally.common import log as logging from rally.common import log as logging
from rally.plugins.openstack.wrappers import network as network_wrapper
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)

View File

@ -19,12 +19,12 @@ from rally.benchmark.scenarios import base
from rally.benchmark.scenarios import utils as scenario_utils from rally.benchmark.scenarios import utils as scenario_utils
from rally.benchmark import types as types from rally.benchmark import types as types
from rally.benchmark import validation from rally.benchmark import validation
from rally.benchmark.wrappers import network as network_wrapper
from rally.common import log as logging from rally.common import log as logging
from rally import consts from rally import consts
from rally import exceptions as rally_exceptions from rally import exceptions as rally_exceptions
from rally.plugins.openstack.scenarios.cinder import utils as cinder_utils from rally.plugins.openstack.scenarios.cinder import utils as cinder_utils
from rally.plugins.openstack.scenarios.nova import utils from rally.plugins.openstack.scenarios.nova import utils
from rally.plugins.openstack.wrappers import network as network_wrapper
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)

View File

@ -21,9 +21,8 @@ import six
from rally.benchmark.scenarios import base from rally.benchmark.scenarios import base
from rally.benchmark import utils as bench_utils from rally.benchmark import utils as bench_utils
from rally.benchmark.wrappers import network as network_wrapper
from rally import exceptions from rally import exceptions
from rally.plugins.openstack.wrappers import network as network_wrapper
NOVA_BENCHMARK_OPTS = [] NOVA_BENCHMARK_OPTS = []
option_names_and_defaults = [ option_names_and_defaults = [

View File

@ -21,11 +21,11 @@ import six
from rally.benchmark.scenarios import base from rally.benchmark.scenarios import base
from rally.benchmark import utils as bench_utils from rally.benchmark import utils as bench_utils
from rally.benchmark.wrappers import network as network_wrapper
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import log as logging from rally.common import log as logging
from rally.common import sshutils from rally.common import sshutils
from rally import exceptions from rally import exceptions
from rally.plugins.openstack.wrappers import network as network_wrapper
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)

View File

@ -0,0 +1,217 @@
# Copyright 2014: Mirantis Inc.
# All Rights Reserved.
#
# 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.
import abc
import collections
from keystoneclient import exceptions
import six
from rally.common import log as logging
LOG = logging.getLogger(__name__)
Project = collections.namedtuple("Project", ["id", "name", "domain_id"])
User = collections.namedtuple("User",
["id", "name", "project_id", "domain_id"])
Service = collections.namedtuple("Service", ["id", "name"])
Role = collections.namedtuple("Role", ["id", "name"])
@six.add_metaclass(abc.ABCMeta)
class KeystoneWrapper(object):
def __init__(self, client):
self.client = client
def __getattr__(self, attr_name):
return getattr(self.client, attr_name)
@abc.abstractmethod
def create_project(self, project_name, domain_name="Default"):
"""Creates new project/tenant and return project object.
:param project_name: Name of project to be created.
:param domain_name: Name or id of domain where to create project, for
implementations that don't support domains this
argument must be None or 'Default'.
"""
@abc.abstractmethod
def delete_project(self, project_id):
"""Deletes project."""
@abc.abstractmethod
def create_user(self, username, password, email=None, project_id=None,
domain_name="Default"):
"""Create user.
:param username: name of user
:param password: user password
:param project: user's default project
:param domain_name: Name or id of domain where to create project, for
implementations that don't support domains this
argument must be None or 'Default'.
"""
@abc.abstractmethod
def delete_user(self, user_id):
"""Deletes user."""
@abc.abstractmethod
def list_users(self):
"""List all users."""
@abc.abstractmethod
def list_projects(self):
"""List all projects/tenants."""
def delete_service(self, service_id):
"""Deletes service."""
self.client.services.delete(service_id)
def list_services(self):
"""List all services."""
return map(KeystoneWrapper._wrap_service, self.client.services.list())
def delete_role(self, role_id):
"""Deletes role."""
self.client.roles.delete(role_id)
def list_roles(self):
"""List all roles."""
return map(KeystoneWrapper._wrap_role, self.client.roles.list())
@staticmethod
def _wrap_service(service):
return Service(id=service.id, name=service.name)
@staticmethod
def _wrap_role(role):
return Role(id=role.id, name=role.name)
class KeystoneV2Wrapper(KeystoneWrapper):
def _check_domain(self, domain_name):
if domain_name.lower() != "default":
raise NotImplementedError("Domain functionality not implemented "
"in Keystone v2")
@staticmethod
def _wrap_v2_tenant(tenant):
return Project(id=tenant.id, name=tenant.name, domain_id="default")
@staticmethod
def _wrap_v2_user(user):
return User(id=user.id, name=user.name,
project_id=getattr(user, "tenantId", None),
domain_id="default")
def create_project(self, project_name, domain_name="Default"):
self._check_domain(domain_name)
tenant = self.client.tenants.create(project_name)
return KeystoneV2Wrapper._wrap_v2_tenant(tenant)
def delete_project(self, project_id):
self.client.tenants.delete(project_id)
def create_user(self, username, password, email=None, project_id=None,
domain_name="Default"):
self._check_domain(domain_name)
user = self.client.users.create(username, password, email, project_id)
return KeystoneV2Wrapper._wrap_v2_user(user)
def delete_user(self, user_id):
self.client.users.delete(user_id)
def list_users(self):
return map(KeystoneV2Wrapper._wrap_v2_user, self.client.users.list())
def list_projects(self):
return map(KeystoneV2Wrapper._wrap_v2_tenant,
self.client.tenants.list())
class KeystoneV3Wrapper(KeystoneWrapper):
def _get_domain_id(self, domain_name_or_id):
try:
# First try to find domain by ID
return self.client.domains.get(domain_name_or_id).id
except exceptions.NotFound:
# Domain not found by ID, try to find it by name
domains = self.client.domains.list(name=domain_name_or_id)
if domains:
return domains[0].id
# Domain not found by name, raise original NotFound exception
raise
@staticmethod
def _wrap_v3_project(project):
return Project(id=project.id, name=project.name,
domain_id=project.domain_id)
@staticmethod
def _wrap_v3_user(user):
# When user has default_project_id that is None user.default_project_id
# will raise AttributeError
project_id = getattr(user, "default_project_id", None)
return User(id=user.id, name=user.name, project_id=project_id,
domain_id=user.domain_id)
def create_project(self, project_name, domain_name="Default"):
domain_id = self._get_domain_id(domain_name)
project = self.client.projects.create(
name=project_name, domain=domain_id)
return KeystoneV3Wrapper._wrap_v3_project(project)
def delete_project(self, project_id):
self.client.projects.delete(project_id)
def create_user(self, username, password, email=None, project_id=None,
domain_name="Default"):
domain_id = self._get_domain_id(domain_name)
user = self.client.users.create(name=username, password=password,
default_project=project_id,
email=email, domain=domain_id)
for role in self.client.roles.list():
if "member" in role.name.lower():
self.client.roles.grant(role.id, user=user.id,
project=project_id)
break
else:
LOG.warning("Unable to set member role to created user.")
return KeystoneV3Wrapper._wrap_v3_user(user)
def delete_user(self, user_id):
self.client.users.delete(user_id)
def list_users(self):
return map(KeystoneV3Wrapper._wrap_v3_user, self.client.users.list())
def list_projects(self):
return map(KeystoneV3Wrapper._wrap_v3_project,
self.client.projects.list())
def wrap(client):
"""Returns keystone wrapper based on keystone client version."""
if client.version == "v2.0":
return KeystoneV2Wrapper(client)
elif client.version == "v3":
return KeystoneV3Wrapper(client)
else:
raise NotImplementedError(
"Wrapper for version %s is not implemented." % client.version)

View File

@ -0,0 +1,407 @@
# Copyright 2014: Mirantis Inc.
# All Rights Reserved.
#
# 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.
import abc
import netaddr
import six
from rally.benchmark import utils as bench_utils
from rally.common.i18n import _
from rally.common import log as logging
from rally.common import utils
from rally import consts
from rally import exceptions
from neutronclient.common import exceptions as neutron_exceptions
from novaclient import exceptions as nova_exceptions
LOG = logging.getLogger(__name__)
cidr_incr = utils.RAMInt()
def generate_cidr(start_cidr="10.2.0.0/24"):
"""Generate next CIDR for network or subnet, without IP overlapping.
This is process and thread safe, because `cidr_incr' points to
value stored directly in RAM. This guarantees that CIDRs will be
serial and unique even under hard multiprocessing/threading load.
:param start_cidr: start CIDR str
:returns: next available CIDR str
"""
cidr = str(netaddr.IPNetwork(start_cidr).next(next(cidr_incr)))
LOG.debug("CIDR generated: %s" % cidr)
return cidr
class NetworkWrapperException(exceptions.RallyException):
msg_fmt = _("%(message)s")
@six.add_metaclass(abc.ABCMeta)
class NetworkWrapper(object):
"""Base class for network service implementations.
We actually have two network services implementations, with different API:
NovaNetwork and Neutron. The idea is (at least to try) to use unified
service, which hides most differences and routines behind the scenes.
This allows to significantly re-use and simplify code.
"""
START_CIDR = "10.2.0.0/24"
SERVICE_IMPL = None
def __init__(self, clients, config=None):
if hasattr(clients, self.SERVICE_IMPL):
self.client = getattr(clients, self.SERVICE_IMPL)()
else:
self.client = clients(self.SERVICE_IMPL)
self.config = config or {}
self.start_cidr = self.config.get("start_cidr", self.START_CIDR)
@abc.abstractmethod
def create_network(self):
"""Create network."""
@abc.abstractmethod
def delete_network(self):
"""Delete network."""
@abc.abstractmethod
def list_networks(self):
"""List networks."""
@abc.abstractmethod
def create_floating_ip(self):
"""Create floating IP."""
@abc.abstractmethod
def delete_floating_ip(self):
"""Delete floating IP."""
@abc.abstractmethod
def supports_security_group(self):
"""Checks whether security group is supported."""
class NovaNetworkWrapper(NetworkWrapper):
SERVICE_IMPL = consts.Service.NOVA
def __init__(self, *args):
super(NovaNetworkWrapper, self).__init__(*args)
self.skip_cidrs = [n.cidr for n in self.client.networks.list()]
def _generate_cidr(self):
cidr = generate_cidr(start_cidr=self.start_cidr)
while cidr in self.skip_cidrs:
cidr = generate_cidr(start_cidr=self.start_cidr)
return cidr
def create_network(self, tenant_id, **kwargs):
"""Create network.
:param tenant_id: str, tenant ID
:param **kwargs: for compatibility, not used here
:returns: dict, network data
"""
cidr = self._generate_cidr()
label = utils.generate_random_name("rally_net_")
network = self.client.networks.create(
tenant_id=tenant_id, cidr=cidr, label=label)
return {"id": network.id,
"cidr": network.cidr,
"name": network.label,
"status": "ACTIVE",
"external": False,
"tenant_id": tenant_id}
def delete_network(self, network):
return self.client.networks.delete(network["id"])
def list_networks(self):
return self.client.networks.list()
def create_floating_ip(self, ext_network=None, **kwargs):
"""Allocate a floating ip from the given nova-network pool
:param ext_network: name or external network, str
:param **kwargs: for compatibility, not used here
:returns: floating IP dict
"""
if not ext_network:
try:
ext_network = self.client.floating_ip_pools.list()[0].name
except IndexError:
raise NetworkWrapperException("No floating IP pools found")
fip = self.client.floating_ips.create(ext_network)
return {"id": fip.id, "ip": fip.ip}
def _get_floating_ip(self, fip_id, do_raise=False):
try:
fip = self.client.floating_ips.get(fip_id)
except nova_exceptions.NotFound:
if not do_raise:
return None
raise exceptions.GetResourceNotFound(
resource="Floating IP %s" % fip_id)
return fip.id
def delete_floating_ip(self, fip_id, wait=False):
"""Delete floating IP.
:param fip_id: int floating IP id
:param wait: if True then wait to return until floating ip is deleted
"""
self.client.floating_ips.delete(fip_id)
if not wait:
return
bench_utils.wait_for_delete(
fip_id,
update_resource=lambda i: self._get_floating_ip(i, do_raise=True))
def supports_security_group(self):
"""Check whether security group is supported
:return: result tuple. Always (True, "") for nova-network.
:rtype: (bool, string)
"""
return True, ""
class NeutronWrapper(NetworkWrapper):
SERVICE_IMPL = consts.Service.NEUTRON
SUBNET_IP_VERSION = 4
@property
def external_networks(self):
return self.client.list_networks(**{
"router:external": True})["networks"]
def get_network(self, net_id=None, name=None):
net = None
try:
if net_id:
net = self.client.show_network(net_id)["network"]
else:
for net in self.client.list_networks(name=name)["networks"]:
break
return {"id": net["id"],
"name": net["name"],
"tenant_id": net["tenant_id"],
"status": net["status"],
"external": net["router:external"],
"subnets": net["subnets"],
"router_id": None}
except (TypeError, neutron_exceptions.NeutronClientException):
raise NetworkWrapperException(
"Network not found: %s" % (name or net_id))
def create_router(self, external=False, **kwargs):
"""Create neutron router.
:param external: bool, whether to set setup external_gateway_info
:param **kwargs: POST /v2.0/routers request options
:returns: neutron router dict
"""
if "name" not in kwargs:
kwargs["name"] = utils.generate_random_name("rally_router_")
if external and "external_gateway_info" not in kwargs:
for net in self.external_networks:
kwargs["external_gateway_info"] = {
"network_id": net["id"], "enable_snat": True}
return self.client.create_router({"router": kwargs})["router"]
def _generate_cidr(self):
# TODO(amaretskiy): Generate CIDRs unique for network, not cluster
return generate_cidr(start_cidr=self.start_cidr)
def create_network(self, tenant_id, **kwargs):
"""Create network.
:param tenant_id: str, tenant ID
:param **kwargs: extra options
:returns: dict, network data
"""
network_args = {
"network": {
"tenant_id": tenant_id,
"name": utils.generate_random_name("rally_net_")
}
}
network = self.client.create_network(network_args)["network"]
router = None
if kwargs.get("add_router", False):
router = self.create_router(external=True, tenant_id=tenant_id)
subnets = []
subnets_num = kwargs.get("subnets_num", 0)
for i in range(subnets_num):
subnet_args = {
"subnet": {
"tenant_id": tenant_id,
"network_id": network["id"],
"name": utils.generate_random_name("rally_subnet_"),
"ip_version": self.SUBNET_IP_VERSION,
"cidr": self._generate_cidr(),
"enable_dhcp": True,
"dns_nameservers": kwargs.get("dns_nameservers",
["8.8.8.8", "8.8.4.4"])
}
}
subnet = self.client.create_subnet(subnet_args)["subnet"]
subnets.append(subnet["id"])
if router:
self.client.add_interface_router(router["id"],
{"subnet_id": subnet["id"]})
return {"id": network["id"],
"name": network["name"],
"status": network["status"],
"subnets": subnets,
"external": network.get("router:external", False),
"router_id": router and router["id"] or None,
"tenant_id": tenant_id}
def delete_network(self, network):
net_dhcps = self.client.list_dhcp_agent_hosting_networks(
network["id"])["agents"]
for net_dhcp in net_dhcps:
self.client.remove_network_from_dhcp_agent(net_dhcp["id"],
network["id"])
router_id = network["router_id"]
if router_id:
self.client.remove_gateway_router(router_id)
for subnet_id in network["subnets"]:
self.client.remove_interface_router(router_id,
{"subnet_id": subnet_id})
self.client.delete_router(router_id)
for port in self.client.list_ports(network_id=network["id"])["ports"]:
self.client.delete_port(port["id"])
for subnet_id in network["subnets"]:
self._delete_subnet(subnet_id)
return self.client.delete_network(network["id"])
def _delete_subnet(self, subnet_id):
self.client.delete_subnet(subnet_id)
def list_networks(self):
return self.client.list_networks()["networks"]
def create_port(self, network_id, **kwargs):
"""Create neutron port.
:param network_id: neutron network id
:param **kwargs: POST /v2.0/ports request options
:returns: neutron port dict
"""
kwargs["network_id"] = network_id
if "name" not in kwargs:
kwargs["name"] = utils.generate_random_name("rally_port_")
return self.client.create_port({"port": kwargs})["port"]
def create_floating_ip(self, ext_network=None, int_network=None,
tenant_id=None, port_id=None, **kwargs):
"""Create Neutron floating IP.
:param ext_network: floating network name or dict
:param int_network: fixed network name or dict
:param tenant_id str tenant id
:param port_id: str port id
:param **kwargs: for compatibility, not used here
:returns: floating IP dict
"""
if not tenant_id:
raise ValueError("Missed tenant_id")
net_id = None
if type(ext_network) is dict:
net_id = ext_network["id"]
elif ext_network:
ext_net = self.get_network(name=ext_network)
if not ext_net["external"]:
raise NetworkWrapperException("Network is not external: %s"
% ext_network)
net_id = ext_net["id"]
else:
ext_networks = self.external_networks
if not ext_networks:
raise NetworkWrapperException(
"Failed to allocate floating IP: "
"no external networks found")
net_id = ext_networks[0]["id"]
if not port_id:
if type(int_network) is dict:
port_id = self.create_port(int_network["id"])["id"]
elif int_network:
int_net = self.get_network(name=int_network)
if int_net["external"]:
raise NetworkWrapperException("Network is external: %s"
% int_network)
port_id = self.create_port(int_net["id"])["id"]
kwargs = {"floatingip": {"floating_network_id": net_id},
"tenant_id": tenant_id,
"port_id": port_id}
fip = self.client.create_floatingip(kwargs)["floatingip"]
return {"id": fip["id"], "ip": fip["floating_ip_address"]}
def delete_floating_ip(self, fip_id, **kwargs):
"""Delete floating IP.
:param fip_id: int floating IP id
:param **kwargs: for compatibility, not used here
"""
self.client.delete_floatingip(fip_id)
def supports_security_group(self):
"""Check whether security group is supported
:return: result tuple
:rtype: (bool, string)
"""
extensions = self.client.list_extensions().get("extensions", [])
use_sg = any(ext.get("alias") == "security-group"
for ext in extensions)
if use_sg:
return True, ""
return False, _("neutron driver does not support security groups")
def wrap(clients, config=None):
"""Returns available network wrapper instance.
:param clients: rally.osclients.Clients instance
:param config: task config dict
:returns: NetworkWrapper subclass instance
"""
if hasattr(clients, "services"):
services = clients.services()
else:
services = clients("services")
if consts.Service.NEUTRON in services.values():
return NeutronWrapper(clients, config)
return NovaNetworkWrapper(clients, config)

View File

@ -0,0 +1,208 @@
# Copyright 2014: Mirantis Inc.
# All Rights Reserved.
#
# 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.
from keystoneclient import exceptions
import mock
from rally.plugins.openstack.wrappers import keystone
from tests.unit import test
class KeystoneWrapperTestBase(object):
def test_list_services(self):
service = mock.MagicMock()
service.id = "fake_id"
service.name = "Foobar"
service.extra_field = "extra_field"
self.client.services.list.return_value = [service]
result = list(self.wrapped_client.list_services())
self.assertEqual([("fake_id", "Foobar")], result)
self.assertEqual("fake_id", result[0].id)
self.assertEqual("Foobar", result[0].name)
self.assertFalse(hasattr(result[0], "extra_field"))
def test_wrap(self):
client = mock.MagicMock()
client.version = "dummy"
self.assertRaises(NotImplementedError, keystone.wrap, client)
def test_delete_service(self):
self.wrapped_client.delete_service("fake_id")
self.client.services.delete.assert_called_once_with("fake_id")
def test_list_roles(self):
role = mock.MagicMock()
role.id = "fake_id"
role.name = "Foobar"
role.extra_field = "extra_field"
self.client.roles.list.return_value = [role]
result = list(self.wrapped_client.list_roles())
self.assertEqual([("fake_id", "Foobar")], result)
self.assertEqual("fake_id", result[0].id)
self.assertEqual("Foobar", result[0].name)
self.assertFalse(hasattr(result[0], "extra_field"))
def test_delete_role(self):
self.wrapped_client.delete_role("fake_id")
self.client.roles.delete.assert_called_once_with("fake_id")
class KeystoneV2WrapperTestCase(test.TestCase, KeystoneWrapperTestBase):
def setUp(self):
super(KeystoneV2WrapperTestCase, self).setUp()
self.client = mock.MagicMock()
self.client.version = "v2.0"
self.wrapped_client = keystone.wrap(self.client)
def test_create_project(self):
self.wrapped_client.create_project("Foobar")
self.client.tenants.create.assert_called_once_with("Foobar")
def test_create_project_in_non_default_domain_fail(self):
self.assertRaises(
NotImplementedError, self.wrapped_client.create_project,
"Foobar", "non-default-domain")
def test_delete_project(self):
self.wrapped_client.delete_project("fake_id")
self.client.tenants.delete.assert_called_once_with("fake_id")
def test_list_projects(self):
tenant = mock.MagicMock()
tenant.id = "fake_id"
tenant.name = "Foobar"
tenant.extra_field = "extra_field"
self.client.tenants.list.return_value = [tenant]
result = list(self.wrapped_client.list_projects())
self.assertEqual([("fake_id", "Foobar", "default")], result)
self.assertEqual("fake_id", result[0].id)
self.assertEqual("Foobar", result[0].name)
self.assertEqual("default", result[0].domain_id)
self.assertFalse(hasattr(result[0], "extra_field"))
def test_create_user(self):
self.wrapped_client.create_user("foo", "bar", email="foo@bar.com",
project_id="tenant_id",
domain_name="default")
self.client.users.create.assert_called_once_with(
"foo", "bar", "foo@bar.com", "tenant_id")
def test_create_user_in_non_default_domain_fail(self):
self.assertRaises(
NotImplementedError, self.wrapped_client.create_user,
"foo", "bar", email="foo@bar.com", project_id="tenant_id",
domain_name="non-default-domain")
def test_delete_user(self):
self.wrapped_client.delete_user("fake_id")
self.client.users.delete.assert_called_once_with("fake_id")
def test_list_users(self):
user = mock.MagicMock()
user.id = "fake_id"
user.name = "foo"
user.tenantId = "tenant_id"
user.extra_field = "extra_field"
self.client.users.list.return_value = [user]
result = list(self.wrapped_client.list_users())
self.assertEqual([("fake_id", "foo", "tenant_id", "default")], result)
self.assertEqual("fake_id", result[0].id)
self.assertEqual("foo", result[0].name)
self.assertEqual("tenant_id", result[0].project_id)
self.assertEqual("default", result[0].domain_id)
self.assertFalse(hasattr(result[0], "extra_field"))
class KeystoneV3WrapperTestCase(test.TestCase, KeystoneWrapperTestBase):
def setUp(self):
super(KeystoneV3WrapperTestCase, self).setUp()
self.client = mock.MagicMock()
self.client.version = "v3"
self.wrapped_client = keystone.wrap(self.client)
self.client.domains.get.side_effect = exceptions.NotFound
self.client.domains.list.return_value = [
mock.MagicMock(id="domain_id")]
def test_create_project(self):
self.wrapped_client.create_project("Foobar", "domain")
self.client.projects.create.assert_called_once_with(
name="Foobar", domain="domain_id")
def test_create_project_with_non_existing_domain_fail(self):
self.client.domains.list.return_value = []
self.assertRaises(exceptions.NotFound,
self.wrapped_client.create_project,
"Foobar", "non-existing-domain")
def test_delete_project(self):
self.wrapped_client.delete_project("fake_id")
self.client.projects.delete.assert_called_once_with("fake_id")
def test_list_projects(self):
project = mock.MagicMock()
project.id = "fake_id"
project.name = "Foobar"
project.domain_id = "domain_id"
project.extra_field = "extra_field"
self.client.projects.list.return_value = [project]
result = list(self.wrapped_client.list_projects())
self.assertEqual([("fake_id", "Foobar", "domain_id")], result)
self.assertEqual("fake_id", result[0].id)
self.assertEqual("Foobar", result[0].name)
self.assertEqual("domain_id", result[0].domain_id)
self.assertFalse(hasattr(result[0], "extra_field"))
def test_create_user(self):
fake_role = mock.MagicMock(id="fake_role_id")
fake_role.name = "__member__"
self.client.roles.list.return_value = [fake_role]
self.client.users.create.return_value = mock.MagicMock(
id="fake_user_id")
self.wrapped_client.create_user(
"foo", "bar", email="foo@bar.com",
project_id="project_id", domain_name="domain")
self.client.users.create.assert_called_once_with(
name="foo", password="bar",
email="foo@bar.com", default_project="project_id",
domain="domain_id")
def test_create_user_with_non_existing_domain_fail(self):
self.client.domains.list.return_value = []
self.assertRaises(exceptions.NotFound,
self.wrapped_client.create_user, "foo", "bar",
email="foo@bar.com", project_id="project_id",
domain_name="non-existing-domain")
def test_delete_user(self):
self.wrapped_client.delete_user("fake_id")
self.client.users.delete.assert_called_once_with("fake_id")
def test_list_users(self):
user = mock.MagicMock()
user.id = "fake_id"
user.name = "foo"
user.default_project_id = "project_id"
user.domain_id = "domain_id"
user.extra_field = "extra_field"
self.client.users.list.return_value = [user]
result = list(self.wrapped_client.list_users())
self.assertEqual([("fake_id", "foo", "project_id", "domain_id")],
result)
self.assertEqual("fake_id", result[0].id)
self.assertEqual("foo", result[0].name)
self.assertEqual("project_id", result[0].project_id)
self.assertEqual("domain_id", result[0].domain_id)
self.assertFalse(hasattr(result[0], "extra_field"))

View File

@ -0,0 +1,494 @@
# Copyright 2014: Mirantis Inc.
# All Rights Reserved.
#
# 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.
import mock
from rally import consts
from rally import exceptions
from rally.plugins.openstack.wrappers import network
from tests.unit import test
from neutronclient.common import exceptions as neutron_exceptions
from novaclient import exceptions as nova_exceptions
SVC = "rally.plugins.openstack.wrappers.network."
class NovaNetworkWrapperTestCase(test.TestCase):
class Net(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def get_wrapper(self, *skip_cidrs, **kwargs):
mock_clients = mock.Mock()
mock_clients.nova.return_value.networks.list.return_value = [
self.Net(cidr=cidr) for cidr in skip_cidrs]
return network.NovaNetworkWrapper(mock_clients, kwargs)
def test__init__(self):
skip_cidrs = ["foo_cidr", "bar_cidr"]
service = self.get_wrapper(*skip_cidrs)
self.assertEqual(service.skip_cidrs, skip_cidrs)
service.client.networks.list.assert_called_once_with()
@mock.patch("rally.plugins.openstack.wrappers.network.generate_cidr")
def test__generate_cidr(self, mock_cidr):
skip_cidrs = [5, 7]
cidrs = iter(range(7))
mock_cidr.side_effect = lambda start_cidr: start_cidr + next(cidrs)
service = self.get_wrapper(*skip_cidrs, start_cidr=3)
self.assertEqual(service._generate_cidr(), 3)
self.assertEqual(service._generate_cidr(), 4)
self.assertEqual(service._generate_cidr(), 6) # 5 is skipped
self.assertEqual(service._generate_cidr(), 8) # 7 is skipped
self.assertEqual(service._generate_cidr(), 9)
self.assertEqual(mock_cidr.mock_calls, [mock.call(start_cidr=3)] * 7)
@mock.patch("rally.common.utils.generate_random_name",
return_value="foo_name")
def test_create_network(self, mock_name):
service = self.get_wrapper()
service.client.networks.create.side_effect = (
lambda **kwargs: self.Net(id="foo_id", **kwargs))
service._generate_cidr = mock.Mock(return_value="foo_cidr")
net = service.create_network("foo_tenant", bar="spam")
self.assertEqual(net, {"id": "foo_id",
"name": "foo_name",
"cidr": "foo_cidr",
"status": "ACTIVE",
"external": False,
"tenant_id": "foo_tenant"})
mock_name.assert_called_once_with("rally_net_")
service._generate_cidr.assert_called_once_with()
service.client.networks.create.assert_called_once_with(
tenant_id="foo_tenant", cidr="foo_cidr", label="foo_name")
def test_delete_network(self):
service = self.get_wrapper()
service.client.networks.delete.return_value = "foo_deleted"
self.assertEqual(service.delete_network({"id": "foo_id"}),
"foo_deleted")
service.client.networks.delete.assert_called_once_with("foo_id")
def test_list_networks(self):
service = self.get_wrapper()
service.client.networks.list.return_value = "foo_list"
service.client.networks.list.reset_mock()
self.assertEqual(service.list_networks(), "foo_list")
service.client.networks.list.assert_called_once_with()
def test__get_floating_ip(self):
wrap = self.get_wrapper()
wrap.client.floating_ips.get.return_value = mock.Mock(id="foo_id",
ip="foo_ip")
fip = wrap._get_floating_ip("fip_id")
wrap.client.floating_ips.get.assert_called_once_with("fip_id")
self.assertEqual(fip, "foo_id")
wrap.client.floating_ips.get.side_effect = (
nova_exceptions.NotFound(""))
self.assertIsNone(wrap._get_floating_ip("fip_id"))
self.assertRaises(exceptions.GetResourceNotFound,
wrap._get_floating_ip, "fip_id", do_raise=True)
def test_create_floating_ip(self):
wrap = self.get_wrapper()
wrap.client.floating_ips.create.return_value = mock.Mock(id="foo_id",
ip="foo_ip")
fip = wrap.create_floating_ip(ext_network="bar_net", bar="spam")
self.assertEqual(fip, {"ip": "foo_ip", "id": "foo_id"})
wrap.client.floating_ips.create.assert_called_once_with("bar_net")
net = mock.Mock()
net.name = "foo_net"
wrap.client.floating_ip_pools.list.return_value = [net]
fip = wrap.create_floating_ip()
self.assertEqual(fip, {"ip": "foo_ip", "id": "foo_id"})
wrap.client.floating_ips.create.assert_called_with("foo_net")
def test_delete_floating_ip(self):
wrap = self.get_wrapper()
fip_found = iter(range(3))
def get_fip(*args, **kwargs):
for i in fip_found:
return "fip_id"
raise exceptions.GetResourceNotFound
wrap._get_floating_ip = mock.Mock(side_effect=get_fip)
wrap.delete_floating_ip("fip_id")
wrap.client.floating_ips.delete.assert_called_once_with("fip_id")
self.assertFalse(wrap._get_floating_ip.called)
wrap.delete_floating_ip("fip_id", wait=True)
self.assertEqual(
[mock.call("fip_id", do_raise=True)] * 4,
wrap._get_floating_ip.mock_calls)
def test_supports_secgroup(self):
wrap = self.get_wrapper()
self.assertTrue(wrap.supports_security_group()[0])
class NeutronWrapperTestCase(test.TestCase):
def get_wrapper(self, *skip_cidrs, **kwargs):
return network.NeutronWrapper(mock.Mock(), kwargs)
def test_SUBNET_IP_VERSION(self):
self.assertEqual(network.NeutronWrapper.SUBNET_IP_VERSION, 4)
@mock.patch("rally.plugins.openstack.wrappers.network.generate_cidr")
def test__generate_cidr(self, mock_cidr):
cidrs = iter(range(5))
mock_cidr.side_effect = lambda start_cidr: start_cidr + next(cidrs)
service = self.get_wrapper(start_cidr=3)
self.assertEqual(service._generate_cidr(), 3)
self.assertEqual(service._generate_cidr(), 4)
self.assertEqual(service._generate_cidr(), 5)
self.assertEqual(service._generate_cidr(), 6)
self.assertEqual(service._generate_cidr(), 7)
self.assertEqual(mock_cidr.mock_calls, [mock.call(start_cidr=3)] * 5)
def test_external_networks(self):
wrap = self.get_wrapper()
wrap.client.list_networks.return_value = {"networks": "foo_networks"}
self.assertEqual(wrap.external_networks, "foo_networks")
wrap.client.list_networks.assert_called_once_with(
**{"router:external": True})
def test_get_network(self):
wrap = self.get_wrapper()
neutron_net = {"id": "foo_id",
"name": "foo_name",
"tenant_id": "foo_tenant",
"status": "foo_status",
"router:external": "foo_external",
"subnets": "foo_subnets"}
expected_net = {"id": "foo_id",
"name": "foo_name",
"tenant_id": "foo_tenant",
"status": "foo_status",
"external": "foo_external",
"router_id": None,
"subnets": "foo_subnets"}
wrap.client.show_network.return_value = {"network": neutron_net}
net = wrap.get_network(net_id="foo_id")
self.assertEqual(net, expected_net)
wrap.client.show_network.assert_called_once_with("foo_id")
wrap.client.show_network.side_effect = (
neutron_exceptions.NeutronClientException)
self.assertRaises(network.NetworkWrapperException, wrap.get_network,
net_id="foo_id")
wrap.client.list_networks.return_value = {"networks": [neutron_net]}
net = wrap.get_network(name="foo_name")
self.assertEqual(net, expected_net)
wrap.client.list_networks.assert_called_once_with(name="foo_name")
wrap.client.list_networks.return_value = {"networks": []}
self.assertRaises(network.NetworkWrapperException, wrap.get_network,
name="foo_name")
@mock.patch("rally.common.utils.generate_random_name")
def test_create_network(self, mock_name):
mock_name.return_value = "foo_name"
service = self.get_wrapper()
service.client.create_network.return_value = {
"network": {"id": "foo_id",
"name": "foo_name",
"status": "foo_status"}}
net = service.create_network("foo_tenant")
mock_name.assert_called_once_with("rally_net_")
service.client.create_network.assert_called_once_with({
"network": {"tenant_id": "foo_tenant", "name": "foo_name"}})
self.assertEqual(net, {"id": "foo_id",
"name": "foo_name",
"status": "foo_status",
"external": False,
"tenant_id": "foo_tenant",
"router_id": None,
"subnets": []})
@mock.patch("rally.common.utils.generate_random_name")
def test_create_network_with_subnets(self, mock_name):
subnets_num = 4
mock_name.return_value = "foo_name"
service = self.get_wrapper()
subnets_cidrs = iter(range(subnets_num))
subnets_ids = iter(range(subnets_num))
service._generate_cidr = mock.Mock(
side_effect=lambda: "cidr-%d" % next(subnets_cidrs))
service.client.create_subnet = mock.Mock(
side_effect=lambda i: {
"subnet": {"id": "subnet-%d" % next(subnets_ids)}})
service.client.create_network.return_value = {
"network": {"id": "foo_id",
"name": "foo_name",
"status": "foo_status"}}
net = service.create_network("foo_tenant", subnets_num=subnets_num)
service.client.create_network.assert_called_once_with({
"network": {"tenant_id": "foo_tenant", "name": "foo_name"}})
self.assertEqual(net, {"id": "foo_id",
"name": "foo_name",
"status": "foo_status",
"external": False,
"router_id": None,
"tenant_id": "foo_tenant",
"subnets": ["subnet-%d" % i
for i in range(subnets_num)]})
self.assertEqual(
service.client.create_subnet.mock_calls,
[mock.call({"subnet": {"name": "foo_name",
"enable_dhcp": True,
"network_id": "foo_id",
"tenant_id": "foo_tenant",
"ip_version": service.SUBNET_IP_VERSION,
"dns_nameservers": ["8.8.8.8", "8.8.4.4"],
"cidr": "cidr-%d" % i}})
for i in range(subnets_num)])
@mock.patch("rally.common.utils.generate_random_name")
def test_create_network_with_router(self, mock_name):
mock_name.return_value = "foo_name"
service = self.get_wrapper()
service.create_router = mock.Mock(return_value={"id": "foo_router"})
service.client.create_network.return_value = {
"network": {"id": "foo_id",
"name": "foo_name",
"status": "foo_status"}}
net = service.create_network("foo_tenant", add_router=True)
self.assertEqual(net, {"id": "foo_id",
"name": "foo_name",
"status": "foo_status",
"external": False,
"tenant_id": "foo_tenant",
"router_id": "foo_router",
"subnets": []})
service.create_router.assert_called_once_with(external=True,
tenant_id="foo_tenant")
@mock.patch("rally.common.utils.generate_random_name")
def test_create_network_with_router_and_subnets(self, mock_name):
subnets_num = 4
mock_name.return_value = "foo_name"
service = self.get_wrapper()
service._generate_cidr = mock.Mock(return_value="foo_cidr")
service.create_router = mock.Mock(return_value={"id": "foo_router"})
service.client.create_subnet = mock.Mock(
return_value={"subnet": {"id": "foo_subnet"}})
service.client.create_network.return_value = {
"network": {"id": "foo_id",
"name": "foo_name",
"status": "foo_status"}}
net = service.create_network("foo_tenant", add_router=True,
subnets_num=subnets_num,
dns_nameservers=["foo_nameservers"])
self.assertEqual(net, {"id": "foo_id",
"name": "foo_name",
"status": "foo_status",
"external": False,
"tenant_id": "foo_tenant",
"router_id": "foo_router",
"subnets": ["foo_subnet"] * subnets_num})
service.create_router.assert_called_once_with(external=True,
tenant_id="foo_tenant")
self.assertEqual(
service.client.create_subnet.mock_calls,
[mock.call({"subnet": {"name": "foo_name",
"enable_dhcp": True,
"network_id": "foo_id",
"tenant_id": "foo_tenant",
"ip_version": service.SUBNET_IP_VERSION,
"dns_nameservers": ["foo_nameservers"],
"cidr": "foo_cidr"}})] * subnets_num)
self.assertEqual(service.client.add_interface_router.mock_calls,
[mock.call("foo_router", {"subnet_id": "foo_subnet"})
for i in range(subnets_num)])
def test_delete_network(self):
service = self.get_wrapper()
service.client.list_dhcp_agent_hosting_networks.return_value = (
{"agents": []})
service.client.list_ports.return_value = {"ports": []}
service.client.delete_network.return_value = "foo_deleted"
result = service.delete_network({"id": "foo_id", "router_id": None,
"subnets": []})
self.assertEqual(result, "foo_deleted")
self.assertEqual(
service.client.remove_network_from_dhcp_agent.mock_calls, [])
self.assertEqual(service.client.remove_gateway_router.mock_calls, [])
self.assertEqual(
service.client.remove_interface_router.mock_calls, [])
self.assertEqual(service.client.delete_router.mock_calls, [])
self.assertEqual(service.client.delete_subnet.mock_calls, [])
service.client.delete_network.assert_called_once_with("foo_id")
def test_delete_network_with_dhcp_and_router_and_ports_and_subnets(self):
service = self.get_wrapper()
agents = ["foo_agent", "bar_agent"]
subnets = ["foo_subnet", "bar_subnet"]
ports = ["foo_port", "bar_port"]
service.client.list_dhcp_agent_hosting_networks.return_value = (
{"agents": [{"id": agent_id} for agent_id in agents]})
service.client.list_ports.return_value = (
{"ports": [{"id": port_id} for port_id in ports]})
service.client.delete_network.return_value = "foo_deleted"
result = service.delete_network(
{"id": "foo_id", "router_id": "foo_router", "subnets": subnets})
self.assertEqual(result, "foo_deleted")
self.assertEqual(
service.client.remove_network_from_dhcp_agent.mock_calls,
[mock.call(agent_id, "foo_id") for agent_id in agents])
self.assertEqual(service.client.remove_gateway_router.mock_calls,
[mock.call("foo_router")])
self.assertEqual(
service.client.remove_interface_router.mock_calls,
[mock.call("foo_router", {"subnet_id": subnet_id})
for subnet_id in subnets])
self.assertEqual(service.client.delete_router.mock_calls,
[mock.call("foo_router")])
self.assertEqual(service.client.delete_port.mock_calls,
[mock.call(port_id) for port_id in ports])
self.assertEqual(service.client.delete_subnet.mock_calls,
[mock.call(subnet_id) for subnet_id in subnets])
service.client.delete_network.assert_called_once_with("foo_id")
def test_list_networks(self):
service = self.get_wrapper()
service.client.list_networks.return_value = {"networks": "foo_nets"}
self.assertEqual(service.list_networks(), "foo_nets")
service.client.list_networks.assert_called_once_with()
@mock.patch(SVC + "NeutronWrapper.external_networks")
def test_create_floating_ip(self, mock_ext_networks):
wrap = self.get_wrapper()
wrap.create_port = mock.Mock(return_value={"id": "port_id"})
wrap.client.create_floatingip = mock.Mock(
return_value={"floatingip": {"id": "fip_id",
"floating_ip_address": "fip_ip"}})
self.assertRaises(ValueError, wrap.create_floating_ip)
mock_ext_networks.__get__ = lambda *args: []
self.assertRaises(network.NetworkWrapperException,
wrap.create_floating_ip, tenant_id="foo_tenant")
mock_ext_networks.__get__ = lambda *args: [{"id": "ext_id"}]
fip = wrap.create_floating_ip(tenant_id="foo_tenant")
self.assertEqual(fip, {"id": "fip_id", "ip": "fip_ip"})
wrap.get_network = mock.Mock(
return_value={"id": "foo_net", "external": True})
self.assertRaises(network.NetworkWrapperException,
wrap.create_floating_ip, tenant_id="foo_tenant",
int_network="int_net")
wrap.create_floating_ip(tenant_id="foo_tenant", ext_network="ext_net")
wrap.get_network = mock.Mock(
return_value={"id": "foo_net", "external": False})
wrap.create_floating_ip(tenant_id="foo_tenant", int_network="int_net")
self.assertRaises(network.NetworkWrapperException,
wrap.create_floating_ip, tenant_id="foo_tenant",
ext_network="ext_net")
def test_delete_floating_ip(self):
wrap = self.get_wrapper()
wrap.delete_floating_ip("fip_id")
wrap.delete_floating_ip("fip_id", ignored_kwarg="bar")
self.assertEqual(wrap.client.delete_floatingip.mock_calls,
[mock.call("fip_id")] * 2)
@mock.patch(SVC + "NeutronWrapper.external_networks")
@mock.patch("rally.common.utils.generate_random_name")
def test_create_router(self, mock_random, mock_ext_networks):
wrap = self.get_wrapper()
mock_random.return_value = "random_name"
wrap.client.create_router.return_value = {"router": "foo_router"}
mock_ext_networks.__get__ = lambda *args: [{"id": "ext_id"}]
router = wrap.create_router(name="foo_name")
wrap.client.create_router.assert_called_once_with(
{"router": {"name": "foo_name"}})
self.assertEqual(router, "foo_router")
router = wrap.create_router(external=True, foo="bar")
wrap.client.create_router.assert_called_with(
{"router": {"name": "random_name",
"external_gateway_info": {
"network_id": "ext_id",
"enable_snat": True},
"foo": "bar"}})
@mock.patch("rally.common.utils.generate_random_name")
def test_create_port(self, mock_random):
wrap = self.get_wrapper()
mock_random.return_value = "random_name"
wrap.client.create_port.return_value = {"port": "foo_port"}
port = wrap.create_port("foo_net", name="foo_name")
wrap.client.create_port.assert_called_once_with(
{"port": {"network_id": "foo_net", "name": "foo_name"}})
self.assertEqual(port, "foo_port")
port = wrap.create_port("foo_net", foo="bar")
wrap.client.create_port.assert_called_with(
{"port": {"network_id": "foo_net",
"name": "random_name", "foo": "bar"}})
def test_supports_security_group(self):
wrap = self.get_wrapper()
wrap.client.list_extensions.return_value = (
{"extensions": [{"alias": "security-group"}]})
self.assertTrue(wrap.supports_security_group()[0])
wrap.client.list_extensions.return_value = (
{"extensions": [{"alias": "dummy-group"}]})
self.assertFalse(wrap.supports_security_group()[0])
wrap.client.list_extensions.return_value = {}
self.assertFalse(wrap.supports_security_group()[0])
class FunctionsTestCase(test.TestCase):
def test_generate_cidr(self):
with mock.patch("rally.plugins.openstack.wrappers.network.cidr_incr",
iter(range(1, 4))):
self.assertEqual(network.generate_cidr(), "10.2.1.0/24")
self.assertEqual(network.generate_cidr(), "10.2.2.0/24")
self.assertEqual(network.generate_cidr(), "10.2.3.0/24")
with mock.patch("rally.plugins.openstack.wrappers.network.cidr_incr",
iter(range(1, 4))):
start_cidr = "1.1.0.0/26"
self.assertEqual(network.generate_cidr(start_cidr), "1.1.0.64/26")
self.assertEqual(network.generate_cidr(start_cidr), "1.1.0.128/26")
self.assertEqual(network.generate_cidr(start_cidr), "1.1.0.192/26")
def test_wrap(self):
mock_clients = mock.Mock()
mock_clients.nova().networks.list.return_value = []
mock_clients.services.return_value = {"foo": consts.Service.NEUTRON}
self.assertIsInstance(network.wrap(mock_clients, {}),
network.NeutronWrapper)
mock_clients.services.return_value = {"foo": "bar"}
self.assertIsInstance(network.wrap(mock_clients, {}),
network.NovaNetworkWrapper)