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:
parent
9b5bd4094f
commit
452028ab7d
1 changed files with 110 additions and 18 deletions
|
@ -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']:
|
||||
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,
|
||||
|
|
Loading…
Reference in a new issue