Merge "Make MidoNet plugin code more testable"
This commit is contained in:
commit
599d73cea8
@ -20,23 +20,35 @@
|
||||
# @author: Ryu Ishimoto, Midokura Japan KK
|
||||
|
||||
|
||||
from webob import exc as w_exc
|
||||
|
||||
from quantum.common import exceptions as q_exc
|
||||
from quantum.openstack.common import log as logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
PREFIX = 'OS_SG_'
|
||||
SUFFIX_IN = '_IN'
|
||||
SUFFIX_OUT = '_OUT'
|
||||
NAME_IDENTIFIABLE_PREFIX_LEN = len(PREFIX) + 36 # 36 = length of uuid
|
||||
OS_FLOATING_IP_RULE_KEY = 'OS_FLOATING_IP'
|
||||
OS_ROUTER_IN_CHAIN_NAME_FORMAT = 'OS_ROUTER_IN_%s'
|
||||
OS_ROUTER_OUT_CHAIN_NAME_FORMAT = 'OS_ROUTER_OUT_%s'
|
||||
NAME_IDENTIFIABLE_PREFIX_LEN = len(PREFIX) + 36 # 36 = length of uuid
|
||||
OS_SG_KEY = 'os_sg_rule_id'
|
||||
OS_TENANT_ROUTER_RULE_KEY = 'OS_TENANT_ROUTER_RULE'
|
||||
SNAT_RULE = 'SNAT'
|
||||
SNAT_RULE_PROPERTY = {OS_TENANT_ROUTER_RULE_KEY: SNAT_RULE}
|
||||
SUFFIX_IN = '_IN'
|
||||
SUFFIX_OUT = '_OUT'
|
||||
|
||||
|
||||
def sg_label(sg_id, sg_name):
|
||||
"""Construct the security group ID used as chain identifier in MidoNet."""
|
||||
return PREFIX + str(sg_id) + '_' + sg_name
|
||||
|
||||
|
||||
def sg_rule_properties(os_sg_rule_id):
|
||||
return {OS_SG_KEY: str(os_sg_rule_id)}
|
||||
|
||||
port_group_name = sg_label
|
||||
|
||||
|
||||
@ -48,18 +60,748 @@ def chain_names(sg_id, sg_name):
|
||||
return {'in': in_chain_name, 'out': out_chain_name}
|
||||
|
||||
|
||||
class ChainManager:
|
||||
def router_chain_names(router_id):
|
||||
in_name = OS_ROUTER_IN_CHAIN_NAME_FORMAT % router_id
|
||||
out_name = OS_ROUTER_OUT_CHAIN_NAME_FORMAT % router_id
|
||||
return {'in': in_name, 'out': out_name}
|
||||
|
||||
|
||||
def handle_api_error(fn):
|
||||
def wrapped(*args, **kwargs):
|
||||
try:
|
||||
return fn(*args, **kwargs)
|
||||
except w_exc.HTTPException as ex:
|
||||
raise MidonetApiException(msg=ex)
|
||||
return wrapped
|
||||
|
||||
|
||||
class MidonetResourceNotFound(q_exc.NotFound):
|
||||
message = _('MidoNet %(resource_type)s %(id)s could not be found')
|
||||
|
||||
|
||||
class MidonetApiException(q_exc.QuantumException):
|
||||
message = _("MidoNet API error: %(msg)s")
|
||||
|
||||
|
||||
class MidoClient:
|
||||
|
||||
def __init__(self, mido_api):
|
||||
self.mido_api = mido_api
|
||||
|
||||
@handle_api_error
|
||||
def create_bridge(self, tenant_id, name):
|
||||
"""Create a new bridge
|
||||
|
||||
:param tenant_id: id of tenant creating the bridge
|
||||
:param name: name of the bridge
|
||||
:returns: newly created bridge
|
||||
"""
|
||||
LOG.debug(_("MidoClient.create_bridge called: "
|
||||
"tenant_id=%(tenant_id)s, name=%(name)s"),
|
||||
{'tenant_id': tenant_id, 'name': name})
|
||||
return self.mido_api.add_bridge().name(name).tenant_id(
|
||||
tenant_id).create()
|
||||
|
||||
@handle_api_error
|
||||
def delete_bridge(self, id):
|
||||
"""Delete a bridge
|
||||
|
||||
:param id: id of the bridge
|
||||
"""
|
||||
LOG.debug(_("MidoClient.delete_bridge called: id=%(id)s"), {'id': id})
|
||||
return self.mido_api.delete_bridge(id)
|
||||
|
||||
@handle_api_error
|
||||
def get_bridge(self, id):
|
||||
"""Get a bridge
|
||||
|
||||
:param id: id of the bridge
|
||||
:returns: requested bridge. None if bridge does not exist.
|
||||
"""
|
||||
LOG.debug(_("MidoClient.get_bridge called: id=%s"), id)
|
||||
try:
|
||||
return self.mido_api.get_bridge(id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
|
||||
|
||||
@handle_api_error
|
||||
def update_bridge(self, id, name):
|
||||
"""Update a bridge of the given id with the new name
|
||||
|
||||
:param id: id of the bridge
|
||||
:param name: name of the bridge to set to
|
||||
:returns: bridge object
|
||||
"""
|
||||
LOG.debug(_("MidoClient.update_bridge called: "
|
||||
"id=%(id)s, name=%(name)s"), {'id': id, 'name': name})
|
||||
try:
|
||||
return self.mido_api.get_bridge(id).name(name).update()
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
|
||||
|
||||
@handle_api_error
|
||||
def create_dhcp(self, bridge, gateway_ip, net_addr, net_len):
|
||||
"""Create a new DHCP entry
|
||||
|
||||
:param bridge: bridge object to add dhcp to
|
||||
:param gateway_ip: IP address of gateway
|
||||
:param net_addr: network IP address
|
||||
:param net_len: network IP address length
|
||||
:returns: newly created dhcp
|
||||
"""
|
||||
LOG.debug(_("MidoClient.create_dhcp called: bridge=%s(bridge)s, "
|
||||
"net_addr=%(net_addr)s, net_len=%(net_len)s, "
|
||||
"gateway_ip=%(gateway_ip)s"),
|
||||
{'bridge': bridge, 'net_addr': net_addr, 'net_len': net_len,
|
||||
'gateway_ip': gateway_ip})
|
||||
return bridge.add_dhcp_subnet().default_gateway(
|
||||
gateway_ip).subnet_prefix(net_addr).subnet_length(
|
||||
net_len).create()
|
||||
|
||||
@handle_api_error
|
||||
def create_dhcp_hosts(self, bridge, ip, mac):
|
||||
"""Create DHCP host entries
|
||||
|
||||
:param bridge: bridge of the DHCP
|
||||
:param ip: IP address
|
||||
:param mac: MAC address
|
||||
"""
|
||||
LOG.debug(_("MidoClient.create_dhcp_hosts called: bridge=%s(bridge), "
|
||||
"ip=%(ip)s, mac=%(mac)s"), {'bridge': bridge, 'ip': ip,
|
||||
'mac': mac})
|
||||
dhcp_subnets = bridge.get_dhcp_subnets()
|
||||
if dhcp_subnets:
|
||||
# Add the host to the first subnet as we currently support one
|
||||
# subnet per network.
|
||||
dhcp_subnets[0].add_dhcp_host().ip_addr(ip).mac_addr(mac).create()
|
||||
|
||||
@handle_api_error
|
||||
def delete_dhcp_hosts(self, bridge_id, ip, mac):
|
||||
"""Delete DHCP host entries
|
||||
|
||||
:param bridge_id: id of the bridge of the DHCP
|
||||
:param ip: IP address
|
||||
:param mac: MAC address
|
||||
"""
|
||||
LOG.debug(_("MidoClient.delete_dhcp_hosts called: "
|
||||
"bridge_id=%s(bridge_id), ip=%(ip)s, mac=%(mac)s"),
|
||||
{'bridge_id': bridge_id, 'ip': ip, 'mac': mac})
|
||||
bridge = self.get_bridge(bridge_id)
|
||||
dhcp_subnets = bridge.get_dhcp_subnets()
|
||||
if dhcp_subnets:
|
||||
for dh in dhcp_subnets[0].get_dhcp_hosts():
|
||||
if dh.get_mac_addr() == mac and dh.get_ip_addr() == ip:
|
||||
dh.delete()
|
||||
|
||||
@handle_api_error
|
||||
def delete_dhcp(self, bridge):
|
||||
"""Delete a DHCP entry
|
||||
|
||||
:param bridge: bridge to remove DHCP from
|
||||
"""
|
||||
LOG.debug(_("MidoClient.delete_dhcp called: bridge=%s(bridge), "),
|
||||
{'bridge': bridge})
|
||||
dhcp = bridge.get_dhcp_subnets()
|
||||
if not dhcp:
|
||||
raise MidonetApiException(msg="Tried to delete non-existent DHCP")
|
||||
dhcp[0].delete()
|
||||
|
||||
@handle_api_error
|
||||
def delete_port(self, id):
|
||||
"""Delete a port
|
||||
|
||||
:param id: id of the port
|
||||
"""
|
||||
LOG.debug(_("MidoClient.delete_port called: id=%(id)s"), {'id': id})
|
||||
self.mido_api.delete_port(id)
|
||||
|
||||
@handle_api_error
|
||||
def get_port(self, id):
|
||||
"""Get a port
|
||||
|
||||
:param id: id of the port
|
||||
:returns: requested port. None if it does not exist
|
||||
"""
|
||||
LOG.debug(_("MidoClient.get_port called: id=%(id)s"), {'id': id})
|
||||
try:
|
||||
return self.mido_api.get_port(id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Port', id=id)
|
||||
|
||||
@handle_api_error
|
||||
def create_exterior_bridge_port(self, bridge):
|
||||
"""Create a new exterior bridge port
|
||||
|
||||
:param bridge: bridge object to add port to
|
||||
:returns: newly created port
|
||||
"""
|
||||
LOG.debug(_("MidoClient.create_exterior_bridge_port called: "
|
||||
"bridge=%(bridge)s"), {'bridge': bridge})
|
||||
return bridge.add_exterior_port().create()
|
||||
|
||||
@handle_api_error
|
||||
def create_interior_bridge_port(self, bridge):
|
||||
"""Create a new interior bridge port
|
||||
|
||||
:param bridge: bridge object to add port to
|
||||
:returns: newly created port
|
||||
"""
|
||||
LOG.debug(_("MidoClient.create_interior_bridge_port called: "
|
||||
"bridge=%(bridge)s"), {'bridge': bridge})
|
||||
return bridge.add_interior_port().create()
|
||||
|
||||
@handle_api_error
|
||||
def create_router(self, tenant_id, name):
|
||||
"""Create a new router
|
||||
|
||||
:param tenant_id: id of tenant creating the router
|
||||
:param name: name of the router
|
||||
:returns: newly created router
|
||||
"""
|
||||
LOG.debug(_("MidoClient.create_router called: "
|
||||
"tenant_id=%(tenant_id)s, name=%(name)s"),
|
||||
{'tenant_id': tenant_id, 'name': name})
|
||||
return self.mido_api.add_router().name(name).tenant_id(
|
||||
tenant_id).create()
|
||||
|
||||
@handle_api_error
|
||||
def create_tenant_router(self, tenant_id, name, metadata_router):
|
||||
"""Create a new tenant router
|
||||
|
||||
:param tenant_id: id of tenant creating the router
|
||||
:param name: name of the router
|
||||
:param metadata_router: metadata router
|
||||
:returns: newly created router
|
||||
"""
|
||||
LOG.debug(_("MidoClient.create_tenant_router called: "
|
||||
"tenant_id=%(tenant_id)s, name=%(name)s"
|
||||
"metadata_router=%(metadata_router)s"),
|
||||
{'tenant_id': tenant_id, 'name': name,
|
||||
'metadata_router': metadata_router})
|
||||
router = self.create_router(tenant_id, name)
|
||||
self.link_router_to_metadata_router(router, metadata_router)
|
||||
return router
|
||||
|
||||
@handle_api_error
|
||||
def delete_tenant_router(self, id, metadata_router):
|
||||
"""Delete a tenant router
|
||||
|
||||
:param id: id of router
|
||||
:param metadata_router: metadata router
|
||||
"""
|
||||
LOG.debug(_("MidoClient.delete_tenant_router called: "
|
||||
"id=%(id)s, metadata_router=%(metadata_router)s"),
|
||||
{'id': id, 'metadata_router': metadata_router})
|
||||
self.unlink_router_from_metadata_router(id, metadata_router)
|
||||
self.destroy_router_chains(id)
|
||||
|
||||
# delete the router
|
||||
self.delete_router(id)
|
||||
|
||||
@handle_api_error
|
||||
def delete_router(self, id):
|
||||
"""Delete a router
|
||||
|
||||
:param id: id of the router
|
||||
"""
|
||||
LOG.debug(_("MidoClient.delete_router called: id=%(id)s"), {'id': id})
|
||||
return self.mido_api.delete_router(id)
|
||||
|
||||
@handle_api_error
|
||||
def get_router(self, id):
|
||||
"""Get a router with the given id
|
||||
|
||||
:param id: id of the router
|
||||
:returns: requested router object. None if it does not exist.
|
||||
"""
|
||||
LOG.debug(_("MidoClient.get_router called: id=%(id)s"), {'id': id})
|
||||
try:
|
||||
return self.mido_api.get_router(id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Router', id=id)
|
||||
|
||||
@handle_api_error
|
||||
def update_router(self, id, name):
|
||||
"""Update a router of the given id with the new name
|
||||
|
||||
:param id: id of the router
|
||||
:param name: name of the router to set to
|
||||
:returns: router object
|
||||
"""
|
||||
LOG.debug(_("MidoClient.update_router called: "
|
||||
"id=%(id)s, name=%(name)s"), {'id': id, 'name': name})
|
||||
try:
|
||||
return self.mido_api.get_router(id).name(name).update()
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Router', id=id)
|
||||
|
||||
@handle_api_error
|
||||
def link_bridge_port_to_router(self, port_id, router_id, gateway_ip,
|
||||
net_addr, net_len, metadata_router):
|
||||
"""Link a tenant bridge port to the router
|
||||
|
||||
:param port_id: port ID
|
||||
:param router_id: router id to link to
|
||||
:param gateway_ip: IP address of gateway
|
||||
:param net_addr: network IP address
|
||||
:param net_len: network IP address length
|
||||
:param metadata_router: metadata router instance
|
||||
"""
|
||||
LOG.debug(_("MidoClient.link_bridge_port_to_router called: "
|
||||
"port_id=%(port_id)s, router_id=%(router_id)s, "
|
||||
"gateway_ip=%(gateway_ip)s net_addr=%(net_addr)s, "
|
||||
"net_len=%(net_len)s, "
|
||||
"metadata_router=%(metadata_router)s"),
|
||||
{'port_id': port_id, 'router_id': router_id,
|
||||
'gateway_ip': gateway_ip, 'net_addr': net_addr,
|
||||
'net_len': net_len, 'metadata_router': metadata_router})
|
||||
router = self.get_router(router_id)
|
||||
|
||||
# create an interior port on the router
|
||||
in_port = router.add_interior_port()
|
||||
router_port = in_port.port_address(gateway_ip).network_address(
|
||||
net_addr).network_length(net_len).create()
|
||||
|
||||
br_port = self.get_port(port_id)
|
||||
router_port.link(br_port.get_id())
|
||||
|
||||
# add a route for the subnet in the provider router
|
||||
router.add_route().type('Normal').src_network_addr(
|
||||
'0.0.0.0').src_network_length(0).dst_network_addr(
|
||||
net_addr).dst_network_length(net_len).weight(
|
||||
100).next_hop_port(router_port.get_id()).create()
|
||||
|
||||
# add a route for the subnet in metadata router; forward
|
||||
# packets destined to the subnet to the tenant router
|
||||
for pp in metadata_router.get_peer_ports():
|
||||
if pp.get_device_id() == router.get_id():
|
||||
mdr_port_id = pp.get_peer_id()
|
||||
break
|
||||
else:
|
||||
raise Exception(
|
||||
_("Couldn't find a md router port for the router=%r"), router)
|
||||
|
||||
metadata_router.add_route().type('Normal').src_network_addr(
|
||||
'0.0.0.0').src_network_length(0).dst_network_addr(
|
||||
net_addr).dst_network_length(net_len).weight(
|
||||
100).next_hop_port(mdr_port_id).create()
|
||||
|
||||
@handle_api_error
|
||||
def unlink_bridge_port_from_router(self, port_id, net_addr, net_len,
|
||||
metadata_router):
|
||||
"""Unlink a tenant bridge port from the router
|
||||
|
||||
:param bridge_id: bridge ID
|
||||
:param net_addr: network IP address
|
||||
:param net_len: network IP address length
|
||||
:param metadata_router: metadata router instance
|
||||
"""
|
||||
LOG.debug(_("MidoClient.unlink_bridge_port_from_router called: "
|
||||
"port_id=%(port_id)s, net_addr=%(net_addr)s, "
|
||||
"net_len=%(net_len)s, "
|
||||
"metadata_router=%(metadata_router)s"),
|
||||
{'port_id': port_id, 'net_addr': net_addr,
|
||||
'net_len': net_len, 'metadata_router': metadata_router})
|
||||
port = self.get_port(port_id)
|
||||
port.unlink()
|
||||
self.delete_port(port.get_peer_id())
|
||||
self.delete_port(port.get_id())
|
||||
|
||||
# delete the route for the subnet in the metadata router
|
||||
for r in metadata_router.get_routes():
|
||||
if (r.get_dst_network_addr() == net_addr and
|
||||
r.get_dst_network_length() == net_len):
|
||||
LOG.debug(_('Deleting route=%r ...'), r)
|
||||
self.mido_api.delete_route(r.get_id())
|
||||
break
|
||||
|
||||
@handle_api_error
|
||||
def link_bridge_to_provider_router(self, bridge, provider_router,
|
||||
gateway_ip, net_addr, net_len):
|
||||
"""Link a tenant bridge to the provider router
|
||||
|
||||
:param bridge: tenant bridge
|
||||
:param provider_router: provider router to link to
|
||||
:param gateway_ip: IP address of gateway
|
||||
:param net_addr: network IP address
|
||||
:param net_len: network IP address length
|
||||
"""
|
||||
LOG.debug(_("MidoClient.link_bridge_to_provider_router called: "
|
||||
"bridge=%(bridge)s, provider_router=%(provider_router)s, "
|
||||
"gateway_ip=%(gateway_ip)s, net_addr=%(net_addr)s, "
|
||||
"net_len=%(net_len)s"),
|
||||
{'bridge': bridge, 'provider_router': provider_router,
|
||||
'gateway_ip': gateway_ip, 'net_addr': net_addr,
|
||||
'net_len': net_len})
|
||||
# create an interior port on the provider router
|
||||
in_port = provider_router.add_interior_port()
|
||||
pr_port = in_port.port_address(gateway_ip).network_address(
|
||||
net_addr).network_length(net_len).create()
|
||||
|
||||
# create an interior bridge port, then link it to the router.
|
||||
br_port = bridge.add_interior_port().create()
|
||||
pr_port.link(br_port.get_id())
|
||||
|
||||
# add a route for the subnet in the provider router
|
||||
provider_router.add_route().type('Normal').src_network_addr(
|
||||
'0.0.0.0').src_network_length(0).dst_network_addr(
|
||||
net_addr).dst_network_length(net_len).weight(
|
||||
100).next_hop_port(pr_port.get_id()).create()
|
||||
|
||||
@handle_api_error
|
||||
def unlink_bridge_from_provider_router(self, bridge, provider_router):
|
||||
"""Unlink a tenant bridge from the provider router
|
||||
|
||||
:param bridge: tenant bridge
|
||||
:param provider_router: provider router to link to
|
||||
"""
|
||||
LOG.debug(_("MidoClient.unlink_bridge_from_provider_router called: "
|
||||
"bridge=%(bridge)s, provider_router=%(provider_router)s"),
|
||||
{'bridge': bridge, 'provider_router': provider_router})
|
||||
# Delete routes and unlink the router and the bridge.
|
||||
routes = provider_router.get_routes()
|
||||
|
||||
bridge_ports_to_delete = [
|
||||
p for p in provider_router.get_peer_ports()
|
||||
if p.get_device_id() == bridge.get_id()]
|
||||
|
||||
for p in bridge.get_peer_ports():
|
||||
if p.get_device_id() == provider_router.get_id():
|
||||
# delete the routes going to the bridge
|
||||
for r in routes:
|
||||
if r.get_next_hop_port() == p.get_id():
|
||||
self.mido_api.delete_route(r.get_id())
|
||||
p.unlink()
|
||||
self.mido_api.delete_port(p.get_id())
|
||||
|
||||
# delete bridge port
|
||||
for port in bridge_ports_to_delete:
|
||||
self.mido_api.delete_port(port.get_id())
|
||||
|
||||
@handle_api_error
|
||||
def set_router_external_gateway(self, id, provider_router, snat_ip):
|
||||
"""Set router external gateway
|
||||
|
||||
:param ID: ID of the tenant router
|
||||
:param provider_router: provider router
|
||||
:param snat_ip: SNAT IP address
|
||||
"""
|
||||
LOG.debug(_("MidoClient.set_router_external_gateway called: "
|
||||
"id=%(id)s, provider_router=%(provider_router)s, "
|
||||
"snat_ip=%s(snat_ip)s)"),
|
||||
{'id': id, 'provider_router': provider_router,
|
||||
'snat_ip': snat_ip})
|
||||
tenant_router = self.get_router(id)
|
||||
|
||||
# Create a interior port in the provider router
|
||||
in_port = provider_router.add_interior_port()
|
||||
pr_port = in_port.network_address(
|
||||
'169.254.255.0').network_length(30).port_address(
|
||||
'169.254.255.1').create()
|
||||
|
||||
# Create a port in the tenant router
|
||||
tr_port = tenant_router.add_interior_port().network_address(
|
||||
'169.254.255.0').network_length(30).port_address(
|
||||
'169.254.255.2').create()
|
||||
|
||||
# Link them
|
||||
pr_port.link(tr_port.get_id())
|
||||
|
||||
# Add a route for snat_ip to bring it down to tenant
|
||||
provider_router.add_route().type(
|
||||
'Normal').src_network_addr('0.0.0.0').src_network_length(
|
||||
0).dst_network_addr(snat_ip).dst_network_length(
|
||||
32).weight(100).next_hop_port(
|
||||
pr_port.get_id()).create()
|
||||
|
||||
# Add default route to uplink in the tenant router
|
||||
tenant_router.add_route().type('Normal').src_network_addr(
|
||||
'0.0.0.0').src_network_length(0).dst_network_addr(
|
||||
'0.0.0.0').dst_network_length(0).weight(
|
||||
100).next_hop_port(tr_port.get_id()).create()
|
||||
|
||||
# ADD SNAT(masquerade) rules
|
||||
chains = self.get_router_chains(
|
||||
tenant_router.get_tenant_id(), tenant_router.get_id())
|
||||
|
||||
chains['in'].add_rule().nw_dst_address(snat_ip).nw_dst_length(
|
||||
32).type('rev_snat').flow_action('accept').in_ports(
|
||||
[tr_port.get_id()]).properties(
|
||||
SNAT_RULE_PROPERTY).position(1).create()
|
||||
|
||||
nat_targets = []
|
||||
nat_targets.append(
|
||||
{'addressFrom': snat_ip, 'addressTo': snat_ip,
|
||||
'portFrom': 1, 'portTo': 65535})
|
||||
|
||||
chains['out'].add_rule().type('snat').flow_action(
|
||||
'accept').nat_targets(nat_targets).out_ports(
|
||||
[tr_port.get_id()]).properties(
|
||||
SNAT_RULE_PROPERTY).position(1).create()
|
||||
|
||||
@handle_api_error
|
||||
def clear_router_external_gateway(self, id):
|
||||
"""Clear router external gateway
|
||||
|
||||
:param ID: ID of the tenant router
|
||||
"""
|
||||
LOG.debug(_("MidoClient.clear_router_external_gateway called: "
|
||||
"id=%(id)s"), {'id': id})
|
||||
tenant_router = self.get_router(id)
|
||||
|
||||
# delete the port that is connected to provider router
|
||||
for p in tenant_router.get_ports():
|
||||
if p.get_port_address() == '169.254.255.2':
|
||||
peer_port_id = p.get_peer_id()
|
||||
p.unlink()
|
||||
self.mido_api.delete_port(peer_port_id)
|
||||
self.mido_api.delete_port(p.get_id())
|
||||
|
||||
# delete default route
|
||||
for r in tenant_router.get_routes():
|
||||
if (r.get_dst_network_addr() == '0.0.0.0' and
|
||||
r.get_dst_network_length() == 0):
|
||||
self.mido_api.delete_route(r.get_id())
|
||||
|
||||
# delete SNAT(masquerade) rules
|
||||
chains = self.get_router_chains(
|
||||
tenant_router.get_tenant_id(),
|
||||
tenant_router.get_id())
|
||||
|
||||
for r in chains['in'].get_rules():
|
||||
if OS_TENANT_ROUTER_RULE_KEY in r.get_properties():
|
||||
if r.get_properties()[
|
||||
OS_TENANT_ROUTER_RULE_KEY] == SNAT_RULE:
|
||||
self.mido_api.delete_rule(r.get_id())
|
||||
|
||||
for r in chains['out'].get_rules():
|
||||
if OS_TENANT_ROUTER_RULE_KEY in r.get_properties():
|
||||
if r.get_properties()[
|
||||
OS_TENANT_ROUTER_RULE_KEY] == SNAT_RULE:
|
||||
self.mido_api.delete_rule(r.get_id())
|
||||
|
||||
@handle_api_error
|
||||
def get_router_chains(self, tenant_id, router_id):
|
||||
"""Get router chains.
|
||||
|
||||
Returns a dictionary that has in/out chain resources key'ed with 'in'
|
||||
and 'out' respectively, given the tenant_id and the router_id passed
|
||||
in in the arguments.
|
||||
"""
|
||||
LOG.debug(_("MidoClient.get_router_chains called: "
|
||||
"tenant_id=%(tenant_id)s router_id=%(router_id)s"),
|
||||
{'tenant_id': tenant_id, 'router_id': router_id})
|
||||
|
||||
chain_names = router_chain_names(router_id)
|
||||
chains = {}
|
||||
for c in self.mido_api.get_chains({'tenant_id': tenant_id}):
|
||||
if c.get_name() == chain_names['in']:
|
||||
chains['in'] = c
|
||||
elif c.get_name() == chain_names['out']:
|
||||
chains['out'] = c
|
||||
return chains
|
||||
|
||||
@handle_api_error
|
||||
def create_router_chains(self, router):
|
||||
"""Create chains for a new router.
|
||||
|
||||
Creates chains for the router and returns the same dictionary as
|
||||
get_router_chains() returns.
|
||||
|
||||
:param router: router to set chains for
|
||||
"""
|
||||
LOG.debug(_("MidoClient.create_router_chains called: "
|
||||
"router=%(router)s"), {'router': router})
|
||||
chains = {}
|
||||
router_id = router.get_id()
|
||||
tenant_id = router.get_tenant_id()
|
||||
chain_names = router_chain_names(router_id)
|
||||
chains['in'] = self.mido_api.add_chain().tenant_id(tenant_id).name(
|
||||
chain_names['in']).create()
|
||||
|
||||
chains['out'] = self.mido_api.add_chain().tenant_id(tenant_id).name(
|
||||
chain_names['out']).create()
|
||||
|
||||
# set chains to in/out filters
|
||||
router.inbound_filter_id(
|
||||
chains['in'].get_id()).outbound_filter_id(
|
||||
chains['out'].get_id()).update()
|
||||
return chains
|
||||
|
||||
@handle_api_error
|
||||
def destroy_router_chains(self, id):
|
||||
"""Deletes chains of a router.
|
||||
|
||||
:param id: router ID to delete chains of
|
||||
"""
|
||||
LOG.debug(_("MidoClient.destroy_router_chains called: "
|
||||
"id=%(id)s"), {'id': id})
|
||||
# delete corresponding chains
|
||||
router = self.get_router(id)
|
||||
chains = self.get_router_chains(router.get_tenant_id(), id)
|
||||
self.mido_api.delete_chain(chains['in'].get_id())
|
||||
self.mido_api.delete_chain(chains['out'].get_id())
|
||||
|
||||
@handle_api_error
|
||||
def link_router_to_metadata_router(self, router, metadata_router):
|
||||
"""Link a router to the metadata router
|
||||
|
||||
:param router: router to link
|
||||
:param metadata_router: metadata router
|
||||
"""
|
||||
LOG.debug(_("MidoClient.link_router_to_metadata_router called: "
|
||||
"router=%(router)s, metadata_router=%(metadata_router)s"),
|
||||
{'router': router, 'metadata_router': metadata_router})
|
||||
# link to metadata router
|
||||
in_port = metadata_router.add_interior_port()
|
||||
mdr_port = in_port.network_address('169.254.255.0').network_length(
|
||||
30).port_address('169.254.255.1').create()
|
||||
|
||||
tr_port = router.add_interior_port().network_address(
|
||||
'169.254.255.0').network_length(30).port_address(
|
||||
'169.254.255.2').create()
|
||||
mdr_port.link(tr_port.get_id())
|
||||
|
||||
# forward metadata traffic to metadata router
|
||||
router.add_route().type('Normal').src_network_addr(
|
||||
'0.0.0.0').src_network_length(0).dst_network_addr(
|
||||
'169.254.169.254').dst_network_length(32).weight(
|
||||
100).next_hop_port(tr_port.get_id()).create()
|
||||
|
||||
@handle_api_error
|
||||
def unlink_router_from_metadata_router(self, id, metadata_router):
|
||||
"""Unlink a router from the metadata router
|
||||
|
||||
:param id: ID of router
|
||||
:param metadata_router: metadata router
|
||||
"""
|
||||
LOG.debug(_("MidoClient.unlink_router_from_metadata_router called: "
|
||||
"id=%(id)s, metadata_router=%(metadata_router)s"),
|
||||
{'id': id, 'metadata_router': metadata_router})
|
||||
# unlink from metadata router and delete the interior ports
|
||||
# that connect metadata router and this router.
|
||||
for pp in metadata_router.get_peer_ports():
|
||||
if pp.get_device_id() == id:
|
||||
mdr_port = self.get_port(pp.get_peer_id())
|
||||
pp.unlink()
|
||||
self.mido_api.delete_port(pp.get_id())
|
||||
self.mido_api.delete_port(mdr_port.get_id())
|
||||
|
||||
@handle_api_error
|
||||
def setup_floating_ip(self, router_id, provider_router, floating_ip,
|
||||
fixed_ip, identifier):
|
||||
"""Setup MidoNet for floating IP
|
||||
|
||||
:param router_id: router_id
|
||||
:param provider_router: provider router
|
||||
:param floating_ip: floating IP address
|
||||
:param fixed_ip: fixed IP address
|
||||
:param identifier: identifier to use to map to MidoNet
|
||||
"""
|
||||
LOG.debug(_("MidoClient.setup_floating_ip called: "
|
||||
"router_id=%(router_id)s, "
|
||||
"provider_router=%(provider_router)s"
|
||||
"floating_ip=%(floating_ip)s, fixed_ip=%(fixed_ip)s"
|
||||
"identifier=%(identifier)s"),
|
||||
{'router_id': router_id, 'provider_router': provider_router,
|
||||
'floating_ip': floating_ip, 'fixed_ip': fixed_ip,
|
||||
'identifier': identifier})
|
||||
# unlink from metadata router and delete the interior ports
|
||||
router = self.mido_api.get_router(router_id)
|
||||
# find the provider router port that is connected to the tenant
|
||||
# of the floating ip
|
||||
for p in router.get_peer_ports():
|
||||
if p.get_device_id() == provider_router.get_id():
|
||||
pr_port = p
|
||||
|
||||
# get the tenant router port id connected to provider router
|
||||
tr_port_id = pr_port.get_peer_id()
|
||||
|
||||
# add a route for the floating ip to bring it to the tenant
|
||||
provider_router.add_route().type(
|
||||
'Normal').src_network_addr('0.0.0.0').src_network_length(
|
||||
0).dst_network_addr(
|
||||
floating_ip).dst_network_length(
|
||||
32).weight(100).next_hop_port(
|
||||
pr_port.get_id()).create()
|
||||
|
||||
chains = self.get_router_chains(router.get_tenant_id(), router_id)
|
||||
|
||||
# add dnat/snat rule pair for the floating ip
|
||||
nat_targets = []
|
||||
nat_targets.append(
|
||||
{'addressFrom': fixed_ip, 'addressTo': fixed_ip,
|
||||
'portFrom': 0, 'portTo': 0})
|
||||
|
||||
floating_property = {OS_FLOATING_IP_RULE_KEY: identifier}
|
||||
chains['in'].add_rule().nw_dst_address(
|
||||
floating_ip).nw_dst_length(32).type(
|
||||
'dnat').flow_action('accept').nat_targets(
|
||||
nat_targets).in_ports([tr_port_id]).position(
|
||||
1).properties(floating_property).create()
|
||||
|
||||
nat_targets = []
|
||||
nat_targets.append(
|
||||
{'addressFrom': floating_ip, 'addressTo': floating_ip,
|
||||
'portFrom': 0, 'portTo': 0})
|
||||
|
||||
chains['out'].add_rule().nw_src_address(
|
||||
fixed_ip).nw_src_length(32).type(
|
||||
'snat').flow_action('accept').nat_targets(
|
||||
nat_targets).out_ports(
|
||||
[tr_port_id]).position(1).properties(
|
||||
floating_property).create()
|
||||
|
||||
@handle_api_error
|
||||
def clear_floating_ip(self, router_id, provider_router, floating_ip,
|
||||
identifier):
|
||||
"""Remove floating IP
|
||||
|
||||
:param router_id: router_id
|
||||
:param provider_router: provider router
|
||||
:param floating_ip: floating IP address
|
||||
:param identifier: identifier to use to map to MidoNet
|
||||
"""
|
||||
LOG.debug(_("MidoClient.clear_floating_ip called: "
|
||||
"router_id=%(router_id)s, "
|
||||
"provider_router=%(provider_router)s"
|
||||
"floating_ip=%(floating_ip)s, identifier=%(identifier)s"),
|
||||
{'router_id': router_id, 'provider_router': provider_router,
|
||||
'floating_ip': floating_ip, 'identifier': identifier})
|
||||
router = self.mido_api.get_router(router_id)
|
||||
|
||||
# find the provider router port that is connected to the tenant
|
||||
# delete the route for this floating ip
|
||||
for r in provider_router.get_routes():
|
||||
if (r.get_dst_network_addr() == floating_ip and
|
||||
r.get_dst_network_length() == 32):
|
||||
self.mido_api.delete_route(r.get_id())
|
||||
|
||||
# delete snat/dnat rule pair for this floating ip
|
||||
chains = self.get_router_chains(router.get_tenant_id(), router_id)
|
||||
|
||||
for r in chains['in'].get_rules():
|
||||
if OS_FLOATING_IP_RULE_KEY in r.get_properties():
|
||||
if r.get_properties()[OS_FLOATING_IP_RULE_KEY] == identifier:
|
||||
LOG.debug(_('deleting rule=%r'), r)
|
||||
self.mido_api.delete_rule(r.get_id())
|
||||
break
|
||||
|
||||
for r in chains['out'].get_rules():
|
||||
if OS_FLOATING_IP_RULE_KEY in r.get_properties():
|
||||
if r.get_properties()[OS_FLOATING_IP_RULE_KEY] == identifier:
|
||||
LOG.debug(_('deleting rule=%r'), r)
|
||||
self.mido_api.delete_rule(r.get_id())
|
||||
break
|
||||
|
||||
@handle_api_error
|
||||
def create_for_sg(self, tenant_id, sg_id, sg_name):
|
||||
"""Create a new chain for security group.
|
||||
|
||||
Creating a security group creates a pair of chains in MidoNet, one for
|
||||
inbound and the other for outbound.
|
||||
"""
|
||||
LOG.debug(_("ChainManager.create_for_sg called: "
|
||||
LOG.debug(_("MidoClient.create_for_sg called: "
|
||||
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
|
||||
"sg_name=%(sg_name)s "),
|
||||
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
|
||||
@ -70,13 +812,18 @@ class ChainManager:
|
||||
self.mido_api.add_chain().tenant_id(tenant_id).name(
|
||||
cnames['out']).create()
|
||||
|
||||
pg_name = port_group_name(sg_id, sg_name)
|
||||
self.mido_api.add_port_group().tenant_id(tenant_id).name(
|
||||
pg_name).create()
|
||||
|
||||
@handle_api_error
|
||||
def delete_for_sg(self, tenant_id, sg_id, sg_name):
|
||||
"""Delete a chain mapped to a security group.
|
||||
|
||||
Delete a SG means deleting all the chains (inbound and outbound)
|
||||
associated with the SG in MidoNet.
|
||||
"""
|
||||
LOG.debug(_("ChainManager.delete_for_sg called: "
|
||||
LOG.debug(_("MidoClient.delete_for_sg called: "
|
||||
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
|
||||
"sg_name=%(sg_name)s "),
|
||||
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
|
||||
@ -85,52 +832,22 @@ class ChainManager:
|
||||
chains = self.mido_api.get_chains({'tenant_id': tenant_id})
|
||||
for c in chains:
|
||||
if c.get_name() == cnames['in'] or c.get_name() == cnames['out']:
|
||||
LOG.debug(_('ChainManager.delete_for_sg: deleting chain=%r'),
|
||||
c)
|
||||
c.delete()
|
||||
LOG.debug(_('MidoClient.delete_for_sg: deleting chain=%r'),
|
||||
c.get_id())
|
||||
self.mido_api.delete_chain(c.get_id())
|
||||
|
||||
def get_router_chains(self, tenant_id, router_id):
|
||||
"""Get router chains.
|
||||
|
||||
Returns a dictionary that has in/out chain resources key'ed with 'in'
|
||||
and 'out' respectively, given the tenant_id and the router_id passed
|
||||
in in the arguments.
|
||||
"""
|
||||
LOG.debug(_("ChainManager.get_router_chains called: "
|
||||
"tenant_id=%(tenant_id)s router_id=%(router_id)s"),
|
||||
{'tenant_id': tenant_id, 'router_id': router_id})
|
||||
|
||||
router_chain_names = self._get_router_chain_names(router_id)
|
||||
chains = {}
|
||||
for c in self.mido_api.get_chains({'tenant_id': tenant_id}):
|
||||
if c.get_name() == router_chain_names['in']:
|
||||
chains['in'] = c
|
||||
elif c.get_name() == router_chain_names['out']:
|
||||
chains['out'] = c
|
||||
return chains
|
||||
|
||||
def create_router_chains(self, tenant_id, router_id):
|
||||
"""Create a new chain on a router.
|
||||
|
||||
Creates chains for the router and returns the same dictionary as
|
||||
get_router_chains() returns.
|
||||
"""
|
||||
LOG.debug(_("ChainManager.create_router_chains called: "
|
||||
"tenant_id=%(tenant_id)s router_id=%(router_id)s"),
|
||||
{'tenant_id': tenant_id, 'router_id': router_id})
|
||||
|
||||
chains = {}
|
||||
router_chain_names = self._get_router_chain_names(router_id)
|
||||
chains['in'] = self.mido_api.add_chain().tenant_id(tenant_id).name(
|
||||
router_chain_names['in']).create()
|
||||
|
||||
chains['out'] = self.mido_api.add_chain().tenant_id(tenant_id).name(
|
||||
router_chain_names['out']).create()
|
||||
return chains
|
||||
pg_name = port_group_name(sg_id, sg_name)
|
||||
pgs = self.mido_api.get_port_groups({'tenant_id': tenant_id})
|
||||
for pg in pgs:
|
||||
if pg.get_name() == pg_name:
|
||||
LOG.debug(_("MidoClient.delete_for_sg: deleting pg=%r"),
|
||||
pg)
|
||||
self.mido_api.delete_port_group(pg.get_id())
|
||||
|
||||
@handle_api_error
|
||||
def get_sg_chains(self, tenant_id, sg_id):
|
||||
"""Get a list of chains mapped to a security group."""
|
||||
LOG.debug(_("ChainManager.get_sg_chains called: "
|
||||
LOG.debug(_("MidoClient.get_sg_chains called: "
|
||||
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s"),
|
||||
{'tenant_id': tenant_id, 'sg_id': sg_id})
|
||||
|
||||
@ -148,44 +865,9 @@ class ChainManager:
|
||||
assert 'out' in chains
|
||||
return chains
|
||||
|
||||
def _get_router_chain_names(self, router_id):
|
||||
LOG.debug(_("ChainManager.get_router_chain_names called: "
|
||||
"router_id=%(router_id)s"), {'router_id': router_id})
|
||||
|
||||
in_name = OS_ROUTER_IN_CHAIN_NAME_FORMAT % router_id
|
||||
out_name = OS_ROUTER_OUT_CHAIN_NAME_FORMAT % router_id
|
||||
router_chain_names = {'in': in_name, 'out': out_name}
|
||||
return router_chain_names
|
||||
|
||||
|
||||
class PortGroupManager:
|
||||
|
||||
def __init__(self, mido_api):
|
||||
self.mido_api = mido_api
|
||||
|
||||
def create(self, tenant_id, sg_id, sg_name):
|
||||
LOG.debug(_("PortGroupManager.create called: "
|
||||
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
|
||||
"sg_name=%(sg_name)s"),
|
||||
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
|
||||
pg_name = port_group_name(sg_id, sg_name)
|
||||
self.mido_api.add_port_group().tenant_id(tenant_id).name(
|
||||
pg_name).create()
|
||||
|
||||
def delete(self, tenant_id, sg_id, sg_name):
|
||||
LOG.debug(_("PortGroupManager.delete called: "
|
||||
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s "
|
||||
"sg_name=%(sg_name)s"),
|
||||
{'tenant_id': tenant_id, 'sg_id': sg_id, 'sg_name': sg_name})
|
||||
pg_name = port_group_name(sg_id, sg_name)
|
||||
pgs = self.mido_api.get_port_groups({'tenant_id': tenant_id})
|
||||
for pg in pgs:
|
||||
if pg.get_name() == pg_name:
|
||||
LOG.debug(_("PortGroupManager.delete: deleting pg=%r"), pg)
|
||||
pg.delete()
|
||||
|
||||
def get_for_sg(self, tenant_id, sg_id):
|
||||
LOG.debug(_("PortGroupManager.get_for_sg called: "
|
||||
@handle_api_error
|
||||
def get_port_groups_for_sg(self, tenant_id, sg_id):
|
||||
LOG.debug(_("MidoClient.get_port_groups_for_sg called: "
|
||||
"tenant_id=%(tenant_id)s sg_id=%(sg_id)s"),
|
||||
{'tenant_id': tenant_id, 'sg_id': sg_id})
|
||||
|
||||
@ -194,25 +876,14 @@ class PortGroupManager:
|
||||
port_groups = self.mido_api.get_port_groups({'tenant_id': tenant_id})
|
||||
for pg in port_groups:
|
||||
if pg.get_name().startswith(pg_name_prefix):
|
||||
LOG.debug(_("PortGroupManager.get_for_sg exiting: pg=%r"), pg)
|
||||
LOG.debug(_(
|
||||
"MidoClient.get_port_groups_for_sg exiting: pg=%r"), pg)
|
||||
return pg
|
||||
return None
|
||||
|
||||
|
||||
class RuleManager:
|
||||
|
||||
OS_SG_KEY = 'os_sg_rule_id'
|
||||
|
||||
def __init__(self, mido_api):
|
||||
self.mido_api = mido_api
|
||||
self.chain_manager = ChainManager(mido_api)
|
||||
self.pg_manager = PortGroupManager(mido_api)
|
||||
|
||||
def _properties(self, os_sg_rule_id):
|
||||
return {self.OS_SG_KEY: str(os_sg_rule_id)}
|
||||
|
||||
@handle_api_error
|
||||
def create_for_sg_rule(self, rule):
|
||||
LOG.debug(_("RuleManager.create_for_sg_rule called: rule=%r"), rule)
|
||||
LOG.debug(_("MidoClient.create_for_sg_rule called: rule=%r"), rule)
|
||||
|
||||
direction = rule['direction']
|
||||
protocol = rule['protocol']
|
||||
@ -264,7 +935,7 @@ class RuleManager:
|
||||
tp_src_start = tp_src_end = icmp_type
|
||||
tp_dst_start = tp_dst_end = icmp_code
|
||||
|
||||
chains = self.chain_manager.get_sg_chains(tenant_id, security_group_id)
|
||||
chains = self.get_sg_chains(tenant_id, security_group_id)
|
||||
chain = None
|
||||
if direction == 'egress':
|
||||
chain = chains['in']
|
||||
@ -274,8 +945,8 @@ class RuleManager:
|
||||
raise Exception(_("Don't know what to do with rule=%r"), rule)
|
||||
|
||||
# create an accept rule
|
||||
properties = self._properties(rule_id)
|
||||
LOG.debug(_("RuleManager.create_for_sg_rule: adding accept rule "
|
||||
properties = sg_rule_properties(rule_id)
|
||||
LOG.debug(_("MidoClient.create_for_sg_rule: adding accept rule "
|
||||
"%(rule_id)s in portgroup %(port_group_id)s"),
|
||||
{'rule_id': rule_id, 'port_group_id': port_group_id})
|
||||
chain.add_rule().port_group(port_group_id).type('accept').nw_proto(
|
||||
@ -284,20 +955,21 @@ class RuleManager:
|
||||
tp_src_end).tp_dst_start(tp_dst_start).tp_dst_end(
|
||||
tp_dst_end).properties(properties).create()
|
||||
|
||||
@handle_api_error
|
||||
def delete_for_sg_rule(self, rule):
|
||||
LOG.debug(_("RuleManager.delete_for_sg_rule called: rule=%r"), rule)
|
||||
LOG.debug(_("MidoClient.delete_for_sg_rule called: rule=%r"), rule)
|
||||
|
||||
tenant_id = rule['tenant_id']
|
||||
security_group_id = rule['security_group_id']
|
||||
rule_id = rule['id']
|
||||
|
||||
properties = self._properties(rule_id)
|
||||
properties = sg_rule_properties(rule_id)
|
||||
# search for the chains to find the rule to delete
|
||||
chains = self.chain_manager.get_sg_chains(tenant_id, security_group_id)
|
||||
chains = self.get_sg_chains(tenant_id, security_group_id)
|
||||
for c in chains['in'], chains['out']:
|
||||
rules = c.get_rules()
|
||||
for r in rules:
|
||||
if r.get_properties() == properties:
|
||||
LOG.debug(_("RuleManager.delete_for_sg_rule: deleting "
|
||||
LOG.debug(_("MidoClient.delete_for_sg_rule: deleting "
|
||||
"rule %r"), r)
|
||||
r.delete()
|
||||
self.mido_api.delete_rule(r.get_id())
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
from midonetclient import api
|
||||
from oslo.config import cfg
|
||||
from webob import exc as w_exc
|
||||
|
||||
from quantum.common import exceptions as q_exc
|
||||
from quantum.db import api as db
|
||||
@ -38,15 +37,6 @@ from quantum.plugins.midonet import midonet_lib
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
OS_TENANT_ROUTER_RULE_KEY = 'OS_TENANT_ROUTER_RULE'
|
||||
OS_FLOATING_IP_RULE_KEY = 'OS_FLOATING_IP'
|
||||
SNAT_RULE = 'SNAT'
|
||||
SNAT_RULE_PROPERTY = {OS_TENANT_ROUTER_RULE_KEY: SNAT_RULE}
|
||||
|
||||
|
||||
class MidonetResourceNotFound(q_exc.NotFound):
|
||||
message = _('MidoNet %(resource_type)s %(id)s could not be found')
|
||||
|
||||
|
||||
class MidonetPluginException(q_exc.QuantumException):
|
||||
message = _("%(msg)s")
|
||||
@ -57,6 +47,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
securitygroups_db.SecurityGroupDbMixin):
|
||||
|
||||
supported_extension_aliases = ['router', 'security-group']
|
||||
__native_bulk_support = False
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@ -73,26 +64,23 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
self.mido_api = api.MidonetApi(midonet_uri, admin_user,
|
||||
admin_pass,
|
||||
project_id=admin_project_id)
|
||||
self.client = midonet_lib.MidoClient(self.mido_api)
|
||||
|
||||
# get MidoNet provider router and metadata router
|
||||
if provider_router_id and metadata_router_id:
|
||||
self.provider_router = self.mido_api.get_router(provider_router_id)
|
||||
self.metadata_router = self.mido_api.get_router(metadata_router_id)
|
||||
# get MidoNet provider router and metadata router
|
||||
self.provider_router = self.client.get_router(provider_router_id)
|
||||
self.metadata_router = self.client.get_router(metadata_router_id)
|
||||
|
||||
# for dev purpose only
|
||||
elif mode == 'dev':
|
||||
msg = _('No provider router and metadata device ids found. '
|
||||
'But skipping because running in dev env.')
|
||||
LOG.debug(msg)
|
||||
else:
|
||||
msg = _('provider_router_id and metadata_router_id '
|
||||
'should be configured in the plugin config file')
|
||||
LOG.exception(msg)
|
||||
raise MidonetPluginException(msg=msg)
|
||||
|
||||
self.chain_manager = midonet_lib.ChainManager(self.mido_api)
|
||||
self.pg_manager = midonet_lib.PortGroupManager(self.mido_api)
|
||||
self.rule_manager = midonet_lib.RuleManager(self.mido_api)
|
||||
elif not provider_router_id or not metadata_router_id:
|
||||
if mode == 'dev':
|
||||
msg = _('No provider router and metadata device ids found. '
|
||||
'But skipping because running in dev env.')
|
||||
LOG.debug(msg)
|
||||
else:
|
||||
msg = _('provider_router_id and metadata_router_id '
|
||||
'should be configured in the plugin config file')
|
||||
LOG.exception(msg)
|
||||
raise MidonetPluginException(msg=msg)
|
||||
|
||||
db.configure_db()
|
||||
|
||||
@ -118,114 +106,27 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
with session.begin(subtransactions=True):
|
||||
sn_entry = super(MidonetPluginV2, self).create_subnet(context,
|
||||
subnet)
|
||||
try:
|
||||
bridge = self.mido_api.get_bridge(sn_entry['network_id'])
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge',
|
||||
id=sn_entry['network_id'])
|
||||
bridge = self.client.get_bridge(sn_entry['network_id'])
|
||||
|
||||
gateway_ip = subnet['subnet']['gateway_ip']
|
||||
network_address, prefix = subnet['subnet']['cidr'].split('/')
|
||||
bridge.add_dhcp_subnet().default_gateway(gateway_ip).subnet_prefix(
|
||||
network_address).subnet_length(prefix).create()
|
||||
self.client.create_dhcp(bridge, gateway_ip, network_address,
|
||||
prefix)
|
||||
|
||||
# If the network is external, link the bridge to MidoNet provider
|
||||
# router
|
||||
# For external network, link the bridge to the provider router.
|
||||
self._extend_network_dict_l3(context, net)
|
||||
if net['router:external']:
|
||||
gateway_ip = sn_entry['gateway_ip']
|
||||
network_address, length = sn_entry['cidr'].split('/')
|
||||
|
||||
# create a interior port in the MidoNet provider router
|
||||
in_port = self.provider_router.add_interior_port()
|
||||
pr_port = in_port.port_address(gateway_ip).network_address(
|
||||
network_address).network_length(length).create()
|
||||
|
||||
# create a interior port in the bridge, then link
|
||||
# it to the provider router.
|
||||
br_port = bridge.add_interior_port().create()
|
||||
pr_port.link(br_port.get_id())
|
||||
|
||||
# add a route for the subnet in the provider router
|
||||
self.provider_router.add_route().type(
|
||||
'Normal').src_network_addr('0.0.0.0').src_network_length(
|
||||
0).dst_network_addr(
|
||||
network_address).dst_network_length(
|
||||
length).weight(100).next_hop_port(
|
||||
pr_port.get_id()).create()
|
||||
self.client.link_bridge_to_provider_router(
|
||||
bridge, self.provider_router, gateway_ip, network_address,
|
||||
length)
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.create_subnet exiting: sn_entry=%r"),
|
||||
sn_entry)
|
||||
return sn_entry
|
||||
|
||||
def get_subnet(self, context, id, fields=None):
|
||||
"""Get Quantum subnet.
|
||||
|
||||
Retrieves a Quantum subnet record but also including the DHCP entry
|
||||
data stored in MidoNet.
|
||||
"""
|
||||
LOG.debug(_("MidonetPluginV2.get_subnet called: id=%(id)s "
|
||||
"fields=%(fields)s"), {'id': id, 'fields': fields})
|
||||
|
||||
qsubnet = super(MidonetPluginV2, self).get_subnet(context, id)
|
||||
bridge_id = qsubnet['network_id']
|
||||
try:
|
||||
bridge = self.mido_api.get_bridge(bridge_id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge',
|
||||
id=bridge_id)
|
||||
|
||||
# get dhcp subnet data from MidoNet bridge.
|
||||
dhcps = bridge.get_dhcp_subnets()
|
||||
b_network_address = dhcps[0].get_subnet_prefix()
|
||||
b_prefix = dhcps[0].get_subnet_length()
|
||||
|
||||
# Validate against quantum database.
|
||||
network_address, prefix = qsubnet['cidr'].split('/')
|
||||
if network_address != b_network_address or int(prefix) != b_prefix:
|
||||
raise MidonetResourceNotFound(resource_type='DhcpSubnet',
|
||||
id=qsubnet['cidr'])
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.get_subnet exiting: qsubnet=%s"), qsubnet)
|
||||
return qsubnet
|
||||
|
||||
def get_subnets(self, context, filters=None, fields=None):
|
||||
"""List Quantum subnets.
|
||||
|
||||
Retrieves Quantum subnets with some fields populated by the data
|
||||
stored in MidoNet.
|
||||
"""
|
||||
LOG.debug(_("MidonetPluginV2.get_subnets called: filters=%(filters)r, "
|
||||
"fields=%(fields)r"),
|
||||
{'filters': filters, 'fields': fields})
|
||||
subnets = super(MidonetPluginV2, self).get_subnets(context, filters,
|
||||
fields)
|
||||
for sn in subnets:
|
||||
if not 'network_id' in sn:
|
||||
continue
|
||||
try:
|
||||
bridge = self.mido_api.get_bridge(sn['network_id'])
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge',
|
||||
id=sn['network_id'])
|
||||
|
||||
# TODO(tomoe): dedupe this part.
|
||||
# get dhcp subnet data from MidoNet bridge.
|
||||
dhcps = bridge.get_dhcp_subnets()
|
||||
b_network_address = dhcps[0].get_subnet_prefix()
|
||||
b_prefix = dhcps[0].get_subnet_length()
|
||||
|
||||
# Validate against quantum database.
|
||||
if sn.get('cidr'):
|
||||
network_address, prefix = sn['cidr'].split('/')
|
||||
if network_address != b_network_address or int(
|
||||
prefix) != b_prefix:
|
||||
raise MidonetResourceNotFound(resource_type='DhcpSubnet',
|
||||
id=sn['cidr'])
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.create_subnet exiting"))
|
||||
return subnets
|
||||
|
||||
def delete_subnet(self, context, id):
|
||||
"""Delete Quantum subnet.
|
||||
|
||||
@ -237,37 +138,14 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
net = super(MidonetPluginV2, self).get_network(context,
|
||||
subnet['network_id'],
|
||||
fields=None)
|
||||
bridge_id = subnet['network_id']
|
||||
try:
|
||||
bridge = self.mido_api.get_bridge(bridge_id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge', id=bridge_id)
|
||||
|
||||
dhcp = bridge.get_dhcp_subnets()
|
||||
dhcp[0].delete()
|
||||
bridge = self.client.get_bridge(subnet['network_id'])
|
||||
self.client.delete_dhcp(bridge)
|
||||
|
||||
# If the network is external, clean up routes, links, ports.
|
||||
self._extend_network_dict_l3(context, net)
|
||||
if net['router:external']:
|
||||
# Delete routes and unlink the router and the bridge.
|
||||
routes = self.provider_router.get_routes()
|
||||
|
||||
bridge_ports_to_delete = []
|
||||
for p in self.provider_router.get_peer_ports():
|
||||
if p.get_device_id() == bridge.get_id():
|
||||
bridge_ports_to_delete.append(p)
|
||||
|
||||
for p in bridge.get_peer_ports():
|
||||
if p.get_device_id() == self.provider_router.get_id():
|
||||
# delete the routes going to the brdge
|
||||
for r in routes:
|
||||
if r.get_next_hop_port() == p.get_id():
|
||||
r.delete()
|
||||
p.unlink()
|
||||
p.delete()
|
||||
|
||||
# delete bridge port
|
||||
map(lambda x: x.delete(), bridge_ports_to_delete)
|
||||
self.client.unlink_bridge_from_provider_router(
|
||||
bridge, self.provider_router)
|
||||
|
||||
super(MidonetPluginV2, self).delete_subnet(context, id)
|
||||
LOG.debug(_("MidonetPluginV2.delete_subnet exiting"))
|
||||
@ -281,9 +159,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
network)
|
||||
|
||||
if network['network']['admin_state_up'] is False:
|
||||
LOG.warning(_('Ignoring admin_state_up=False for network=%r'
|
||||
'Overriding with True'), network)
|
||||
network['network']['admin_state_up'] = True
|
||||
LOG.warning(_('Ignoring admin_state_up=False for network=%r '
|
||||
'because it is not yet supported'), network)
|
||||
|
||||
tenant_id = self._get_tenant_id_for_create(context, network['network'])
|
||||
|
||||
@ -291,8 +168,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
bridge = self.mido_api.add_bridge().name(
|
||||
network['network']['name']).tenant_id(tenant_id).create()
|
||||
bridge = self.client.create_bridge(tenant_id,
|
||||
network['network']['name'])
|
||||
|
||||
# Set MidoNet bridge ID to the quantum DB entry
|
||||
network['network']['id'] = bridge.get_id()
|
||||
@ -324,11 +201,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
with session.begin(subtransactions=True):
|
||||
net = super(MidonetPluginV2, self).update_network(
|
||||
context, id, network)
|
||||
try:
|
||||
bridge = self.mido_api.get_bridge(id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
|
||||
bridge.name(net['name']).update()
|
||||
self.client.update_bridge(id, net['name'])
|
||||
|
||||
self._extend_network_dict_l3(context, net)
|
||||
LOG.debug(_("MidonetPluginV2.update_network exiting: net=%r"), net)
|
||||
@ -345,10 +218,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
# NOTE: Get network data with all fields (fields=None) for
|
||||
# _extend_network_dict_l3() method, which needs 'id' field
|
||||
qnet = super(MidonetPluginV2, self).get_network(context, id, None)
|
||||
try:
|
||||
self.mido_api.get_bridge(id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge', id=id)
|
||||
self.client.get_bridge(id)
|
||||
|
||||
self._extend_network_dict_l3(context, qnet)
|
||||
LOG.debug(_("MidonetPluginV2.get_network exiting: qnet=%r"), qnet)
|
||||
@ -364,13 +234,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
# _extend_network_dict_l3() method, which needs 'id' field
|
||||
qnets = super(MidonetPluginV2, self).get_networks(context, filters,
|
||||
None)
|
||||
self.mido_api.get_bridges({'tenant_id': context.tenant_id})
|
||||
for n in qnets:
|
||||
try:
|
||||
self.mido_api.get_bridge(n['id'])
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge',
|
||||
id=n['id'])
|
||||
self._extend_network_dict_l3(context, n)
|
||||
|
||||
return [self._fields(net, fields) for net in qnets]
|
||||
@ -378,8 +242,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
def delete_network(self, context, id):
|
||||
"""Delete a network and its corresponding MidoNet bridge."""
|
||||
LOG.debug(_("MidonetPluginV2.delete_network called: id=%r"), id)
|
||||
|
||||
self.mido_api.get_bridge(id).delete()
|
||||
self.client.delete_bridge(id)
|
||||
try:
|
||||
super(MidonetPluginV2, self).delete_network(context, id)
|
||||
except Exception:
|
||||
@ -394,25 +257,21 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
is_compute_interface = False
|
||||
port_data = port['port']
|
||||
# get the bridge and create a port on it.
|
||||
try:
|
||||
bridge = self.mido_api.get_bridge(port_data['network_id'])
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Bridge',
|
||||
id=port_data['network_id'])
|
||||
bridge = self.client.get_bridge(port_data['network_id'])
|
||||
|
||||
device_owner = port_data['device_owner']
|
||||
|
||||
if device_owner.startswith('compute:') or device_owner is '':
|
||||
is_compute_interface = True
|
||||
bridge_port = bridge.add_exterior_port().create()
|
||||
bridge_port = self.client.create_exterior_bridge_port(bridge)
|
||||
elif device_owner == l3_db.DEVICE_OWNER_ROUTER_INTF:
|
||||
bridge_port = bridge.add_interior_port().create()
|
||||
bridge_port = self.client.create_interior_bridge_port(bridge)
|
||||
elif (device_owner == l3_db.DEVICE_OWNER_ROUTER_GW or
|
||||
device_owner == l3_db.DEVICE_OWNER_FLOATINGIP):
|
||||
|
||||
# This is a dummy port to make l3_db happy.
|
||||
# This will not be used in MidoNet
|
||||
bridge_port = bridge.add_interior_port().create()
|
||||
bridge_port = self.client.create_interior_bridge_port(bridge)
|
||||
|
||||
if bridge_port:
|
||||
# set midonet port id to quantum port id and create a DB record.
|
||||
@ -433,20 +292,11 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
fixed_ip = port_db_entry['fixed_ips'][0]['ip_address']
|
||||
mac = port_db_entry['mac_address']
|
||||
# create dhcp host entry under the bridge.
|
||||
dhcp_subnets = bridge.get_dhcp_subnets()
|
||||
if dhcp_subnets:
|
||||
dhcp_subnets[0].add_dhcp_host().ip_addr(
|
||||
fixed_ip).mac_addr(mac).create()
|
||||
self.client.create_dhcp_hosts(bridge, fixed_ip, mac)
|
||||
LOG.debug(_("MidonetPluginV2.create_port exiting: port_db_entry=%r"),
|
||||
port_db_entry)
|
||||
return port_db_entry
|
||||
|
||||
def update_port(self, context, id, port):
|
||||
"""Update port."""
|
||||
LOG.debug(_("MidonetPluginV2.update_port called: id=%(id)s "
|
||||
"port=%(port)r"), {'id': id, 'port': port})
|
||||
return super(MidonetPluginV2, self).update_port(context, id, port)
|
||||
|
||||
def get_port(self, context, id, fields=None):
|
||||
"""Retrieve port."""
|
||||
LOG.debug(_("MidonetPluginV2.get_port called: id=%(id)s "
|
||||
@ -456,10 +306,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
port_db_entry = super(MidonetPluginV2, self).get_port(context,
|
||||
id, fields)
|
||||
# verify that corresponding port exists in MidoNet.
|
||||
try:
|
||||
self.mido_api.get_port(id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Port', id=id)
|
||||
self.client.get_port(id)
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.get_port exiting: port_db_entry=%r"),
|
||||
port_db_entry)
|
||||
@ -474,12 +321,9 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
filters,
|
||||
fields)
|
||||
if ports_db_entry:
|
||||
try:
|
||||
for port in ports_db_entry:
|
||||
self.mido_api.get_port(port['id'])
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Port',
|
||||
id=port['id'])
|
||||
for port in ports_db_entry:
|
||||
if 'security_gorups' in port:
|
||||
self._extend_port_dict_security_group(context, port)
|
||||
return ports_db_entry
|
||||
|
||||
def delete_port(self, context, id, l3_port_check=True):
|
||||
@ -496,7 +340,6 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
with session.begin(subtransactions=True):
|
||||
port_db_entry = super(MidonetPluginV2, self).get_port(context,
|
||||
id, None)
|
||||
bridge = self.mido_api.get_bridge(port_db_entry['network_id'])
|
||||
# Clean up dhcp host entry if needed.
|
||||
if 'ip_address' in (port_db_entry['fixed_ips'] or [{}])[0]:
|
||||
# get ip and mac from DB record.
|
||||
@ -504,13 +347,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
mac = port_db_entry['mac_address']
|
||||
|
||||
# create dhcp host entry under the bridge.
|
||||
dhcp_subnets = bridge.get_dhcp_subnets()
|
||||
if dhcp_subnets:
|
||||
for dh in dhcp_subnets[0].get_dhcp_hosts():
|
||||
if dh.get_mac_addr() == mac and dh.get_ip_addr() == ip:
|
||||
dh.delete()
|
||||
self.client.delete_dhcp_hosts(port_db_entry['network_id'], ip,
|
||||
mac)
|
||||
|
||||
self.mido_api.get_port(id).delete()
|
||||
self.client.delete_port(id)
|
||||
return super(MidonetPluginV2, self).delete_port(context, id)
|
||||
|
||||
#
|
||||
@ -528,40 +368,17 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
tenant_id = self._get_tenant_id_for_create(context, router['router'])
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
mrouter = self.mido_api.add_router().name(
|
||||
router['router']['name']).tenant_id(tenant_id).create()
|
||||
mrouter = self.client.create_tenant_router(
|
||||
tenant_id, router['router']['name'], self.metadata_router)
|
||||
|
||||
qrouter = super(MidonetPluginV2, self).create_router(context,
|
||||
router)
|
||||
|
||||
chains = self.chain_manager.create_router_chains(tenant_id,
|
||||
mrouter.get_id())
|
||||
|
||||
# set chains to in/out filters
|
||||
mrouter.inbound_filter_id(
|
||||
chains['in'].get_id()).outbound_filter_id(
|
||||
chains['out'].get_id()).update()
|
||||
|
||||
# get entry from the DB and update 'id' with MidoNet router id.
|
||||
qrouter_entry = self._get_router(context, qrouter['id'])
|
||||
qrouter['id'] = mrouter.get_id()
|
||||
qrouter_entry.update(qrouter)
|
||||
|
||||
# link to metadata router
|
||||
in_port = self.metadata_router.add_interior_port()
|
||||
mdr_port = in_port.network_address('169.254.255.0').network_length(
|
||||
30).port_address('169.254.255.1').create()
|
||||
|
||||
tr_port = mrouter.add_interior_port().network_address(
|
||||
'169.254.255.0').network_length(30).port_address(
|
||||
'169.254.255.2').create()
|
||||
mdr_port.link(tr_port.get_id())
|
||||
|
||||
# forward metadata traffic to metadata router
|
||||
mrouter.add_route().type('Normal').src_network_addr(
|
||||
'0.0.0.0').src_network_length(0).dst_network_addr(
|
||||
'169.254.169.254').dst_network_length(32).weight(
|
||||
100).next_hop_port(tr_port.get_id()).create()
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.create_router exiting: qrouter=%r"),
|
||||
qrouter)
|
||||
return qrouter
|
||||
@ -603,9 +420,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
|
||||
changed_name = router['router'].get('name')
|
||||
if changed_name:
|
||||
self.mido_api.get_router(id).name(changed_name).update()
|
||||
self.client.update_router(id, changed_name)
|
||||
|
||||
tenant_router = self.mido_api.get_router(id)
|
||||
if op_gateway_set:
|
||||
# find a qport with the network_id for the router
|
||||
qports = super(MidonetPluginV2, self).get_ports(
|
||||
@ -615,82 +431,12 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
qport = qports[0]
|
||||
snat_ip = qport['fixed_ips'][0]['ip_address']
|
||||
|
||||
in_port = self.provider_router.add_interior_port()
|
||||
pr_port = in_port.network_address(
|
||||
'169.254.255.0').network_length(30).port_address(
|
||||
'169.254.255.1').create()
|
||||
|
||||
# Create a port in the tenant router
|
||||
tr_port = tenant_router.add_interior_port().network_address(
|
||||
'169.254.255.0').network_length(30).port_address(
|
||||
'169.254.255.2').create()
|
||||
|
||||
# Link them
|
||||
pr_port.link(tr_port.get_id())
|
||||
|
||||
# Add a route for snat_ip to bring it down to tenant
|
||||
self.provider_router.add_route().type(
|
||||
'Normal').src_network_addr('0.0.0.0').src_network_length(
|
||||
0).dst_network_addr(snat_ip).dst_network_length(
|
||||
32).weight(100).next_hop_port(
|
||||
pr_port.get_id()).create()
|
||||
|
||||
# Add default route to uplink in the tenant router
|
||||
tenant_router.add_route().type('Normal').src_network_addr(
|
||||
'0.0.0.0').src_network_length(0).dst_network_addr(
|
||||
'0.0.0.0').dst_network_length(0).weight(
|
||||
100).next_hop_port(tr_port.get_id()).create()
|
||||
|
||||
# ADD SNAT(masquerade) rules
|
||||
chains = self.chain_manager.get_router_chains(
|
||||
tenant_router.get_tenant_id(), tenant_router.get_id())
|
||||
|
||||
chains['in'].add_rule().nw_dst_address(snat_ip).nw_dst_length(
|
||||
32).type('rev_snat').flow_action('accept').in_ports(
|
||||
[tr_port.get_id()]).properties(
|
||||
SNAT_RULE_PROPERTY).position(1).create()
|
||||
|
||||
nat_targets = []
|
||||
nat_targets.append(
|
||||
{'addressFrom': snat_ip, 'addressTo': snat_ip,
|
||||
'portFrom': 1, 'portTo': 65535})
|
||||
|
||||
chains['out'].add_rule().type('snat').flow_action(
|
||||
'accept').nat_targets(nat_targets).out_ports(
|
||||
[tr_port.get_id()]).properties(
|
||||
SNAT_RULE_PROPERTY).position(1).create()
|
||||
self.client.set_router_external_gateway(id,
|
||||
self.provider_router,
|
||||
snat_ip)
|
||||
|
||||
if op_gateway_clear:
|
||||
# delete the port that is connected to provider router
|
||||
for p in tenant_router.get_ports():
|
||||
if p.get_port_address() == '169.254.255.2':
|
||||
peer_port_id = p.get_peer_id()
|
||||
p.unlink()
|
||||
self.mido_api.get_port(peer_port_id).delete()
|
||||
p.delete()
|
||||
|
||||
# delete default route
|
||||
for r in tenant_router.get_routes():
|
||||
if (r.get_dst_network_addr() == '0.0.0.0' and
|
||||
r.get_dst_network_length() == 0):
|
||||
r.delete()
|
||||
|
||||
# delete SNAT(masquerade) rules
|
||||
chains = self.chain_manager.get_router_chains(
|
||||
tenant_router.get_tenant_id(),
|
||||
tenant_router.get_id())
|
||||
|
||||
for r in chains['in'].get_rules():
|
||||
if OS_TENANT_ROUTER_RULE_KEY in r.get_properties():
|
||||
if r.get_properties()[
|
||||
OS_TENANT_ROUTER_RULE_KEY] == SNAT_RULE:
|
||||
r.delete()
|
||||
|
||||
for r in chains['out'].get_rules():
|
||||
if OS_TENANT_ROUTER_RULE_KEY in r.get_properties():
|
||||
if r.get_properties()[
|
||||
OS_TENANT_ROUTER_RULE_KEY] == SNAT_RULE:
|
||||
r.delete()
|
||||
self.client.clear_router_external_gateway(id)
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.update_router exiting: qrouter=%r"),
|
||||
qrouter)
|
||||
@ -699,61 +445,13 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
def delete_router(self, context, id):
|
||||
LOG.debug(_("MidonetPluginV2.delete_router called: id=%s"), id)
|
||||
|
||||
mrouter = self.mido_api.get_router(id)
|
||||
tenant_id = mrouter.get_tenant_id()
|
||||
|
||||
# unlink from metadata router and delete the interior ports
|
||||
# that connect metadata router and this router.
|
||||
for pp in self.metadata_router.get_peer_ports():
|
||||
if pp.get_device_id() == mrouter.get_id():
|
||||
mdr_port = self.mido_api.get_port(pp.get_peer_id())
|
||||
pp.unlink()
|
||||
pp.delete()
|
||||
mdr_port.delete()
|
||||
|
||||
# delete corresponding chains
|
||||
chains = self.chain_manager.get_router_chains(tenant_id,
|
||||
mrouter.get_id())
|
||||
chains['in'].delete()
|
||||
chains['out'].delete()
|
||||
|
||||
# delete the router
|
||||
mrouter.delete()
|
||||
self.client.delete_tenant_router(id)
|
||||
|
||||
result = super(MidonetPluginV2, self).delete_router(context, id)
|
||||
LOG.debug(_("MidonetPluginV2.delete_router exiting: result=%s"),
|
||||
result)
|
||||
return result
|
||||
|
||||
def get_router(self, context, id, fields=None):
|
||||
LOG.debug(_("MidonetPluginV2.get_router called: id=%(id)s "
|
||||
"fields=%(fields)r"), {'id': id, 'fields': fields})
|
||||
qrouter = super(MidonetPluginV2, self).get_router(context, id, fields)
|
||||
|
||||
try:
|
||||
self.mido_api.get_router(id)
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Router', id=id)
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.get_router exiting: qrouter=%r"),
|
||||
qrouter)
|
||||
return qrouter
|
||||
|
||||
def get_routers(self, context, filters=None, fields=None):
|
||||
LOG.debug(_("MidonetPluginV2.get_routers called: filters=%(filters)s "
|
||||
"fields=%(fields)r"),
|
||||
{'filters': filters, 'fields': fields})
|
||||
|
||||
qrouters = super(MidonetPluginV2, self).get_routers(
|
||||
context, filters, fields)
|
||||
for qr in qrouters:
|
||||
try:
|
||||
self.mido_api.get_router(qr['id'])
|
||||
except w_exc.HTTPNotFound:
|
||||
raise MidonetResourceNotFound(resource_type='Router',
|
||||
id=qr['id'])
|
||||
return qrouters
|
||||
|
||||
def add_router_interface(self, context, router_id, interface_info):
|
||||
LOG.debug(_("MidonetPluginV2.add_router_interface called: "
|
||||
"router_id=%(router_id)s "
|
||||
@ -772,33 +470,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
network_address, length = subnet['cidr'].split('/')
|
||||
|
||||
# Link the router and the bridge port.
|
||||
mrouter = self.mido_api.get_router(router_id)
|
||||
mrouter_port = mrouter.add_interior_port().port_address(
|
||||
gateway_ip).network_address(
|
||||
network_address).network_length(length).create()
|
||||
|
||||
mbridge_port = self.mido_api.get_port(qport['port_id'])
|
||||
mrouter_port.link(mbridge_port.get_id())
|
||||
|
||||
# Add a route entry to the subnet
|
||||
mrouter.add_route().type('Normal').src_network_addr(
|
||||
'0.0.0.0').src_network_length(0).dst_network_addr(
|
||||
network_address).dst_network_length(length).weight(
|
||||
100).next_hop_port(mrouter_port.get_id()).create()
|
||||
|
||||
# add a route for the subnet in metadata router; forward
|
||||
# packets destined to the subnet to the tenant router
|
||||
found = False
|
||||
for pp in self.metadata_router.get_peer_ports():
|
||||
if pp.get_device_id() == mrouter.get_id():
|
||||
mdr_port_id = pp.get_peer_id()
|
||||
found = True
|
||||
assert found
|
||||
|
||||
self.metadata_router.add_route().type(
|
||||
'Normal').src_network_addr('0.0.0.0').src_network_length(
|
||||
0).dst_network_addr(network_address).dst_network_length(
|
||||
length).weight(100).next_hop_port(mdr_port_id).create()
|
||||
self.client.link_bridge_port_to_router(qport['port_id'], router_id,
|
||||
gateway_ip, network_address,
|
||||
length,
|
||||
self.metadata_router)
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.add_router_interface exiting: "
|
||||
"qport=%r"), qport)
|
||||
@ -810,9 +485,10 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
"router_id=%(router_id)s "
|
||||
"interface_info=%(interface_info)r"),
|
||||
{'router_id': router_id, 'interface_info': interface_info})
|
||||
port_id = None
|
||||
if 'port_id' in interface_info:
|
||||
|
||||
mbridge_port = self.mido_api.get_port(interface_info['port_id'])
|
||||
port_id = interface_info['port_id']
|
||||
subnet_id = self.get_port(context,
|
||||
interface_info['port_id']
|
||||
)['fixed_ips'][0]['subnet_id']
|
||||
@ -837,36 +513,18 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
network_port = p
|
||||
break
|
||||
assert network_port
|
||||
mbridge_port = self.mido_api.get_port(network_port['id'])
|
||||
port_id = network_port['id']
|
||||
|
||||
assert port_id
|
||||
|
||||
# get network information from subnet data
|
||||
network_addr, network_length = subnet['cidr'].split('/')
|
||||
network_length = int(network_length)
|
||||
|
||||
# Unlink the router and the bridge.
|
||||
mrouter = self.mido_api.get_router(router_id)
|
||||
mrouter_port = self.mido_api.get_port(mbridge_port.get_peer_id())
|
||||
mrouter_port.unlink()
|
||||
|
||||
# Delete the route for the subnet.
|
||||
found = False
|
||||
for r in mrouter.get_routes():
|
||||
if r.get_next_hop_port() == mrouter_port.get_id():
|
||||
r.delete()
|
||||
found = True
|
||||
#break # commented out due to issue#314
|
||||
assert found
|
||||
|
||||
# delete the route for the subnet in the metadata router
|
||||
found = False
|
||||
for r in self.metadata_router.get_routes():
|
||||
if (r.get_dst_network_addr() == network_addr and
|
||||
r.get_dst_network_length() == network_length):
|
||||
LOG.debug(_('Deleting route=%r ...'), r)
|
||||
r.delete()
|
||||
found = True
|
||||
break
|
||||
assert found
|
||||
self.client.unlink_bridge_port_from_router(port_id, network_addr,
|
||||
network_length,
|
||||
self.metadata_router)
|
||||
|
||||
info = super(MidonetPluginV2, self).remove_router_interface(
|
||||
context, router_id, interface_info)
|
||||
@ -883,91 +541,18 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
if floatingip['floatingip']['port_id']:
|
||||
fip = super(MidonetPluginV2, self).update_floatingip(
|
||||
context, id, floatingip)
|
||||
router_id = fip['router_id']
|
||||
floating_address = fip['floating_ip_address']
|
||||
fixed_address = fip['fixed_ip_address']
|
||||
|
||||
tenant_router = self.mido_api.get_router(router_id)
|
||||
# find the provider router port that is connected to the tenant
|
||||
# of the floating ip
|
||||
for p in tenant_router.get_peer_ports():
|
||||
if p.get_device_id() == self.provider_router.get_id():
|
||||
pr_port = p
|
||||
|
||||
# get the tenant router port id connected to provider router
|
||||
tr_port_id = pr_port.get_peer_id()
|
||||
|
||||
# add a route for the floating ip to bring it to the tenant
|
||||
self.provider_router.add_route().type(
|
||||
'Normal').src_network_addr('0.0.0.0').src_network_length(
|
||||
0).dst_network_addr(
|
||||
floating_address).dst_network_length(
|
||||
32).weight(100).next_hop_port(
|
||||
pr_port.get_id()).create()
|
||||
|
||||
chains = self.chain_manager.get_router_chains(fip['tenant_id'],
|
||||
fip['router_id'])
|
||||
# add dnat/snat rule pair for the floating ip
|
||||
nat_targets = []
|
||||
nat_targets.append(
|
||||
{'addressFrom': fixed_address, 'addressTo': fixed_address,
|
||||
'portFrom': 0, 'portTo': 0})
|
||||
|
||||
floating_property = {OS_FLOATING_IP_RULE_KEY: id}
|
||||
chains['in'].add_rule().nw_dst_address(
|
||||
floating_address).nw_dst_length(32).type(
|
||||
'dnat').flow_action('accept').nat_targets(
|
||||
nat_targets).in_ports([tr_port_id]).position(
|
||||
1).properties(floating_property).create()
|
||||
|
||||
nat_targets = []
|
||||
nat_targets.append(
|
||||
{'addressFrom': floating_address,
|
||||
'addressTo': floating_address,
|
||||
'portFrom': 0,
|
||||
'portTo': 0})
|
||||
|
||||
chains['out'].add_rule().nw_src_address(
|
||||
fixed_address).nw_src_length(32).type(
|
||||
'snat').flow_action('accept').nat_targets(
|
||||
nat_targets).out_ports(
|
||||
[tr_port_id]).position(1).properties(
|
||||
floating_property).create()
|
||||
|
||||
self.client.setup_floating_ip(fip['router_id'],
|
||||
self.provider_router,
|
||||
fip['floating_ip_address'],
|
||||
fip['fixed_ip_address'], id)
|
||||
# disassociate floating IP
|
||||
elif floatingip['floatingip']['port_id'] is None:
|
||||
|
||||
fip = super(MidonetPluginV2, self).get_floatingip(context, id)
|
||||
|
||||
router_id = fip['router_id']
|
||||
floating_address = fip['floating_ip_address']
|
||||
fixed_address = fip['fixed_ip_address']
|
||||
|
||||
# delete the route for this floating ip
|
||||
for r in self.provider_router.get_routes():
|
||||
if (r.get_dst_network_addr() == floating_address and
|
||||
r.get_dst_network_length() == 32):
|
||||
r.delete()
|
||||
|
||||
# delete snat/dnat rule pair for this floating ip
|
||||
chains = self.chain_manager.get_router_chains(fip['tenant_id'],
|
||||
fip['router_id'])
|
||||
LOG.debug(_('chains=%r'), chains)
|
||||
|
||||
for r in chains['in'].get_rules():
|
||||
if OS_FLOATING_IP_RULE_KEY in r.get_properties():
|
||||
if r.get_properties()[OS_FLOATING_IP_RULE_KEY] == id:
|
||||
LOG.debug(_('deleting rule=%r'), r)
|
||||
r.delete()
|
||||
break
|
||||
|
||||
for r in chains['out'].get_rules():
|
||||
if OS_FLOATING_IP_RULE_KEY in r.get_properties():
|
||||
if r.get_properties()[OS_FLOATING_IP_RULE_KEY] == id:
|
||||
LOG.debug(_('deleting rule=%r'), r)
|
||||
r.delete()
|
||||
break
|
||||
|
||||
self.client.clear_floating_ip(fip['router_id'],
|
||||
self.provider_router,
|
||||
fip['floating_ip_address'], id)
|
||||
super(MidonetPluginV2, self).update_floatingip(context, id,
|
||||
floatingip)
|
||||
|
||||
@ -993,10 +578,8 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
context, security_group, default_sg)
|
||||
|
||||
# Create MidoNet chains and portgroup for the SG
|
||||
sg_id = sg_db_entry['id']
|
||||
sg_name = sg_db_entry['name']
|
||||
self.chain_manager.create_for_sg(tenant_id, sg_id, sg_name)
|
||||
self.pg_manager.create(tenant_id, sg_id, sg_name)
|
||||
self.client.create_for_sg(tenant_id, sg_db_entry['id'],
|
||||
sg_db_entry['name'])
|
||||
|
||||
LOG.debug(_("MidonetPluginV2.create_security_group exiting: "
|
||||
"sg_db_entry=%r"), sg_db_entry)
|
||||
@ -1026,8 +609,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
raise ext_sg.SecurityGroupInUse(id=sg_id)
|
||||
|
||||
# Delete MidoNet Chains and portgroup for the SG
|
||||
self.chain_manager.delete_for_sg(tenant_id, sg_id, sg_name)
|
||||
self.pg_manager.delete(tenant_id, sg_id, sg_name)
|
||||
self.client.delete_for_sg(tenant_id, sg_id, sg_name)
|
||||
|
||||
return super(MidonetPluginV2, self).delete_security_group(
|
||||
context, id)
|
||||
@ -1057,7 +639,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
MidonetPluginV2, self).create_security_group_rule(
|
||||
context, security_group_rule)
|
||||
|
||||
self.rule_manager.create_for_sg_rule(rule_db_entry)
|
||||
self.client.create_for_sg_rule(rule_db_entry)
|
||||
LOG.debug(_("MidonetPluginV2.create_security_group_rule exiting: "
|
||||
"rule_db_entry=%r"), rule_db_entry)
|
||||
return rule_db_entry
|
||||
@ -1073,7 +655,7 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
if not rule_db_entry:
|
||||
raise ext_sg.SecurityGroupRuleNotFound(id=sgrid)
|
||||
|
||||
self.rule_manager.delete_for_sg_rule(rule_db_entry)
|
||||
self.client.delete_for_sg_rule(rule_db_entry)
|
||||
return super(MidonetPluginV2,
|
||||
self).delete_security_group_rule(context, sgrid)
|
||||
|
||||
|
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: Tomoe Sugihara, Midokura Japan KK
|
||||
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
import webob.exc as w_exc
|
||||
|
||||
from quantum.openstack.common import uuidutils
|
||||
from quantum.plugins.midonet import midonet_lib
|
||||
from quantum.tests import base
|
||||
import quantum.tests.unit.midonet.mock_lib as mock_lib
|
||||
|
||||
|
||||
class MidonetLibTestCase(base.BaseTestCase):
|
||||
def _create_test_chain(id, name, tenant_id):
|
||||
return {'id': id, 'name': name, 'tenant_id': tenant_id}
|
||||
|
||||
|
||||
def _create_test_port_group(sg_id, sg_name, id, tenant_id):
|
||||
return {"id": id, "name": "OS_SG_%s_%s" % (sg_id, sg_name),
|
||||
"tenant_id": tenant_id}
|
||||
|
||||
|
||||
def _create_test_router_in_chain(router_id, id, tenant_id):
|
||||
name = "OS_ROUTER_IN_%s" % router_id
|
||||
return _create_test_chain(id, name, tenant_id)
|
||||
|
||||
|
||||
def _create_test_router_out_chain(router_id, id, tenant_id):
|
||||
name = "OS_ROUTER_OUT_%s" % router_id
|
||||
return _create_test_chain(id, name, tenant_id)
|
||||
|
||||
|
||||
def _create_test_rule(id, chain_id, properties):
|
||||
return {"id": id, "chain_id": chain_id, "properties": properties}
|
||||
|
||||
|
||||
def _create_test_sg_in_chain(sg_id, sg_name, id, tenant_id):
|
||||
if sg_name:
|
||||
name = "OS_SG_%s_%s_IN" % (sg_id, sg_name)
|
||||
else:
|
||||
name = "OS_SG_%s_IN" % sg_id
|
||||
return _create_test_chain(id, name, tenant_id)
|
||||
|
||||
|
||||
def _create_test_sg_out_chain(sg_id, sg_name, id, tenant_id):
|
||||
if sg_name:
|
||||
name = "OS_SG_%s_%s_OUT" % (sg_id, sg_name)
|
||||
else:
|
||||
name = "OS_SG_%s_OUT" % sg_id
|
||||
return _create_test_chain(id, name, tenant_id)
|
||||
|
||||
|
||||
def _create_test_sg_rule(tenant_id, sg_id, id,
|
||||
direction="egress", protocol="tcp", port_min=1,
|
||||
port_max=65535, src_ip='192.168.1.0/24',
|
||||
src_group_id=None, ethertype=0x0800, properties=None):
|
||||
return {"tenant_id": tenant_id, "security_group_id": sg_id,
|
||||
"id": id, "direction": direction, "protocol": protocol,
|
||||
"remote_ip_prefix": src_ip, "remote_group_id": src_group_id,
|
||||
"port_range_min": port_min, "port_range_max": port_max,
|
||||
"ethertype": ethertype, "external_id": None}
|
||||
|
||||
|
||||
def _create_test_sg_chain_rule(id, chain_id, sg_rule_id):
|
||||
props = {"os_sg_rule_id": sg_rule_id}
|
||||
return _create_test_rule(id, chain_id, props)
|
||||
|
||||
|
||||
class MidoClientTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(MidonetLibTestCase, self).setUp()
|
||||
super(MidoClientTestCase, self).setUp()
|
||||
self._tenant_id = 'test-tenant'
|
||||
self.mock_api = mock.Mock()
|
||||
|
||||
def _create_mock_chains(self, sg_id, sg_name):
|
||||
mock_in_chain = mock.Mock()
|
||||
mock_in_chain.get_name.return_value = "OS_SG_%s_%s_IN" % (sg_id,
|
||||
sg_name)
|
||||
mock_out_chain = mock.Mock()
|
||||
mock_out_chain.get_name.return_value = "OS_SG_%s_%s_OUT" % (sg_id,
|
||||
sg_name)
|
||||
return (mock_in_chain, mock_out_chain)
|
||||
|
||||
def _create_mock_router_chains(self, router_id):
|
||||
mock_in_chain = mock.Mock()
|
||||
mock_in_chain.get_name.return_value = "OS_ROUTER_IN_%s" % (router_id)
|
||||
|
||||
mock_out_chain = mock.Mock()
|
||||
mock_out_chain.get_name.return_value = "OS_ROUTER_OUT_%s" % (router_id)
|
||||
return (mock_in_chain, mock_out_chain)
|
||||
|
||||
def _create_mock_port_group(self, sg_id, sg_name):
|
||||
mock_pg = mock.Mock()
|
||||
mock_pg.get_name.return_value = "OS_SG_%s_%s" % (sg_id, sg_name)
|
||||
return mock_pg
|
||||
|
||||
def _create_mock_rule(self, rule_id):
|
||||
mock_rule = mock.Mock()
|
||||
mock_rule.get_properties.return_value = {"os_sg_rule_id": rule_id}
|
||||
return mock_rule
|
||||
|
||||
|
||||
class MidonetChainManagerTestCase(MidonetLibTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(MidonetChainManagerTestCase, self).setUp()
|
||||
self.mgr = midonet_lib.ChainManager(self.mock_api)
|
||||
self.mock_api_cfg = mock_lib.MidoClientMockConfig(self.mock_api)
|
||||
self.mock_api_cfg.setup()
|
||||
self.client = midonet_lib.MidoClient(self.mock_api)
|
||||
|
||||
def test_create_for_sg(self):
|
||||
tenant_id = 'test_tenant'
|
||||
sg_id = str(uuid.uuid4())
|
||||
sg_name = 'test_sg_name'
|
||||
calls = [mock.call.add_chain().tenant_id(tenant_id)]
|
||||
sg_id = uuidutils.generate_uuid()
|
||||
sg_name = 'test-sg'
|
||||
calls = [mock.call.add_chain().tenant_id(self._tenant_id),
|
||||
mock.call.add_port_group().tenant_id(self._tenant_id)]
|
||||
|
||||
self.mgr.create_for_sg(tenant_id, sg_id, sg_name)
|
||||
self.client.create_for_sg(self._tenant_id, sg_id, sg_name)
|
||||
|
||||
self.mock_api.assert_has_calls(calls)
|
||||
self.mock_api.assert_has_calls(calls, any_order=True)
|
||||
|
||||
def test_delete_for_sg(self):
|
||||
tenant_id = 'test_tenant'
|
||||
sg_id = str(uuid.uuid4())
|
||||
sg_name = 'test_sg_name'
|
||||
in_chain, out_chain = self._create_mock_chains(sg_id, sg_name)
|
||||
def test_create_for_sg_rule(self):
|
||||
sg_id = uuidutils.generate_uuid()
|
||||
sg_name = 'test-sg'
|
||||
in_chain_id = uuidutils.generate_uuid()
|
||||
out_chain_id = uuidutils.generate_uuid()
|
||||
self.mock_api_cfg.chains_in = [
|
||||
_create_test_sg_in_chain(sg_id, sg_name, in_chain_id,
|
||||
self._tenant_id),
|
||||
_create_test_sg_out_chain(sg_id, sg_name, out_chain_id,
|
||||
self._tenant_id)]
|
||||
|
||||
# Mock get_chains returned values
|
||||
self.mock_api.get_chains.return_value = [in_chain, out_chain]
|
||||
sg_rule_id = uuidutils.generate_uuid()
|
||||
sg_rule = _create_test_sg_rule(self._tenant_id, sg_id, sg_rule_id)
|
||||
|
||||
self.mgr.delete_for_sg(tenant_id, sg_id, sg_name)
|
||||
props = {"os_sg_rule_id": sg_rule_id}
|
||||
calls = [mock.call.add_rule().port_group(None).type(
|
||||
'accept').nw_proto(6).nw_src_address(
|
||||
'192.168.1.0').nw_src_length(24).tp_src_start(
|
||||
None).tp_src_end(None).tp_dst_start(1).tp_dst_end(
|
||||
65535).properties(props).create()]
|
||||
|
||||
self.mock_api.assert_has_calls(mock.call.get_chains(
|
||||
{"tenant_id": tenant_id}))
|
||||
in_chain.delete.assert_called_once_with()
|
||||
out_chain.delete.assert_called_once_with()
|
||||
self.client.create_for_sg_rule(sg_rule)
|
||||
|
||||
def test_get_router_chains(self):
|
||||
tenant_id = 'test_tenant'
|
||||
router_id = str(uuid.uuid4())
|
||||
in_chain, out_chain = self._create_mock_router_chains(router_id)
|
||||
|
||||
# Mock get_chains returned values
|
||||
self.mock_api.get_chains.return_value = [in_chain, out_chain]
|
||||
|
||||
chains = self.mgr.get_router_chains(tenant_id, router_id)
|
||||
|
||||
self.mock_api.assert_has_calls(mock.call.get_chains(
|
||||
{"tenant_id": tenant_id}))
|
||||
self.assertEqual(len(chains), 2)
|
||||
self.assertEqual(chains['in'], in_chain)
|
||||
self.assertEqual(chains['out'], out_chain)
|
||||
# Egress chain rule added
|
||||
self.mock_api_cfg.chains_out[0].assert_has_calls(calls)
|
||||
|
||||
def test_create_router_chains(self):
|
||||
tenant_id = 'test_tenant'
|
||||
router_id = str(uuid.uuid4())
|
||||
calls = [mock.call.add_chain().tenant_id(tenant_id)]
|
||||
router = mock_lib.get_router_mock(tenant_id=self._tenant_id)
|
||||
api_calls = [mock.call.add_chain().tenant_id(self._tenant_id)]
|
||||
router_calls = [
|
||||
mock.call.inbound_filter_id().outbound_filter_id().update()]
|
||||
|
||||
self.mgr.create_router_chains(tenant_id, router_id)
|
||||
self.client.create_router_chains(router)
|
||||
|
||||
self.mock_api.assert_has_calls(api_calls)
|
||||
router.assert_has_calls(router_calls)
|
||||
|
||||
def test_delete_for_sg(self):
|
||||
sg_id = uuidutils.generate_uuid()
|
||||
sg_name = 'test-sg'
|
||||
in_chain_id = uuidutils.generate_uuid()
|
||||
out_chain_id = uuidutils.generate_uuid()
|
||||
pg_id = uuidutils.generate_uuid()
|
||||
self.mock_api_cfg.chains_in = [
|
||||
_create_test_sg_in_chain(sg_id, sg_name, in_chain_id,
|
||||
self._tenant_id),
|
||||
_create_test_sg_out_chain(sg_id, sg_name, out_chain_id,
|
||||
self._tenant_id)]
|
||||
self.mock_api_cfg.port_groups_in = [
|
||||
_create_test_port_group(sg_id, sg_name, pg_id, self._tenant_id)]
|
||||
|
||||
calls = [mock.call.get_chains({"tenant_id": self._tenant_id}),
|
||||
mock.call.delete_chain(in_chain_id),
|
||||
mock.call.delete_chain(out_chain_id),
|
||||
mock.call.get_port_groups({"tenant_id": self._tenant_id}),
|
||||
mock.call.delete_port_group(pg_id)]
|
||||
|
||||
self.client.delete_for_sg(self._tenant_id, sg_id, sg_name)
|
||||
|
||||
self.mock_api.assert_has_calls(calls)
|
||||
|
||||
def test_get_sg_chains(self):
|
||||
tenant_id = 'test_tenant'
|
||||
sg_id = str(uuid.uuid4())
|
||||
in_chain, out_chain = self._create_mock_chains(sg_id, 'foo')
|
||||
def test_delete_for_sg_rule(self):
|
||||
sg_id = uuidutils.generate_uuid()
|
||||
sg_name = 'test-sg'
|
||||
in_chain_id = uuidutils.generate_uuid()
|
||||
out_chain_id = uuidutils.generate_uuid()
|
||||
self.mock_api_cfg.chains_in = [
|
||||
_create_test_sg_in_chain(sg_id, sg_name, in_chain_id,
|
||||
self._tenant_id),
|
||||
_create_test_sg_out_chain(sg_id, sg_name, out_chain_id,
|
||||
self._tenant_id)]
|
||||
|
||||
# Mock get_chains returned values
|
||||
self.mock_api.get_chains.return_value = [in_chain, out_chain]
|
||||
rule_id = uuidutils.generate_uuid()
|
||||
sg_rule_id = uuidutils.generate_uuid()
|
||||
rule = _create_test_sg_chain_rule(rule_id, in_chain_id, sg_rule_id)
|
||||
self.mock_api_cfg.chains_in[0]['rules'] = [rule]
|
||||
sg_rule = _create_test_sg_rule(self._tenant_id, sg_id, sg_rule_id)
|
||||
|
||||
chains = self.mgr.get_sg_chains(tenant_id, sg_id)
|
||||
self.client.delete_for_sg_rule(sg_rule)
|
||||
|
||||
self.mock_api.assert_has_calls(mock.call.get_chains(
|
||||
{"tenant_id": tenant_id}))
|
||||
self.assertEqual(len(chains), 2)
|
||||
self.assertEqual(chains['in'], in_chain)
|
||||
self.assertEqual(chains['out'], out_chain)
|
||||
self.mock_api.delete_rule.assert_called_once_with(rule_id)
|
||||
|
||||
def test_get_bridge(self):
|
||||
bridge_id = uuidutils.generate_uuid()
|
||||
|
||||
class MidonetPortGroupManagerTestCase(MidonetLibTestCase):
|
||||
bridge = self.client.get_bridge(bridge_id)
|
||||
|
||||
def setUp(self):
|
||||
super(MidonetPortGroupManagerTestCase, self).setUp()
|
||||
self.mgr = midonet_lib.PortGroupManager(self.mock_api)
|
||||
self.assertIsNotNone(bridge)
|
||||
self.assertEqual(bridge.get_id(), bridge_id)
|
||||
|
||||
def test_create(self):
|
||||
tenant_id = 'test_tenant'
|
||||
sg_id = str(uuid.uuid4())
|
||||
sg_name = 'test_sg'
|
||||
pg_mock = self._create_mock_port_group(sg_id, sg_name)
|
||||
rv = self.mock_api.add_port_group.return_value.tenant_id.return_value
|
||||
rv.name.return_value = pg_mock
|
||||
def test_get_bridge_error(self):
|
||||
self.mock_api.get_bridge.side_effect = w_exc.HTTPInternalServerError()
|
||||
self.assertRaises(midonet_lib.MidonetApiException,
|
||||
self.client.get_bridge, uuidutils.generate_uuid())
|
||||
|
||||
self.mgr.create(tenant_id, sg_id, sg_name)
|
||||
def test_get_bridge_not_found(self):
|
||||
self.mock_api.get_bridge.side_effect = w_exc.HTTPNotFound()
|
||||
self.assertRaises(midonet_lib.MidonetResourceNotFound,
|
||||
self.client.get_bridge, uuidutils.generate_uuid())
|
||||
|
||||
pg_mock.create.assert_called_once_with()
|
||||
def test_get_port_groups_for_sg(self):
|
||||
sg_id = uuidutils.generate_uuid()
|
||||
pg_id = uuidutils.generate_uuid()
|
||||
self.mock_api_cfg.port_groups_in = [
|
||||
_create_test_port_group(sg_id, 'test-sg', pg_id, self._tenant_id)]
|
||||
|
||||
def test_delete(self):
|
||||
tenant_id = 'test_tenant'
|
||||
sg_id = str(uuid.uuid4())
|
||||
sg_name = 'test_sg'
|
||||
pg_mock1 = self._create_mock_port_group(sg_id, sg_name)
|
||||
pg_mock2 = self._create_mock_port_group(sg_id, sg_name)
|
||||
self.mock_api.get_port_groups.return_value = [pg_mock1, pg_mock2]
|
||||
pg = self.client.get_port_groups_for_sg(self._tenant_id, sg_id)
|
||||
|
||||
self.mgr.delete(tenant_id, sg_id, sg_name)
|
||||
|
||||
self.mock_api.assert_has_calls(mock.call.get_port_groups(
|
||||
{"tenant_id": tenant_id}))
|
||||
pg_mock1.delete.assert_called_once_with()
|
||||
pg_mock2.delete.assert_called_once_with()
|
||||
|
||||
def test_get_for_sg(self):
|
||||
tenant_id = 'test_tenant'
|
||||
sg_id = str(uuid.uuid4())
|
||||
pg_mock = self._create_mock_port_group(sg_id, 'foo')
|
||||
self.mock_api.get_port_groups.return_value = [pg_mock]
|
||||
|
||||
pg = self.mgr.get_for_sg(tenant_id, sg_id)
|
||||
|
||||
self.assertEqual(pg, pg_mock)
|
||||
|
||||
|
||||
class MidonetRuleManagerTestCase(MidonetLibTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(MidonetRuleManagerTestCase, self).setUp()
|
||||
self.mgr = midonet_lib.RuleManager(self.mock_api)
|
||||
self.mgr.chain_manager = mock.Mock()
|
||||
self.mgr.pg_manager = mock.Mock()
|
||||
self.assertIsNotNone(pg)
|
||||
self.assertEqual(pg.get_id(), pg_id)
|
||||
|
||||
def _create_test_rule(self, tenant_id, sg_id, rule_id, direction="egress",
|
||||
protocol="tcp", port_min=1, port_max=65535,
|
||||
@ -198,41 +226,53 @@ class MidonetRuleManagerTestCase(MidonetLibTestCase):
|
||||
"port_range_min": port_min, "port_range_max": port_max,
|
||||
"ethertype": ethertype, "id": rule_id, "external_id": None}
|
||||
|
||||
def test_create_for_sg_rule(self):
|
||||
tenant_id = 'test_tenant'
|
||||
sg_id = str(uuid.uuid4())
|
||||
rule_id = str(uuid.uuid4())
|
||||
in_chain, out_chain = self._create_mock_chains(sg_id, 'foo')
|
||||
self.mgr.chain_manager.get_sg_chains.return_value = {"in": in_chain,
|
||||
"out": out_chain}
|
||||
props = {"os_sg_rule_id": rule_id}
|
||||
rule = self._create_test_rule(tenant_id, sg_id, rule_id)
|
||||
calls = [mock.call.add_rule().port_group(None).type(
|
||||
'accept').nw_proto(6).nw_src_address(
|
||||
'192.168.1.0').nw_src_length(24).tp_src_start(
|
||||
None).tp_src_end(None).tp_dst_start(1).tp_dst_end(
|
||||
65535).properties(props).create()]
|
||||
def test_get_router_error(self):
|
||||
self.mock_api.get_router.side_effect = w_exc.HTTPInternalServerError()
|
||||
self.assertRaises(midonet_lib.MidonetApiException,
|
||||
self.client.get_router, uuidutils.generate_uuid())
|
||||
|
||||
self.mgr.create_for_sg_rule(rule)
|
||||
def test_get_router_not_found(self):
|
||||
self.mock_api.get_router.side_effect = w_exc.HTTPNotFound()
|
||||
self.assertRaises(midonet_lib.MidonetResourceNotFound,
|
||||
self.client.get_router, uuidutils.generate_uuid())
|
||||
|
||||
in_chain.assert_has_calls(calls)
|
||||
def test_get_router_chains(self):
|
||||
router_id = uuidutils.generate_uuid()
|
||||
in_chain_id = uuidutils.generate_uuid()
|
||||
out_chain_id = uuidutils.generate_uuid()
|
||||
self.mock_api_cfg.chains_in = [
|
||||
_create_test_router_in_chain(router_id, in_chain_id,
|
||||
self._tenant_id),
|
||||
_create_test_router_out_chain(router_id, out_chain_id,
|
||||
self._tenant_id)]
|
||||
|
||||
def test_delete_for_sg_rule(self):
|
||||
tenant_id = 'test_tenant'
|
||||
sg_id = str(uuid.uuid4())
|
||||
rule_id = str(uuid.uuid4())
|
||||
in_chain, out_chain = self._create_mock_chains(sg_id, 'foo')
|
||||
self.mgr.chain_manager.get_sg_chains.return_value = {"in": in_chain,
|
||||
"out": out_chain}
|
||||
chains = self.client.get_router_chains(self._tenant_id, router_id)
|
||||
|
||||
# Mock the rules returned for each chain
|
||||
mock_rule_in = self._create_mock_rule(rule_id)
|
||||
mock_rule_out = self._create_mock_rule(rule_id)
|
||||
in_chain.get_rules.return_value = [mock_rule_in]
|
||||
out_chain.get_rules.return_value = [mock_rule_out]
|
||||
self.mock_api.assert_has_calls(mock.call.get_chains(
|
||||
{"tenant_id": self._tenant_id}))
|
||||
self.assertEqual(len(chains), 2)
|
||||
self.assertIn('in', chains)
|
||||
self.assertIn('out', chains)
|
||||
self.assertEqual(chains['in'].get_id(), in_chain_id)
|
||||
self.assertEqual(chains['out'].get_id(), out_chain_id)
|
||||
|
||||
rule = self._create_test_rule(tenant_id, sg_id, rule_id)
|
||||
self.mgr.delete_for_sg_rule(rule)
|
||||
def test_get_sg_chains(self):
|
||||
sg_id = uuidutils.generate_uuid()
|
||||
sg_name = 'test-sg'
|
||||
in_chain_id = uuidutils.generate_uuid()
|
||||
out_chain_id = uuidutils.generate_uuid()
|
||||
self.mock_api_cfg.chains_in = [
|
||||
_create_test_sg_in_chain(sg_id, sg_name, in_chain_id,
|
||||
self._tenant_id),
|
||||
_create_test_sg_out_chain(sg_id, sg_name, out_chain_id,
|
||||
self._tenant_id)]
|
||||
|
||||
mock_rule_in.delete.assert_called_once_with()
|
||||
mock_rule_out.delete.assert_called_once_with()
|
||||
chains = self.client.get_sg_chains(self._tenant_id, sg_id)
|
||||
|
||||
self.mock_api.assert_has_calls(mock.call.get_chains(
|
||||
{"tenant_id": self._tenant_id}))
|
||||
self.assertEqual(len(chains), 2)
|
||||
self.assertIn('in', chains)
|
||||
self.assertIn('out', chains)
|
||||
self.assertEqual(chains['in'].get_id(), in_chain_id)
|
||||
self.assertEqual(chains['out'].get_id(), out_chain_id)
|
||||
|
@ -20,16 +20,18 @@
|
||||
# @author: Ryu Ishimoto, Midokura Japan KK
|
||||
# @author: Tomoe Sugihara, Midokura Japan KK
|
||||
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
import os
|
||||
import sys
|
||||
|
||||
import quantum.common.test_lib as test_lib
|
||||
import quantum.tests.unit.midonet.mock_lib as mock_lib
|
||||
import quantum.tests.unit.test_db_plugin as test_plugin
|
||||
|
||||
|
||||
MIDOKURA_PKG_PATH = "quantum.plugins.midonet.plugin"
|
||||
|
||||
|
||||
# Need to mock the midonetclient module since the plugin will try to load it.
|
||||
sys.modules["midonetclient"] = mock.Mock()
|
||||
|
||||
@ -39,730 +41,83 @@ class MidonetPluginV2TestCase(test_plugin.QuantumDbPluginV2TestCase):
|
||||
_plugin_name = ('%s.MidonetPluginV2' % MIDOKURA_PKG_PATH)
|
||||
|
||||
def setUp(self):
|
||||
self.mock_api = mock.patch('midonetclient.api.MidonetApi')
|
||||
self.mock_api = mock.patch(
|
||||
'quantum.plugins.midonet.midonet_lib.MidoClient')
|
||||
etc_path = os.path.join(os.path.dirname(__file__), 'etc')
|
||||
test_lib.test_config['config_files'] = [os.path.join(
|
||||
etc_path, 'midonet.ini.test')]
|
||||
|
||||
self.instance = self.mock_api.start()
|
||||
mock_cfg = mock_lib.MidonetLibMockConfig(self.instance.return_value)
|
||||
mock_cfg.setup()
|
||||
super(MidonetPluginV2TestCase, self).setUp(self._plugin_name)
|
||||
|
||||
def tearDown(self):
|
||||
super(MidonetPluginV2TestCase, self).tearDown()
|
||||
self.mock_api.stop()
|
||||
|
||||
def _setup_bridge_mock(self, bridge_id=str(uuid.uuid4()), name='net'):
|
||||
# Set up mocks needed for the parent network() method
|
||||
bridge = mock.Mock()
|
||||
bridge.get_id.return_value = bridge_id
|
||||
bridge.get_name.return_value = name
|
||||
|
||||
self.instance.return_value.add_bridge.return_value.name.return_value\
|
||||
.tenant_id.return_value.create.return_value = bridge
|
||||
self.instance.return_value.get_bridges.return_value = [bridge]
|
||||
self.instance.return_value.get_bridge.return_value = bridge
|
||||
return bridge
|
||||
|
||||
def _setup_subnet_mocks(self, subnet_id=str(uuid.uuid4()),
|
||||
subnet_prefix='10.0.0.0', subnet_len=int(24)):
|
||||
# Set up mocks needed for the parent subnet() method
|
||||
bridge = self._setup_bridge_mock()
|
||||
subnet = mock.Mock()
|
||||
subnet.get_subnet_prefix.return_value = subnet_prefix
|
||||
subnet.get_subnet_length.return_value = subnet_len
|
||||
subnet.get_id.return_value = subnet_prefix + '/' + str(subnet_len)
|
||||
bridge.add_dhcp_subnet.return_value.default_gateway\
|
||||
.return_value.subnet_prefix.return_value.subnet_length\
|
||||
.return_value.create.return_value = subnet
|
||||
bridge.get_dhcp_subnets.return_value = [subnet]
|
||||
return (bridge, subnet)
|
||||
|
||||
def _setup_port_mocks(self, port_id=str(uuid.uuid4())):
|
||||
# Set up mocks needed for the parent port() method
|
||||
bridge, subnet = self._setup_subnet_mocks()
|
||||
port = mock.Mock()
|
||||
port.get_id.return_value = port_id
|
||||
self.instance.return_value.create_port.return_value = port
|
||||
self.instance.return_value.get_port.return_value = port
|
||||
bridge.add_exterior_port.return_value.create.return_value = (
|
||||
port
|
||||
)
|
||||
|
||||
dhcp_host = mock.Mock()
|
||||
rv1 = subnet.add_dhcp_host.return_value.ip_addr.return_value
|
||||
rv1.mac_addr.return_value.create.return_value = dhcp_host
|
||||
|
||||
subnet.get_dhcp_hosts.return_value = [dhcp_host]
|
||||
return (bridge, subnet, port, dhcp_host)
|
||||
|
||||
|
||||
class TestMidonetNetworksV2(test_plugin.TestNetworksV2,
|
||||
MidonetPluginV2TestCase):
|
||||
|
||||
def test_create_network(self):
|
||||
self._setup_bridge_mock()
|
||||
super(TestMidonetNetworksV2, self).test_create_network()
|
||||
|
||||
def test_create_public_network(self):
|
||||
self._setup_bridge_mock()
|
||||
super(TestMidonetNetworksV2, self).test_create_public_network()
|
||||
|
||||
def test_create_public_network_no_admin_tenant(self):
|
||||
self._setup_bridge_mock()
|
||||
super(TestMidonetNetworksV2,
|
||||
self).test_create_public_network_no_admin_tenant()
|
||||
|
||||
def test_update_network(self):
|
||||
self._setup_bridge_mock()
|
||||
super(TestMidonetNetworksV2, self).test_update_network()
|
||||
|
||||
def test_list_networks(self):
|
||||
self._setup_bridge_mock()
|
||||
with self.network(name='net1') as net1:
|
||||
req = self.new_list_request('networks')
|
||||
res = self.deserialize('json', req.get_response(self.api))
|
||||
self.assertEqual(res['networks'][0]['name'],
|
||||
net1['network']['name'])
|
||||
|
||||
def test_show_network(self):
|
||||
self._setup_bridge_mock()
|
||||
super(TestMidonetNetworksV2, self).test_show_network()
|
||||
|
||||
def test_update_shared_network_noadmin_returns_403(self):
|
||||
self._setup_bridge_mock()
|
||||
super(TestMidonetNetworksV2,
|
||||
self).test_update_shared_network_noadmin_returns_403()
|
||||
|
||||
def test_update_network_set_shared(self):
|
||||
pass
|
||||
|
||||
def test_update_network_with_subnet_set_shared(self):
|
||||
pass
|
||||
|
||||
def test_update_network_set_not_shared_single_tenant(self):
|
||||
pass
|
||||
|
||||
def test_update_network_set_not_shared_other_tenant_returns_409(self):
|
||||
pass
|
||||
|
||||
def test_update_network_set_not_shared_multi_tenants_returns_409(self):
|
||||
pass
|
||||
|
||||
def test_update_network_set_not_shared_multi_tenants2_returns_409(self):
|
||||
pass
|
||||
|
||||
def test_create_networks_bulk_native(self):
|
||||
pass
|
||||
|
||||
def test_create_networks_bulk_native_quotas(self):
|
||||
pass
|
||||
|
||||
def test_create_networks_bulk_tenants_and_quotas(self):
|
||||
pass
|
||||
|
||||
def test_create_networks_bulk_tenants_and_quotas_fail(self):
|
||||
pass
|
||||
|
||||
def test_create_networks_bulk_emulated(self):
|
||||
pass
|
||||
|
||||
def test_create_networks_bulk_wrong_input(self):
|
||||
pass
|
||||
|
||||
def test_create_networks_bulk_emulated_plugin_failure(self):
|
||||
pass
|
||||
|
||||
def test_create_networks_bulk_native_plugin_failure(self):
|
||||
pass
|
||||
|
||||
def test_list_networks_with_parameters(self):
|
||||
pass
|
||||
|
||||
def test_list_networks_with_fields(self):
|
||||
pass
|
||||
|
||||
def test_list_networks_with_parameters_invalid_values(self):
|
||||
pass
|
||||
|
||||
def test_list_shared_networks_with_non_admin_user(self):
|
||||
pass
|
||||
|
||||
def test_show_network_with_subnet(self):
|
||||
pass
|
||||
|
||||
def test_invalid_admin_status(self):
|
||||
pass
|
||||
|
||||
def test_list_networks_with_pagination_emulated(self):
|
||||
pass
|
||||
|
||||
def test_list_networks_with_pagination_reverse_emulated(self):
|
||||
pass
|
||||
|
||||
def test_list_networks_with_sort_emulated(self):
|
||||
pass
|
||||
|
||||
def test_list_networks_without_pk_in_fields_pagination_emulated(self):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class TestMidonetSubnetsV2(test_plugin.TestSubnetsV2,
|
||||
MidonetPluginV2TestCase):
|
||||
|
||||
def test_create_subnet(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet()
|
||||
|
||||
def test_create_two_subnets(self):
|
||||
pass
|
||||
|
||||
def test_create_two_subnets_same_cidr_returns_400(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_bad_V4_cidr(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_V4_cidr()
|
||||
|
||||
def test_create_subnet_bad_V6_cidr(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_V4_cidr()
|
||||
|
||||
def test_create_2_subnets_overlapping_cidr_allowed_returns_200(self):
|
||||
pass
|
||||
|
||||
def test_create_2_subnets_overlapping_cidr_not_allowed_returns_400(self):
|
||||
pass
|
||||
|
||||
def test_create_subnets_bulk_native(self):
|
||||
pass
|
||||
|
||||
def test_create_subnets_bulk_emulated(self):
|
||||
pass
|
||||
|
||||
def test_create_subnets_bulk_emulated_plugin_failure(self):
|
||||
pass
|
||||
|
||||
def test_create_subnets_bulk_native_plugin_failure(self):
|
||||
pass
|
||||
|
||||
def test_delete_subnet(self):
|
||||
_bridge, subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_delete_subnet()
|
||||
subnet.delete.assert_called_once_with()
|
||||
|
||||
def test_delete_subnet_port_exists_owned_by_network(self):
|
||||
_bridge, subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_delete_subnet_port_exists_owned_by_network()
|
||||
|
||||
def test_delete_subnet_port_exists_owned_by_other(self):
|
||||
pass
|
||||
|
||||
def test_delete_network(self):
|
||||
bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_delete_network()
|
||||
bridge.delete.assert_called_once_with()
|
||||
|
||||
def test_create_subnet_bad_tenant(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_tenant()
|
||||
|
||||
def test_create_subnet_bad_ip_version(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_ip_version()
|
||||
|
||||
def test_create_subnet_bad_ip_version_null(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_bad_ip_version_null()
|
||||
|
||||
def test_create_subnet_bad_uuid(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_uuid()
|
||||
|
||||
def test_create_subnet_bad_boolean(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_boolean()
|
||||
|
||||
def test_create_subnet_bad_pools(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_pools()
|
||||
|
||||
def test_create_subnet_bad_nameserver(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_nameserver()
|
||||
|
||||
def test_create_subnet_bad_hostroutes(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_bad_hostroutes()
|
||||
|
||||
def test_create_subnet_defaults(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_defaults()
|
||||
|
||||
def test_create_subnet_gw_values(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_gw_values()
|
||||
|
||||
def test_create_subnet_gw_outside_cidr_force_on_returns_400(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_gw_outside_cidr_force_on_returns_400()
|
||||
|
||||
def test_create_subnet_gw_of_network_force_on_returns_400(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_gw_of_network_force_on_returns_400()
|
||||
|
||||
def test_create_subnet_gw_bcast_force_on_returns_400(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_gw_bcast_force_on_returns_400()
|
||||
|
||||
def test_create_subnet_with_allocation_pool(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_with_allocation_pool()
|
||||
|
||||
def test_create_subnet_with_none_gateway(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_with_none_gateway()
|
||||
|
||||
def test_create_subnet_with_none_gateway_fully_allocated(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_with_none_gateway_fully_allocated()
|
||||
|
||||
def test_subnet_with_allocation_range(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_with_none_gateway_allocation_pool(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_with_none_gateway_allocation_pool()
|
||||
|
||||
def test_create_subnet_with_v6_allocation_pool(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_with_large_allocation_pool(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_multiple_allocation_pools(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_with_dhcp_disabled(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_default_gw_conflict_allocation_pool_returns_409(
|
||||
self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_gateway_in_allocation_pool_returns_409(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self)\
|
||||
.test_create_subnet_gateway_in_allocation_pool_returns_409()
|
||||
|
||||
def test_create_subnet_overlapping_allocation_pools_returns_409(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self)\
|
||||
.test_create_subnet_overlapping_allocation_pools_returns_409()
|
||||
|
||||
def test_create_subnet_invalid_allocation_pool_returns_400(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_invalid_allocation_pool_returns_400()
|
||||
|
||||
def test_create_subnet_out_of_range_allocation_pool_returns_400(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self)\
|
||||
.test_create_subnet_out_of_range_allocation_pool_returns_400()
|
||||
|
||||
def test_create_subnet_shared_returns_400(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_shared_returns_400()
|
||||
|
||||
# IPv6 is not supported by MidoNet yet. Ignore tests that attempt to
|
||||
# create IPv6 subnet.
|
||||
def test_create_subnet_inconsistent_ipv6_cidrv4(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_inconsistent_ipv4_cidrv6(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_inconsistent_ipv4_gatewayv6(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_inconsistent_ipv6_gatewayv4(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_inconsistent_ipv6_dns_v4(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_inconsistent_ipv4_hostroute_dst_v6(self):
|
||||
pass
|
||||
|
||||
def test_create_subnet_inconsistent_ipv4_hostroute_np_v6(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_update_subnet()
|
||||
|
||||
def test_update_subnet_shared_returns_400(self):
|
||||
self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_update_subnet_shared_returns_400()
|
||||
|
||||
def test_update_subnet_gw_outside_cidr_force_on_returns_400(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet_inconsistent_ipv4_gatewayv6(self):
|
||||
def test_create_subnet_with_v6_allocation_pool(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet_inconsistent_ipv6_gatewayv4(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet_inconsistent_ipv4_dns_v6(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
|
||||
pass
|
||||
|
||||
def test_show_subnet(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_show_subnet()
|
||||
|
||||
def test_list_subnets(self):
|
||||
def test_create_subnet_inconsistent_ipv6_gatewayv4(self):
|
||||
pass
|
||||
|
||||
def test_list_subnets_shared(self):
|
||||
# Multiple subnets in a network is not supported by MidoNet yet. Ignore
|
||||
# tests that attempt to create them.
|
||||
|
||||
def test_create_subnets_bulk_emulated(self):
|
||||
pass
|
||||
|
||||
def test_create_two_subnets(self):
|
||||
pass
|
||||
|
||||
def test_list_subnets(self):
|
||||
pass
|
||||
|
||||
def test_list_subnets_with_parameter(self):
|
||||
pass
|
||||
|
||||
def test_invalid_ip_version(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_invalid_ip_version()
|
||||
|
||||
def test_invalid_subnet(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_invalid_subnet()
|
||||
|
||||
def test_invalid_ip_address(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_invalid_ip_address()
|
||||
|
||||
def test_invalid_uuid(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_invalid_uuid()
|
||||
|
||||
def test_create_subnet_with_one_dns(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_with_one_dns()
|
||||
|
||||
def test_create_subnet_with_two_dns(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_create_subnet_with_two_dns()
|
||||
|
||||
def test_create_subnet_with_too_many_dns(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_with_too_many_dns()
|
||||
|
||||
def test_create_subnet_with_one_host_route(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_with_one_host_route()
|
||||
|
||||
def test_create_subnet_with_two_host_routes(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_with_two_host_routes()
|
||||
|
||||
def test_create_subnet_with_too_many_routes(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_create_subnet_with_too_many_routes()
|
||||
|
||||
def test_update_subnet_dns(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_update_subnet_dns()
|
||||
|
||||
def test_update_subnet_dns_to_None(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_update_subnet_dns_to_None()
|
||||
|
||||
def test_update_subnet_dns_with_too_many_entries(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_update_subnet_dns_with_too_many_entries()
|
||||
|
||||
def test_update_subnet_route(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_update_subnet_route()
|
||||
|
||||
def test_update_subnet_route_to_None(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_update_subnet_route_to_None()
|
||||
|
||||
def test_update_subnet_route_with_too_many_entries(self):
|
||||
_bridge, _subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_update_subnet_route_with_too_many_entries()
|
||||
|
||||
def test_delete_subnet_with_dns(self):
|
||||
_bridge, subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_delete_subnet_with_dns()
|
||||
subnet.delete.assert_called_once_with()
|
||||
|
||||
def test_delete_subnet_with_route(self):
|
||||
_bridge, subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2, self).test_delete_subnet_with_route()
|
||||
subnet.delete.assert_called_once_with()
|
||||
|
||||
def test_delete_subnet_with_dns_and_route(self):
|
||||
_bridge, subnet = self._setup_subnet_mocks()
|
||||
super(TestMidonetSubnetsV2,
|
||||
self).test_delete_subnet_with_dns_and_route()
|
||||
subnet.delete.assert_called_once_with()
|
||||
|
||||
def test_update_subnet_gateway_in_allocation_pool_returns_409(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetSubnetsV2, self)\
|
||||
.test_update_subnet_gateway_in_allocation_pool_returns_409()
|
||||
|
||||
def test_list_subnets_with_pagination_emulated(self):
|
||||
pass
|
||||
|
||||
def test_list_subnets_with_pagination_reverse_emulated(self):
|
||||
pass
|
||||
|
||||
def test_list_subnets_with_sort_emulated(self):
|
||||
def test_create_two_subnets_same_cidr_returns_400(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestMidonetPortsV2(test_plugin.TestPortsV2,
|
||||
MidonetPluginV2TestCase):
|
||||
|
||||
def test_create_port_json(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_create_port_json()
|
||||
|
||||
def test_create_port_bad_tenant(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_create_port_bad_tenant()
|
||||
|
||||
def test_create_port_public_network(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_create_port_public_network()
|
||||
|
||||
def test_create_port_public_network_with_ip(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2,
|
||||
self).test_create_port_public_network_with_ip()
|
||||
|
||||
def test_create_ports_bulk_native(self):
|
||||
pass
|
||||
|
||||
def test_create_ports_bulk_emulated(self):
|
||||
pass
|
||||
|
||||
def test_create_ports_bulk_wrong_input(self):
|
||||
pass
|
||||
|
||||
def test_create_ports_bulk_emulated_plugin_failure(self):
|
||||
pass
|
||||
|
||||
def test_create_ports_bulk_native_plugin_failure(self):
|
||||
pass
|
||||
|
||||
def test_list_ports(self):
|
||||
pass
|
||||
|
||||
def test_list_ports_filtered_by_fixed_ip(self):
|
||||
pass
|
||||
|
||||
def test_list_ports_public_network(self):
|
||||
pass
|
||||
|
||||
def test_show_port(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_show_port()
|
||||
|
||||
def test_delete_port(self):
|
||||
_bridge, _subnet, port, _dhcp = self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_delete_port()
|
||||
port.delete.assert_called_once_with()
|
||||
|
||||
def test_delete_port_public_network(self):
|
||||
_bridge, _subnet, port, _dhcp = self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_delete_port_public_network()
|
||||
port.delete.assert_called_once_with()
|
||||
|
||||
def test_update_port(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_update_port()
|
||||
|
||||
def test_update_device_id_null(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_update_device_id_null()
|
||||
|
||||
def test_delete_network_if_port_exists(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_delete_network_if_port_exists()
|
||||
|
||||
def test_delete_network_port_exists_owned_by_network(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2,
|
||||
self).test_delete_network_port_exists_owned_by_network()
|
||||
|
||||
def test_update_port_delete_ip(self):
|
||||
pass
|
||||
|
||||
def test_no_more_port_exception(self):
|
||||
pass
|
||||
|
||||
def test_update_port_update_ip(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_update_port_update_ip()
|
||||
|
||||
def test_update_port_update_ip_address_only(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2,
|
||||
self).test_update_port_update_ip_address_only()
|
||||
|
||||
def test_update_port_update_ips(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_update_port_update_ips()
|
||||
|
||||
def test_update_port_add_additional_ip(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_update_port_add_additional_ip()
|
||||
|
||||
def test_requested_duplicate_mac(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_requested_duplicate_mac()
|
||||
|
||||
def test_mac_generation(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_mac_generation()
|
||||
|
||||
def test_mac_generation_4octet(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_mac_generation_4octet()
|
||||
|
||||
def test_bad_mac_format(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_bad_mac_format()
|
||||
|
||||
def test_mac_exhaustion(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_mac_exhaustion()
|
||||
|
||||
def test_requested_duplicate_ip(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_requested_duplicate_ip()
|
||||
|
||||
def test_requested_subnet_delete(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_requested_subnet_delete()
|
||||
|
||||
def test_requested_subnet_id(self):
|
||||
pass
|
||||
|
||||
def test_requested_subnet_id_not_on_network(self):
|
||||
pass
|
||||
|
||||
def test_overlapping_subnets(self):
|
||||
pass
|
||||
# IPv6 is not supported by MidoNet yet. Ignore tests that attempt to
|
||||
# create IPv6 subnet.
|
||||
|
||||
def test_requested_subnet_id_v4_and_v6(self):
|
||||
pass
|
||||
|
||||
def test_range_allocation(self):
|
||||
pass
|
||||
# Multiple subnets in a network is not supported by MidoNet yet. Ignore
|
||||
# tests that attempt to create them.
|
||||
|
||||
def test_requested_invalid_fixed_ips(self):
|
||||
pass
|
||||
|
||||
def test_invalid_ip(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_invalid_ip()
|
||||
|
||||
def test_requested_split(self):
|
||||
pass
|
||||
|
||||
def test_duplicate_ips(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_duplicate_ips()
|
||||
|
||||
def test_fixed_ip_invalid_subnet_id(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_fixed_ip_invalid_subnet_id()
|
||||
|
||||
def test_fixed_ip_invalid_ip(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_fixed_ip_invalid_ip()
|
||||
|
||||
def test_requested_ips_only(self):
|
||||
pass
|
||||
|
||||
def test_recycling(self):
|
||||
pass
|
||||
|
||||
def test_invalid_admin_state(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_invalid_admin_state()
|
||||
|
||||
def test_invalid_mac_address(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_invalid_mac_address()
|
||||
|
||||
def test_default_allocation_expiration(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_default_allocation_expiration()
|
||||
|
||||
def test_update_fixed_ip_lease_expiration(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2,
|
||||
self).test_update_fixed_ip_lease_expiration()
|
||||
|
||||
def test_port_delete_holds_ip(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_port_delete_holds_ip()
|
||||
|
||||
def test_update_fixed_ip_lease_expiration_invalid_address(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2,
|
||||
self).test_update_fixed_ip_lease_expiration_invalid_address()
|
||||
|
||||
def test_hold_ip_address(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_hold_ip_address()
|
||||
|
||||
def test_recycle_held_ip_address(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_recycle_held_ip_address()
|
||||
|
||||
def test_recycle_expired_previously_run_within_context(self):
|
||||
pass
|
||||
|
||||
def test_update_port_not_admin(self):
|
||||
self._setup_port_mocks()
|
||||
super(TestMidonetPortsV2, self).test_update_port_not_admin()
|
||||
|
||||
def test_list_ports_with_pagination_emulated(self):
|
||||
pass
|
||||
|
||||
def test_list_ports_with_pagination_reverse_emulated(self):
|
||||
pass
|
||||
|
||||
def test_list_ports_with_sort_emulated(self):
|
||||
pass
|
||||
|
||||
def test_max_fixed_ips_exceeded(self):
|
||||
pass
|
||||
|
||||
def test_update_max_fixed_ips_exceeded(self):
|
||||
pass
|
||||
def test_overlapping_subnets(self):
|
||||
pass
|
||||
|
Loading…
x
Reference in New Issue
Block a user