Merge "Make MidoNet plugin code more testable"

This commit is contained in:
Jenkins 2013-05-31 14:28:59 +00:00 committed by Gerrit Code Review
commit 599d73cea8
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