diff options
Diffstat (limited to 'lib/ansible/modules/cloud/openstack/os_router.py')
-rw-r--r-- | lib/ansible/modules/cloud/openstack/os_router.py | 487 |
1 files changed, 0 insertions, 487 deletions
diff --git a/lib/ansible/modules/cloud/openstack/os_router.py b/lib/ansible/modules/cloud/openstack/os_router.py deleted file mode 100644 index 56abc21493..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_router.py +++ /dev/null @@ -1,487 +0,0 @@ -#!/usr/bin/python -# -# Copyright: Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_router -short_description: Create or delete routers from OpenStack -extends_documentation_fragment: openstack -version_added: "2.0" -author: "David Shrewsbury (@Shrews)" -description: - - Create or Delete routers from OpenStack. Although Neutron allows - routers to share the same name, this module enforces name uniqueness - to be more user friendly. -options: - state: - description: - - Indicate desired state of the resource - choices: ['present', 'absent'] - default: present - name: - description: - - Name to be give to the router - required: true - admin_state_up: - description: - - Desired admin state of the created or existing router. - type: bool - default: 'yes' - enable_snat: - description: - - Enable Source NAT (SNAT) attribute. - type: bool - network: - description: - - Unique name or ID of the external gateway network. - - required I(interfaces) or I(enable_snat) are provided. - project: - description: - - Unique name or ID of the project. - version_added: "2.2" - external_fixed_ips: - description: - - The IP address parameters for the external gateway network. Each - is a dictionary with the subnet name or ID (subnet) and the IP - address to assign on the subnet (ip). If no IP is specified, - one is automatically assigned from that subnet. - interfaces: - description: - - 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. - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: ["openstacksdk"] -''' - -EXAMPLES = ''' -# Create a simple router, not attached to a gateway or subnets. -- os_router: - cloud: mycloud - state: present - name: simple_router - -# Create a simple router, not attached to a gateway or subnets for a given project. -- os_router: - cloud: mycloud - state: present - name: simple_router - project: myproj - -# Creates a router attached to ext_network1 on an IPv4 subnet and one -# internal subnet interface. -- os_router: - cloud: mycloud - state: present - name: router1 - network: ext_network1 - external_fixed_ips: - - subnet: public-subnet - ip: 172.24.4.2 - 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. -- os_router: - cloud: mycloud - state: present - name: router1 - network: ext_network1 - external_fixed_ips: - - subnet: public-subnet - ip: 172.24.4.2 - - subnet: ipv6-public-subnet - ip: 2001:db8::3 - -# Delete router1 -- os_router: - cloud: mycloud - state: absent - name: router1 -''' - -RETURN = ''' -router: - description: Dictionary describing the router. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Router ID. - type: str - sample: "474acfe5-be34-494c-b339-50f06aa143e4" - name: - description: Router name. - type: str - sample: "router1" - admin_state_up: - description: Administrative state of the router. - type: bool - sample: true - status: - description: The router status. - type: str - sample: "ACTIVE" - tenant_id: - description: The tenant ID. - type: str - sample: "861174b82b43463c9edc5202aadc60ef" - external_gateway_info: - description: The external gateway parameters. - type: dict - sample: { - "enable_snat": true, - "external_fixed_ips": [ - { - "ip_address": "10.6.6.99", - "subnet_id": "4272cb52-a456-4c20-8f3c-c26024ecfa81" - } - ] - } - routes: - description: The extra routes configuration for L3 router. - type: list -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -ROUTER_INTERFACE_OWNERS = set([ - 'network:router_interface', - 'network:router_interface_distributed', - 'network:ha_router_replicated_interface' -]) - - -def _router_internal_interfaces(cloud, router): - for port in cloud.list_router_interfaces(router, 'internal'): - if port['device_owner'] in ROUTER_INTERFACE_OWNERS: - yield port - - -def _needs_update(cloud, module, router, network, internal_subnet_ids, internal_port_ids, filters=None): - """Decide if the given router needs an update. - """ - if router['admin_state_up'] != module.params['admin_state_up']: - return True - if router['external_gateway_info']: - # check if enable_snat is set in module params - if module.params['enable_snat'] is not None: - if router['external_gateway_info'].get('enable_snat', True) != module.params['enable_snat']: - return True - if network: - if not router['external_gateway_info']: - return True - elif router['external_gateway_info']['network_id'] != network['id']: - return True - - # check external interfaces - if module.params['external_fixed_ips']: - for new_iface in module.params['external_fixed_ips']: - subnet = cloud.get_subnet(new_iface['subnet'], filters) - exists = False - - # compare the requested interface with existing, looking for an existing match - for existing_iface in router['external_gateway_info']['external_fixed_ips']: - if existing_iface['subnet_id'] == subnet['id']: - if 'ip' in new_iface: - if existing_iface['ip_address'] == new_iface['ip']: - # both subnet id and ip address match - exists = True - break - else: - # only the subnet was given, so ip doesn't matter - exists = True - break - - # this interface isn't present on the existing router - if not exists: - return True - - # check internal interfaces - if module.params['interfaces']: - existing_subnet_ids = [] - for port in _router_internal_interfaces(cloud, router): - if 'fixed_ips' in port: - 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, internal_portids, filters=None): - """Check if the system state would be changed.""" - state = module.params['state'] - if state == 'absent' and router: - return True - if state == 'present': - if not router: - return True - return _needs_update(cloud, module, router, network, internal_ids, internal_portids, filters) - return False - - -def _build_kwargs(cloud, module, router, network): - kwargs = { - 'admin_state_up': module.params['admin_state_up'], - } - - if router: - kwargs['name_or_id'] = router['id'] - else: - kwargs['name'] = module.params['name'] - - if network: - kwargs['ext_gateway_net_id'] = network['id'] - # can't send enable_snat unless we have a network - if module.params.get('enable_snat') is not None: - kwargs['enable_snat'] = module.params['enable_snat'] - - if module.params['external_fixed_ips']: - kwargs['ext_fixed_ips'] = [] - for iface in module.params['external_fixed_ips']: - subnet = cloud.get_subnet(iface['subnet']) - d = {'subnet_id': subnet['id']} - if 'ip' in iface: - d['ip_address'] = iface['ip'] - kwargs['ext_fixed_ips'].append(d) - - return kwargs - - -def _validate_subnets(module, cloud, filters=None): - 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']) - if not subnet: - module.fail_json(msg='subnet %s not found' % iface['subnet']) - external_subnet_ids.append(subnet['id']) - - if module.params['interfaces']: - for iface in module.params['interfaces']: - if isinstance(iface, str): - subnet = cloud.get_subnet(iface, filters) - 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'], filters) - 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, internal_port_ids - - -def main(): - argument_spec = openstack_full_argument_spec( - state=dict(default='present', choices=['absent', 'present']), - name=dict(required=True), - admin_state_up=dict(type='bool', default=True), - enable_snat=dict(type='bool'), - network=dict(default=None), - interfaces=dict(type='list', default=None), - external_fixed_ips=dict(type='list', default=None), - project=dict(default=None) - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - state = module.params['state'] - name = module.params['name'] - network = module.params['network'] - project = module.params['project'] - - if module.params['external_fixed_ips'] and not network: - module.fail_json(msg='network is required when supplying external_fixed_ips') - - sdk, cloud = openstack_cloud_from_module(module) - try: - if project is not None: - proj = cloud.get_project(project) - if proj is None: - module.fail_json(msg='Project %s could not be found' % project) - project_id = proj['id'] - filters = {'tenant_id': project_id} - else: - project_id = None - filters = None - - router = cloud.get_router(name, filters=filters) - net = None - if network: - net = cloud.get_network(network) - if not net: - module.fail_json(msg='network %s not found' % network) - - # Validate and cache the subnet IDs so we can avoid duplicate checks - # and expensive API calls. - external_ids, subnet_internal_ids, internal_portids = _validate_subnets(module, cloud, filters) - if module.check_mode: - module.exit_json( - changed=_system_state_change(cloud, module, router, net, subnet_internal_ids, internal_portids, filters) - ) - - if state == 'present': - changed = False - - if not router: - kwargs = _build_kwargs(cloud, module, router, net) - if project_id: - kwargs['project_id'] = project_id - router = cloud.create_router(**kwargs) - 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, subnet_internal_ids, internal_portids, filters): - kwargs = _build_kwargs(cloud, module, router, net) - updated_router = cloud.update_router(**kwargs) - - # Protect against update_router() not actually - # updating the router. - if not updated_router: - changed = False - - # On a router update, if any internal interfaces were supplied, - # just detach all existing internal interfaces and attach the new. - 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']) - if internal_portids: - external_ids, subnet_internal_ids, internal_portids = _validate_subnets(module, cloud, filters) - 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, - router=router, - id=router['id']) - - elif state == 'absent': - if not router: - module.exit_json(changed=False) - else: - # We need to detach all internal interfaces on a router before - # we will be allowed to delete it. - ports = _router_internal_interfaces(cloud, router) - router_id = router['id'] - for port in ports: - cloud.remove_router_interface(router, port_id=port['id']) - cloud.delete_router(router_id) - module.exit_json(changed=True) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() |