Merge "Change dhcp port creation mechanism"
This commit is contained in:
commit
7785d7725a
tricircle
common
network
tests
xjob
@ -438,6 +438,7 @@ class Client(object):
|
||||
resource -> args -> kwargs
|
||||
--------------------------
|
||||
router -> body -> none
|
||||
subnet -> body -> none
|
||||
--------------------------
|
||||
:return: a dict containing resource information
|
||||
:raises: EndpointNotAvailable
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -21,7 +21,9 @@ from oslotest import base
|
||||
CONFLICT_OPT_NAMES = [
|
||||
'api_extensions_path',
|
||||
'bind_port',
|
||||
'bind_host'
|
||||
'bind_host',
|
||||
'allow_pagination',
|
||||
'allow_sorting'
|
||||
]
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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')
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user