Merge "Make MidoNet plugin code more testable"
This commit is contained in:
commit
599d73cea8
@ -20,23 +20,35 @@
|
|||||||
# @author: Ryu Ishimoto, Midokura Japan KK
|
# @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
|
from quantum.openstack.common import log as logging
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
PREFIX = 'OS_SG_'
|
PREFIX = 'OS_SG_'
|
||||||
SUFFIX_IN = '_IN'
|
NAME_IDENTIFIABLE_PREFIX_LEN = len(PREFIX) + 36 # 36 = length of uuid
|
||||||
SUFFIX_OUT = '_OUT'
|
OS_FLOATING_IP_RULE_KEY = 'OS_FLOATING_IP'
|
||||||
OS_ROUTER_IN_CHAIN_NAME_FORMAT = 'OS_ROUTER_IN_%s'
|
OS_ROUTER_IN_CHAIN_NAME_FORMAT = 'OS_ROUTER_IN_%s'
|
||||||
OS_ROUTER_OUT_CHAIN_NAME_FORMAT = 'OS_ROUTER_OUT_%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):
|
def sg_label(sg_id, sg_name):
|
||||||
"""Construct the security group ID used as chain identifier in MidoNet."""
|
"""Construct the security group ID used as chain identifier in MidoNet."""
|
||||||
return PREFIX + str(sg_id) + '_' + sg_name
|
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
|
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}
|
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):
|
def __init__(self, mido_api):
|
||||||
self.mido_api = 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):
|
def create_for_sg(self, tenant_id, sg_id, sg_name):
|
||||||
"""Create a new chain for security group.
|
"""Create a new chain for security group.
|
||||||
|
|
||||||
Creating a security group creates a pair of chains in MidoNet, one for
|
Creating a security group creates a pair of chains in MidoNet, one for
|
||||||
inbound and the other for outbound.
|
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 "
|
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
|
||||||
"sg_name=%(sg_name)s "),
|
"sg_name=%(sg_name)s "),
|
||||||
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
|
{'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(
|
self.mido_api.add_chain().tenant_id(tenant_id).name(
|
||||||
cnames['out']).create()
|
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):
|
def delete_for_sg(self, tenant_id, sg_id, sg_name):
|
||||||
"""Delete a chain mapped to a security group.
|
"""Delete a chain mapped to a security group.
|
||||||
|
|
||||||
Delete a SG means deleting all the chains (inbound and outbound)
|
Delete a SG means deleting all the chains (inbound and outbound)
|
||||||
associated with the SG in MidoNet.
|
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 "
|
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
|
||||||
"sg_name=%(sg_name)s "),
|
"sg_name=%(sg_name)s "),
|
||||||
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
|
{'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})
|
chains = self.mido_api.get_chains({'tenant_id': tenant_id})
|
||||||
for c in chains:
|
for c in chains:
|
||||||
if c.get_name() == cnames['in'] or c.get_name() == cnames['out']:
|
if c.get_name() == cnames['in'] or c.get_name() == cnames['out']:
|
||||||
LOG.debug(_('ChainManager.delete_for_sg: deleting chain=%r'),
|
LOG.debug(_('MidoClient.delete_for_sg: deleting chain=%r'),
|
||||||
c)
|
c.get_id())
|
||||||
c.delete()
|
self.mido_api.delete_chain(c.get_id())
|
||||||
|
|
||||||
def get_router_chains(self, tenant_id, router_id):
|
pg_name = port_group_name(sg_id, sg_name)
|
||||||
"""Get router chains.
|
pgs = self.mido_api.get_port_groups({'tenant_id': tenant_id})
|
||||||
|
for pg in pgs:
|
||||||
Returns a dictionary that has in/out chain resources key'ed with 'in'
|
if pg.get_name() == pg_name:
|
||||||
and 'out' respectively, given the tenant_id and the router_id passed
|
LOG.debug(_("MidoClient.delete_for_sg: deleting pg=%r"),
|
||||||
in in the arguments.
|
pg)
|
||||||
"""
|
self.mido_api.delete_port_group(pg.get_id())
|
||||||
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
|
|
||||||
|
|
||||||
|
@handle_api_error
|
||||||
def get_sg_chains(self, tenant_id, sg_id):
|
def get_sg_chains(self, tenant_id, sg_id):
|
||||||
"""Get a list of chains mapped to a security group."""
|
"""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)s sg_id=%(sg_id)s"),
|
||||||
{'tenant_id': tenant_id, 'sg_id': sg_id})
|
{'tenant_id': tenant_id, 'sg_id': sg_id})
|
||||||
|
|
||||||
@ -148,44 +865,9 @@ class ChainManager:
|
|||||||
assert 'out' in chains
|
assert 'out' in chains
|
||||||
return chains
|
return chains
|
||||||
|
|
||||||
def _get_router_chain_names(self, router_id):
|
@handle_api_error
|
||||||
LOG.debug(_("ChainManager.get_router_chain_names called: "
|
def get_port_groups_for_sg(self, tenant_id, sg_id):
|
||||||
"router_id=%(router_id)s"), {'router_id': router_id})
|
LOG.debug(_("MidoClient.get_port_groups_for_sg called: "
|
||||||
|
|
||||||
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: "
|
|
||||||
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s"),
|
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s"),
|
||||||
{'tenant_id': tenant_id, 'sg_id': sg_id})
|
{'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})
|
port_groups = self.mido_api.get_port_groups({'tenant_id': tenant_id})
|
||||||
for pg in port_groups:
|
for pg in port_groups:
|
||||||
if pg.get_name().startswith(pg_name_prefix):
|
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 pg
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@handle_api_error
|
||||||
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)}
|
|
||||||
|
|
||||||
def create_for_sg_rule(self, rule):
|
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']
|
direction = rule['direction']
|
||||||
protocol = rule['protocol']
|
protocol = rule['protocol']
|
||||||
@ -264,7 +935,7 @@ class RuleManager:
|
|||||||
tp_src_start = tp_src_end = icmp_type
|
tp_src_start = tp_src_end = icmp_type
|
||||||
tp_dst_start = tp_dst_end = icmp_code
|
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
|
chain = None
|
||||||
if direction == 'egress':
|
if direction == 'egress':
|
||||||
chain = chains['in']
|
chain = chains['in']
|
||||||
@ -274,8 +945,8 @@ class RuleManager:
|
|||||||
raise Exception(_("Don't know what to do with rule=%r"), rule)
|
raise Exception(_("Don't know what to do with rule=%r"), rule)
|
||||||
|
|
||||||
# create an accept rule
|
# create an accept rule
|
||||||
properties = self._properties(rule_id)
|
properties = sg_rule_properties(rule_id)
|
||||||
LOG.debug(_("RuleManager.create_for_sg_rule: adding accept rule "
|
LOG.debug(_("MidoClient.create_for_sg_rule: adding accept rule "
|
||||||
"%(rule_id)s in portgroup %(port_group_id)s"),
|
"%(rule_id)s in portgroup %(port_group_id)s"),
|
||||||
{'rule_id': rule_id, 'port_group_id': port_group_id})
|
{'rule_id': rule_id, 'port_group_id': port_group_id})
|
||||||
chain.add_rule().port_group(port_group_id).type('accept').nw_proto(
|
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_src_end).tp_dst_start(tp_dst_start).tp_dst_end(
|
||||||
tp_dst_end).properties(properties).create()
|
tp_dst_end).properties(properties).create()
|
||||||
|
|
||||||
|
@handle_api_error
|
||||||
def delete_for_sg_rule(self, rule):
|
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']
|
tenant_id = rule['tenant_id']
|
||||||
security_group_id = rule['security_group_id']
|
security_group_id = rule['security_group_id']
|
||||||
rule_id = rule['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
|
# 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']:
|
for c in chains['in'], chains['out']:
|
||||||
rules = c.get_rules()
|
rules = c.get_rules()
|
||||||
for r in rules:
|
for r in rules:
|
||||||
if r.get_properties() == properties:
|
if r.get_properties() == properties:
|
||||||
LOG.debug(_("RuleManager.delete_for_sg_rule: deleting "
|
LOG.debug(_("MidoClient.delete_for_sg_rule: deleting "
|
||||||
"rule %r"), r)
|
"rule %r"), r)
|
||||||
r.delete()
|
self.mido_api.delete_rule(r.get_id())
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
from midonetclient import api
|
from midonetclient import api
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
from webob import exc as w_exc
|
|
||||||
|
|
||||||
from quantum.common import exceptions as q_exc
|
from quantum.common import exceptions as q_exc
|
||||||
from quantum.db import api as db
|
from quantum.db import api as db
|
||||||
@ -38,15 +37,6 @@ from quantum.plugins.midonet import midonet_lib
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
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):
|
class MidonetPluginException(q_exc.QuantumException):
|
||||||
message = _("%(msg)s")
|
message = _("%(msg)s")
|
||||||
@ -57,6 +47,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
securitygroups_db.SecurityGroupDbMixin):
|
securitygroups_db.SecurityGroupDbMixin):
|
||||||
|
|
||||||
supported_extension_aliases = ['router', 'security-group']
|
supported_extension_aliases = ['router', 'security-group']
|
||||||
|
__native_bulk_support = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
@ -73,26 +64,23 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
self.mido_api = api.MidonetApi(midonet_uri, admin_user,
|
self.mido_api = api.MidonetApi(midonet_uri, admin_user,
|
||||||
admin_pass,
|
admin_pass,
|
||||||
project_id=admin_project_id)
|
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:
|
if provider_router_id and metadata_router_id:
|
||||||
self.provider_router = self.mido_api.get_router(provider_router_id)
|
# get MidoNet provider router and metadata router
|
||||||
self.metadata_router = self.mido_api.get_router(metadata_router_id)
|
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 not provider_router_id or not metadata_router_id:
|
||||||
elif mode == 'dev':
|
if mode == 'dev':
|
||||||
msg = _('No provider router and metadata device ids found. '
|
msg = _('No provider router and metadata device ids found. '
|
||||||
'But skipping because running in dev env.')
|
'But skipping because running in dev env.')
|
||||||
LOG.debug(msg)
|
LOG.debug(msg)
|
||||||
else:
|
else:
|
||||||
msg = _('provider_router_id and metadata_router_id '
|
msg = _('provider_router_id and metadata_router_id '
|
||||||
'should be configured in the plugin config file')
|
'should be configured in the plugin config file')
|
||||||
LOG.exception(msg)
|
LOG.exception(msg)
|
||||||
raise MidonetPluginException(msg=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)
|
|
||||||
|
|
||||||
db.configure_db()
|
db.configure_db()
|
||||||
|
|
||||||
@ -118,114 +106,27 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
sn_entry = super(MidonetPluginV2, self).create_subnet(context,
|
sn_entry = super(MidonetPluginV2, self).create_subnet(context,
|
||||||
subnet)
|
subnet)
|
||||||
try:
|
bridge = self.client.get_bridge(sn_entry['network_id'])
|
||||||
bridge = self.mido_api.get_bridge(sn_entry['network_id'])
|
|
||||||
except w_exc.HTTPNotFound:
|
|
||||||
raise MidonetResourceNotFound(resource_type='Bridge',
|
|
||||||
id=sn_entry['network_id'])
|
|
||||||
|
|
||||||
gateway_ip = subnet['subnet']['gateway_ip']
|
gateway_ip = subnet['subnet']['gateway_ip']
|
||||||
network_address, prefix = subnet['subnet']['cidr'].split('/')
|
network_address, prefix = subnet['subnet']['cidr'].split('/')
|
||||||
bridge.add_dhcp_subnet().default_gateway(gateway_ip).subnet_prefix(
|
self.client.create_dhcp(bridge, gateway_ip, network_address,
|
||||||
network_address).subnet_length(prefix).create()
|
prefix)
|
||||||
|
|
||||||
# If the network is external, link the bridge to MidoNet provider
|
# For external network, link the bridge to the provider router.
|
||||||
# router
|
|
||||||
self._extend_network_dict_l3(context, net)
|
self._extend_network_dict_l3(context, net)
|
||||||
if net['router:external']:
|
if net['router:external']:
|
||||||
gateway_ip = sn_entry['gateway_ip']
|
gateway_ip = sn_entry['gateway_ip']
|
||||||
network_address, length = sn_entry['cidr'].split('/')
|
network_address, length = sn_entry['cidr'].split('/')
|
||||||
|
|
||||||
# create a interior port in the MidoNet provider router
|
self.client.link_bridge_to_provider_router(
|
||||||
in_port = self.provider_router.add_interior_port()
|
bridge, self.provider_router, gateway_ip, network_address,
|
||||||
pr_port = in_port.port_address(gateway_ip).network_address(
|
length)
|
||||||
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()
|
|
||||||
|
|
||||||
LOG.debug(_("MidonetPluginV2.create_subnet exiting: sn_entry=%r"),
|
LOG.debug(_("MidonetPluginV2.create_subnet exiting: sn_entry=%r"),
|
||||||
sn_entry)
|
sn_entry)
|
||||||
return 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):
|
def delete_subnet(self, context, id):
|
||||||
"""Delete Quantum subnet.
|
"""Delete Quantum subnet.
|
||||||
|
|
||||||
@ -237,37 +138,14 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
net = super(MidonetPluginV2, self).get_network(context,
|
net = super(MidonetPluginV2, self).get_network(context,
|
||||||
subnet['network_id'],
|
subnet['network_id'],
|
||||||
fields=None)
|
fields=None)
|
||||||
bridge_id = subnet['network_id']
|
bridge = self.client.get_bridge(subnet['network_id'])
|
||||||
try:
|
self.client.delete_dhcp(bridge)
|
||||||
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()
|
|
||||||
|
|
||||||
# If the network is external, clean up routes, links, ports.
|
# If the network is external, clean up routes, links, ports.
|
||||||
self._extend_network_dict_l3(context, net)
|
self._extend_network_dict_l3(context, net)
|
||||||
if net['router:external']:
|
if net['router:external']:
|
||||||
# Delete routes and unlink the router and the bridge.
|
self.client.unlink_bridge_from_provider_router(
|
||||||
routes = self.provider_router.get_routes()
|
bridge, self.provider_router)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
super(MidonetPluginV2, self).delete_subnet(context, id)
|
super(MidonetPluginV2, self).delete_subnet(context, id)
|
||||||
LOG.debug(_("MidonetPluginV2.delete_subnet exiting"))
|
LOG.debug(_("MidonetPluginV2.delete_subnet exiting"))
|
||||||
@ -281,9 +159,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
network)
|
network)
|
||||||
|
|
||||||
if network['network']['admin_state_up'] is False:
|
if network['network']['admin_state_up'] is False:
|
||||||
LOG.warning(_('Ignoring admin_state_up=False for network=%r'
|
LOG.warning(_('Ignoring admin_state_up=False for network=%r '
|
||||||
'Overriding with True'), network)
|
'because it is not yet supported'), network)
|
||||||
network['network']['admin_state_up'] = True
|
|
||||||
|
|
||||||
tenant_id = self._get_tenant_id_for_create(context, network['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
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
bridge = self.mido_api.add_bridge().name(
|
bridge = self.client.create_bridge(tenant_id,
|
||||||
network['network']['name']).tenant_id(tenant_id).create()
|
network['network']['name'])
|
||||||
|
|
||||||
# Set MidoNet bridge ID to the quantum DB entry
|
# Set MidoNet bridge ID to the quantum DB entry
|
||||||
network['network']['id'] = bridge.get_id()
|
network['network']['id'] = bridge.get_id()
|
||||||
@ -324,11 +201,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
net = super(MidonetPluginV2, self).update_network(
|
net = super(MidonetPluginV2, self).update_network(
|
||||||
context, id, network)
|
context, id, network)
|
||||||
try:
|
self.client.update_bridge(id, net['name'])
|
||||||
bridge = self.mido_api.get_bridge(id)
|
|
||||||
except w_exc.HTTPNotFound:
|
|
||||||
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
|
|
||||||
bridge.name(net['name']).update()
|
|
||||||
|
|
||||||
self._extend_network_dict_l3(context, net)
|
self._extend_network_dict_l3(context, net)
|
||||||
LOG.debug(_("MidonetPluginV2.update_network exiting: net=%r"), 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
|
# NOTE: Get network data with all fields (fields=None) for
|
||||||
# _extend_network_dict_l3() method, which needs 'id' field
|
# _extend_network_dict_l3() method, which needs 'id' field
|
||||||
qnet = super(MidonetPluginV2, self).get_network(context, id, None)
|
qnet = super(MidonetPluginV2, self).get_network(context, id, None)
|
||||||
try:
|
self.client.get_bridge(id)
|
||||||
self.mido_api.get_bridge(id)
|
|
||||||
except w_exc.HTTPNotFound:
|
|
||||||
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
|
|
||||||
|
|
||||||
self._extend_network_dict_l3(context, qnet)
|
self._extend_network_dict_l3(context, qnet)
|
||||||
LOG.debug(_("MidonetPluginV2.get_network exiting: qnet=%r"), 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
|
# _extend_network_dict_l3() method, which needs 'id' field
|
||||||
qnets = super(MidonetPluginV2, self).get_networks(context, filters,
|
qnets = super(MidonetPluginV2, self).get_networks(context, filters,
|
||||||
None)
|
None)
|
||||||
self.mido_api.get_bridges({'tenant_id': context.tenant_id})
|
|
||||||
for n in qnets:
|
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)
|
self._extend_network_dict_l3(context, n)
|
||||||
|
|
||||||
return [self._fields(net, fields) for net in qnets]
|
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):
|
def delete_network(self, context, id):
|
||||||
"""Delete a network and its corresponding MidoNet bridge."""
|
"""Delete a network and its corresponding MidoNet bridge."""
|
||||||
LOG.debug(_("MidonetPluginV2.delete_network called: id=%r"), id)
|
LOG.debug(_("MidonetPluginV2.delete_network called: id=%r"), id)
|
||||||
|
self.client.delete_bridge(id)
|
||||||
self.mido_api.get_bridge(id).delete()
|
|
||||||
try:
|
try:
|
||||||
super(MidonetPluginV2, self).delete_network(context, id)
|
super(MidonetPluginV2, self).delete_network(context, id)
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -394,25 +257,21 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
is_compute_interface = False
|
is_compute_interface = False
|
||||||
port_data = port['port']
|
port_data = port['port']
|
||||||
# get the bridge and create a port on it.
|
# get the bridge and create a port on it.
|
||||||
try:
|
bridge = self.client.get_bridge(port_data['network_id'])
|
||||||
bridge = self.mido_api.get_bridge(port_data['network_id'])
|
|
||||||
except w_exc.HTTPNotFound:
|
|
||||||
raise MidonetResourceNotFound(resource_type='Bridge',
|
|
||||||
id=port_data['network_id'])
|
|
||||||
|
|
||||||
device_owner = port_data['device_owner']
|
device_owner = port_data['device_owner']
|
||||||
|
|
||||||
if device_owner.startswith('compute:') or device_owner is '':
|
if device_owner.startswith('compute:') or device_owner is '':
|
||||||
is_compute_interface = True
|
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:
|
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
|
elif (device_owner == l3_db.DEVICE_OWNER_ROUTER_GW or
|
||||||
device_owner == l3_db.DEVICE_OWNER_FLOATINGIP):
|
device_owner == l3_db.DEVICE_OWNER_FLOATINGIP):
|
||||||
|
|
||||||
# This is a dummy port to make l3_db happy.
|
# This is a dummy port to make l3_db happy.
|
||||||
# This will not be used in MidoNet
|
# 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:
|
if bridge_port:
|
||||||
# set midonet port id to quantum port id and create a DB record.
|
# 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']
|
fixed_ip = port_db_entry['fixed_ips'][0]['ip_address']
|
||||||
mac = port_db_entry['mac_address']
|
mac = port_db_entry['mac_address']
|
||||||
# create dhcp host entry under the bridge.
|
# create dhcp host entry under the bridge.
|
||||||
dhcp_subnets = bridge.get_dhcp_subnets()
|
self.client.create_dhcp_hosts(bridge, fixed_ip, mac)
|
||||||
if dhcp_subnets:
|
|
||||||
dhcp_subnets[0].add_dhcp_host().ip_addr(
|
|
||||||
fixed_ip).mac_addr(mac).create()
|
|
||||||
LOG.debug(_("MidonetPluginV2.create_port exiting: port_db_entry=%r"),
|
LOG.debug(_("MidonetPluginV2.create_port exiting: port_db_entry=%r"),
|
||||||
port_db_entry)
|
port_db_entry)
|
||||||
return 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):
|
def get_port(self, context, id, fields=None):
|
||||||
"""Retrieve port."""
|
"""Retrieve port."""
|
||||||
LOG.debug(_("MidonetPluginV2.get_port called: id=%(id)s "
|
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,
|
port_db_entry = super(MidonetPluginV2, self).get_port(context,
|
||||||
id, fields)
|
id, fields)
|
||||||
# verify that corresponding port exists in MidoNet.
|
# verify that corresponding port exists in MidoNet.
|
||||||
try:
|
self.client.get_port(id)
|
||||||
self.mido_api.get_port(id)
|
|
||||||
except w_exc.HTTPNotFound:
|
|
||||||
raise MidonetResourceNotFound(resource_type='Port', id=id)
|
|
||||||
|
|
||||||
LOG.debug(_("MidonetPluginV2.get_port exiting: port_db_entry=%r"),
|
LOG.debug(_("MidonetPluginV2.get_port exiting: port_db_entry=%r"),
|
||||||
port_db_entry)
|
port_db_entry)
|
||||||
@ -474,12 +321,9 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
filters,
|
filters,
|
||||||
fields)
|
fields)
|
||||||
if ports_db_entry:
|
if ports_db_entry:
|
||||||
try:
|
for port in ports_db_entry:
|
||||||
for port in ports_db_entry:
|
if 'security_gorups' in port:
|
||||||
self.mido_api.get_port(port['id'])
|
self._extend_port_dict_security_group(context, port)
|
||||||
except w_exc.HTTPNotFound:
|
|
||||||
raise MidonetResourceNotFound(resource_type='Port',
|
|
||||||
id=port['id'])
|
|
||||||
return ports_db_entry
|
return ports_db_entry
|
||||||
|
|
||||||
def delete_port(self, context, id, l3_port_check=True):
|
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):
|
with session.begin(subtransactions=True):
|
||||||
port_db_entry = super(MidonetPluginV2, self).get_port(context,
|
port_db_entry = super(MidonetPluginV2, self).get_port(context,
|
||||||
id, None)
|
id, None)
|
||||||
bridge = self.mido_api.get_bridge(port_db_entry['network_id'])
|
|
||||||
# Clean up dhcp host entry if needed.
|
# Clean up dhcp host entry if needed.
|
||||||
if 'ip_address' in (port_db_entry['fixed_ips'] or [{}])[0]:
|
if 'ip_address' in (port_db_entry['fixed_ips'] or [{}])[0]:
|
||||||
# get ip and mac from DB record.
|
# get ip and mac from DB record.
|
||||||
@ -504,13 +347,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
mac = port_db_entry['mac_address']
|
mac = port_db_entry['mac_address']
|
||||||
|
|
||||||
# create dhcp host entry under the bridge.
|
# create dhcp host entry under the bridge.
|
||||||
dhcp_subnets = bridge.get_dhcp_subnets()
|
self.client.delete_dhcp_hosts(port_db_entry['network_id'], ip,
|
||||||
if dhcp_subnets:
|
mac)
|
||||||
for dh in dhcp_subnets[0].get_dhcp_hosts():
|
|
||||||
if dh.get_mac_addr() == mac and dh.get_ip_addr() == ip:
|
|
||||||
dh.delete()
|
|
||||||
|
|
||||||
self.mido_api.get_port(id).delete()
|
self.client.delete_port(id)
|
||||||
return super(MidonetPluginV2, self).delete_port(context, 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'])
|
tenant_id = self._get_tenant_id_for_create(context, router['router'])
|
||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
mrouter = self.mido_api.add_router().name(
|
mrouter = self.client.create_tenant_router(
|
||||||
router['router']['name']).tenant_id(tenant_id).create()
|
tenant_id, router['router']['name'], self.metadata_router)
|
||||||
|
|
||||||
qrouter = super(MidonetPluginV2, self).create_router(context,
|
qrouter = super(MidonetPluginV2, self).create_router(context,
|
||||||
router)
|
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.
|
# get entry from the DB and update 'id' with MidoNet router id.
|
||||||
qrouter_entry = self._get_router(context, qrouter['id'])
|
qrouter_entry = self._get_router(context, qrouter['id'])
|
||||||
qrouter['id'] = mrouter.get_id()
|
qrouter['id'] = mrouter.get_id()
|
||||||
qrouter_entry.update(qrouter)
|
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"),
|
LOG.debug(_("MidonetPluginV2.create_router exiting: qrouter=%r"),
|
||||||
qrouter)
|
qrouter)
|
||||||
return qrouter
|
return qrouter
|
||||||
@ -603,9 +420,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
|
|
||||||
changed_name = router['router'].get('name')
|
changed_name = router['router'].get('name')
|
||||||
if changed_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:
|
if op_gateway_set:
|
||||||
# find a qport with the network_id for the router
|
# find a qport with the network_id for the router
|
||||||
qports = super(MidonetPluginV2, self).get_ports(
|
qports = super(MidonetPluginV2, self).get_ports(
|
||||||
@ -615,82 +431,12 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
qport = qports[0]
|
qport = qports[0]
|
||||||
snat_ip = qport['fixed_ips'][0]['ip_address']
|
snat_ip = qport['fixed_ips'][0]['ip_address']
|
||||||
|
|
||||||
in_port = self.provider_router.add_interior_port()
|
self.client.set_router_external_gateway(id,
|
||||||
pr_port = in_port.network_address(
|
self.provider_router,
|
||||||
'169.254.255.0').network_length(30).port_address(
|
snat_ip)
|
||||||
'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()
|
|
||||||
|
|
||||||
if op_gateway_clear:
|
if op_gateway_clear:
|
||||||
# delete the port that is connected to provider router
|
self.client.clear_router_external_gateway(id)
|
||||||
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()
|
|
||||||
|
|
||||||
LOG.debug(_("MidonetPluginV2.update_router exiting: qrouter=%r"),
|
LOG.debug(_("MidonetPluginV2.update_router exiting: qrouter=%r"),
|
||||||
qrouter)
|
qrouter)
|
||||||
@ -699,61 +445,13 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
def delete_router(self, context, id):
|
def delete_router(self, context, id):
|
||||||
LOG.debug(_("MidonetPluginV2.delete_router called: id=%s"), id)
|
LOG.debug(_("MidonetPluginV2.delete_router called: id=%s"), id)
|
||||||
|
|
||||||
mrouter = self.mido_api.get_router(id)
|
self.client.delete_tenant_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()
|
|
||||||
|
|
||||||
result = super(MidonetPluginV2, self).delete_router(context, id)
|
result = super(MidonetPluginV2, self).delete_router(context, id)
|
||||||
LOG.debug(_("MidonetPluginV2.delete_router exiting: result=%s"),
|
LOG.debug(_("MidonetPluginV2.delete_router exiting: result=%s"),
|
||||||
result)
|
result)
|
||||||
return 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):
|
def add_router_interface(self, context, router_id, interface_info):
|
||||||
LOG.debug(_("MidonetPluginV2.add_router_interface called: "
|
LOG.debug(_("MidonetPluginV2.add_router_interface called: "
|
||||||
"router_id=%(router_id)s "
|
"router_id=%(router_id)s "
|
||||||
@ -772,33 +470,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
network_address, length = subnet['cidr'].split('/')
|
network_address, length = subnet['cidr'].split('/')
|
||||||
|
|
||||||
# Link the router and the bridge port.
|
# Link the router and the bridge port.
|
||||||
mrouter = self.mido_api.get_router(router_id)
|
self.client.link_bridge_port_to_router(qport['port_id'], router_id,
|
||||||
mrouter_port = mrouter.add_interior_port().port_address(
|
gateway_ip, network_address,
|
||||||
gateway_ip).network_address(
|
length,
|
||||||
network_address).network_length(length).create()
|
self.metadata_router)
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
LOG.debug(_("MidonetPluginV2.add_router_interface exiting: "
|
LOG.debug(_("MidonetPluginV2.add_router_interface exiting: "
|
||||||
"qport=%r"), qport)
|
"qport=%r"), qport)
|
||||||
@ -810,9 +485,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
"router_id=%(router_id)s "
|
"router_id=%(router_id)s "
|
||||||
"interface_info=%(interface_info)r"),
|
"interface_info=%(interface_info)r"),
|
||||||
{'router_id': router_id, 'interface_info': interface_info})
|
{'router_id': router_id, 'interface_info': interface_info})
|
||||||
|
port_id = None
|
||||||
if 'port_id' in interface_info:
|
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,
|
subnet_id = self.get_port(context,
|
||||||
interface_info['port_id']
|
interface_info['port_id']
|
||||||
)['fixed_ips'][0]['subnet_id']
|
)['fixed_ips'][0]['subnet_id']
|
||||||
@ -837,36 +513,18 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
network_port = p
|
network_port = p
|
||||||
break
|
break
|
||||||
assert network_port
|
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
|
# get network information from subnet data
|
||||||
network_addr, network_length = subnet['cidr'].split('/')
|
network_addr, network_length = subnet['cidr'].split('/')
|
||||||
network_length = int(network_length)
|
network_length = int(network_length)
|
||||||
|
|
||||||
# Unlink the router and the bridge.
|
# Unlink the router and the bridge.
|
||||||
mrouter = self.mido_api.get_router(router_id)
|
self.client.unlink_bridge_port_from_router(port_id, network_addr,
|
||||||
mrouter_port = self.mido_api.get_port(mbridge_port.get_peer_id())
|
network_length,
|
||||||
mrouter_port.unlink()
|
self.metadata_router)
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
info = super(MidonetPluginV2, self).remove_router_interface(
|
info = super(MidonetPluginV2, self).remove_router_interface(
|
||||||
context, router_id, interface_info)
|
context, router_id, interface_info)
|
||||||
@ -883,91 +541,18 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
if floatingip['floatingip']['port_id']:
|
if floatingip['floatingip']['port_id']:
|
||||||
fip = super(MidonetPluginV2, self).update_floatingip(
|
fip = super(MidonetPluginV2, self).update_floatingip(
|
||||||
context, id, 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
|
# disassociate floating IP
|
||||||
elif floatingip['floatingip']['port_id'] is None:
|
elif floatingip['floatingip']['port_id'] is None:
|
||||||
|
|
||||||
fip = super(MidonetPluginV2, self).get_floatingip(context, id)
|
fip = super(MidonetPluginV2, self).get_floatingip(context, id)
|
||||||
|
self.client.clear_floating_ip(fip['router_id'],
|
||||||
router_id = fip['router_id']
|
self.provider_router,
|
||||||
floating_address = fip['floating_ip_address']
|
fip['floating_ip_address'], id)
|
||||||
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
|
|
||||||
|
|
||||||
super(MidonetPluginV2, self).update_floatingip(context, id,
|
super(MidonetPluginV2, self).update_floatingip(context, id,
|
||||||
floatingip)
|
floatingip)
|
||||||
|
|
||||||
@ -993,10 +578,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
context, security_group, default_sg)
|
context, security_group, default_sg)
|
||||||
|
|
||||||
# Create MidoNet chains and portgroup for the SG
|
# Create MidoNet chains and portgroup for the SG
|
||||||
sg_id = sg_db_entry['id']
|
self.client.create_for_sg(tenant_id, sg_db_entry['id'],
|
||||||
sg_name = sg_db_entry['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)
|
|
||||||
|
|
||||||
LOG.debug(_("MidonetPluginV2.create_security_group exiting: "
|
LOG.debug(_("MidonetPluginV2.create_security_group exiting: "
|
||||||
"sg_db_entry=%r"), sg_db_entry)
|
"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)
|
raise ext_sg.SecurityGroupInUse(id=sg_id)
|
||||||
|
|
||||||
# Delete MidoNet Chains and portgroup for the SG
|
# Delete MidoNet Chains and portgroup for the SG
|
||||||
self.chain_manager.delete_for_sg(tenant_id, sg_id, sg_name)
|
self.client.delete_for_sg(tenant_id, sg_id, sg_name)
|
||||||
self.pg_manager.delete(tenant_id, sg_id, sg_name)
|
|
||||||
|
|
||||||
return super(MidonetPluginV2, self).delete_security_group(
|
return super(MidonetPluginV2, self).delete_security_group(
|
||||||
context, id)
|
context, id)
|
||||||
@ -1057,7 +639,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
MidonetPluginV2, self).create_security_group_rule(
|
MidonetPluginV2, self).create_security_group_rule(
|
||||||
context, 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: "
|
LOG.debug(_("MidonetPluginV2.create_security_group_rule exiting: "
|
||||||
"rule_db_entry=%r"), rule_db_entry)
|
"rule_db_entry=%r"), rule_db_entry)
|
||||||
return rule_db_entry
|
return rule_db_entry
|
||||||
@ -1073,7 +655,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
if not rule_db_entry:
|
if not rule_db_entry:
|
||||||
raise ext_sg.SecurityGroupRuleNotFound(id=sgrid)
|
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,
|
return super(MidonetPluginV2,
|
||||||
self).delete_security_group_rule(context, sgrid)
|
self).delete_security_group_rule(context, sgrid)
|
||||||
|
|
||||||
|
16
quantum/tests/unit/midonet/etc/midonet.ini.test
Normal file
16
quantum/tests/unit/midonet/etc/midonet.ini.test
Normal 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
|
253
quantum/tests/unit/midonet/mock_lib.py
Normal file
253
quantum/tests/unit/midonet/mock_lib.py
Normal 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
|
@ -19,173 +19,201 @@
|
|||||||
# @author: Ryu Ishimoto, Midokura Japan KK
|
# @author: Ryu Ishimoto, Midokura Japan KK
|
||||||
# @author: Tomoe Sugihara, Midokura Japan KK
|
# @author: Tomoe Sugihara, Midokura Japan KK
|
||||||
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
import mock
|
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.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):
|
def setUp(self):
|
||||||
super(MidonetLibTestCase, self).setUp()
|
super(MidoClientTestCase, self).setUp()
|
||||||
|
self._tenant_id = 'test-tenant'
|
||||||
self.mock_api = mock.Mock()
|
self.mock_api = mock.Mock()
|
||||||
|
self.mock_api_cfg = mock_lib.MidoClientMockConfig(self.mock_api)
|
||||||
def _create_mock_chains(self, sg_id, sg_name):
|
self.mock_api_cfg.setup()
|
||||||
mock_in_chain = mock.Mock()
|
self.client = midonet_lib.MidoClient(self.mock_api)
|
||||||
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)
|
|
||||||
|
|
||||||
def test_create_for_sg(self):
|
def test_create_for_sg(self):
|
||||||
tenant_id = 'test_tenant'
|
sg_id = uuidutils.generate_uuid()
|
||||||
sg_id = str(uuid.uuid4())
|
sg_name = 'test-sg'
|
||||||
sg_name = 'test_sg_name'
|
calls = [mock.call.add_chain().tenant_id(self._tenant_id),
|
||||||
calls = [mock.call.add_chain().tenant_id(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):
|
def test_create_for_sg_rule(self):
|
||||||
tenant_id = 'test_tenant'
|
sg_id = uuidutils.generate_uuid()
|
||||||
sg_id = str(uuid.uuid4())
|
sg_name = 'test-sg'
|
||||||
sg_name = 'test_sg_name'
|
in_chain_id = uuidutils.generate_uuid()
|
||||||
in_chain, out_chain = self._create_mock_chains(sg_id, sg_name)
|
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
|
sg_rule_id = uuidutils.generate_uuid()
|
||||||
self.mock_api.get_chains.return_value = [in_chain, out_chain]
|
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(
|
self.client.create_for_sg_rule(sg_rule)
|
||||||
{"tenant_id": tenant_id}))
|
|
||||||
in_chain.delete.assert_called_once_with()
|
|
||||||
out_chain.delete.assert_called_once_with()
|
|
||||||
|
|
||||||
def test_get_router_chains(self):
|
# Egress chain rule added
|
||||||
tenant_id = 'test_tenant'
|
self.mock_api_cfg.chains_out[0].assert_has_calls(calls)
|
||||||
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)
|
|
||||||
|
|
||||||
def test_create_router_chains(self):
|
def test_create_router_chains(self):
|
||||||
tenant_id = 'test_tenant'
|
router = mock_lib.get_router_mock(tenant_id=self._tenant_id)
|
||||||
router_id = str(uuid.uuid4())
|
api_calls = [mock.call.add_chain().tenant_id(self._tenant_id)]
|
||||||
calls = [mock.call.add_chain().tenant_id(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)
|
self.mock_api.assert_has_calls(calls)
|
||||||
|
|
||||||
def test_get_sg_chains(self):
|
def test_delete_for_sg_rule(self):
|
||||||
tenant_id = 'test_tenant'
|
sg_id = uuidutils.generate_uuid()
|
||||||
sg_id = str(uuid.uuid4())
|
sg_name = 'test-sg'
|
||||||
in_chain, out_chain = self._create_mock_chains(sg_id, 'foo')
|
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
|
rule_id = uuidutils.generate_uuid()
|
||||||
self.mock_api.get_chains.return_value = [in_chain, out_chain]
|
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(
|
self.mock_api.delete_rule.assert_called_once_with(rule_id)
|
||||||
{"tenant_id": tenant_id}))
|
|
||||||
self.assertEqual(len(chains), 2)
|
|
||||||
self.assertEqual(chains['in'], in_chain)
|
|
||||||
self.assertEqual(chains['out'], out_chain)
|
|
||||||
|
|
||||||
|
def test_get_bridge(self):
|
||||||
|
bridge_id = uuidutils.generate_uuid()
|
||||||
|
|
||||||
class MidonetPortGroupManagerTestCase(MidonetLibTestCase):
|
bridge = self.client.get_bridge(bridge_id)
|
||||||
|
|
||||||
def setUp(self):
|
self.assertIsNotNone(bridge)
|
||||||
super(MidonetPortGroupManagerTestCase, self).setUp()
|
self.assertEqual(bridge.get_id(), bridge_id)
|
||||||
self.mgr = midonet_lib.PortGroupManager(self.mock_api)
|
|
||||||
|
|
||||||
def test_create(self):
|
def test_get_bridge_error(self):
|
||||||
tenant_id = 'test_tenant'
|
self.mock_api.get_bridge.side_effect = w_exc.HTTPInternalServerError()
|
||||||
sg_id = str(uuid.uuid4())
|
self.assertRaises(midonet_lib.MidonetApiException,
|
||||||
sg_name = 'test_sg'
|
self.client.get_bridge, uuidutils.generate_uuid())
|
||||||
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
|
|
||||||
|
|
||||||
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):
|
pg = self.client.get_port_groups_for_sg(self._tenant_id, sg_id)
|
||||||
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]
|
|
||||||
|
|
||||||
self.mgr.delete(tenant_id, sg_id, sg_name)
|
self.assertIsNotNone(pg)
|
||||||
|
self.assertEqual(pg.get_id(), pg_id)
|
||||||
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()
|
|
||||||
|
|
||||||
def _create_test_rule(self, tenant_id, sg_id, rule_id, direction="egress",
|
def _create_test_rule(self, tenant_id, sg_id, rule_id, direction="egress",
|
||||||
protocol="tcp", port_min=1, port_max=65535,
|
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,
|
"port_range_min": port_min, "port_range_max": port_max,
|
||||||
"ethertype": ethertype, "id": rule_id, "external_id": None}
|
"ethertype": ethertype, "id": rule_id, "external_id": None}
|
||||||
|
|
||||||
def test_create_for_sg_rule(self):
|
def test_get_router_error(self):
|
||||||
tenant_id = 'test_tenant'
|
self.mock_api.get_router.side_effect = w_exc.HTTPInternalServerError()
|
||||||
sg_id = str(uuid.uuid4())
|
self.assertRaises(midonet_lib.MidonetApiException,
|
||||||
rule_id = str(uuid.uuid4())
|
self.client.get_router, uuidutils.generate_uuid())
|
||||||
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()]
|
|
||||||
|
|
||||||
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):
|
chains = self.client.get_router_chains(self._tenant_id, router_id)
|
||||||
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}
|
|
||||||
|
|
||||||
# Mock the rules returned for each chain
|
self.mock_api.assert_has_calls(mock.call.get_chains(
|
||||||
mock_rule_in = self._create_mock_rule(rule_id)
|
{"tenant_id": self._tenant_id}))
|
||||||
mock_rule_out = self._create_mock_rule(rule_id)
|
self.assertEqual(len(chains), 2)
|
||||||
in_chain.get_rules.return_value = [mock_rule_in]
|
self.assertIn('in', chains)
|
||||||
out_chain.get_rules.return_value = [mock_rule_out]
|
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)
|
def test_get_sg_chains(self):
|
||||||
self.mgr.delete_for_sg_rule(rule)
|
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()
|
chains = self.client.get_sg_chains(self._tenant_id, sg_id)
|
||||||
mock_rule_out.delete.assert_called_once_with()
|
|
||||||
|
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)
|
||||||
|
@ -20,16 +20,18 @@
|
|||||||
# @author: Ryu Ishimoto, Midokura Japan KK
|
# @author: Ryu Ishimoto, Midokura Japan KK
|
||||||
# @author: Tomoe Sugihara, Midokura Japan KK
|
# @author: Tomoe Sugihara, Midokura Japan KK
|
||||||
|
|
||||||
import sys
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
import mock
|
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
|
import quantum.tests.unit.test_db_plugin as test_plugin
|
||||||
|
|
||||||
|
|
||||||
MIDOKURA_PKG_PATH = "quantum.plugins.midonet.plugin"
|
MIDOKURA_PKG_PATH = "quantum.plugins.midonet.plugin"
|
||||||
|
|
||||||
|
|
||||||
# Need to mock the midonetclient module since the plugin will try to load it.
|
# Need to mock the midonetclient module since the plugin will try to load it.
|
||||||
sys.modules["midonetclient"] = mock.Mock()
|
sys.modules["midonetclient"] = mock.Mock()
|
||||||
|
|
||||||
@ -39,730 +41,83 @@ class MidonetPluginV2TestCase(test_plugin.QuantumDbPluginV2TestCase):
|
|||||||
_plugin_name = ('%s.MidonetPluginV2' % MIDOKURA_PKG_PATH)
|
_plugin_name = ('%s.MidonetPluginV2' % MIDOKURA_PKG_PATH)
|
||||||
|
|
||||||
def setUp(self):
|
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()
|
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)
|
super(MidonetPluginV2TestCase, self).setUp(self._plugin_name)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(MidonetPluginV2TestCase, self).tearDown()
|
super(MidonetPluginV2TestCase, self).tearDown()
|
||||||
self.mock_api.stop()
|
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,
|
class TestMidonetNetworksV2(test_plugin.TestNetworksV2,
|
||||||
MidonetPluginV2TestCase):
|
MidonetPluginV2TestCase):
|
||||||
|
pass
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class TestMidonetSubnetsV2(test_plugin.TestSubnetsV2,
|
class TestMidonetSubnetsV2(test_plugin.TestSubnetsV2,
|
||||||
MidonetPluginV2TestCase):
|
MidonetPluginV2TestCase):
|
||||||
|
|
||||||
def test_create_subnet(self):
|
# IPv6 is not supported by MidoNet yet. Ignore tests that attempt to
|
||||||
self._setup_subnet_mocks()
|
# create IPv6 subnet.
|
||||||
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()
|
|
||||||
|
|
||||||
def test_create_subnet_inconsistent_ipv6_cidrv4(self):
|
def test_create_subnet_inconsistent_ipv6_cidrv4(self):
|
||||||
pass
|
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):
|
def test_create_subnet_inconsistent_ipv6_dns_v4(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_create_subnet_inconsistent_ipv4_hostroute_dst_v6(self):
|
def test_create_subnet_with_v6_allocation_pool(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):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_update_subnet_inconsistent_ipv6_gatewayv4(self):
|
def test_update_subnet_inconsistent_ipv6_gatewayv4(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_update_subnet_inconsistent_ipv4_dns_v6(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
|
def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
|
def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_show_subnet(self):
|
def test_create_subnet_inconsistent_ipv6_gatewayv4(self):
|
||||||
_bridge, _subnet = self._setup_subnet_mocks()
|
|
||||||
super(TestMidonetSubnetsV2, self).test_show_subnet()
|
|
||||||
|
|
||||||
def test_list_subnets(self):
|
|
||||||
pass
|
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
|
pass
|
||||||
|
|
||||||
def test_list_subnets_with_parameter(self):
|
def test_list_subnets_with_parameter(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_invalid_ip_version(self):
|
def test_create_two_subnets_same_cidr_returns_400(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):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestMidonetPortsV2(test_plugin.TestPortsV2,
|
class TestMidonetPortsV2(test_plugin.TestPortsV2,
|
||||||
MidonetPluginV2TestCase):
|
MidonetPluginV2TestCase):
|
||||||
|
|
||||||
def test_create_port_json(self):
|
# IPv6 is not supported by MidoNet yet. Ignore tests that attempt to
|
||||||
self._setup_port_mocks()
|
# create IPv6 subnet.
|
||||||
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
|
|
||||||
|
|
||||||
def test_requested_subnet_id_v4_and_v6(self):
|
def test_requested_subnet_id_v4_and_v6(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_range_allocation(self):
|
# Multiple subnets in a network is not supported by MidoNet yet. Ignore
|
||||||
pass
|
# tests that attempt to create them.
|
||||||
|
|
||||||
def test_requested_invalid_fixed_ips(self):
|
def test_overlapping_subnets(self):
|
||||||
pass
|
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
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user