Make MidoNet plugin code more testable

Refactor plugin.py and midonet_lib.py to improve unit testing of
the MidoNet plugin.  Make all the tests pass in the plugin except
those that test features that are not currently supported by the
plugin, which are IPv6 and multiple subnets per network.
Consolidate the mocking code in mock_lib.py to be shared by
plugin.py and midonet_lib.py.

Change-Id: Idcdfc3d90d5ec9e0be29bb6833d336af596fe363
Fixes: bug #1133215
Signed-off-by: Ryu Ishimoto <ryu@midokura.com>
Signed-off-by: Tomoe Sugihara <tomoe@midokura.com>
This commit is contained in:
Ryu Ishimoto 2013-02-26 01:34:46 +09:00 committed by Tomoe Sugihara
parent c65a39deaf
commit 23aec9a5bb
6 changed files with 1367 additions and 1449 deletions

View File

@ -20,23 +20,35 @@
# @author: Ryu Ishimoto, Midokura Japan KK
from webob import exc as w_exc
from quantum.common import exceptions as q_exc
from quantum.openstack.common import log as logging
LOG = logging.getLogger(__name__)
PREFIX = 'OS_SG_'
SUFFIX_IN = '_IN'
SUFFIX_OUT = '_OUT'
NAME_IDENTIFIABLE_PREFIX_LEN = len(PREFIX) + 36 # 36 = length of uuid
OS_FLOATING_IP_RULE_KEY = 'OS_FLOATING_IP'
OS_ROUTER_IN_CHAIN_NAME_FORMAT = 'OS_ROUTER_IN_%s'
OS_ROUTER_OUT_CHAIN_NAME_FORMAT = 'OS_ROUTER_OUT_%s'
NAME_IDENTIFIABLE_PREFIX_LEN = len(PREFIX) + 36 # 36 = length of uuid
OS_SG_KEY = 'os_sg_rule_id'
OS_TENANT_ROUTER_RULE_KEY = 'OS_TENANT_ROUTER_RULE'
SNAT_RULE = 'SNAT'
SNAT_RULE_PROPERTY = {OS_TENANT_ROUTER_RULE_KEY: SNAT_RULE}
SUFFIX_IN = '_IN'
SUFFIX_OUT = '_OUT'
def sg_label(sg_id, sg_name):
"""Construct the security group ID used as chain identifier in MidoNet."""
return PREFIX + str(sg_id) + '_' + sg_name
def sg_rule_properties(os_sg_rule_id):
return {OS_SG_KEY: str(os_sg_rule_id)}
port_group_name = sg_label
@ -48,18 +60,748 @@ def chain_names(sg_id, sg_name):
return {'in': in_chain_name, 'out': out_chain_name}
class ChainManager:
def router_chain_names(router_id):
in_name = OS_ROUTER_IN_CHAIN_NAME_FORMAT % router_id
out_name = OS_ROUTER_OUT_CHAIN_NAME_FORMAT % router_id
return {'in': in_name, 'out': out_name}
def handle_api_error(fn):
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs)
except w_exc.HTTPException as ex:
raise MidonetApiException(msg=ex)
return wrapped
class MidonetResourceNotFound(q_exc.NotFound):
message = _('MidoNet %(resource_type)s %(id)s could not be found')
class MidonetApiException(q_exc.QuantumException):
message = _("MidoNet API error: %(msg)s")
class MidoClient:
def __init__(self, mido_api):
self.mido_api = mido_api
@handle_api_error
def create_bridge(self, tenant_id, name):
"""Create a new bridge
:param tenant_id: id of tenant creating the bridge
:param name: name of the bridge
:returns: newly created bridge
"""
LOG.debug(_("MidoClient.create_bridge called: "
"tenant_id=%(tenant_id)s, name=%(name)s"),
{'tenant_id': tenant_id, 'name': name})
return self.mido_api.add_bridge().name(name).tenant_id(
tenant_id).create()
@handle_api_error
def delete_bridge(self, id):
"""Delete a bridge
:param id: id of the bridge
"""
LOG.debug(_("MidoClient.delete_bridge called: id=%(id)s"), {'id': id})
return self.mido_api.delete_bridge(id)
@handle_api_error
def get_bridge(self, id):
"""Get a bridge
:param id: id of the bridge
:returns: requested bridge. None if bridge does not exist.
"""
LOG.debug(_("MidoClient.get_bridge called: id=%s"), id)
try:
return self.mido_api.get_bridge(id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
@handle_api_error
def update_bridge(self, id, name):
"""Update a bridge of the given id with the new name
:param id: id of the bridge
:param name: name of the bridge to set to
:returns: bridge object
"""
LOG.debug(_("MidoClient.update_bridge called: "
"id=%(id)s, name=%(name)s"), {'id': id, 'name': name})
try:
return self.mido_api.get_bridge(id).name(name).update()
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
@handle_api_error
def create_dhcp(self, bridge, gateway_ip, net_addr, net_len):
"""Create a new DHCP entry
:param bridge: bridge object to add dhcp to
:param gateway_ip: IP address of gateway
:param net_addr: network IP address
:param net_len: network IP address length
:returns: newly created dhcp
"""
LOG.debug(_("MidoClient.create_dhcp called: bridge=%s(bridge)s, "
"net_addr=%(net_addr)s, net_len=%(net_len)s, "
"gateway_ip=%(gateway_ip)s"),
{'bridge': bridge, 'net_addr': net_addr, 'net_len': net_len,
'gateway_ip': gateway_ip})
return bridge.add_dhcp_subnet().default_gateway(
gateway_ip).subnet_prefix(net_addr).subnet_length(
net_len).create()
@handle_api_error
def create_dhcp_hosts(self, bridge, ip, mac):
"""Create DHCP host entries
:param bridge: bridge of the DHCP
:param ip: IP address
:param mac: MAC address
"""
LOG.debug(_("MidoClient.create_dhcp_hosts called: bridge=%s(bridge), "
"ip=%(ip)s, mac=%(mac)s"), {'bridge': bridge, 'ip': ip,
'mac': mac})
dhcp_subnets = bridge.get_dhcp_subnets()
if dhcp_subnets:
# Add the host to the first subnet as we currently support one
# subnet per network.
dhcp_subnets[0].add_dhcp_host().ip_addr(ip).mac_addr(mac).create()
@handle_api_error
def delete_dhcp_hosts(self, bridge_id, ip, mac):
"""Delete DHCP host entries
:param bridge_id: id of the bridge of the DHCP
:param ip: IP address
:param mac: MAC address
"""
LOG.debug(_("MidoClient.delete_dhcp_hosts called: "
"bridge_id=%s(bridge_id), ip=%(ip)s, mac=%(mac)s"),
{'bridge_id': bridge_id, 'ip': ip, 'mac': mac})
bridge = self.get_bridge(bridge_id)
dhcp_subnets = bridge.get_dhcp_subnets()
if dhcp_subnets:
for dh in dhcp_subnets[0].get_dhcp_hosts():
if dh.get_mac_addr() == mac and dh.get_ip_addr() == ip:
dh.delete()
@handle_api_error
def delete_dhcp(self, bridge):
"""Delete a DHCP entry
:param bridge: bridge to remove DHCP from
"""
LOG.debug(_("MidoClient.delete_dhcp called: bridge=%s(bridge), "),
{'bridge': bridge})
dhcp = bridge.get_dhcp_subnets()
if not dhcp:
raise MidonetApiException(msg="Tried to delete non-existent DHCP")
dhcp[0].delete()
@handle_api_error
def delete_port(self, id):
"""Delete a port
:param id: id of the port
"""
LOG.debug(_("MidoClient.delete_port called: id=%(id)s"), {'id': id})
self.mido_api.delete_port(id)
@handle_api_error
def get_port(self, id):
"""Get a port
:param id: id of the port
:returns: requested port. None if it does not exist
"""
LOG.debug(_("MidoClient.get_port called: id=%(id)s"), {'id': id})
try:
return self.mido_api.get_port(id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Port', id=id)
@handle_api_error
def create_exterior_bridge_port(self, bridge):
"""Create a new exterior bridge port
:param bridge: bridge object to add port to
:returns: newly created port
"""
LOG.debug(_("MidoClient.create_exterior_bridge_port called: "
"bridge=%(bridge)s"), {'bridge': bridge})
return bridge.add_exterior_port().create()
@handle_api_error
def create_interior_bridge_port(self, bridge):
"""Create a new interior bridge port
:param bridge: bridge object to add port to
:returns: newly created port
"""
LOG.debug(_("MidoClient.create_interior_bridge_port called: "
"bridge=%(bridge)s"), {'bridge': bridge})
return bridge.add_interior_port().create()
@handle_api_error
def create_router(self, tenant_id, name):
"""Create a new router
:param tenant_id: id of tenant creating the router
:param name: name of the router
:returns: newly created router
"""
LOG.debug(_("MidoClient.create_router called: "
"tenant_id=%(tenant_id)s, name=%(name)s"),
{'tenant_id': tenant_id, 'name': name})
return self.mido_api.add_router().name(name).tenant_id(
tenant_id).create()
@handle_api_error
def create_tenant_router(self, tenant_id, name, metadata_router):
"""Create a new tenant router
:param tenant_id: id of tenant creating the router
:param name: name of the router
:param metadata_router: metadata router
:returns: newly created router
"""
LOG.debug(_("MidoClient.create_tenant_router called: "
"tenant_id=%(tenant_id)s, name=%(name)s"
"metadata_router=%(metadata_router)s"),
{'tenant_id': tenant_id, 'name': name,
'metadata_router': metadata_router})
router = self.create_router(tenant_id, name)
self.link_router_to_metadata_router(router, metadata_router)
return router
@handle_api_error
def delete_tenant_router(self, id, metadata_router):
"""Delete a tenant router
:param id: id of router
:param metadata_router: metadata router
"""
LOG.debug(_("MidoClient.delete_tenant_router called: "
"id=%(id)s, metadata_router=%(metadata_router)s"),
{'id': id, 'metadata_router': metadata_router})
self.unlink_router_from_metadata_router(id, metadata_router)
self.destroy_router_chains(id)
# delete the router
self.delete_router(id)
@handle_api_error
def delete_router(self, id):
"""Delete a router
:param id: id of the router
"""
LOG.debug(_("MidoClient.delete_router called: id=%(id)s"), {'id': id})
return self.mido_api.delete_router(id)
@handle_api_error
def get_router(self, id):
"""Get a router with the given id
:param id: id of the router
:returns: requested router object. None if it does not exist.
"""
LOG.debug(_("MidoClient.get_router called: id=%(id)s"), {'id': id})
try:
return self.mido_api.get_router(id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Router', id=id)
@handle_api_error
def update_router(self, id, name):
"""Update a router of the given id with the new name
:param id: id of the router
:param name: name of the router to set to
:returns: router object
"""
LOG.debug(_("MidoClient.update_router called: "
"id=%(id)s, name=%(name)s"), {'id': id, 'name': name})
try:
return self.mido_api.get_router(id).name(name).update()
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Router', id=id)
@handle_api_error
def link_bridge_port_to_router(self, port_id, router_id, gateway_ip,
net_addr, net_len, metadata_router):
"""Link a tenant bridge port to the router
:param port_id: port ID
:param router_id: router id to link to
:param gateway_ip: IP address of gateway
:param net_addr: network IP address
:param net_len: network IP address length
:param metadata_router: metadata router instance
"""
LOG.debug(_("MidoClient.link_bridge_port_to_router called: "
"port_id=%(port_id)s, router_id=%(router_id)s, "
"gateway_ip=%(gateway_ip)s net_addr=%(net_addr)s, "
"net_len=%(net_len)s, "
"metadata_router=%(metadata_router)s"),
{'port_id': port_id, 'router_id': router_id,
'gateway_ip': gateway_ip, 'net_addr': net_addr,
'net_len': net_len, 'metadata_router': metadata_router})
router = self.get_router(router_id)
# create an interior port on the router
in_port = router.add_interior_port()
router_port = in_port.port_address(gateway_ip).network_address(
net_addr).network_length(net_len).create()
br_port = self.get_port(port_id)
router_port.link(br_port.get_id())
# add a route for the subnet in the provider router
router.add_route().type('Normal').src_network_addr(
'0.0.0.0').src_network_length(0).dst_network_addr(
net_addr).dst_network_length(net_len).weight(
100).next_hop_port(router_port.get_id()).create()
# add a route for the subnet in metadata router; forward
# packets destined to the subnet to the tenant router
for pp in metadata_router.get_peer_ports():
if pp.get_device_id() == router.get_id():
mdr_port_id = pp.get_peer_id()
break
else:
raise Exception(
_("Couldn't find a md router port for the router=%r"), router)
metadata_router.add_route().type('Normal').src_network_addr(
'0.0.0.0').src_network_length(0).dst_network_addr(
net_addr).dst_network_length(net_len).weight(
100).next_hop_port(mdr_port_id).create()
@handle_api_error
def unlink_bridge_port_from_router(self, port_id, net_addr, net_len,
metadata_router):
"""Unlink a tenant bridge port from the router
:param bridge_id: bridge ID
:param net_addr: network IP address
:param net_len: network IP address length
:param metadata_router: metadata router instance
"""
LOG.debug(_("MidoClient.unlink_bridge_port_from_router called: "
"port_id=%(port_id)s, net_addr=%(net_addr)s, "
"net_len=%(net_len)s, "
"metadata_router=%(metadata_router)s"),
{'port_id': port_id, 'net_addr': net_addr,
'net_len': net_len, 'metadata_router': metadata_router})
port = self.get_port(port_id)
port.unlink()
self.delete_port(port.get_peer_id())
self.delete_port(port.get_id())
# delete the route for the subnet in the metadata router
for r in metadata_router.get_routes():
if (r.get_dst_network_addr() == net_addr and
r.get_dst_network_length() == net_len):
LOG.debug(_('Deleting route=%r ...'), r)
self.mido_api.delete_route(r.get_id())
break
@handle_api_error
def link_bridge_to_provider_router(self, bridge, provider_router,
gateway_ip, net_addr, net_len):
"""Link a tenant bridge to the provider router
:param bridge: tenant bridge
:param provider_router: provider router to link to
:param gateway_ip: IP address of gateway
:param net_addr: network IP address
:param net_len: network IP address length
"""
LOG.debug(_("MidoClient.link_bridge_to_provider_router called: "
"bridge=%(bridge)s, provider_router=%(provider_router)s, "
"gateway_ip=%(gateway_ip)s, net_addr=%(net_addr)s, "
"net_len=%(net_len)s"),
{'bridge': bridge, 'provider_router': provider_router,
'gateway_ip': gateway_ip, 'net_addr': net_addr,
'net_len': net_len})
# create an interior port on the provider router
in_port = provider_router.add_interior_port()
pr_port = in_port.port_address(gateway_ip).network_address(
net_addr).network_length(net_len).create()
# create an interior bridge port, then link it to the router.
br_port = bridge.add_interior_port().create()
pr_port.link(br_port.get_id())
# add a route for the subnet in the provider router
provider_router.add_route().type('Normal').src_network_addr(
'0.0.0.0').src_network_length(0).dst_network_addr(
net_addr).dst_network_length(net_len).weight(
100).next_hop_port(pr_port.get_id()).create()
@handle_api_error
def unlink_bridge_from_provider_router(self, bridge, provider_router):
"""Unlink a tenant bridge from the provider router
:param bridge: tenant bridge
:param provider_router: provider router to link to
"""
LOG.debug(_("MidoClient.unlink_bridge_from_provider_router called: "
"bridge=%(bridge)s, provider_router=%(provider_router)s"),
{'bridge': bridge, 'provider_router': provider_router})
# Delete routes and unlink the router and the bridge.
routes = provider_router.get_routes()
bridge_ports_to_delete = [
p for p in provider_router.get_peer_ports()
if p.get_device_id() == bridge.get_id()]
for p in bridge.get_peer_ports():
if p.get_device_id() == provider_router.get_id():
# delete the routes going to the bridge
for r in routes:
if r.get_next_hop_port() == p.get_id():
self.mido_api.delete_route(r.get_id())
p.unlink()
self.mido_api.delete_port(p.get_id())
# delete bridge port
for port in bridge_ports_to_delete:
self.mido_api.delete_port(port.get_id())
@handle_api_error
def set_router_external_gateway(self, id, provider_router, snat_ip):
"""Set router external gateway
:param ID: ID of the tenant router
:param provider_router: provider router
:param snat_ip: SNAT IP address
"""
LOG.debug(_("MidoClient.set_router_external_gateway called: "
"id=%(id)s, provider_router=%(provider_router)s, "
"snat_ip=%s(snat_ip)s)"),
{'id': id, 'provider_router': provider_router,
'snat_ip': snat_ip})
tenant_router = self.get_router(id)
# Create a interior port in the provider router
in_port = provider_router.add_interior_port()
pr_port = in_port.network_address(
'169.254.255.0').network_length(30).port_address(
'169.254.255.1').create()
# Create a port in the tenant router
tr_port = tenant_router.add_interior_port().network_address(
'169.254.255.0').network_length(30).port_address(
'169.254.255.2').create()
# Link them
pr_port.link(tr_port.get_id())
# Add a route for snat_ip to bring it down to tenant
provider_router.add_route().type(
'Normal').src_network_addr('0.0.0.0').src_network_length(
0).dst_network_addr(snat_ip).dst_network_length(
32).weight(100).next_hop_port(
pr_port.get_id()).create()
# Add default route to uplink in the tenant router
tenant_router.add_route().type('Normal').src_network_addr(
'0.0.0.0').src_network_length(0).dst_network_addr(
'0.0.0.0').dst_network_length(0).weight(
100).next_hop_port(tr_port.get_id()).create()
# ADD SNAT(masquerade) rules
chains = self.get_router_chains(
tenant_router.get_tenant_id(), tenant_router.get_id())
chains['in'].add_rule().nw_dst_address(snat_ip).nw_dst_length(
32).type('rev_snat').flow_action('accept').in_ports(
[tr_port.get_id()]).properties(
SNAT_RULE_PROPERTY).position(1).create()
nat_targets = []
nat_targets.append(
{'addressFrom': snat_ip, 'addressTo': snat_ip,
'portFrom': 1, 'portTo': 65535})
chains['out'].add_rule().type('snat').flow_action(
'accept').nat_targets(nat_targets).out_ports(
[tr_port.get_id()]).properties(
SNAT_RULE_PROPERTY).position(1).create()
@handle_api_error
def clear_router_external_gateway(self, id):
"""Clear router external gateway
:param ID: ID of the tenant router
"""
LOG.debug(_("MidoClient.clear_router_external_gateway called: "
"id=%(id)s"), {'id': id})
tenant_router = self.get_router(id)
# delete the port that is connected to provider router
for p in tenant_router.get_ports():
if p.get_port_address() == '169.254.255.2':
peer_port_id = p.get_peer_id()
p.unlink()
self.mido_api.delete_port(peer_port_id)
self.mido_api.delete_port(p.get_id())
# delete default route
for r in tenant_router.get_routes():
if (r.get_dst_network_addr() == '0.0.0.0' and
r.get_dst_network_length() == 0):
self.mido_api.delete_route(r.get_id())
# delete SNAT(masquerade) rules
chains = self.get_router_chains(
tenant_router.get_tenant_id(),
tenant_router.get_id())
for r in chains['in'].get_rules():
if OS_TENANT_ROUTER_RULE_KEY in r.get_properties():
if r.get_properties()[
OS_TENANT_ROUTER_RULE_KEY] == SNAT_RULE:
self.mido_api.delete_rule(r.get_id())
for r in chains['out'].get_rules():
if OS_TENANT_ROUTER_RULE_KEY in r.get_properties():
if r.get_properties()[
OS_TENANT_ROUTER_RULE_KEY] == SNAT_RULE:
self.mido_api.delete_rule(r.get_id())
@handle_api_error
def get_router_chains(self, tenant_id, router_id):
"""Get router chains.
Returns a dictionary that has in/out chain resources key'ed with 'in'
and 'out' respectively, given the tenant_id and the router_id passed
in in the arguments.
"""
LOG.debug(_("MidoClient.get_router_chains called: "
"tenant_id=%(tenant_id)s router_id=%(router_id)s"),
{'tenant_id': tenant_id, 'router_id': router_id})
chain_names = router_chain_names(router_id)
chains = {}
for c in self.mido_api.get_chains({'tenant_id': tenant_id}):
if c.get_name() == chain_names['in']:
chains['in'] = c
elif c.get_name() == chain_names['out']:
chains['out'] = c
return chains
@handle_api_error
def create_router_chains(self, router):
"""Create chains for a new router.
Creates chains for the router and returns the same dictionary as
get_router_chains() returns.
:param router: router to set chains for
"""
LOG.debug(_("MidoClient.create_router_chains called: "
"router=%(router)s"), {'router': router})
chains = {}
router_id = router.get_id()
tenant_id = router.get_tenant_id()
chain_names = router_chain_names(router_id)
chains['in'] = self.mido_api.add_chain().tenant_id(tenant_id).name(
chain_names['in']).create()
chains['out'] = self.mido_api.add_chain().tenant_id(tenant_id).name(
chain_names['out']).create()
# set chains to in/out filters
router.inbound_filter_id(
chains['in'].get_id()).outbound_filter_id(
chains['out'].get_id()).update()
return chains
@handle_api_error
def destroy_router_chains(self, id):
"""Deletes chains of a router.
:param id: router ID to delete chains of
"""
LOG.debug(_("MidoClient.destroy_router_chains called: "
"id=%(id)s"), {'id': id})
# delete corresponding chains
router = self.get_router(id)
chains = self.get_router_chains(router.get_tenant_id(), id)
self.mido_api.delete_chain(chains['in'].get_id())
self.mido_api.delete_chain(chains['out'].get_id())
@handle_api_error
def link_router_to_metadata_router(self, router, metadata_router):
"""Link a router to the metadata router
:param router: router to link
:param metadata_router: metadata router
"""
LOG.debug(_("MidoClient.link_router_to_metadata_router called: "
"router=%(router)s, metadata_router=%(metadata_router)s"),
{'router': router, 'metadata_router': metadata_router})
# link to metadata router
in_port = metadata_router.add_interior_port()
mdr_port = in_port.network_address('169.254.255.0').network_length(
30).port_address('169.254.255.1').create()
tr_port = router.add_interior_port().network_address(
'169.254.255.0').network_length(30).port_address(
'169.254.255.2').create()
mdr_port.link(tr_port.get_id())
# forward metadata traffic to metadata router
router.add_route().type('Normal').src_network_addr(
'0.0.0.0').src_network_length(0).dst_network_addr(
'169.254.169.254').dst_network_length(32).weight(
100).next_hop_port(tr_port.get_id()).create()
@handle_api_error
def unlink_router_from_metadata_router(self, id, metadata_router):
"""Unlink a router from the metadata router
:param id: ID of router
:param metadata_router: metadata router
"""
LOG.debug(_("MidoClient.unlink_router_from_metadata_router called: "
"id=%(id)s, metadata_router=%(metadata_router)s"),
{'id': id, 'metadata_router': metadata_router})
# unlink from metadata router and delete the interior ports
# that connect metadata router and this router.
for pp in metadata_router.get_peer_ports():
if pp.get_device_id() == id:
mdr_port = self.get_port(pp.get_peer_id())
pp.unlink()
self.mido_api.delete_port(pp.get_id())
self.mido_api.delete_port(mdr_port.get_id())
@handle_api_error
def setup_floating_ip(self, router_id, provider_router, floating_ip,
fixed_ip, identifier):
"""Setup MidoNet for floating IP
:param router_id: router_id
:param provider_router: provider router
:param floating_ip: floating IP address
:param fixed_ip: fixed IP address
:param identifier: identifier to use to map to MidoNet
"""
LOG.debug(_("MidoClient.setup_floating_ip called: "
"router_id=%(router_id)s, "
"provider_router=%(provider_router)s"
"floating_ip=%(floating_ip)s, fixed_ip=%(fixed_ip)s"
"identifier=%(identifier)s"),
{'router_id': router_id, 'provider_router': provider_router,
'floating_ip': floating_ip, 'fixed_ip': fixed_ip,
'identifier': identifier})
# unlink from metadata router and delete the interior ports
router = self.mido_api.get_router(router_id)
# find the provider router port that is connected to the tenant
# of the floating ip
for p in router.get_peer_ports():
if p.get_device_id() == provider_router.get_id():
pr_port = p
# get the tenant router port id connected to provider router
tr_port_id = pr_port.get_peer_id()
# add a route for the floating ip to bring it to the tenant
provider_router.add_route().type(
'Normal').src_network_addr('0.0.0.0').src_network_length(
0).dst_network_addr(
floating_ip).dst_network_length(
32).weight(100).next_hop_port(
pr_port.get_id()).create()
chains = self.get_router_chains(router.get_tenant_id(), router_id)
# add dnat/snat rule pair for the floating ip
nat_targets = []
nat_targets.append(
{'addressFrom': fixed_ip, 'addressTo': fixed_ip,
'portFrom': 0, 'portTo': 0})
floating_property = {OS_FLOATING_IP_RULE_KEY: identifier}
chains['in'].add_rule().nw_dst_address(
floating_ip).nw_dst_length(32).type(
'dnat').flow_action('accept').nat_targets(
nat_targets).in_ports([tr_port_id]).position(
1).properties(floating_property).create()
nat_targets = []
nat_targets.append(
{'addressFrom': floating_ip, 'addressTo': floating_ip,
'portFrom': 0, 'portTo': 0})
chains['out'].add_rule().nw_src_address(
fixed_ip).nw_src_length(32).type(
'snat').flow_action('accept').nat_targets(
nat_targets).out_ports(
[tr_port_id]).position(1).properties(
floating_property).create()
@handle_api_error
def clear_floating_ip(self, router_id, provider_router, floating_ip,
identifier):
"""Remove floating IP
:param router_id: router_id
:param provider_router: provider router
:param floating_ip: floating IP address
:param identifier: identifier to use to map to MidoNet
"""
LOG.debug(_("MidoClient.clear_floating_ip called: "
"router_id=%(router_id)s, "
"provider_router=%(provider_router)s"
"floating_ip=%(floating_ip)s, identifier=%(identifier)s"),
{'router_id': router_id, 'provider_router': provider_router,
'floating_ip': floating_ip, 'identifier': identifier})
router = self.mido_api.get_router(router_id)
# find the provider router port that is connected to the tenant
# delete the route for this floating ip
for r in provider_router.get_routes():
if (r.get_dst_network_addr() == floating_ip and
r.get_dst_network_length() == 32):
self.mido_api.delete_route(r.get_id())
# delete snat/dnat rule pair for this floating ip
chains = self.get_router_chains(router.get_tenant_id(), router_id)
for r in chains['in'].get_rules():
if OS_FLOATING_IP_RULE_KEY in r.get_properties():
if r.get_properties()[OS_FLOATING_IP_RULE_KEY] == identifier:
LOG.debug(_('deleting rule=%r'), r)
self.mido_api.delete_rule(r.get_id())
break
for r in chains['out'].get_rules():
if OS_FLOATING_IP_RULE_KEY in r.get_properties():
if r.get_properties()[OS_FLOATING_IP_RULE_KEY] == identifier:
LOG.debug(_('deleting rule=%r'), r)
self.mido_api.delete_rule(r.get_id())
break
@handle_api_error
def create_for_sg(self, tenant_id, sg_id, sg_name):
"""Create a new chain for security group.
Creating a security group creates a pair of chains in MidoNet, one for
inbound and the other for outbound.
"""
LOG.debug(_("ChainManager.create_for_sg called: "
LOG.debug(_("MidoClient.create_for_sg called: "
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
"sg_name=%(sg_name)s "),
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
@ -70,13 +812,18 @@ class ChainManager:
self.mido_api.add_chain().tenant_id(tenant_id).name(
cnames['out']).create()
pg_name = port_group_name(sg_id, sg_name)
self.mido_api.add_port_group().tenant_id(tenant_id).name(
pg_name).create()
@handle_api_error
def delete_for_sg(self, tenant_id, sg_id, sg_name):
"""Delete a chain mapped to a security group.
Delete a SG means deleting all the chains (inbound and outbound)
associated with the SG in MidoNet.
"""
LOG.debug(_("ChainManager.delete_for_sg called: "
LOG.debug(_("MidoClient.delete_for_sg called: "
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
"sg_name=%(sg_name)s "),
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
@ -85,52 +832,22 @@ class ChainManager:
chains = self.mido_api.get_chains({'tenant_id': tenant_id})
for c in chains:
if c.get_name() == cnames['in'] or c.get_name() == cnames['out']:
LOG.debug(_('ChainManager.delete_for_sg: deleting chain=%r'),
c)
c.delete()
LOG.debug(_('MidoClient.delete_for_sg: deleting chain=%r'),
c.get_id())
self.mido_api.delete_chain(c.get_id())
def get_router_chains(self, tenant_id, router_id):
"""Get router chains.
Returns a dictionary that has in/out chain resources key'ed with 'in'
and 'out' respectively, given the tenant_id and the router_id passed
in in the arguments.
"""
LOG.debug(_("ChainManager.get_router_chains called: "
"tenant_id=%(tenant_id)s router_id=%(router_id)s"),
{'tenant_id': tenant_id, 'router_id': router_id})
router_chain_names = self._get_router_chain_names(router_id)
chains = {}
for c in self.mido_api.get_chains({'tenant_id': tenant_id}):
if c.get_name() == router_chain_names['in']:
chains['in'] = c
elif c.get_name() == router_chain_names['out']:
chains['out'] = c
return chains
def create_router_chains(self, tenant_id, router_id):
"""Create a new chain on a router.
Creates chains for the router and returns the same dictionary as
get_router_chains() returns.
"""
LOG.debug(_("ChainManager.create_router_chains called: "
"tenant_id=%(tenant_id)s router_id=%(router_id)s"),
{'tenant_id': tenant_id, 'router_id': router_id})
chains = {}
router_chain_names = self._get_router_chain_names(router_id)
chains['in'] = self.mido_api.add_chain().tenant_id(tenant_id).name(
router_chain_names['in']).create()
chains['out'] = self.mido_api.add_chain().tenant_id(tenant_id).name(
router_chain_names['out']).create()
return chains
pg_name = port_group_name(sg_id, sg_name)
pgs = self.mido_api.get_port_groups({'tenant_id': tenant_id})
for pg in pgs:
if pg.get_name() == pg_name:
LOG.debug(_("MidoClient.delete_for_sg: deleting pg=%r"),
pg)
self.mido_api.delete_port_group(pg.get_id())
@handle_api_error
def get_sg_chains(self, tenant_id, sg_id):
"""Get a list of chains mapped to a security group."""
LOG.debug(_("ChainManager.get_sg_chains called: "
LOG.debug(_("MidoClient.get_sg_chains called: "
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s"),
{'tenant_id': tenant_id, 'sg_id': sg_id})
@ -148,44 +865,9 @@ class ChainManager:
assert 'out' in chains
return chains
def _get_router_chain_names(self, router_id):
LOG.debug(_("ChainManager.get_router_chain_names called: "
"router_id=%(router_id)s"), {'router_id': router_id})
in_name = OS_ROUTER_IN_CHAIN_NAME_FORMAT % router_id
out_name = OS_ROUTER_OUT_CHAIN_NAME_FORMAT % router_id
router_chain_names = {'in': in_name, 'out': out_name}
return router_chain_names
class PortGroupManager:
def __init__(self, mido_api):
self.mido_api = mido_api
def create(self, tenant_id, sg_id, sg_name):
LOG.debug(_("PortGroupManager.create called: "
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
"sg_name=%(sg_name)s"),
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
pg_name = port_group_name(sg_id, sg_name)
self.mido_api.add_port_group().tenant_id(tenant_id).name(
pg_name).create()
def delete(self, tenant_id, sg_id, sg_name):
LOG.debug(_("PortGroupManager.delete called: "
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
"sg_name=%(sg_name)s"),
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
pg_name = port_group_name(sg_id, sg_name)
pgs = self.mido_api.get_port_groups({'tenant_id': tenant_id})
for pg in pgs:
if pg.get_name() == pg_name:
LOG.debug(_("PortGroupManager.delete: deleting pg=%r"), pg)
pg.delete()
def get_for_sg(self, tenant_id, sg_id):
LOG.debug(_("PortGroupManager.get_for_sg called: "
@handle_api_error
def get_port_groups_for_sg(self, tenant_id, sg_id):
LOG.debug(_("MidoClient.get_port_groups_for_sg called: "
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s"),
{'tenant_id': tenant_id, 'sg_id': sg_id})
@ -194,25 +876,14 @@ class PortGroupManager:
port_groups = self.mido_api.get_port_groups({'tenant_id': tenant_id})
for pg in port_groups:
if pg.get_name().startswith(pg_name_prefix):
LOG.debug(_("PortGroupManager.get_for_sg exiting: pg=%r"), pg)
LOG.debug(_(
"MidoClient.get_port_groups_for_sg exiting: pg=%r"), pg)
return pg
return None
class RuleManager:
OS_SG_KEY = 'os_sg_rule_id'
def __init__(self, mido_api):
self.mido_api = mido_api
self.chain_manager = ChainManager(mido_api)
self.pg_manager = PortGroupManager(mido_api)
def _properties(self, os_sg_rule_id):
return {self.OS_SG_KEY: str(os_sg_rule_id)}
@handle_api_error
def create_for_sg_rule(self, rule):
LOG.debug(_("RuleManager.create_for_sg_rule called: rule=%r"), rule)
LOG.debug(_("MidoClient.create_for_sg_rule called: rule=%r"), rule)
direction = rule['direction']
protocol = rule['protocol']
@ -264,7 +935,7 @@ class RuleManager:
tp_src_start = tp_src_end = icmp_type
tp_dst_start = tp_dst_end = icmp_code
chains = self.chain_manager.get_sg_chains(tenant_id, security_group_id)
chains = self.get_sg_chains(tenant_id, security_group_id)
chain = None
if direction == 'egress':
chain = chains['in']
@ -274,8 +945,8 @@ class RuleManager:
raise Exception(_("Don't know what to do with rule=%r"), rule)
# create an accept rule
properties = self._properties(rule_id)
LOG.debug(_("RuleManager.create_for_sg_rule: adding accept rule "
properties = sg_rule_properties(rule_id)
LOG.debug(_("MidoClient.create_for_sg_rule: adding accept rule "
"%(rule_id)s in portgroup %(port_group_id)s"),
{'rule_id': rule_id, 'port_group_id': port_group_id})
chain.add_rule().port_group(port_group_id).type('accept').nw_proto(
@ -284,20 +955,21 @@ class RuleManager:
tp_src_end).tp_dst_start(tp_dst_start).tp_dst_end(
tp_dst_end).properties(properties).create()
@handle_api_error
def delete_for_sg_rule(self, rule):
LOG.debug(_("RuleManager.delete_for_sg_rule called: rule=%r"), rule)
LOG.debug(_("MidoClient.delete_for_sg_rule called: rule=%r"), rule)
tenant_id = rule['tenant_id']
security_group_id = rule['security_group_id']
rule_id = rule['id']
properties = self._properties(rule_id)
properties = sg_rule_properties(rule_id)
# search for the chains to find the rule to delete
chains = self.chain_manager.get_sg_chains(tenant_id, security_group_id)
chains = self.get_sg_chains(tenant_id, security_group_id)
for c in chains['in'], chains['out']:
rules = c.get_rules()
for r in rules:
if r.get_properties() == properties:
LOG.debug(_("RuleManager.delete_for_sg_rule: deleting "
LOG.debug(_("MidoClient.delete_for_sg_rule: deleting "
"rule %r"), r)
r.delete()
self.mido_api.delete_rule(r.get_id())

View File

@ -22,7 +22,6 @@
from midonetclient import api
from oslo.config import cfg
from webob import exc as w_exc
from quantum.common import exceptions as q_exc
from quantum.db import api as db
@ -38,15 +37,6 @@ from quantum.plugins.midonet import midonet_lib
LOG = logging.getLogger(__name__)
OS_TENANT_ROUTER_RULE_KEY = 'OS_TENANT_ROUTER_RULE'
OS_FLOATING_IP_RULE_KEY = 'OS_FLOATING_IP'
SNAT_RULE = 'SNAT'
SNAT_RULE_PROPERTY = {OS_TENANT_ROUTER_RULE_KEY: SNAT_RULE}
class MidonetResourceNotFound(q_exc.NotFound):
message = _('MidoNet %(resource_type)s %(id)s could not be found')
class MidonetPluginException(q_exc.QuantumException):
message = _("%(msg)s")
@ -57,6 +47,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
securitygroups_db.SecurityGroupDbMixin):
supported_extension_aliases = ['router', 'security-group']
__native_bulk_support = False
def __init__(self):
@ -73,26 +64,23 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
self.mido_api = api.MidonetApi(midonet_uri, admin_user,
admin_pass,
project_id=admin_project_id)
self.client = midonet_lib.MidoClient(self.mido_api)
# get MidoNet provider router and metadata router
if provider_router_id and metadata_router_id:
self.provider_router = self.mido_api.get_router(provider_router_id)
self.metadata_router = self.mido_api.get_router(metadata_router_id)
# get MidoNet provider router and metadata router
self.provider_router = self.client.get_router(provider_router_id)
self.metadata_router = self.client.get_router(metadata_router_id)
# for dev purpose only
elif mode == 'dev':
msg = _('No provider router and metadata device ids found. '
'But skipping because running in dev env.')
LOG.debug(msg)
else:
msg = _('provider_router_id and metadata_router_id '
'should be configured in the plugin config file')
LOG.exception(msg)
raise MidonetPluginException(msg=msg)
self.chain_manager = midonet_lib.ChainManager(self.mido_api)
self.pg_manager = midonet_lib.PortGroupManager(self.mido_api)
self.rule_manager = midonet_lib.RuleManager(self.mido_api)
elif not provider_router_id or not metadata_router_id:
if mode == 'dev':
msg = _('No provider router and metadata device ids found. '
'But skipping because running in dev env.')
LOG.debug(msg)
else:
msg = _('provider_router_id and metadata_router_id '
'should be configured in the plugin config file')
LOG.exception(msg)
raise MidonetPluginException(msg=msg)
db.configure_db()
@ -118,114 +106,27 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
with session.begin(subtransactions=True):
sn_entry = super(MidonetPluginV2, self).create_subnet(context,
subnet)
try:
bridge = self.mido_api.get_bridge(sn_entry['network_id'])
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge',
id=sn_entry['network_id'])
bridge = self.client.get_bridge(sn_entry['network_id'])
gateway_ip = subnet['subnet']['gateway_ip']
network_address, prefix = subnet['subnet']['cidr'].split('/')
bridge.add_dhcp_subnet().default_gateway(gateway_ip).subnet_prefix(
network_address).subnet_length(prefix).create()
self.client.create_dhcp(bridge, gateway_ip, network_address,
prefix)
# If the network is external, link the bridge to MidoNet provider
# router
# For external network, link the bridge to the provider router.
self._extend_network_dict_l3(context, net)
if net['router:external']:
gateway_ip = sn_entry['gateway_ip']
network_address, length = sn_entry['cidr'].split('/')
# create a interior port in the MidoNet provider router
in_port = self.provider_router.add_interior_port()
pr_port = in_port.port_address(gateway_ip).network_address(
network_address).network_length(length).create()
# create a interior port in the bridge, then link
# it to the provider router.
br_port = bridge.add_interior_port().create()
pr_port.link(br_port.get_id())
# add a route for the subnet in the provider router
self.provider_router.add_route().type(
'Normal').src_network_addr('0.0.0.0').src_network_length(
0).dst_network_addr(
network_address).dst_network_length(
length).weight(100).next_hop_port(
pr_port.get_id()).create()
self.client.link_bridge_to_provider_router(
bridge, self.provider_router, gateway_ip, network_address,
length)
LOG.debug(_("MidonetPluginV2.create_subnet exiting: sn_entry=%r"),
sn_entry)
return sn_entry
def get_subnet(self, context, id, fields=None):
"""Get Quantum subnet.
Retrieves a Quantum subnet record but also including the DHCP entry
data stored in MidoNet.
"""
LOG.debug(_("MidonetPluginV2.get_subnet called: id=%(id)s "
"fields=%(fields)s"), {'id': id, 'fields': fields})
qsubnet = super(MidonetPluginV2, self).get_subnet(context, id)
bridge_id = qsubnet['network_id']
try:
bridge = self.mido_api.get_bridge(bridge_id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge',
id=bridge_id)
# get dhcp subnet data from MidoNet bridge.
dhcps = bridge.get_dhcp_subnets()
b_network_address = dhcps[0].get_subnet_prefix()
b_prefix = dhcps[0].get_subnet_length()
# Validate against quantum database.
network_address, prefix = qsubnet['cidr'].split('/')
if network_address != b_network_address or int(prefix) != b_prefix:
raise MidonetResourceNotFound(resource_type='DhcpSubnet',
id=qsubnet['cidr'])
LOG.debug(_("MidonetPluginV2.get_subnet exiting: qsubnet=%s"), qsubnet)
return qsubnet
def get_subnets(self, context, filters=None, fields=None):
"""List Quantum subnets.
Retrieves Quantum subnets with some fields populated by the data
stored in MidoNet.
"""
LOG.debug(_("MidonetPluginV2.get_subnets called: filters=%(filters)r, "
"fields=%(fields)r"),
{'filters': filters, 'fields': fields})
subnets = super(MidonetPluginV2, self).get_subnets(context, filters,
fields)
for sn in subnets:
if not 'network_id' in sn:
continue
try:
bridge = self.mido_api.get_bridge(sn['network_id'])
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge',
id=sn['network_id'])
# TODO(tomoe): dedupe this part.
# get dhcp subnet data from MidoNet bridge.
dhcps = bridge.get_dhcp_subnets()
b_network_address = dhcps[0].get_subnet_prefix()
b_prefix = dhcps[0].get_subnet_length()
# Validate against quantum database.
if sn.get('cidr'):
network_address, prefix = sn['cidr'].split('/')
if network_address != b_network_address or int(
prefix) != b_prefix:
raise MidonetResourceNotFound(resource_type='DhcpSubnet',
id=sn['cidr'])
LOG.debug(_("MidonetPluginV2.create_subnet exiting"))
return subnets
def delete_subnet(self, context, id):
"""Delete Quantum subnet.
@ -237,37 +138,14 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
net = super(MidonetPluginV2, self).get_network(context,
subnet['network_id'],
fields=None)
bridge_id = subnet['network_id']
try:
bridge = self.mido_api.get_bridge(bridge_id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge', id=bridge_id)
dhcp = bridge.get_dhcp_subnets()
dhcp[0].delete()
bridge = self.client.get_bridge(subnet['network_id'])
self.client.delete_dhcp(bridge)
# If the network is external, clean up routes, links, ports.
self._extend_network_dict_l3(context, net)
if net['router:external']:
# Delete routes and unlink the router and the bridge.
routes = self.provider_router.get_routes()
bridge_ports_to_delete = []
for p in self.provider_router.get_peer_ports():
if p.get_device_id() == bridge.get_id():
bridge_ports_to_delete.append(p)
for p in bridge.get_peer_ports():
if p.get_device_id() == self.provider_router.get_id():
# delete the routes going to the brdge
for r in routes:
if r.get_next_hop_port() == p.get_id():
r.delete()
p.unlink()
p.delete()
# delete bridge port
map(lambda x: x.delete(), bridge_ports_to_delete)
self.client.unlink_bridge_from_provider_router(
bridge, self.provider_router)
super(MidonetPluginV2, self).delete_subnet(context, id)
LOG.debug(_("MidonetPluginV2.delete_subnet exiting"))
@ -281,9 +159,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
network)
if network['network']['admin_state_up'] is False:
LOG.warning(_('Ignoring admin_state_up=False for network=%r'
'Overriding with True'), network)
network['network']['admin_state_up'] = True
LOG.warning(_('Ignoring admin_state_up=False for network=%r '
'because it is not yet supported'), network)
tenant_id = self._get_tenant_id_for_create(context, network['network'])
@ -291,8 +168,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
session = context.session
with session.begin(subtransactions=True):
bridge = self.mido_api.add_bridge().name(
network['network']['name']).tenant_id(tenant_id).create()
bridge = self.client.create_bridge(tenant_id,
network['network']['name'])
# Set MidoNet bridge ID to the quantum DB entry
network['network']['id'] = bridge.get_id()
@ -324,11 +201,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
with session.begin(subtransactions=True):
net = super(MidonetPluginV2, self).update_network(
context, id, network)
try:
bridge = self.mido_api.get_bridge(id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
bridge.name(net['name']).update()
self.client.update_bridge(id, net['name'])
self._extend_network_dict_l3(context, net)
LOG.debug(_("MidonetPluginV2.update_network exiting: net=%r"), net)
@ -345,10 +218,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
# NOTE: Get network data with all fields (fields=None) for
# _extend_network_dict_l3() method, which needs 'id' field
qnet = super(MidonetPluginV2, self).get_network(context, id, None)
try:
self.mido_api.get_bridge(id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
self.client.get_bridge(id)
self._extend_network_dict_l3(context, qnet)
LOG.debug(_("MidonetPluginV2.get_network exiting: qnet=%r"), qnet)
@ -364,13 +234,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
# _extend_network_dict_l3() method, which needs 'id' field
qnets = super(MidonetPluginV2, self).get_networks(context, filters,
None)
self.mido_api.get_bridges({'tenant_id': context.tenant_id})
for n in qnets:
try:
self.mido_api.get_bridge(n['id'])
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge',
id=n['id'])
self._extend_network_dict_l3(context, n)
return [self._fields(net, fields) for net in qnets]
@ -378,8 +242,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
def delete_network(self, context, id):
"""Delete a network and its corresponding MidoNet bridge."""
LOG.debug(_("MidonetPluginV2.delete_network called: id=%r"), id)
self.mido_api.get_bridge(id).delete()
self.client.delete_bridge(id)
try:
super(MidonetPluginV2, self).delete_network(context, id)
except Exception:
@ -394,25 +257,21 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
is_compute_interface = False
port_data = port['port']
# get the bridge and create a port on it.
try:
bridge = self.mido_api.get_bridge(port_data['network_id'])
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Bridge',
id=port_data['network_id'])
bridge = self.client.get_bridge(port_data['network_id'])
device_owner = port_data['device_owner']
if device_owner.startswith('compute:') or device_owner is '':
is_compute_interface = True
bridge_port = bridge.add_exterior_port().create()
bridge_port = self.client.create_exterior_bridge_port(bridge)
elif device_owner == l3_db.DEVICE_OWNER_ROUTER_INTF:
bridge_port = bridge.add_interior_port().create()
bridge_port = self.client.create_interior_bridge_port(bridge)
elif (device_owner == l3_db.DEVICE_OWNER_ROUTER_GW or
device_owner == l3_db.DEVICE_OWNER_FLOATINGIP):
# This is a dummy port to make l3_db happy.
# This will not be used in MidoNet
bridge_port = bridge.add_interior_port().create()
bridge_port = self.client.create_interior_bridge_port(bridge)
if bridge_port:
# set midonet port id to quantum port id and create a DB record.
@ -433,20 +292,11 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
fixed_ip = port_db_entry['fixed_ips'][0]['ip_address']
mac = port_db_entry['mac_address']
# create dhcp host entry under the bridge.
dhcp_subnets = bridge.get_dhcp_subnets()
if dhcp_subnets:
dhcp_subnets[0].add_dhcp_host().ip_addr(
fixed_ip).mac_addr(mac).create()
self.client.create_dhcp_hosts(bridge, fixed_ip, mac)
LOG.debug(_("MidonetPluginV2.create_port exiting: port_db_entry=%r"),
port_db_entry)
return port_db_entry
def update_port(self, context, id, port):
"""Update port."""
LOG.debug(_("MidonetPluginV2.update_port called: id=%(id)s "
"port=%(port)r"), {'id': id, 'port': port})
return super(MidonetPluginV2, self).update_port(context, id, port)
def get_port(self, context, id, fields=None):
"""Retrieve port."""
LOG.debug(_("MidonetPluginV2.get_port called: id=%(id)s "
@ -456,10 +306,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
port_db_entry = super(MidonetPluginV2, self).get_port(context,
id, fields)
# verify that corresponding port exists in MidoNet.
try:
self.mido_api.get_port(id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Port', id=id)
self.client.get_port(id)
LOG.debug(_("MidonetPluginV2.get_port exiting: port_db_entry=%r"),
port_db_entry)
@ -474,12 +321,9 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
filters,
fields)
if ports_db_entry:
try:
for port in ports_db_entry:
self.mido_api.get_port(port['id'])
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Port',
id=port['id'])
for port in ports_db_entry:
if 'security_gorups' in port:
self._extend_port_dict_security_group(context, port)
return ports_db_entry
def delete_port(self, context, id, l3_port_check=True):
@ -496,7 +340,6 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
with session.begin(subtransactions=True):
port_db_entry = super(MidonetPluginV2, self).get_port(context,
id, None)
bridge = self.mido_api.get_bridge(port_db_entry['network_id'])
# Clean up dhcp host entry if needed.
if 'ip_address' in (port_db_entry['fixed_ips'] or [{}])[0]:
# get ip and mac from DB record.
@ -504,13 +347,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
mac = port_db_entry['mac_address']
# create dhcp host entry under the bridge.
dhcp_subnets = bridge.get_dhcp_subnets()
if dhcp_subnets:
for dh in dhcp_subnets[0].get_dhcp_hosts():
if dh.get_mac_addr() == mac and dh.get_ip_addr() == ip:
dh.delete()
self.client.delete_dhcp_hosts(port_db_entry['network_id'], ip,
mac)
self.mido_api.get_port(id).delete()
self.client.delete_port(id)
return super(MidonetPluginV2, self).delete_port(context, id)
#
@ -528,40 +368,17 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
tenant_id = self._get_tenant_id_for_create(context, router['router'])
session = context.session
with session.begin(subtransactions=True):
mrouter = self.mido_api.add_router().name(
router['router']['name']).tenant_id(tenant_id).create()
mrouter = self.client.create_tenant_router(
tenant_id, router['router']['name'], self.metadata_router)
qrouter = super(MidonetPluginV2, self).create_router(context,
router)
chains = self.chain_manager.create_router_chains(tenant_id,
mrouter.get_id())
# set chains to in/out filters
mrouter.inbound_filter_id(
chains['in'].get_id()).outbound_filter_id(
chains['out'].get_id()).update()
# get entry from the DB and update 'id' with MidoNet router id.
qrouter_entry = self._get_router(context, qrouter['id'])
qrouter['id'] = mrouter.get_id()
qrouter_entry.update(qrouter)
# link to metadata router
in_port = self.metadata_router.add_interior_port()
mdr_port = in_port.network_address('169.254.255.0').network_length(
30).port_address('169.254.255.1').create()
tr_port = mrouter.add_interior_port().network_address(
'169.254.255.0').network_length(30).port_address(
'169.254.255.2').create()
mdr_port.link(tr_port.get_id())
# forward metadata traffic to metadata router
mrouter.add_route().type('Normal').src_network_addr(
'0.0.0.0').src_network_length(0).dst_network_addr(
'169.254.169.254').dst_network_length(32).weight(
100).next_hop_port(tr_port.get_id()).create()
LOG.debug(_("MidonetPluginV2.create_router exiting: qrouter=%r"),
qrouter)
return qrouter
@ -603,9 +420,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
changed_name = router['router'].get('name')
if changed_name:
self.mido_api.get_router(id).name(changed_name).update()
self.client.update_router(id, changed_name)
tenant_router = self.mido_api.get_router(id)
if op_gateway_set:
# find a qport with the network_id for the router
qports = super(MidonetPluginV2, self).get_ports(
@ -615,82 +431,12 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
qport = qports[0]
snat_ip = qport['fixed_ips'][0]['ip_address']
in_port = self.provider_router.add_interior_port()
pr_port = in_port.network_address(
'169.254.255.0').network_length(30).port_address(
'169.254.255.1').create()
# Create a port in the tenant router
tr_port = tenant_router.add_interior_port().network_address(
'169.254.255.0').network_length(30).port_address(
'169.254.255.2').create()
# Link them
pr_port.link(tr_port.get_id())
# Add a route for snat_ip to bring it down to tenant
self.provider_router.add_route().type(
'Normal').src_network_addr('0.0.0.0').src_network_length(
0).dst_network_addr(snat_ip).dst_network_length(
32).weight(100).next_hop_port(
pr_port.get_id()).create()
# Add default route to uplink in the tenant router
tenant_router.add_route().type('Normal').src_network_addr(
'0.0.0.0').src_network_length(0).dst_network_addr(
'0.0.0.0').dst_network_length(0).weight(
100).next_hop_port(tr_port.get_id()).create()
# ADD SNAT(masquerade) rules
chains = self.chain_manager.get_router_chains(
tenant_router.get_tenant_id(), tenant_router.get_id())
chains['in'].add_rule().nw_dst_address(snat_ip).nw_dst_length(
32).type('rev_snat').flow_action('accept').in_ports(
[tr_port.get_id()]).properties(
SNAT_RULE_PROPERTY).position(1).create()
nat_targets = []
nat_targets.append(
{'addressFrom': snat_ip, 'addressTo': snat_ip,
'portFrom': 1, 'portTo': 65535})
chains['out'].add_rule().type('snat').flow_action(
'accept').nat_targets(nat_targets).out_ports(
[tr_port.get_id()]).properties(
SNAT_RULE_PROPERTY).position(1).create()
self.client.set_router_external_gateway(id,
self.provider_router,
snat_ip)
if op_gateway_clear:
# delete the port that is connected to provider router
for p in tenant_router.get_ports():
if p.get_port_address() == '169.254.255.2':
peer_port_id = p.get_peer_id()
p.unlink()
self.mido_api.get_port(peer_port_id).delete()
p.delete()
# delete default route
for r in tenant_router.get_routes():
if (r.get_dst_network_addr() == '0.0.0.0' and
r.get_dst_network_length() == 0):
r.delete()
# delete SNAT(masquerade) rules
chains = self.chain_manager.get_router_chains(
tenant_router.get_tenant_id(),
tenant_router.get_id())
for r in chains['in'].get_rules():
if OS_TENANT_ROUTER_RULE_KEY in r.get_properties():
if r.get_properties()[
OS_TENANT_ROUTER_RULE_KEY] == SNAT_RULE:
r.delete()
for r in chains['out'].get_rules():
if OS_TENANT_ROUTER_RULE_KEY in r.get_properties():
if r.get_properties()[
OS_TENANT_ROUTER_RULE_KEY] == SNAT_RULE:
r.delete()
self.client.clear_router_external_gateway(id)
LOG.debug(_("MidonetPluginV2.update_router exiting: qrouter=%r"),
qrouter)
@ -699,61 +445,13 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
def delete_router(self, context, id):
LOG.debug(_("MidonetPluginV2.delete_router called: id=%s"), id)
mrouter = self.mido_api.get_router(id)
tenant_id = mrouter.get_tenant_id()
# unlink from metadata router and delete the interior ports
# that connect metadata router and this router.
for pp in self.metadata_router.get_peer_ports():
if pp.get_device_id() == mrouter.get_id():
mdr_port = self.mido_api.get_port(pp.get_peer_id())
pp.unlink()
pp.delete()
mdr_port.delete()
# delete corresponding chains
chains = self.chain_manager.get_router_chains(tenant_id,
mrouter.get_id())
chains['in'].delete()
chains['out'].delete()
# delete the router
mrouter.delete()
self.client.delete_tenant_router(id)
result = super(MidonetPluginV2, self).delete_router(context, id)
LOG.debug(_("MidonetPluginV2.delete_router exiting: result=%s"),
result)
return result
def get_router(self, context, id, fields=None):
LOG.debug(_("MidonetPluginV2.get_router called: id=%(id)s "
"fields=%(fields)r"), {'id': id, 'fields': fields})
qrouter = super(MidonetPluginV2, self).get_router(context, id, fields)
try:
self.mido_api.get_router(id)
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Router', id=id)
LOG.debug(_("MidonetPluginV2.get_router exiting: qrouter=%r"),
qrouter)
return qrouter
def get_routers(self, context, filters=None, fields=None):
LOG.debug(_("MidonetPluginV2.get_routers called: filters=%(filters)s "
"fields=%(fields)r"),
{'filters': filters, 'fields': fields})
qrouters = super(MidonetPluginV2, self).get_routers(
context, filters, fields)
for qr in qrouters:
try:
self.mido_api.get_router(qr['id'])
except w_exc.HTTPNotFound:
raise MidonetResourceNotFound(resource_type='Router',
id=qr['id'])
return qrouters
def add_router_interface(self, context, router_id, interface_info):
LOG.debug(_("MidonetPluginV2.add_router_interface called: "
"router_id=%(router_id)s "
@ -772,33 +470,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
network_address, length = subnet['cidr'].split('/')
# Link the router and the bridge port.
mrouter = self.mido_api.get_router(router_id)
mrouter_port = mrouter.add_interior_port().port_address(
gateway_ip).network_address(
network_address).network_length(length).create()
mbridge_port = self.mido_api.get_port(qport['port_id'])
mrouter_port.link(mbridge_port.get_id())
# Add a route entry to the subnet
mrouter.add_route().type('Normal').src_network_addr(
'0.0.0.0').src_network_length(0).dst_network_addr(
network_address).dst_network_length(length).weight(
100).next_hop_port(mrouter_port.get_id()).create()
# add a route for the subnet in metadata router; forward
# packets destined to the subnet to the tenant router
found = False
for pp in self.metadata_router.get_peer_ports():
if pp.get_device_id() == mrouter.get_id():
mdr_port_id = pp.get_peer_id()
found = True
assert found
self.metadata_router.add_route().type(
'Normal').src_network_addr('0.0.0.0').src_network_length(
0).dst_network_addr(network_address).dst_network_length(
length).weight(100).next_hop_port(mdr_port_id).create()
self.client.link_bridge_port_to_router(qport['port_id'], router_id,
gateway_ip, network_address,
length,
self.metadata_router)
LOG.debug(_("MidonetPluginV2.add_router_interface exiting: "
"qport=%r"), qport)
@ -810,9 +485,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
"router_id=%(router_id)s "
"interface_info=%(interface_info)r"),
{'router_id': router_id, 'interface_info': interface_info})
port_id = None
if 'port_id' in interface_info:
mbridge_port = self.mido_api.get_port(interface_info['port_id'])
port_id = interface_info['port_id']
subnet_id = self.get_port(context,
interface_info['port_id']
)['fixed_ips'][0]['subnet_id']
@ -837,36 +513,18 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
network_port = p
break
assert network_port
mbridge_port = self.mido_api.get_port(network_port['id'])
port_id = network_port['id']
assert port_id
# get network information from subnet data
network_addr, network_length = subnet['cidr'].split('/')
network_length = int(network_length)
# Unlink the router and the bridge.
mrouter = self.mido_api.get_router(router_id)
mrouter_port = self.mido_api.get_port(mbridge_port.get_peer_id())
mrouter_port.unlink()
# Delete the route for the subnet.
found = False
for r in mrouter.get_routes():
if r.get_next_hop_port() == mrouter_port.get_id():
r.delete()
found = True
#break # commented out due to issue#314
assert found
# delete the route for the subnet in the metadata router
found = False
for r in self.metadata_router.get_routes():
if (r.get_dst_network_addr() == network_addr and
r.get_dst_network_length() == network_length):
LOG.debug(_('Deleting route=%r ...'), r)
r.delete()
found = True
break
assert found
self.client.unlink_bridge_port_from_router(port_id, network_addr,
network_length,
self.metadata_router)
info = super(MidonetPluginV2, self).remove_router_interface(
context, router_id, interface_info)
@ -883,91 +541,18 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
if floatingip['floatingip']['port_id']:
fip = super(MidonetPluginV2, self).update_floatingip(
context, id, floatingip)
router_id = fip['router_id']
floating_address = fip['floating_ip_address']
fixed_address = fip['fixed_ip_address']
tenant_router = self.mido_api.get_router(router_id)
# find the provider router port that is connected to the tenant
# of the floating ip
for p in tenant_router.get_peer_ports():
if p.get_device_id() == self.provider_router.get_id():
pr_port = p
# get the tenant router port id connected to provider router
tr_port_id = pr_port.get_peer_id()
# add a route for the floating ip to bring it to the tenant
self.provider_router.add_route().type(
'Normal').src_network_addr('0.0.0.0').src_network_length(
0).dst_network_addr(
floating_address).dst_network_length(
32).weight(100).next_hop_port(
pr_port.get_id()).create()
chains = self.chain_manager.get_router_chains(fip['tenant_id'],
fip['router_id'])
# add dnat/snat rule pair for the floating ip
nat_targets = []
nat_targets.append(
{'addressFrom': fixed_address, 'addressTo': fixed_address,
'portFrom': 0, 'portTo': 0})
floating_property = {OS_FLOATING_IP_RULE_KEY: id}
chains['in'].add_rule().nw_dst_address(
floating_address).nw_dst_length(32).type(
'dnat').flow_action('accept').nat_targets(
nat_targets).in_ports([tr_port_id]).position(
1).properties(floating_property).create()
nat_targets = []
nat_targets.append(
{'addressFrom': floating_address,
'addressTo': floating_address,
'portFrom': 0,
'portTo': 0})
chains['out'].add_rule().nw_src_address(
fixed_address).nw_src_length(32).type(
'snat').flow_action('accept').nat_targets(
nat_targets).out_ports(
[tr_port_id]).position(1).properties(
floating_property).create()
self.client.setup_floating_ip(fip['router_id'],
self.provider_router,
fip['floating_ip_address'],
fip['fixed_ip_address'], id)
# disassociate floating IP
elif floatingip['floatingip']['port_id'] is None:
fip = super(MidonetPluginV2, self).get_floatingip(context, id)
router_id = fip['router_id']
floating_address = fip['floating_ip_address']
fixed_address = fip['fixed_ip_address']
# delete the route for this floating ip
for r in self.provider_router.get_routes():
if (r.get_dst_network_addr() == floating_address and
r.get_dst_network_length() == 32):
r.delete()
# delete snat/dnat rule pair for this floating ip
chains = self.chain_manager.get_router_chains(fip['tenant_id'],
fip['router_id'])
LOG.debug(_('chains=%r'), chains)
for r in chains['in'].get_rules():
if OS_FLOATING_IP_RULE_KEY in r.get_properties():
if r.get_properties()[OS_FLOATING_IP_RULE_KEY] == id:
LOG.debug(_('deleting rule=%r'), r)
r.delete()
break
for r in chains['out'].get_rules():
if OS_FLOATING_IP_RULE_KEY in r.get_properties():
if r.get_properties()[OS_FLOATING_IP_RULE_KEY] == id:
LOG.debug(_('deleting rule=%r'), r)
r.delete()
break
self.client.clear_floating_ip(fip['router_id'],
self.provider_router,
fip['floating_ip_address'], id)
super(MidonetPluginV2, self).update_floatingip(context, id,
floatingip)
@ -993,10 +578,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
context, security_group, default_sg)
# Create MidoNet chains and portgroup for the SG
sg_id = sg_db_entry['id']
sg_name = sg_db_entry['name']
self.chain_manager.create_for_sg(tenant_id, sg_id, sg_name)
self.pg_manager.create(tenant_id, sg_id, sg_name)
self.client.create_for_sg(tenant_id, sg_db_entry['id'],
sg_db_entry['name'])
LOG.debug(_("MidonetPluginV2.create_security_group exiting: "
"sg_db_entry=%r"), sg_db_entry)
@ -1026,8 +609,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
raise ext_sg.SecurityGroupInUse(id=sg_id)
# Delete MidoNet Chains and portgroup for the SG
self.chain_manager.delete_for_sg(tenant_id, sg_id, sg_name)
self.pg_manager.delete(tenant_id, sg_id, sg_name)
self.client.delete_for_sg(tenant_id, sg_id, sg_name)
return super(MidonetPluginV2, self).delete_security_group(
context, id)
@ -1057,7 +639,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
MidonetPluginV2, self).create_security_group_rule(
context, security_group_rule)
self.rule_manager.create_for_sg_rule(rule_db_entry)
self.client.create_for_sg_rule(rule_db_entry)
LOG.debug(_("MidonetPluginV2.create_security_group_rule exiting: "
"rule_db_entry=%r"), rule_db_entry)
return rule_db_entry
@ -1073,7 +655,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
if not rule_db_entry:
raise ext_sg.SecurityGroupRuleNotFound(id=sgrid)
self.rule_manager.delete_for_sg_rule(rule_db_entry)
self.client.delete_for_sg_rule(rule_db_entry)
return super(MidonetPluginV2,
self).delete_security_group_rule(context, sgrid)

View File

@ -0,0 +1,16 @@
[MIDONET]
# MidoNet API server URI
midonet_uri = http://localhost:8080/midonet-api
# MidoNet admin username
username = admin
# MidoNet admin password
password = passw0rd
# Virtual provider router ID
provider_router_id = 00112233-0011-0011-0011-001122334455
# Virtual metadata router ID
metadata_router_id = ffeeddcc-ffee-ffee-ffee-ffeeddccbbaa

View File

@ -0,0 +1,253 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2013 Midokura PTE LTD
# 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.
#
# @author: Ryu Ishimoto, Midokura Japan KK
import mock
import uuid
def get_bridge_mock(id=None, tenant_id='test-tenant', name='net'):
if id is None:
id = str(uuid.uuid4())
bridge = mock.Mock()
bridge.get_id.return_value = id
bridge.get_tenant_id.return_value = tenant_id
bridge.get_name.return_value = name
return bridge
def get_bridge_port_mock(id=None, bridge_id=None,
type='ExteriorBridge'):
if id is None:
id = str(uuid.uuid4())
if bridge_id is None:
bridge_id = str(uuid.uuid4())
port = mock.Mock()
port.get_id.return_value = id
port.get_brige_id.return_value = bridge_id
port.get_type.return_value = type
return port
def get_chain_mock(id=None, tenant_id='test-tenant', name='chain',
rules=None):
if id is None:
id = str(uuid.uuid4())
if rules is None:
rules = []
chain = mock.Mock()
chain.get_id.return_value = id
chain.get_tenant_id.return_value = tenant_id
chain.get_name.return_value = name
chain.get_rules.return_value = rules
return chain
def get_exterior_bridge_port_mock(id=None, bridge_id=None):
if id is None:
id = str(uuid.uuid4())
if bridge_id is None:
bridge_id = str(uuid.uuid4())
return get_bridge_port_mock(id=id, bridge_id=bridge_id,
type='ExteriorBridge')
def get_interior_bridge_port_mock(id=None, bridge_id=None):
if id is None:
id = str(uuid.uuid4())
if bridge_id is None:
bridge_id = str(uuid.uuid4())
return get_bridge_port_mock(id=id, bridge_id=bridge_id,
type='InteriorBridge')
def get_port_group_mock(id=None, tenant_id='test-tenant', name='pg'):
if id is None:
id = str(uuid.uuid4())
port_group = mock.Mock()
port_group.get_id.return_value = id
port_group.get_tenant_id.return_value = tenant_id
port_group.get_name.return_value = name
return port_group
def get_router_mock(id=None, tenant_id='test-tenant', name='router'):
if id is None:
id = str(uuid.uuid4())
router = mock.Mock()
router.get_id.return_value = id
router.get_tenant_id.return_value = tenant_id
router.get_name.return_value = name
return router
def get_rule_mock(id=None, chain_id=None, properties=None):
if id is None:
id = str(uuid.uuid4())
if chain_id is None:
chain_id = str(uuid.uuid4())
if properties is None:
properties = {}
rule = mock.Mock()
rule.get_id.return_value = id
rule.get_chain_id.return_value = chain_id
rule.get_properties.return_value = properties
return rule
def get_subnet_mock(bridge_id=None, gateway_ip='10.0.0.1',
subnet_prefix='10.0.0.0', subnet_len=int(24)):
if bridge_id is None:
bridge_id = str(uuid.uuid4())
subnet = mock.Mock()
subnet.get_id.return_value = subnet_prefix + '/' + str(subnet_len)
subnet.get_bridge_id.return_value = bridge_id
subnet.get_default_gateway.return_value = gateway_ip
subnet.get_subnet_prefix.return_value = subnet_prefix
subnet.get_subnet_length.return_value = subnet_len
return subnet
class MidonetLibMockConfig():
def __init__(self, inst):
self.inst = inst
def _create_bridge(self, tenant_id, name):
return get_bridge_mock(tenant_id=tenant_id, name=name)
def _create_exterior_bridge_port(self, bridge):
return get_exterior_bridge_port_mock(bridge_id=bridge.get_id())
def _create_interior_bridge_port(self, bridge):
return get_interior_bridge_port_mock(bridge_id=bridge.get_id())
def _create_subnet(self, bridge, gateway_ip, subnet_prefix, subnet_len):
return get_subnet_mock(bridge.get_id(), gateway_ip=gateway_ip,
subnet_prefix=subnet_prefix,
subnet_len=subnet_len)
def _get_bridge(self, id):
return get_bridge_mock(id=id)
def _get_port(self, id):
return get_exterior_bridge_port_mock(id=id)
def _get_router(self, id):
return get_router_mock(id=id)
def _update_bridge(self, id, name):
return get_bridge_mock(id=id, name=name)
def setup(self):
# Bridge methods side effects
self.inst.create_bridge.side_effect = self._create_bridge
self.inst.get_bridge.side_effect = self._get_bridge
self.inst.update_bridge.side_effect = self._update_bridge
# Subnet methods side effects
self.inst.create_subnet.side_effect = self._create_subnet
# Port methods side effects
ex_bp = self.inst.create_exterior_bridge_port
ex_bp.side_effect = self._create_exterior_bridge_port
in_bp = self.inst.create_interior_bridge_port
in_bp.side_effect = self._create_interior_bridge_port
self.inst.get_port.side_effect = self._get_port
# Router methods side effects
self.inst.get_router.side_effect = self._get_router
class MidoClientMockConfig():
def __init__(self, inst):
self.inst = inst
self.chains_in = None
self.port_groups_in = None
self.chains_out = None
self.rules_out = None
self.port_groups_out = None
def _get_query_tenant_id(self, query):
if query is not None and query['tenant_id']:
tenant_id = query['tenant_id']
else:
tenant_id = 'test-tenant'
return tenant_id
def _get_bridge(self, id):
return get_bridge_mock(id=id)
def _get_chains(self, query=None):
if not self.chains_in:
return []
tenant_id = self._get_query_tenant_id(query)
self.chains_out = []
self.rules_out = []
for chain in self.chains_in:
chain_id = chain['id']
rule_mocks = []
if 'rules' in chain:
for rule in chain['rules']:
rule_mocks.append(
get_rule_mock(id=rule['id'],
chain_id=id,
properties=rule['properties']))
self.rules_out += rule_mocks
self.chains_out.append(get_chain_mock(id=chain_id,
name=chain['name'],
tenant_id=tenant_id,
rules=rule_mocks))
return self.chains_out
def _get_port_groups(self, query=None):
if not self.port_groups_in:
return []
tenant_id = self._get_query_tenant_id(query)
self.port_groups_out = []
for port_group in self.port_groups_in:
self.port_groups_out.append(get_port_group_mock(
id=port_group['id'], name=port_group['name'],
tenant_id=tenant_id))
return self.port_groups_out
def _get_router(self, id):
return get_router_mock(id=id)
def setup(self):
self.inst.get_bridge.side_effect = self._get_bridge
self.inst.get_chains.side_effect = self._get_chains
self.inst.get_port_groups.side_effect = self._get_port_groups
self.inst.get_router.side_effect = self._get_router

View File

@ -19,173 +19,201 @@
# @author: Ryu Ishimoto, Midokura Japan KK
# @author: Tomoe Sugihara, Midokura Japan KK
import uuid
import mock
import testtools
import webob.exc as w_exc
from quantum.openstack.common import uuidutils
from quantum.plugins.midonet import midonet_lib
from quantum.tests import base
import quantum.tests.unit.midonet.mock_lib as mock_lib
class MidonetLibTestCase(base.BaseTestCase):
def _create_test_chain(id, name, tenant_id):
return {'id': id, 'name': name, 'tenant_id': tenant_id}
def _create_test_port_group(sg_id, sg_name, id, tenant_id):
return {"id": id, "name": "OS_SG_%s_%s" % (sg_id, sg_name),
"tenant_id": tenant_id}
def _create_test_router_in_chain(router_id, id, tenant_id):
name = "OS_ROUTER_IN_%s" % router_id
return _create_test_chain(id, name, tenant_id)
def _create_test_router_out_chain(router_id, id, tenant_id):
name = "OS_ROUTER_OUT_%s" % router_id
return _create_test_chain(id, name, tenant_id)
def _create_test_rule(id, chain_id, properties):
return {"id": id, "chain_id": chain_id, "properties": properties}
def _create_test_sg_in_chain(sg_id, sg_name, id, tenant_id):
if sg_name:
name = "OS_SG_%s_%s_IN" % (sg_id, sg_name)
else:
name = "OS_SG_%s_IN" % sg_id
return _create_test_chain(id, name, tenant_id)
def _create_test_sg_out_chain(sg_id, sg_name, id, tenant_id):
if sg_name:
name = "OS_SG_%s_%s_OUT" % (sg_id, sg_name)
else:
name = "OS_SG_%s_OUT" % sg_id
return _create_test_chain(id, name, tenant_id)
def _create_test_sg_rule(tenant_id, sg_id, id,
direction="egress", protocol="tcp", port_min=1,
port_max=65535, src_ip='192.168.1.0/24',
src_group_id=None, ethertype=0x0800, properties=None):
return {"tenant_id": tenant_id, "security_group_id": sg_id,
"id": id, "direction": direction, "protocol": protocol,
"remote_ip_prefix": src_ip, "remote_group_id": src_group_id,
"port_range_min": port_min, "port_range_max": port_max,
"ethertype": ethertype, "external_id": None}
def _create_test_sg_chain_rule(id, chain_id, sg_rule_id):
props = {"os_sg_rule_id": sg_rule_id}
return _create_test_rule(id, chain_id, props)
class MidoClientTestCase(testtools.TestCase):
def setUp(self):
super(MidonetLibTestCase, self).setUp()
super(MidoClientTestCase, self).setUp()
self._tenant_id = 'test-tenant'
self.mock_api = mock.Mock()
def _create_mock_chains(self, sg_id, sg_name):
mock_in_chain = mock.Mock()
mock_in_chain.get_name.return_value = "OS_SG_%s_%s_IN" % (sg_id,
sg_name)
mock_out_chain = mock.Mock()
mock_out_chain.get_name.return_value = "OS_SG_%s_%s_OUT" % (sg_id,
sg_name)
return (mock_in_chain, mock_out_chain)
def _create_mock_router_chains(self, router_id):
mock_in_chain = mock.Mock()
mock_in_chain.get_name.return_value = "OS_ROUTER_IN_%s" % (router_id)
mock_out_chain = mock.Mock()
mock_out_chain.get_name.return_value = "OS_ROUTER_OUT_%s" % (router_id)
return (mock_in_chain, mock_out_chain)
def _create_mock_port_group(self, sg_id, sg_name):
mock_pg = mock.Mock()
mock_pg.get_name.return_value = "OS_SG_%s_%s" % (sg_id, sg_name)
return mock_pg
def _create_mock_rule(self, rule_id):
mock_rule = mock.Mock()
mock_rule.get_properties.return_value = {"os_sg_rule_id": rule_id}
return mock_rule
class MidonetChainManagerTestCase(MidonetLibTestCase):
def setUp(self):
super(MidonetChainManagerTestCase, self).setUp()
self.mgr = midonet_lib.ChainManager(self.mock_api)
self.mock_api_cfg = mock_lib.MidoClientMockConfig(self.mock_api)
self.mock_api_cfg.setup()
self.client = midonet_lib.MidoClient(self.mock_api)
def test_create_for_sg(self):
tenant_id = 'test_tenant'
sg_id = str(uuid.uuid4())
sg_name = 'test_sg_name'
calls = [mock.call.add_chain().tenant_id(tenant_id)]
sg_id = uuidutils.generate_uuid()
sg_name = 'test-sg'
calls = [mock.call.add_chain().tenant_id(self._tenant_id),
mock.call.add_port_group().tenant_id(self._tenant_id)]
self.mgr.create_for_sg(tenant_id, sg_id, sg_name)
self.client.create_for_sg(self._tenant_id, sg_id, sg_name)
self.mock_api.assert_has_calls(calls)
self.mock_api.assert_has_calls(calls, any_order=True)
def test_delete_for_sg(self):
tenant_id = 'test_tenant'
sg_id = str(uuid.uuid4())
sg_name = 'test_sg_name'
in_chain, out_chain = self._create_mock_chains(sg_id, sg_name)
def test_create_for_sg_rule(self):
sg_id = uuidutils.generate_uuid()
sg_name = 'test-sg'
in_chain_id = uuidutils.generate_uuid()
out_chain_id = uuidutils.generate_uuid()
self.mock_api_cfg.chains_in = [
_create_test_sg_in_chain(sg_id, sg_name, in_chain_id,
self._tenant_id),
_create_test_sg_out_chain(sg_id, sg_name, out_chain_id,
self._tenant_id)]
# Mock get_chains returned values
self.mock_api.get_chains.return_value = [in_chain, out_chain]
sg_rule_id = uuidutils.generate_uuid()
sg_rule = _create_test_sg_rule(self._tenant_id, sg_id, sg_rule_id)
self.mgr.delete_for_sg(tenant_id, sg_id, sg_name)
props = {"os_sg_rule_id": sg_rule_id}
calls = [mock.call.add_rule().port_group(None).type(
'accept').nw_proto(6).nw_src_address(
'192.168.1.0').nw_src_length(24).tp_src_start(
None).tp_src_end(None).tp_dst_start(1).tp_dst_end(
65535).properties(props).create()]
self.mock_api.assert_has_calls(mock.call.get_chains(
{"tenant_id": tenant_id}))
in_chain.delete.assert_called_once_with()
out_chain.delete.assert_called_once_with()
self.client.create_for_sg_rule(sg_rule)
def test_get_router_chains(self):
tenant_id = 'test_tenant'
router_id = str(uuid.uuid4())
in_chain, out_chain = self._create_mock_router_chains(router_id)
# Mock get_chains returned values
self.mock_api.get_chains.return_value = [in_chain, out_chain]
chains = self.mgr.get_router_chains(tenant_id, router_id)
self.mock_api.assert_has_calls(mock.call.get_chains(
{"tenant_id": tenant_id}))
self.assertEqual(len(chains), 2)
self.assertEqual(chains['in'], in_chain)
self.assertEqual(chains['out'], out_chain)
# Egress chain rule added
self.mock_api_cfg.chains_out[0].assert_has_calls(calls)
def test_create_router_chains(self):
tenant_id = 'test_tenant'
router_id = str(uuid.uuid4())
calls = [mock.call.add_chain().tenant_id(tenant_id)]
router = mock_lib.get_router_mock(tenant_id=self._tenant_id)
api_calls = [mock.call.add_chain().tenant_id(self._tenant_id)]
router_calls = [
mock.call.inbound_filter_id().outbound_filter_id().update()]
self.mgr.create_router_chains(tenant_id, router_id)
self.client.create_router_chains(router)
self.mock_api.assert_has_calls(api_calls)
router.assert_has_calls(router_calls)
def test_delete_for_sg(self):
sg_id = uuidutils.generate_uuid()
sg_name = 'test-sg'
in_chain_id = uuidutils.generate_uuid()
out_chain_id = uuidutils.generate_uuid()
pg_id = uuidutils.generate_uuid()
self.mock_api_cfg.chains_in = [
_create_test_sg_in_chain(sg_id, sg_name, in_chain_id,
self._tenant_id),
_create_test_sg_out_chain(sg_id, sg_name, out_chain_id,
self._tenant_id)]
self.mock_api_cfg.port_groups_in = [
_create_test_port_group(sg_id, sg_name, pg_id, self._tenant_id)]
calls = [mock.call.get_chains({"tenant_id": self._tenant_id}),
mock.call.delete_chain(in_chain_id),
mock.call.delete_chain(out_chain_id),
mock.call.get_port_groups({"tenant_id": self._tenant_id}),
mock.call.delete_port_group(pg_id)]
self.client.delete_for_sg(self._tenant_id, sg_id, sg_name)
self.mock_api.assert_has_calls(calls)
def test_get_sg_chains(self):
tenant_id = 'test_tenant'
sg_id = str(uuid.uuid4())
in_chain, out_chain = self._create_mock_chains(sg_id, 'foo')
def test_delete_for_sg_rule(self):
sg_id = uuidutils.generate_uuid()
sg_name = 'test-sg'
in_chain_id = uuidutils.generate_uuid()
out_chain_id = uuidutils.generate_uuid()
self.mock_api_cfg.chains_in = [
_create_test_sg_in_chain(sg_id, sg_name, in_chain_id,
self._tenant_id),
_create_test_sg_out_chain(sg_id, sg_name, out_chain_id,
self._tenant_id)]
# Mock get_chains returned values
self.mock_api.get_chains.return_value = [in_chain, out_chain]
rule_id = uuidutils.generate_uuid()
sg_rule_id = uuidutils.generate_uuid()
rule = _create_test_sg_chain_rule(rule_id, in_chain_id, sg_rule_id)
self.mock_api_cfg.chains_in[0]['rules'] = [rule]
sg_rule = _create_test_sg_rule(self._tenant_id, sg_id, sg_rule_id)
chains = self.mgr.get_sg_chains(tenant_id, sg_id)
self.client.delete_for_sg_rule(sg_rule)
self.mock_api.assert_has_calls(mock.call.get_chains(
{"tenant_id": tenant_id}))
self.assertEqual(len(chains), 2)
self.assertEqual(chains['in'], in_chain)
self.assertEqual(chains['out'], out_chain)
self.mock_api.delete_rule.assert_called_once_with(rule_id)
def test_get_bridge(self):
bridge_id = uuidutils.generate_uuid()
class MidonetPortGroupManagerTestCase(MidonetLibTestCase):
bridge = self.client.get_bridge(bridge_id)
def setUp(self):
super(MidonetPortGroupManagerTestCase, self).setUp()
self.mgr = midonet_lib.PortGroupManager(self.mock_api)
self.assertIsNotNone(bridge)
self.assertEqual(bridge.get_id(), bridge_id)
def test_create(self):
tenant_id = 'test_tenant'
sg_id = str(uuid.uuid4())
sg_name = 'test_sg'
pg_mock = self._create_mock_port_group(sg_id, sg_name)
rv = self.mock_api.add_port_group.return_value.tenant_id.return_value
rv.name.return_value = pg_mock
def test_get_bridge_error(self):
self.mock_api.get_bridge.side_effect = w_exc.HTTPInternalServerError()
self.assertRaises(midonet_lib.MidonetApiException,
self.client.get_bridge, uuidutils.generate_uuid())
self.mgr.create(tenant_id, sg_id, sg_name)
def test_get_bridge_not_found(self):
self.mock_api.get_bridge.side_effect = w_exc.HTTPNotFound()
self.assertRaises(midonet_lib.MidonetResourceNotFound,
self.client.get_bridge, uuidutils.generate_uuid())
pg_mock.create.assert_called_once_with()
def test_get_port_groups_for_sg(self):
sg_id = uuidutils.generate_uuid()
pg_id = uuidutils.generate_uuid()
self.mock_api_cfg.port_groups_in = [
_create_test_port_group(sg_id, 'test-sg', pg_id, self._tenant_id)]
def test_delete(self):
tenant_id = 'test_tenant'
sg_id = str(uuid.uuid4())
sg_name = 'test_sg'
pg_mock1 = self._create_mock_port_group(sg_id, sg_name)
pg_mock2 = self._create_mock_port_group(sg_id, sg_name)
self.mock_api.get_port_groups.return_value = [pg_mock1, pg_mock2]
pg = self.client.get_port_groups_for_sg(self._tenant_id, sg_id)
self.mgr.delete(tenant_id, sg_id, sg_name)
self.mock_api.assert_has_calls(mock.call.get_port_groups(
{"tenant_id": tenant_id}))
pg_mock1.delete.assert_called_once_with()
pg_mock2.delete.assert_called_once_with()
def test_get_for_sg(self):
tenant_id = 'test_tenant'
sg_id = str(uuid.uuid4())
pg_mock = self._create_mock_port_group(sg_id, 'foo')
self.mock_api.get_port_groups.return_value = [pg_mock]
pg = self.mgr.get_for_sg(tenant_id, sg_id)
self.assertEqual(pg, pg_mock)
class MidonetRuleManagerTestCase(MidonetLibTestCase):
def setUp(self):
super(MidonetRuleManagerTestCase, self).setUp()
self.mgr = midonet_lib.RuleManager(self.mock_api)
self.mgr.chain_manager = mock.Mock()
self.mgr.pg_manager = mock.Mock()
self.assertIsNotNone(pg)
self.assertEqual(pg.get_id(), pg_id)
def _create_test_rule(self, tenant_id, sg_id, rule_id, direction="egress",
protocol="tcp", port_min=1, port_max=65535,
@ -198,41 +226,53 @@ class MidonetRuleManagerTestCase(MidonetLibTestCase):
"port_range_min": port_min, "port_range_max": port_max,
"ethertype": ethertype, "id": rule_id, "external_id": None}
def test_create_for_sg_rule(self):
tenant_id = 'test_tenant'
sg_id = str(uuid.uuid4())
rule_id = str(uuid.uuid4())
in_chain, out_chain = self._create_mock_chains(sg_id, 'foo')
self.mgr.chain_manager.get_sg_chains.return_value = {"in": in_chain,
"out": out_chain}
props = {"os_sg_rule_id": rule_id}
rule = self._create_test_rule(tenant_id, sg_id, rule_id)
calls = [mock.call.add_rule().port_group(None).type(
'accept').nw_proto(6).nw_src_address(
'192.168.1.0').nw_src_length(24).tp_src_start(
None).tp_src_end(None).tp_dst_start(1).tp_dst_end(
65535).properties(props).create()]
def test_get_router_error(self):
self.mock_api.get_router.side_effect = w_exc.HTTPInternalServerError()
self.assertRaises(midonet_lib.MidonetApiException,
self.client.get_router, uuidutils.generate_uuid())
self.mgr.create_for_sg_rule(rule)
def test_get_router_not_found(self):
self.mock_api.get_router.side_effect = w_exc.HTTPNotFound()
self.assertRaises(midonet_lib.MidonetResourceNotFound,
self.client.get_router, uuidutils.generate_uuid())
in_chain.assert_has_calls(calls)
def test_get_router_chains(self):
router_id = uuidutils.generate_uuid()
in_chain_id = uuidutils.generate_uuid()
out_chain_id = uuidutils.generate_uuid()
self.mock_api_cfg.chains_in = [
_create_test_router_in_chain(router_id, in_chain_id,
self._tenant_id),
_create_test_router_out_chain(router_id, out_chain_id,
self._tenant_id)]
def test_delete_for_sg_rule(self):
tenant_id = 'test_tenant'
sg_id = str(uuid.uuid4())
rule_id = str(uuid.uuid4())
in_chain, out_chain = self._create_mock_chains(sg_id, 'foo')
self.mgr.chain_manager.get_sg_chains.return_value = {"in": in_chain,
"out": out_chain}
chains = self.client.get_router_chains(self._tenant_id, router_id)
# Mock the rules returned for each chain
mock_rule_in = self._create_mock_rule(rule_id)
mock_rule_out = self._create_mock_rule(rule_id)
in_chain.get_rules.return_value = [mock_rule_in]
out_chain.get_rules.return_value = [mock_rule_out]
self.mock_api.assert_has_calls(mock.call.get_chains(
{"tenant_id": self._tenant_id}))
self.assertEqual(len(chains), 2)
self.assertIn('in', chains)
self.assertIn('out', chains)
self.assertEqual(chains['in'].get_id(), in_chain_id)
self.assertEqual(chains['out'].get_id(), out_chain_id)
rule = self._create_test_rule(tenant_id, sg_id, rule_id)
self.mgr.delete_for_sg_rule(rule)
def test_get_sg_chains(self):
sg_id = uuidutils.generate_uuid()
sg_name = 'test-sg'
in_chain_id = uuidutils.generate_uuid()
out_chain_id = uuidutils.generate_uuid()
self.mock_api_cfg.chains_in = [
_create_test_sg_in_chain(sg_id, sg_name, in_chain_id,
self._tenant_id),
_create_test_sg_out_chain(sg_id, sg_name, out_chain_id,
self._tenant_id)]
mock_rule_in.delete.assert_called_once_with()
mock_rule_out.delete.assert_called_once_with()
chains = self.client.get_sg_chains(self._tenant_id, sg_id)
self.mock_api.assert_has_calls(mock.call.get_chains(
{"tenant_id": self._tenant_id}))
self.assertEqual(len(chains), 2)
self.assertIn('in', chains)
self.assertIn('out', chains)
self.assertEqual(chains['in'].get_id(), in_chain_id)
self.assertEqual(chains['out'].get_id(), out_chain_id)

View File

@ -20,16 +20,18 @@
# @author: Ryu Ishimoto, Midokura Japan KK
# @author: Tomoe Sugihara, Midokura Japan KK
import sys
import uuid
import mock
import os
import sys
import quantum.common.test_lib as test_lib
import quantum.tests.unit.midonet.mock_lib as mock_lib
import quantum.tests.unit.test_db_plugin as test_plugin
MIDOKURA_PKG_PATH = "quantum.plugins.midonet.plugin"
# Need to mock the midonetclient module since the plugin will try to load it.
sys.modules["midonetclient"] = mock.Mock()
@ -39,730 +41,83 @@ class MidonetPluginV2TestCase(test_plugin.QuantumDbPluginV2TestCase):
_plugin_name = ('%s.MidonetPluginV2' % MIDOKURA_PKG_PATH)
def setUp(self):
self.mock_api = mock.patch('midonetclient.api.MidonetApi')
self.mock_api = mock.patch(
'quantum.plugins.midonet.midonet_lib.MidoClient')
etc_path = os.path.join(os.path.dirname(__file__), 'etc')
test_lib.test_config['config_files'] = [os.path.join(
etc_path, 'midonet.ini.test')]
self.instance = self.mock_api.start()
mock_cfg = mock_lib.MidonetLibMockConfig(self.instance.return_value)
mock_cfg.setup()
super(MidonetPluginV2TestCase, self).setUp(self._plugin_name)
def tearDown(self):
super(MidonetPluginV2TestCase, self).tearDown()
self.mock_api.stop()
def _setup_bridge_mock(self, bridge_id=str(uuid.uuid4()), name='net'):
# Set up mocks needed for the parent network() method
bridge = mock.Mock()
bridge.get_id.return_value = bridge_id
bridge.get_name.return_value = name
self.instance.return_value.add_bridge.return_value.name.return_value\
.tenant_id.return_value.create.return_value = bridge
self.instance.return_value.get_bridges.return_value = [bridge]
self.instance.return_value.get_bridge.return_value = bridge
return bridge
def _setup_subnet_mocks(self, subnet_id=str(uuid.uuid4()),
subnet_prefix='10.0.0.0', subnet_len=int(24)):
# Set up mocks needed for the parent subnet() method
bridge = self._setup_bridge_mock()
subnet = mock.Mock()
subnet.get_subnet_prefix.return_value = subnet_prefix
subnet.get_subnet_length.return_value = subnet_len
subnet.get_id.return_value = subnet_prefix + '/' + str(subnet_len)
bridge.add_dhcp_subnet.return_value.default_gateway\
.return_value.subnet_prefix.return_value.subnet_length\
.return_value.create.return_value = subnet
bridge.get_dhcp_subnets.return_value = [subnet]
return (bridge, subnet)
def _setup_port_mocks(self, port_id=str(uuid.uuid4())):
# Set up mocks needed for the parent port() method
bridge, subnet = self._setup_subnet_mocks()
port = mock.Mock()
port.get_id.return_value = port_id
self.instance.return_value.create_port.return_value = port
self.instance.return_value.get_port.return_value = port
bridge.add_exterior_port.return_value.create.return_value = (
port
)
dhcp_host = mock.Mock()
rv1 = subnet.add_dhcp_host.return_value.ip_addr.return_value
rv1.mac_addr.return_value.create.return_value = dhcp_host
subnet.get_dhcp_hosts.return_value = [dhcp_host]
return (bridge, subnet, port, dhcp_host)
class TestMidonetNetworksV2(test_plugin.TestNetworksV2,
MidonetPluginV2TestCase):
def test_create_network(self):
self._setup_bridge_mock()
super(TestMidonetNetworksV2, self).test_create_network()
def test_create_public_network(self):
self._setup_bridge_mock()
super(TestMidonetNetworksV2, self).test_create_public_network()
def test_create_public_network_no_admin_tenant(self):
self._setup_bridge_mock()
super(TestMidonetNetworksV2,
self).test_create_public_network_no_admin_tenant()
def test_update_network(self):
self._setup_bridge_mock()
super(TestMidonetNetworksV2, self).test_update_network()
def test_list_networks(self):
self._setup_bridge_mock()
with self.network(name='net1') as net1:
req = self.new_list_request('networks')
res = self.deserialize('json', req.get_response(self.api))
self.assertEqual(res['networks'][0]['name'],
net1['network']['name'])
def test_show_network(self):
self._setup_bridge_mock()
super(TestMidonetNetworksV2, self).test_show_network()
def test_update_shared_network_noadmin_returns_403(self):
self._setup_bridge_mock()
super(TestMidonetNetworksV2,
self).test_update_shared_network_noadmin_returns_403()
def test_update_network_set_shared(self):
pass
def test_update_network_with_subnet_set_shared(self):
pass
def test_update_network_set_not_shared_single_tenant(self):
pass
def test_update_network_set_not_shared_other_tenant_returns_409(self):
pass
def test_update_network_set_not_shared_multi_tenants_returns_409(self):
pass
def test_update_network_set_not_shared_multi_tenants2_returns_409(self):
pass
def test_create_networks_bulk_native(self):
pass
def test_create_networks_bulk_native_quotas(self):
pass
def test_create_networks_bulk_tenants_and_quotas(self):
pass
def test_create_networks_bulk_tenants_and_quotas_fail(self):
pass
def test_create_networks_bulk_emulated(self):
pass
def test_create_networks_bulk_wrong_input(self):
pass
def test_create_networks_bulk_emulated_plugin_failure(self):
pass
def test_create_networks_bulk_native_plugin_failure(self):
pass
def test_list_networks_with_parameters(self):
pass
def test_list_networks_with_fields(self):
pass
def test_list_networks_with_parameters_invalid_values(self):
pass
def test_list_shared_networks_with_non_admin_user(self):
pass
def test_show_network_with_subnet(self):
pass
def test_invalid_admin_status(self):
pass
def test_list_networks_with_pagination_emulated(self):
pass
def test_list_networks_with_pagination_reverse_emulated(self):
pass
def test_list_networks_with_sort_emulated(self):
pass
def test_list_networks_without_pk_in_fields_pagination_emulated(self):
pass
pass
class TestMidonetSubnetsV2(test_plugin.TestSubnetsV2,
MidonetPluginV2TestCase):
def test_create_subnet(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet()
def test_create_two_subnets(self):
pass
def test_create_two_subnets_same_cidr_returns_400(self):
pass
def test_create_subnet_bad_V4_cidr(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_V4_cidr()
def test_create_subnet_bad_V6_cidr(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_V4_cidr()
def test_create_2_subnets_overlapping_cidr_allowed_returns_200(self):
pass
def test_create_2_subnets_overlapping_cidr_not_allowed_returns_400(self):
pass
def test_create_subnets_bulk_native(self):
pass
def test_create_subnets_bulk_emulated(self):
pass
def test_create_subnets_bulk_emulated_plugin_failure(self):
pass
def test_create_subnets_bulk_native_plugin_failure(self):
pass
def test_delete_subnet(self):
_bridge, subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_delete_subnet()
subnet.delete.assert_called_once_with()
def test_delete_subnet_port_exists_owned_by_network(self):
_bridge, subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_delete_subnet_port_exists_owned_by_network()
def test_delete_subnet_port_exists_owned_by_other(self):
pass
def test_delete_network(self):
bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_delete_network()
bridge.delete.assert_called_once_with()
def test_create_subnet_bad_tenant(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_tenant()
def test_create_subnet_bad_ip_version(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_ip_version()
def test_create_subnet_bad_ip_version_null(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_bad_ip_version_null()
def test_create_subnet_bad_uuid(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_uuid()
def test_create_subnet_bad_boolean(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_boolean()
def test_create_subnet_bad_pools(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_pools()
def test_create_subnet_bad_nameserver(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_nameserver()
def test_create_subnet_bad_hostroutes(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_hostroutes()
def test_create_subnet_defaults(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_defaults()
def test_create_subnet_gw_values(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_gw_values()
def test_create_subnet_gw_outside_cidr_force_on_returns_400(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_gw_outside_cidr_force_on_returns_400()
def test_create_subnet_gw_of_network_force_on_returns_400(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_gw_of_network_force_on_returns_400()
def test_create_subnet_gw_bcast_force_on_returns_400(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_gw_bcast_force_on_returns_400()
def test_create_subnet_with_allocation_pool(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_with_allocation_pool()
def test_create_subnet_with_none_gateway(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_with_none_gateway()
def test_create_subnet_with_none_gateway_fully_allocated(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_with_none_gateway_fully_allocated()
def test_subnet_with_allocation_range(self):
pass
def test_create_subnet_with_none_gateway_allocation_pool(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_with_none_gateway_allocation_pool()
def test_create_subnet_with_v6_allocation_pool(self):
pass
def test_create_subnet_with_large_allocation_pool(self):
pass
def test_create_subnet_multiple_allocation_pools(self):
pass
def test_create_subnet_with_dhcp_disabled(self):
pass
def test_create_subnet_default_gw_conflict_allocation_pool_returns_409(
self):
pass
def test_create_subnet_gateway_in_allocation_pool_returns_409(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self)\
.test_create_subnet_gateway_in_allocation_pool_returns_409()
def test_create_subnet_overlapping_allocation_pools_returns_409(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self)\
.test_create_subnet_overlapping_allocation_pools_returns_409()
def test_create_subnet_invalid_allocation_pool_returns_400(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_invalid_allocation_pool_returns_400()
def test_create_subnet_out_of_range_allocation_pool_returns_400(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self)\
.test_create_subnet_out_of_range_allocation_pool_returns_400()
def test_create_subnet_shared_returns_400(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_shared_returns_400()
# IPv6 is not supported by MidoNet yet. Ignore tests that attempt to
# create IPv6 subnet.
def test_create_subnet_inconsistent_ipv6_cidrv4(self):
pass
def test_create_subnet_inconsistent_ipv4_cidrv6(self):
pass
def test_create_subnet_inconsistent_ipv4_gatewayv6(self):
pass
def test_create_subnet_inconsistent_ipv6_gatewayv4(self):
pass
def test_create_subnet_inconsistent_ipv6_dns_v4(self):
pass
def test_create_subnet_inconsistent_ipv4_hostroute_dst_v6(self):
pass
def test_create_subnet_inconsistent_ipv4_hostroute_np_v6(self):
pass
def test_update_subnet(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_update_subnet()
def test_update_subnet_shared_returns_400(self):
self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_update_subnet_shared_returns_400()
def test_update_subnet_gw_outside_cidr_force_on_returns_400(self):
pass
def test_update_subnet_inconsistent_ipv4_gatewayv6(self):
def test_create_subnet_with_v6_allocation_pool(self):
pass
def test_update_subnet_inconsistent_ipv6_gatewayv4(self):
pass
def test_update_subnet_inconsistent_ipv4_dns_v6(self):
pass
def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
pass
def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
pass
def test_show_subnet(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_show_subnet()
def test_list_subnets(self):
def test_create_subnet_inconsistent_ipv6_gatewayv4(self):
pass
def test_list_subnets_shared(self):
# Multiple subnets in a network is not supported by MidoNet yet. Ignore
# tests that attempt to create them.
def test_create_subnets_bulk_emulated(self):
pass
def test_create_two_subnets(self):
pass
def test_list_subnets(self):
pass
def test_list_subnets_with_parameter(self):
pass
def test_invalid_ip_version(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_invalid_ip_version()
def test_invalid_subnet(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_invalid_subnet()
def test_invalid_ip_address(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_invalid_ip_address()
def test_invalid_uuid(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_invalid_uuid()
def test_create_subnet_with_one_dns(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_with_one_dns()
def test_create_subnet_with_two_dns(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_create_subnet_with_two_dns()
def test_create_subnet_with_too_many_dns(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_with_too_many_dns()
def test_create_subnet_with_one_host_route(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_with_one_host_route()
def test_create_subnet_with_two_host_routes(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_with_two_host_routes()
def test_create_subnet_with_too_many_routes(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_create_subnet_with_too_many_routes()
def test_update_subnet_dns(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_update_subnet_dns()
def test_update_subnet_dns_to_None(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_update_subnet_dns_to_None()
def test_update_subnet_dns_with_too_many_entries(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_update_subnet_dns_with_too_many_entries()
def test_update_subnet_route(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_update_subnet_route()
def test_update_subnet_route_to_None(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_update_subnet_route_to_None()
def test_update_subnet_route_with_too_many_entries(self):
_bridge, _subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_update_subnet_route_with_too_many_entries()
def test_delete_subnet_with_dns(self):
_bridge, subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_delete_subnet_with_dns()
subnet.delete.assert_called_once_with()
def test_delete_subnet_with_route(self):
_bridge, subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2, self).test_delete_subnet_with_route()
subnet.delete.assert_called_once_with()
def test_delete_subnet_with_dns_and_route(self):
_bridge, subnet = self._setup_subnet_mocks()
super(TestMidonetSubnetsV2,
self).test_delete_subnet_with_dns_and_route()
subnet.delete.assert_called_once_with()
def test_update_subnet_gateway_in_allocation_pool_returns_409(self):
self._setup_port_mocks()
super(TestMidonetSubnetsV2, self)\
.test_update_subnet_gateway_in_allocation_pool_returns_409()
def test_list_subnets_with_pagination_emulated(self):
pass
def test_list_subnets_with_pagination_reverse_emulated(self):
pass
def test_list_subnets_with_sort_emulated(self):
def test_create_two_subnets_same_cidr_returns_400(self):
pass
class TestMidonetPortsV2(test_plugin.TestPortsV2,
MidonetPluginV2TestCase):
def test_create_port_json(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_create_port_json()
def test_create_port_bad_tenant(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_create_port_bad_tenant()
def test_create_port_public_network(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_create_port_public_network()
def test_create_port_public_network_with_ip(self):
self._setup_port_mocks()
super(TestMidonetPortsV2,
self).test_create_port_public_network_with_ip()
def test_create_ports_bulk_native(self):
pass
def test_create_ports_bulk_emulated(self):
pass
def test_create_ports_bulk_wrong_input(self):
pass
def test_create_ports_bulk_emulated_plugin_failure(self):
pass
def test_create_ports_bulk_native_plugin_failure(self):
pass
def test_list_ports(self):
pass
def test_list_ports_filtered_by_fixed_ip(self):
pass
def test_list_ports_public_network(self):
pass
def test_show_port(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_show_port()
def test_delete_port(self):
_bridge, _subnet, port, _dhcp = self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_delete_port()
port.delete.assert_called_once_with()
def test_delete_port_public_network(self):
_bridge, _subnet, port, _dhcp = self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_delete_port_public_network()
port.delete.assert_called_once_with()
def test_update_port(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_update_port()
def test_update_device_id_null(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_update_device_id_null()
def test_delete_network_if_port_exists(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_delete_network_if_port_exists()
def test_delete_network_port_exists_owned_by_network(self):
self._setup_port_mocks()
super(TestMidonetPortsV2,
self).test_delete_network_port_exists_owned_by_network()
def test_update_port_delete_ip(self):
pass
def test_no_more_port_exception(self):
pass
def test_update_port_update_ip(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_update_port_update_ip()
def test_update_port_update_ip_address_only(self):
self._setup_port_mocks()
super(TestMidonetPortsV2,
self).test_update_port_update_ip_address_only()
def test_update_port_update_ips(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_update_port_update_ips()
def test_update_port_add_additional_ip(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_update_port_add_additional_ip()
def test_requested_duplicate_mac(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_requested_duplicate_mac()
def test_mac_generation(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_mac_generation()
def test_mac_generation_4octet(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_mac_generation_4octet()
def test_bad_mac_format(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_bad_mac_format()
def test_mac_exhaustion(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_mac_exhaustion()
def test_requested_duplicate_ip(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_requested_duplicate_ip()
def test_requested_subnet_delete(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_requested_subnet_delete()
def test_requested_subnet_id(self):
pass
def test_requested_subnet_id_not_on_network(self):
pass
def test_overlapping_subnets(self):
pass
# IPv6 is not supported by MidoNet yet. Ignore tests that attempt to
# create IPv6 subnet.
def test_requested_subnet_id_v4_and_v6(self):
pass
def test_range_allocation(self):
pass
# Multiple subnets in a network is not supported by MidoNet yet. Ignore
# tests that attempt to create them.
def test_requested_invalid_fixed_ips(self):
pass
def test_invalid_ip(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_invalid_ip()
def test_requested_split(self):
pass
def test_duplicate_ips(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_duplicate_ips()
def test_fixed_ip_invalid_subnet_id(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_fixed_ip_invalid_subnet_id()
def test_fixed_ip_invalid_ip(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_fixed_ip_invalid_ip()
def test_requested_ips_only(self):
pass
def test_recycling(self):
pass
def test_invalid_admin_state(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_invalid_admin_state()
def test_invalid_mac_address(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_invalid_mac_address()
def test_default_allocation_expiration(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_default_allocation_expiration()
def test_update_fixed_ip_lease_expiration(self):
self._setup_port_mocks()
super(TestMidonetPortsV2,
self).test_update_fixed_ip_lease_expiration()
def test_port_delete_holds_ip(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_port_delete_holds_ip()
def test_update_fixed_ip_lease_expiration_invalid_address(self):
self._setup_port_mocks()
super(TestMidonetPortsV2,
self).test_update_fixed_ip_lease_expiration_invalid_address()
def test_hold_ip_address(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_hold_ip_address()
def test_recycle_held_ip_address(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_recycle_held_ip_address()
def test_recycle_expired_previously_run_within_context(self):
pass
def test_update_port_not_admin(self):
self._setup_port_mocks()
super(TestMidonetPortsV2, self).test_update_port_not_admin()
def test_list_ports_with_pagination_emulated(self):
pass
def test_list_ports_with_pagination_reverse_emulated(self):
pass
def test_list_ports_with_sort_emulated(self):
pass
def test_max_fixed_ips_exceeded(self):
pass
def test_update_max_fixed_ips_exceeded(self):
pass
def test_overlapping_subnets(self):
pass