Merge "Change dhcp port creation mechanism"

This commit is contained in:
Jenkins 2016-08-05 11:32:35 +00:00 committed by Gerrit Code Review
commit 7785d7725a
7 changed files with 83 additions and 150 deletions

View File

@ -438,6 +438,7 @@ class Client(object):
resource -> args -> kwargs
--------------------------
router -> body -> none
subnet -> body -> none
--------------------------
:return: a dict containing resource information
:raises: EndpointNotAvailable

View File

@ -118,7 +118,7 @@ class GlanceResourceHandle(ResourceHandle):
class NeutronResourceHandle(ResourceHandle):
service_type = cons.ST_NEUTRON
support_resource = {'network': LIST | CREATE | DELETE | GET,
'subnet': LIST | CREATE | DELETE | GET,
'subnet': LIST | CREATE | DELETE | GET | UPDATE,
'port': LIST | CREATE | DELETE | GET,
'router': LIST | CREATE | ACTION | GET | UPDATE,
'security_group': LIST | CREATE | GET,

View File

@ -21,8 +21,6 @@ import tricircle.common.context as t_context
import tricircle.common.lock_handle as t_lock
from tricircle.common import utils
import tricircle.db.api as db_api
from tricircle.db import core
from tricircle.db import models
# manually define these constants to avoid depending on neutron repos
@ -228,7 +226,7 @@ class NetworkHelper(object):
'cidr': t_subnet['cidr'],
'gateway_ip': t_subnet['gateway_ip'],
'allocation_pools': t_subnet['allocation_pools'],
'enable_dhcp': t_subnet['enable_dhcp'],
'enable_dhcp': False,
'tenant_id': project_id
}
}
@ -294,6 +292,8 @@ class NetworkHelper(object):
# subnet
subnet_map = {}
subnet_dhcp_map = {}
for subnet in t_subnets:
subnet_body = self.get_create_subnet_body(
project_id, subnet, b_net_id)
@ -301,11 +301,17 @@ class NetworkHelper(object):
t_ctx, project_id, pod, subnet, t_constants.RT_SUBNET,
subnet_body)
subnet_map[subnet['id']] = b_subnet_id
subnet_dhcp_map[subnet['id']] = subnet['enable_dhcp']
# dhcp port
for t_subnet_id, b_subnet_id in subnet_map.iteritems():
if not subnet_dhcp_map[t_subnet_id]:
continue
self.prepare_dhcp_port(t_ctx, project_id, pod, t_net['id'],
t_subnet_id, b_net_id, b_subnet_id)
b_client = self._get_client(pod['pod_name'])
b_client.update_subnets(t_ctx, b_subnet_id,
{'subnet': {'enable_dhcp': True}})
return b_net_id, subnet_map
@ -409,7 +415,6 @@ class NetworkHelper(object):
:return: None
"""
t_client = self._get_client()
b_client = self._get_client(b_pod['pod_name'])
t_dhcp_name = t_constants.dhcp_port_name % t_subnet_id
t_dhcp_port_body = {
@ -436,71 +441,7 @@ class NetworkHelper(object):
ctx, None, project_id, db_api.get_top_pod(ctx),
{'id': t_dhcp_name}, t_constants.RT_PORT, t_dhcp_port_body)
t_dhcp_port = t_client.get_ports(ctx, t_dhcp_port_id)
mappings = db_api.get_bottom_mappings_by_top_id(
ctx, t_dhcp_port['id'], t_constants.RT_PORT)
pod_list = [mapping[0]['pod_id'] for mapping in mappings]
if b_pod['pod_id'] in pod_list:
# mapping exists, skip this subnet
return
dhcp_port_filters = [
{'key': 'device_owner', 'comparator': 'eq',
'value': 'network:dhcp'},
{'key': 'network_id', 'comparator': 'eq',
'value': b_net_id},
]
dhcp_port_body = self._get_create_dhcp_port_body(
project_id, t_dhcp_port, b_subnet_id, b_net_id)
t_dhcp_ip = t_dhcp_port['fixed_ips'][0]['ip_address']
b_dhcp_port = None
try:
b_dhcp_port = b_client.create_ports(ctx, dhcp_port_body)
except Exception:
# examine if we conflicted with a dhcp port which was
# automatically created by bottom pod
b_dhcp_ports = b_client.list_ports(ctx,
dhcp_port_filters)
dhcp_port_match = False
for dhcp_port in b_dhcp_ports:
subnet_id = dhcp_port['fixed_ips'][0]['subnet_id']
ip = dhcp_port['fixed_ips'][0]['ip_address']
if b_subnet_id == subnet_id and t_dhcp_ip == ip:
with ctx.session.begin():
core.create_resource(
ctx, models.ResourceRouting,
{'top_id': t_dhcp_port['id'],
'bottom_id': dhcp_port['id'],
'pod_id': b_pod['pod_id'],
'project_id': project_id,
'resource_type': t_constants.RT_PORT})
dhcp_port_match = True
break
if not dhcp_port_match:
# so we didn't conflict with a dhcp port, raise exception
raise
if b_dhcp_port:
with ctx.session.begin():
core.create_resource(ctx, models.ResourceRouting,
{'top_id': t_dhcp_port['id'],
'bottom_id': b_dhcp_port['id'],
'pod_id': b_pod['pod_id'],
'project_id': project_id,
'resource_type': t_constants.RT_PORT})
# there is still one thing to do, there may be other dhcp ports
# created by bottom pod, we need to delete them
b_dhcp_ports = b_client.list_ports(ctx,
dhcp_port_filters)
remove_port_list = []
for dhcp_port in b_dhcp_ports:
subnet_id = dhcp_port['fixed_ips'][0]['subnet_id']
ip = dhcp_port['fixed_ips'][0]['ip_address']
if b_subnet_id == subnet_id and t_dhcp_ip != ip:
remove_port_list.append(dhcp_port['id'])
for dhcp_port_id in remove_port_list:
# NOTE(zhiyuan) dhcp agent will receive this port-delete
# notification and re-configure dhcp so our newly created
# dhcp port can be used
b_client.delete_ports(ctx, dhcp_port_id)
self.prepare_bottom_element(ctx, project_id, b_pod, t_dhcp_port,
t_constants.RT_PORT, dhcp_port_body)

View File

@ -21,7 +21,9 @@ from oslotest import base
CONFLICT_OPT_NAMES = [
'api_extensions_path',
'bind_port',
'bind_host'
'bind_host',
'allow_pagination',
'allow_sorting'
]

View File

@ -277,6 +277,9 @@ class FakeClient(object):
'comparator': 'eq',
'value': subnet_id}])[0]
def update_subnets(self, ctx, subnet_id, body):
pass
def create_ports(self, ctx, body):
return self.create_resources('port', ctx, body)
@ -615,6 +618,8 @@ class FakeSession(object):
if model_obj.__tablename__ not in RES_MAP:
return
model_dict = DotDict(model_obj._as_dict())
if 'project_id' in model_dict:
model_dict['tenant_id'] = model_dict['project_id']
if model_obj.__tablename__ == 'networks':
model_dict['subnets'] = []
@ -758,7 +763,10 @@ class FakePlugin(plugin.TricirclePlugin):
def _make_network_dict(self, network, fields=None,
process_extensions=True, context=None):
return _transform_az(network)
network = _transform_az(network)
if 'project_id' in network:
network['tenant_id'] = network['project_id']
return network
def _make_subnet_dict(self, subnet, fields=None, context=None):
return subnet
@ -781,7 +789,11 @@ class FakePlugin(plugin.TricirclePlugin):
'ip_address': allocation['ip_address']}]
else:
ret[key] = value
if 'project_id' in ret:
ret['tenant_id'] = ret['project_id']
return ret
if 'project_id' in port:
port['tenant_id'] = port['project_id']
return port
def _make_security_group_dict(self, security_group, fields=None):

View File

@ -233,6 +233,11 @@ class FakeClient(object):
'subnet', ctx,
[{'key': 'id', 'comparator': 'eq', 'value': subnet_id}])[0]
def update_subnets(self, ctx, subnet_id, body):
subnet = self.get_subnets(ctx, subnet_id)
for key, value in body['subnet'].iteritems():
subnet[key] = value
def get_ports(self, ctx, port_id):
return self.list_resources(
'port', ctx,
@ -416,33 +421,48 @@ class ServerTest(unittest.TestCase):
def _check_routes(self):
for res in (TOP_NETS, TOP_SUBNETS, BOTTOM_NETS, BOTTOM_SUBNETS):
self.assertEqual(1, len(res))
self.assertEqual(2, len(TOP_PORTS))
self.assertEqual(2, len(BOTTOM_PORTS))
enable_dhcp = TOP_SUBNETS[0]['enable_dhcp']
self.assertEqual(enable_dhcp, BOTTOM_SUBNETS[0]['enable_dhcp'])
port_num = 2 if enable_dhcp else 1
self.assertEqual(port_num, len(TOP_PORTS))
self.assertEqual(port_num, len(BOTTOM_PORTS))
with self.context.session.begin():
routes = core.query_resource(self.context,
models.ResourceRouting, [], [])
# bottom network, bottom subnet, bottom port, top dhcp, bottom dhcp
self.assertEqual(5, len(routes))
actual = [[], [], [], [], []]
actual[4].append(constants.dhcp_port_name % TOP_SUBNETS[0]['id'])
# bottom network, bottom subnet, bottom port, no top dhcp and bottom
# dhcp if dhcp disabled
entry_num = 5 if enable_dhcp else 3
self.assertEqual(entry_num, len(routes))
actual = [[], [], []]
if entry_num > 3:
actual.extend([[], []])
for region in ('t_region', 'b_region'):
actual[0].append(self.controller._get_client(
region).list_resources('network', self.context, [])[0]['id'])
actual[1].append(self.controller._get_client(
region).list_resources('subnet', self.context, [])[0]['id'])
t_ports = self.controller._get_client(
ports = self.controller._get_client(
region).list_resources('port', self.context, [])
if 'device_id' in t_ports[0]:
actual[2].append(t_ports[0]['id'])
actual[3].append(t_ports[1]['id'])
if region == 't_region':
actual[4].append(t_ports[0]['id'])
if 'device_id' not in ports[0]:
actual[2].append(ports[0]['id'])
else:
actual[2].append(t_ports[1]['id'])
actual[3].append(t_ports[0]['id'])
if region == 't_region':
actual[4].append(t_ports[1]['id'])
actual[2].append(ports[1]['id'])
if entry_num > 3:
actual[4].append(constants.dhcp_port_name % TOP_SUBNETS[0]['id'])
for region in ('t_region', 'b_region'):
ports = self.controller._get_client(
region).list_resources('port', self.context, [])
if 'device_id' in ports[0]:
actual[3].append(ports[0]['id'])
if region == 't_region':
actual[4].append(ports[0]['id'])
else:
actual[3].append(ports[1]['id'])
if region == 't_region':
actual[4].append(ports[1]['id'])
expect = [[route['top_id'], route['bottom_id']] for route in routes]
self.assertItemsEqual(expect, actual)
@ -463,6 +483,22 @@ class ServerTest(unittest.TestCase):
self.controller._handle_network(self.context, b_pod, net, [subnet])
self._check_routes()
def test_handle_network_dhcp_disable(self):
t_pod, b_pod = self._prepare_pod()
net = {'id': 'top_net_id', 'name': 'net'}
subnet = {'id': 'top_subnet_id',
'network_id': 'top_net_id',
'ip_version': 4,
'cidr': '10.0.0.0/24',
'gateway_ip': '10.0.0.1',
'allocation_pools': {'start': '10.0.0.2',
'end': '10.0.0.254'},
'enable_dhcp': False}
TOP_NETS.append(net)
TOP_SUBNETS.append(subnet)
self.controller._handle_network(self.context, b_pod, net, [subnet])
self._check_routes()
def test_handle_port(self):
t_pod, b_pod = self._prepare_pod()
net = {'id': 'top_net_id', 'name': 'net'}
@ -487,67 +523,6 @@ class ServerTest(unittest.TestCase):
self.controller._handle_port(self.context, b_pod, port)
self._check_routes()
def _test_handle_network_dhcp_port(self, dhcp_ip):
t_pod, b_pod = self._prepare_pod()
top_net_id = 'top_net_id'
bottom_net_id = 'bottom_net_id'
top_subnet_id = 'top_subnet_id'
bottom_subnet_id = 'bottom_subnet_id'
t_net = {'id': top_net_id, 'name': 'net'}
b_net = {'id': bottom_net_id}
t_subnet = {'id': top_subnet_id,
'network_id': top_net_id,
'ip_version': 4,
'cidr': '10.0.0.0/24',
'gateway_ip': '10.0.0.1',
'allocation_pools': {'start': '10.0.0.2',
'end': '10.0.0.254'},
'enable_dhcp': True}
b_subnet = {'id': bottom_subnet_id,
'network_id': bottom_net_id,
'ip_version': 4,
'cidr': '10.0.0.0/24',
'gateway_ip': '10.0.0.1',
'allocation_pools': {'start': '10.0.0.2',
'end': '10.0.0.254'},
'enable_dhcp': True}
b_dhcp_port = {'id': 'bottom_dhcp_port_id',
'network_id': bottom_net_id,
'fixed_ips': [
{'subnet_id': bottom_subnet_id,
'ip_address': dhcp_ip}
],
'mac_address': 'fa:16:3e:96:41:0a',
'binding:profile': {},
'device_id': 'reserved_dhcp_port',
'device_owner': 'network:dhcp'}
TOP_NETS.append(t_net)
TOP_SUBNETS.append(t_subnet)
BOTTOM_NETS.append(b_net)
BOTTOM_SUBNETS.append(b_subnet)
BOTTOM_PORTS.append(b_dhcp_port)
with self.context.session.begin():
core.create_resource(
self.context, models.ResourceRouting,
{'top_id': top_net_id, 'bottom_id': bottom_net_id,
'pod_id': b_pod['pod_id'], 'project_id': self.project_id,
'resource_type': 'network'})
core.create_resource(
self.context, models.ResourceRouting,
{'top_id': top_subnet_id, 'bottom_id': bottom_subnet_id,
'pod_id': b_pod['pod_id'], 'project_id': self.project_id,
'resource_type': 'subnet'})
self.controller._handle_network(self.context,
b_pod, t_net, [t_subnet])
self._check_routes()
def test_handle_network_dhcp_port_same_ip(self):
self._test_handle_network_dhcp_port('10.0.0.2')
def test_handle_network_dhcp_port_exist_diff_ip(self):
self._test_handle_network_dhcp_port('10.0.0.4')
@patch.object(pecan, 'response', new=FakeResponse)
@patch.object(FakeClient, 'create_servers')
@patch.object(context, 'extract_context_from_environ')

View File

@ -44,6 +44,8 @@ _TIMER_INTERVAL = 30
_TIMER_INTERVAL_MAX = 60
common_opts = [
cfg.StrOpt('host', default='tricircle.xhost',
help=_("The host name for RPC server")),
cfg.IntOpt('workers', default=1,
help=_("Number of workers")),
cfg.IntOpt('worker_handle_timeout', default=1800,