Issue 19612 os router to allow adding interface by port ip (#30409)

* check if need update for internal port

* validate port ip

* os_router modified in local

* my_os_router.py tested upto port not found

* tested need update

*  default port attached with subnet getting deleted

* update happened with subnet and port id but rerun update=true?

* update working with portid converted subnetid for match checking

* tested and worked

* extra debug commnets cleaned up

* os_router with port ip tested fine

* deleted test files used wq for my development

* interface type changed for backward compatibility

* check if need update for internal port

* validate port ip

* os_router modified in local

* my_os_router.py tested upto port not found

* tested need update

*  default port attached with subnet getting deleted

* update happened with subnet and port id but rerun update=true?

* update working with portid converted subnetid for match checking

* tested and worked

* extra debug commnets cleaned up

* os_router with port ip tested fine

* deleted test files used wq for my development

* check if need update for internal port

* validate port ip

* os_router modified in local

* my_os_router.py tested upto port not found

* tested need update

*  default port attached with subnet getting deleted

* update happened with subnet and port id but rerun update=true?

* update working with portid converted subnetid for match checking

* tested and worked

* extra debug commnets cleaned up

* os_router with port ip tested fine

* deleted test files used wq for my development

* interface type changed for backward compatibility

* interface type changed for backward compatibility

* restoring requirement.txt which was deleted accidentally

* isinstance instead of type and white space removal

* trailing spaces removal

* multiple space after keyword 379,441

* fail.json interface type and deug msg changes

* test for membership should be 'not in'
This commit is contained in:
BhujayKumarBhatta 2017-11-28 20:16:08 +05:30 committed by Sam Doran
parent 9b5bd4094f
commit 452028ab7d

View file

@ -65,7 +65,17 @@ options:
default: None
interfaces:
description:
- List of subnets to attach to the router internal interface.
- List of subnets to attach to the router internal interface. Default
gateway associated with the subnet will be automatically attached
with the router's internal interface.
In order to provide an ip address different from the default
gateway,parameters are passed as dictionary with keys as network
name or ID(net), subnet name or ID (subnet) and the IP of
port (portip) from the network.
User defined portip is often required when a multiple router need
to be connected to a single subnet for which the default gateway has
been already used.
required: false
default: None
availability_zone:
@ -102,6 +112,45 @@ EXAMPLES = '''
interfaces:
- private-subnet
# Create another router with two internal subnet interfaces.One with user defined port
# ip and another with default gateway.
- os_router:
cloud: mycloud
state: present
name: router2
network: ext_network1
interfaces:
- net: private-net
subnet: private-subnet
portip: 10.1.1.10
- project-subnet
# Create another router with two internal subnet interface.One with user defined port
# ip and and another with default gateway.
- os_router:
cloud: mycloud
state: present
name: router2
network: ext_network1
interfaces:
- net: private-net
subnet: private-subnet
portip: 10.1.1.10
- project-subnet
# Create another router with two internal subnet interface. one with user defined port
# ip and and another with default gateway.
- os_router:
cloud: mycloud
state: present
name: router2
network: ext_network1
interfaces:
- net: private-net
subnet: private-subnet
portip: 10.1.1.10
- project-subnet
# Update existing router1 external gateway to include the IPv6 subnet.
# Note that since 'interfaces' is not provided, any existing internal
# interfaces on an existing router will be left intact.
@ -191,7 +240,7 @@ def _router_internal_interfaces(cloud, router):
yield port
def _needs_update(cloud, module, router, network, internal_subnet_ids):
def _needs_update(cloud, module, router, network, internal_subnet_ids, internal_port_ids):
"""Decide if the given router needs an update.
"""
if router['admin_state_up'] != module.params['admin_state_up']:
@ -236,13 +285,22 @@ def _needs_update(cloud, module, router, network, internal_subnet_ids):
for fixed_ip in port['fixed_ips']:
existing_subnet_ids.append(fixed_ip['subnet_id'])
for iface in module.params['interfaces']:
if isinstance(iface, dict):
for p_id in internal_port_ids:
p = cloud.get_port(name_or_id=p_id)
if 'fixed_ips' in p:
for fip in p['fixed_ips']:
internal_subnet_ids.append(fip['subnet_id'])
if set(internal_subnet_ids) != set(existing_subnet_ids):
internal_subnet_ids = []
return True
return False
def _system_state_change(cloud, module, router, network, internal_ids):
def _system_state_change(cloud, module, router, network, internal_ids, internal_portids):
"""Check if the system state would be changed."""
state = module.params['state']
if state == 'absent' and router:
@ -250,7 +308,7 @@ def _system_state_change(cloud, module, router, network, internal_ids):
if state == 'present':
if not router:
return True
return _needs_update(cloud, module, router, network, internal_ids)
return _needs_update(cloud, module, router, network, internal_ids, internal_portids)
return False
@ -284,6 +342,9 @@ def _build_kwargs(cloud, module, router, network):
def _validate_subnets(module, cloud):
external_subnet_ids = []
internal_subnet_ids = []
internal_port_ids = []
existing_port_ips = []
existing_port_ids = []
if module.params['external_fixed_ips']:
for iface in module.params['external_fixed_ips']:
subnet = cloud.get_subnet(iface['subnet'])
@ -293,12 +354,34 @@ def _validate_subnets(module, cloud):
if module.params['interfaces']:
for iface in module.params['interfaces']:
subnet = cloud.get_subnet(iface)
if not subnet:
module.fail_json(msg='subnet %s not found' % iface)
internal_subnet_ids.append(subnet['id'])
if isinstance(iface, str):
subnet = cloud.get_subnet(iface)
if not subnet:
module.fail_json(msg='subnet %s not found' % iface)
internal_subnet_ids.append(subnet['id'])
elif isinstance(iface, dict):
subnet = cloud.get_subnet(iface['subnet'])
if not subnet:
module.fail_json(msg='subnet %s not found' % iface['subnet'])
net = cloud.get_network(iface['net'])
if not net:
module.fail_json(msg='net %s not found' % iface['net'])
if "portip" not in iface:
internal_subnet_ids.append(subnet['id'])
elif not iface['portip']:
module.fail_json(msg='put an ip in portip or remove it from list to assign default port to router')
else:
for existing_port in cloud.list_ports(filters={'network_id': net.id}):
for fixed_ip in existing_port['fixed_ips']:
if iface['portip'] == fixed_ip['ip_address']:
internal_port_ids.append(existing_port.id)
existing_port_ips.append(fixed_ip['ip_address'])
if iface['portip'] not in existing_port_ips:
p = cloud.create_port(network_id=net.id, fixed_ips=[{'ip_address': iface['portip'], 'subnet_id': subnet.id}])
if p:
internal_port_ids.append(p.id)
return external_subnet_ids, internal_subnet_ids
return external_subnet_ids, internal_subnet_ids, internal_port_ids
def main():
@ -355,11 +438,10 @@ def main():
# Validate and cache the subnet IDs so we can avoid duplicate checks
# and expensive API calls.
external_ids, internal_ids = _validate_subnets(module, cloud)
external_ids, subnet_internal_ids, internal_portids = _validate_subnets(module, cloud)
if module.check_mode:
module.exit_json(
changed=_system_state_change(cloud, module, router, net, internal_ids)
changed=_system_state_change(cloud, module, router, net, subnet_internal_ids, internal_portids)
)
if state == 'present':
@ -370,11 +452,15 @@ def main():
if project_id:
kwargs['project_id'] = project_id
router = cloud.create_router(**kwargs)
for internal_subnet_id in internal_ids:
cloud.add_router_interface(router, subnet_id=internal_subnet_id)
for int_s_id in subnet_internal_ids:
cloud.add_router_interface(router, subnet_id=int_s_id)
changed = True
# add interface by port id as well
for int_p_id in internal_portids:
cloud.add_router_interface(router, port_id=int_p_id)
changed = True
else:
if _needs_update(cloud, module, router, net, internal_ids):
if _needs_update(cloud, module, router, net, subnet_internal_ids, internal_portids):
kwargs = _build_kwargs(cloud, module, router, net)
updated_router = cloud.update_router(**kwargs)
@ -385,13 +471,19 @@ def main():
# On a router update, if any internal interfaces were supplied,
# just detach all existing internal interfaces and attach the new.
elif internal_ids:
if internal_portids or subnet_internal_ids:
router = updated_router
ports = _router_internal_interfaces(cloud, router)
for port in ports:
cloud.remove_router_interface(router, port_id=port['id'])
for internal_subnet_id in internal_ids:
cloud.add_router_interface(router, subnet_id=internal_subnet_id)
if internal_portids:
external_ids, subnet_internal_ids, internal_portids = _validate_subnets(module, cloud)
for int_p_id in internal_portids:
cloud.add_router_interface(router, port_id=int_p_id)
changed = True
if subnet_internal_ids:
for s_id in subnet_internal_ids:
cloud.add_router_interface(router, subnet_id=s_id)
changed = True
module.exit_json(changed=changed,