mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-25 06:10:22 -07:00
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
|
default: None
|
||||||
interfaces:
|
interfaces:
|
||||||
description:
|
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
|
required: false
|
||||||
default: None
|
default: None
|
||||||
availability_zone:
|
availability_zone:
|
||||||
|
@ -102,6 +112,45 @@ EXAMPLES = '''
|
||||||
interfaces:
|
interfaces:
|
||||||
- private-subnet
|
- 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.
|
# Update existing router1 external gateway to include the IPv6 subnet.
|
||||||
# Note that since 'interfaces' is not provided, any existing internal
|
# Note that since 'interfaces' is not provided, any existing internal
|
||||||
# interfaces on an existing router will be left intact.
|
# interfaces on an existing router will be left intact.
|
||||||
|
@ -191,7 +240,7 @@ def _router_internal_interfaces(cloud, router):
|
||||||
yield port
|
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.
|
"""Decide if the given router needs an update.
|
||||||
"""
|
"""
|
||||||
if router['admin_state_up'] != module.params['admin_state_up']:
|
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']:
|
for fixed_ip in port['fixed_ips']:
|
||||||
existing_subnet_ids.append(fixed_ip['subnet_id'])
|
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):
|
if set(internal_subnet_ids) != set(existing_subnet_ids):
|
||||||
|
internal_subnet_ids = []
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
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."""
|
"""Check if the system state would be changed."""
|
||||||
state = module.params['state']
|
state = module.params['state']
|
||||||
if state == 'absent' and router:
|
if state == 'absent' and router:
|
||||||
|
@ -250,7 +308,7 @@ def _system_state_change(cloud, module, router, network, internal_ids):
|
||||||
if state == 'present':
|
if state == 'present':
|
||||||
if not router:
|
if not router:
|
||||||
return True
|
return True
|
||||||
return _needs_update(cloud, module, router, network, internal_ids)
|
return _needs_update(cloud, module, router, network, internal_ids, internal_portids)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -284,6 +342,9 @@ def _build_kwargs(cloud, module, router, network):
|
||||||
def _validate_subnets(module, cloud):
|
def _validate_subnets(module, cloud):
|
||||||
external_subnet_ids = []
|
external_subnet_ids = []
|
||||||
internal_subnet_ids = []
|
internal_subnet_ids = []
|
||||||
|
internal_port_ids = []
|
||||||
|
existing_port_ips = []
|
||||||
|
existing_port_ids = []
|
||||||
if module.params['external_fixed_ips']:
|
if module.params['external_fixed_ips']:
|
||||||
for iface in module.params['external_fixed_ips']:
|
for iface in module.params['external_fixed_ips']:
|
||||||
subnet = cloud.get_subnet(iface['subnet'])
|
subnet = cloud.get_subnet(iface['subnet'])
|
||||||
|
@ -293,12 +354,34 @@ def _validate_subnets(module, cloud):
|
||||||
|
|
||||||
if module.params['interfaces']:
|
if module.params['interfaces']:
|
||||||
for iface in module.params['interfaces']:
|
for iface in module.params['interfaces']:
|
||||||
subnet = cloud.get_subnet(iface)
|
if isinstance(iface, str):
|
||||||
if not subnet:
|
subnet = cloud.get_subnet(iface)
|
||||||
module.fail_json(msg='subnet %s not found' % iface)
|
if not subnet:
|
||||||
internal_subnet_ids.append(subnet['id'])
|
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():
|
def main():
|
||||||
|
@ -355,11 +438,10 @@ def main():
|
||||||
|
|
||||||
# Validate and cache the subnet IDs so we can avoid duplicate checks
|
# Validate and cache the subnet IDs so we can avoid duplicate checks
|
||||||
# and expensive API calls.
|
# 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:
|
if module.check_mode:
|
||||||
module.exit_json(
|
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':
|
if state == 'present':
|
||||||
|
@ -370,11 +452,15 @@ def main():
|
||||||
if project_id:
|
if project_id:
|
||||||
kwargs['project_id'] = project_id
|
kwargs['project_id'] = project_id
|
||||||
router = cloud.create_router(**kwargs)
|
router = cloud.create_router(**kwargs)
|
||||||
for internal_subnet_id in internal_ids:
|
for int_s_id in subnet_internal_ids:
|
||||||
cloud.add_router_interface(router, subnet_id=internal_subnet_id)
|
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
|
changed = True
|
||||||
else:
|
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)
|
kwargs = _build_kwargs(cloud, module, router, net)
|
||||||
updated_router = cloud.update_router(**kwargs)
|
updated_router = cloud.update_router(**kwargs)
|
||||||
|
|
||||||
|
@ -385,13 +471,19 @@ def main():
|
||||||
|
|
||||||
# On a router update, if any internal interfaces were supplied,
|
# On a router update, if any internal interfaces were supplied,
|
||||||
# just detach all existing internal interfaces and attach the new.
|
# just detach all existing internal interfaces and attach the new.
|
||||||
elif internal_ids:
|
if internal_portids or subnet_internal_ids:
|
||||||
router = updated_router
|
router = updated_router
|
||||||
ports = _router_internal_interfaces(cloud, router)
|
ports = _router_internal_interfaces(cloud, router)
|
||||||
for port in ports:
|
for port in ports:
|
||||||
cloud.remove_router_interface(router, port_id=port['id'])
|
cloud.remove_router_interface(router, port_id=port['id'])
|
||||||
for internal_subnet_id in internal_ids:
|
if internal_portids:
|
||||||
cloud.add_router_interface(router, subnet_id=internal_subnet_id)
|
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
|
changed = True
|
||||||
|
|
||||||
module.exit_json(changed=changed,
|
module.exit_json(changed=changed,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue