Skip to content

Commit

Permalink
Fix to create instance ip from subnet-uuid.
Browse files Browse the repository at this point in the history
Also modified the port_create function in vnc_opentstack to use this fix

Backported from the master branch

Closes-bug: #1369841

Change-Id: Id19efca8e0061a7564673b9e27ec3ba48172b00f
  • Loading branch information
anbu-enovance authored and Gerrit Code Review committed Oct 10, 2014
1 parent 8e8d9fe commit a269b01
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 25 deletions.
48 changes: 48 additions & 0 deletions src/config/api-server/tests/test_crud_basic.py
Expand Up @@ -372,6 +372,54 @@ def test_ip_alloc_on_link_local(self):
pass
# end test_ip_alloc_on_link_local

def test_alloc_with_subnet_id(self):
ipam_fixt = self.useFixture(NetworkIpamTestFixtureGen(self._vnc_lib))

subnet_vnc = IpamSubnetType(subnet=SubnetType('1.1.1.0', 24))
vnsn_data = VnSubnetsType([subnet_vnc])
subnet_vnc_1 = IpamSubnetType(subnet=SubnetType('2.2.2.0', 24),
default_gateway='2.2.2.128')
vnsn_data.add_ipam_subnets(subnet_vnc_1)
vn_fixt = self.useFixture(VirtualNetworkTestFixtureGen(self._vnc_lib,
network_ipam_ref_infos=[(ipam_fixt.getObj(), vnsn_data)]))
vn_fixt.getObj().set_router_external(True)
self._vnc_lib.virtual_network_update(vn_fixt.getObj())

vn_obj = self._vnc_lib.virtual_network_read(fq_name=vn_fixt.getobj().get_fq_name())
ipam_subnets = vn_obj.network_ipam_refs[0]['attr'].get_ipam_subnets()
# This should be using the first subnet, ie 1.1.1.x
iip_fixt_1 = self.useFixture(
InstanceIpTestFixtureGen(
self._vnc_lib, 'iip1', auto_prop_val=False,
virtual_network_refs=[vn_fixt.getObj()]))
self.assertEqual(iip_fixt_1.getObj().instance_ip_address[:6], "1.1.1.")

# This should be using the first subnet since its uuid is used
iip_fixt_2 = self.useFixture(
InstanceIpTestFixtureGen(
self._vnc_lib, 'iip2', auto_prop_val=False,
subnet_uuid=ipam_subnets[0].subnet_uuid,
virtual_network_refs=[vn_fixt.getObj()]))
self.assertEqual(iip_fixt_2.getObj().instance_ip_address[:6], "1.1.1.")

# Since second subnet's uuid is used, we should get IP from that
iip_fixt_3 = self.useFixture(
InstanceIpTestFixtureGen(
self._vnc_lib, 'iip3', auto_prop_val=False,
subnet_uuid=ipam_subnets[1].subnet_uuid,
virtual_network_refs=[vn_fixt.getObj()]))
self.assertEqual(iip_fixt_3.getObj().instance_ip_address[:6], "2.2.2.")

# Mismatched UUID and IP address combination, should catch an exception
with self.assertRaises(cfgm_common.exceptions.HttpError) as e:
iip_fixt_4 = self.useFixture(
InstanceIpTestFixtureGen(
self._vnc_lib, 'iip4', auto_prop_val=False,
subnet_uuid=ipam_subnets[1].subnet_uuid,
instance_ip_address='1.1.1.4',
virtual_network_refs=[vn_fixt.getObj()]))
#end test_alloc_with_subnet_id

# end class TestNetAddrAlloc


Expand Down
35 changes: 34 additions & 1 deletion src/config/api-server/vnc_cfg_ifmap.py
Expand Up @@ -24,6 +24,7 @@
import errno
import subprocess
import netaddr
from netaddr import IPNetwork
from bitarray import bitarray

from cfgm_common import ignore_exceptions
Expand Down Expand Up @@ -1507,7 +1508,36 @@ def match_uuid(self, obj_dict, obj_uuid):
return True

return False
# end
# end match_uuid

def _update_subnet_uuid(self, vn_dict):
vn_uuid = vn_dict['uuid']

def _get_subnet_key(subnet):
pfx = subnet['subnet']['ip_prefix']
pfx_len = subnet['subnet']['ip_prefix_len']

network = IPNetwork('%s/%s' % (pfx, pfx_len))
return '%s %s/%s' % (vn_uuid, str(network.ip), pfx_len)

ipam_refs = vn_dict['network_ipam_refs']
updated = False
for ipam in ipam_refs:
vnsn = ipam['attr']
subnets = vnsn['ipam_subnets']
for subnet in subnets:
if subnet.get('subnet_uuid'):
continue

subnet_key = _get_subnet_key(subnet)
subnet_uuid = self.useragent_kv_retrieve(subnet_key)
subnet['subnet_uuid'] = subnet_uuid
if not updated:
updated = True

if updated:
self._cassandra_db._cassandra_virtual_network_update(vn_uuid, vn_dict)
# end _update_subnet_uuid

def _dbe_resync(self, obj_uuid, obj_cols):
obj_type = None
Expand All @@ -1526,6 +1556,9 @@ def _dbe_resync(self, obj_uuid, obj_cols):
'logical_router',
router['uuid'])

if (obj_type == 'virtual_network' and
'network_ipam_refs' in obj_dict):
self._update_subnet_uuid(obj_dict)
except Exception as e:
self.config_object_error(
obj_uuid, None, obj_type, 'dbe_resync:cassandra_read', str(e))
Expand Down
40 changes: 39 additions & 1 deletion src/config/api-server/vnc_cfg_types.py
Expand Up @@ -155,6 +155,19 @@ def dbe_delete_notification(cls, obj_ids, obj_dict):
class InstanceIpServer(InstanceIpServerGen):
generate_default_instance = False

@classmethod
def _get_subnet_name(cls, vn_dict, subnet_uuid):
ipam_refs = vn_dict.get('network_ipam_refs', [])
subnet_name = None
for ipam in ipam_refs:
ipam_subnets = ipam['attr'].get('ipam_subnets', [])
for subnet in ipam_subnets:
if subnet['subnet_uuid'] == subnet_uuid:
subnet_dict = subnet['subnet']
subnet_name = subnet_dict['ip_prefix'] + '/' + str(
subnet_dict['ip_prefix_len'])
return subnet_name

@classmethod
def http_post_collection(cls, tenant_name, obj_dict, db_conn):
vn_fq_name = obj_dict['virtual_network_refs'][0]['to']
Expand All @@ -164,9 +177,19 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn):
return True, ""

req_ip = obj_dict.get("instance_ip_address", None)

vn_id = {'uuid': db_conn.fq_name_to_uuid('virtual-network', vn_fq_name)}
(read_ok, vn_dict) = db_conn.dbe_read('virtual-network', vn_id)
if not read_ok:
return (False, (500, 'Internal error : ' + pformat(vn_dict)))

subnet_uuid = obj_dict.get('subnet_uuid', None)
sub = cls._get_subnet_name(vn_dict, subnet_uuid) if subnet_uuid else None
if subnet_uuid and not sub:
return (False, (404, "Subnet id " + subnet_uuid + " not found"))
try:
ip_addr = cls.addr_mgmt.ip_alloc_req(
vn_fq_name, asked_ip_addr=req_ip)
vn_fq_name, sub=sub, asked_ip_addr=req_ip)
except Exception as e:
return (False, (500, str(e)))
obj_dict['instance_ip_address'] = ip_addr
Expand Down Expand Up @@ -343,6 +366,17 @@ def _check_route_targets(cls, obj_dict, db_conn):
return (True, '')
# end _check_route_targets

@classmethod
def _check_and_create_subnet_uuid(cls, vn_dict):
ipam_refs = vn_dict.get('network_ipam_refs', [])
for ipam in ipam_refs:
vnsn = ipam['attr']
subnets = vnsn['ipam_subnets']
for subnet in subnets:
if not subnet['subnet_uuid']:
subnet['subnet_uuid'] = str(uuid.uuid4())
# end _check_and_create_subnet_uuid

@classmethod
def http_post_collection(cls, tenant_name, obj_dict, db_conn):
try:
Expand All @@ -362,6 +396,8 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn):
if not ok:
return (False, (403, pformat(obj_dict['fq_name']) + ' : ' + quota_limit))

cls._check_and_create_subnet_uuid(obj_dict)

(ok, error) = cls._check_route_targets(obj_dict, db_conn)
if not ok:
return (False, (400, error))
Expand Down Expand Up @@ -417,6 +453,8 @@ def http_put(cls, id, fq_name, obj_dict, db_conn):
except Exception as e:
return (False, (500, str(e)))

cls._check_and_create_subnet_uuid(obj_dict)

(ok, error) = cls._check_route_targets(obj_dict, db_conn)
if not ok:
return (False, (400, error))
Expand Down
37 changes: 14 additions & 23 deletions src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py
Expand Up @@ -1170,17 +1170,13 @@ def _subnet_vnc_read_mapping(self, id=None, key=None):

#end _subnet_vnc_read_mapping

def _subnet_vnc_read_or_create_mapping(self, id=None, key=None):
if id:
return self._subnet_vnc_read_mapping(id=id)

def _subnet_vnc_read_or_create_mapping(self, id, key):
# if subnet was created outside of neutron handle it and create
# neutron representation now (lazily)
try:
return self._subnet_vnc_read_mapping(key=key)
except NoIdError:
subnet_id = str(uuid.uuid4())
self._subnet_vnc_create_mapping(subnet_id, key)
self._subnet_vnc_create_mapping(id, key)
return self._subnet_vnc_read_mapping(key=key)
#end _subnet_vnc_read_or_create_mapping

Expand Down Expand Up @@ -1242,10 +1238,7 @@ def _ip_address_to_subnet_id(self, ip_addr, net_obj, memo_req=None):
cidr = '%s/%s' % (subnet_vnc.subnet.get_ip_prefix(),
subnet_vnc.subnet.get_ip_prefix_len())
if IPAddress(ip_addr) in IPSet([cidr]):
subnet_key = self._subnet_vnc_get_key(subnet_vnc,
net_obj.uuid)
subnet_id = self._subnet_vnc_read_or_create_mapping(
key=subnet_key)
subnet_id = subnet_vnc.subnet_uuid
return subnet_id

return None
Expand All @@ -1260,10 +1253,7 @@ def _virtual_network_to_subnets(self, net_obj):
for ipam_ref in ipam_refs:
subnet_vncs = ipam_ref['attr'].get_ipam_subnets()
for subnet_vnc in subnet_vncs:
subnet_key = self._subnet_vnc_get_key(subnet_vnc,
net_obj.uuid)
subnet_id = self._subnet_vnc_read_or_create_mapping(
key=subnet_key)
subnet_id = subnet_vnc.subnet_uuid
cidr = '%s/%s' % (subnet_vnc.subnet.get_ip_prefix(),
subnet_vnc.subnet.get_ip_prefix_len())
ret_subnets.append({'id': subnet_id, 'cidr': cidr})
Expand Down Expand Up @@ -1709,7 +1699,8 @@ def _subnet_neutron_to_vnc(self, subnet_q):
addr_from_start=True,
dhcp_option_list=dhcp_option_list,
host_routes=host_route_list,
subnet_name=sn_name)
subnet_name=sn_name,
subnet_uuid=str(uuid.uuid4()))

return subnet_vnc
#end _subnet_neutron_to_vnc
Expand All @@ -1732,7 +1723,8 @@ def _subnet_vnc_to_neutron(self, subnet_vnc, net_obj, ipam_fq_name):
sn_q_dict['cidr'] = cidr

subnet_key = self._subnet_vnc_get_key(subnet_vnc, net_obj.uuid)
sn_id = self._subnet_vnc_read_or_create_mapping(key=subnet_key)
sn_id = self._subnet_vnc_read_or_create_mapping(id=subnet_vnc.subnet_uuid,
key=subnet_key)

sn_q_dict['id'] = sn_id

Expand Down Expand Up @@ -2738,7 +2730,7 @@ def subnet_create(self, subnet_q):

# allocate an id to the subnet and store mapping with
# api-server
subnet_id = str(uuid.uuid4())
subnet_id = subnet_vnc.subnet_uuid
self._subnet_vnc_create_mapping(subnet_id, subnet_key)

# Read in subnet from server to get updated values for gw etc.
Expand Down Expand Up @@ -3661,10 +3653,13 @@ def _ip_addr_in_net_id(self, ip_addr, net_id):
self._instance_ip_list(back_ref_id=[net_id])]
return ip_addr in net_ip_list

def _create_instance_ip(self, net_obj, port_obj, ip_addr=None):
def _create_instance_ip(self, net_obj, port_obj, ip_addr=None,
subnet_uuid=None):
ip_name = str(uuid.uuid4())
ip_obj = InstanceIp(name=ip_name)
ip_obj.uuid = ip_name
if subnet_uuid:
ip_obj.set_subnet_uuid(subnet_uuid)
ip_obj.set_virtual_machine_interface(port_obj)
ip_obj.set_virtual_network(net_obj)
if ip_addr:
Expand All @@ -3683,12 +3678,8 @@ def _port_create_instance_ip(self, net_obj, port_obj, port_q):
try:
ip_addr = fixed_ip.get('ip_address')
subnet_id = fixed_ip.get('subnet_id')
if not ip_addr and 'subnet_id' in fixed_ip:
subnet_key = self._subnet_vnc_read_mapping(id=subnet_id)
ip_addr = self._vnc_lib.virtual_network_ip_alloc(net_obj,
subnet=subnet_key.split()[1])[0]

ip_id = self._create_instance_ip(net_obj, port_obj, ip_addr)
ip_id = self._create_instance_ip(net_obj, port_obj, ip_addr, subnet_id)
created_iip_ids.append(ip_id)
except vnc_exc.HttpError as e:
# Resources are not available
Expand Down

0 comments on commit a269b01

Please sign in to comment.