--- # Ensure clean environment - name: Ensure router doesn't exist before tests openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: "{{ router_name }}" - name: Find network openstack.cloud.networks_info: cloud: "{{ cloud }}" name: "{{ network_name }}" register: networks - name: Get ports in internal network when: networks.networks|length > 0 openstack.cloud.port_info: cloud: "{{ cloud }}" filters: network_id: "{{ networks.networks.0.id }}" register: existing_ports - name: Ensure ports don't exist before tests when: networks.networks|length > 0 openstack.cloud.port: cloud: "{{ cloud }}" name: "{{ item.id }}" state: absent loop: "{{ existing_ports.ports }}" - name: Delete subnets before tests openstack.cloud.subnet: cloud: "{{ cloud }}" state: absent name: "{{ item.name }}" loop: "{{ test_subnets }}" # Regular user operation - name: Create internal network openstack.cloud.network: cloud: "{{ cloud }}" state: present name: "{{ network_name }}" external: false - name: Create subnets 1-4 openstack.cloud.subnet: "{{ item }}" loop: "{{ test_subnets }}" - name: Ensure router doesn't exist before tests openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: "{{ router_name }}" - name: Create router openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" register: router - name: Verify returned values assert: that: item in router.router loop: "{{ expected_fields }}" - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" register: info - name: Verify routers info assert: that: - info.routers|length == 1 - info.routers.0.name == router_name - info.routers.0.is_admin_state_up - name: List ports of router openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ router.router.id }}" register: ports - name: Verify router ports assert: that: ports.ports|length == 0 - name: Update router (add interface) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet1 - name: Update router (add interface) again openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet1 register: router - name: Assert idempotent module assert: that: router is not changed - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" register: info - name: Verify routers info assert: that: - info.routers.0.name == router_name - info.routers.0.is_admin_state_up - name: List ports of router openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ router.router.id }}" register: ports - name: Verify router ports assert: that: - ports.ports|length == 1 - (ports.ports.0.fixed_ips|map(attribute='ip_address')|sort|list == ['10.7.7.1']) or ports.ports.0.fixed_ips|length > 0 - name: Verify existence of return values assert: that: item in info.routers[0] loop: "{{ expected_fields }}" - name: Gather routers info with filters openstack.cloud.routers_info: cloud: "{{ cloud }}" filters: is_admin_state_up: true name: "{{ router_name }}" register: info - name: Verify routers info with filters assert: that: - info.routers.0.name == router_name - info.routers.0.id == router.router.id - name: Gather routers info with other filters openstack.cloud.routers_info: cloud: "{{ cloud }}" filters: is_admin_state_up: false name: "{{ router_name }}" register: info - name: Verify routers info with other filters assert: that: info.routers == [] - name: Update router (change interfaces) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - net: '{{ network_name }}' subnet: shade_subnet2 portip: 10.8.8.1 - net: '{{ network_name }}' subnet: shade_subnet3 - shade_subnet4 - name: Update router (change interfaces) again openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - net: '{{ network_name }}' subnet: shade_subnet2 portip: 10.8.8.1 - net: '{{ network_name }}' subnet: shade_subnet3 - shade_subnet4 register: router - name: Assert idempotent module assert: that: router is not changed - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" register: info - name: Verify routers info assert: that: - info.routers|length == 1 - info.routers.0.name == router_name - info.routers.0.id == router.router.id - name: List ports of router openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ router.router.id }}" register: ports - name: Verify router ports assert: that: - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|list|length == 3 - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|sort|list == ['10.10.10.1', '10.8.8.1', '10.9.9.1'] - name: Update router (remove interfaces) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet4 - name: Update router (remove interfaces) again openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet4 register: router - name: Assert idempotent module assert: that: router is not changed - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" register: info - name: Verify routers info assert: that: - info.routers.0.name == router_name - info.routers.0.id == router.router.id - name: List ports of router openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ router.router.id }}" register: ports - name: Verify router ports assert: that: - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|list|length == 1 - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|sort|list == ['10.10.10.1'] - name: Update router (replace interfaces) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - net: '{{ network_name }}' subnet: shade_subnet1 portip: 10.7.7.1 - name: List ports of router openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ router.router.id }}" register: ports - name: Verify router ports assert: that: - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|list|length == 1 - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|sort|list == ['10.7.7.1'] - name: Update router (replace interfaces) again openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - net: '{{ network_name }}' subnet: shade_subnet1 portip: 10.7.7.1 register: router - name: Assert idempotent module assert: that: router is not changed - name: List ports of router openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ router.router.id }}" register: ports - name: Verify router ports assert: that: - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|list|length == 1 - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|sort|list == ['10.7.7.1'] # Admin operation - name: Create external network openstack.cloud.network: cloud: "{{ cloud }}" state: present name: "{{ external_network_name }}" external: true - name: Create subnet5 openstack.cloud.subnet: cloud: "{{ cloud }}" state: present network_name: "{{ external_network_name }}" name: shade_subnet5 cidr: 10.6.6.0/24 - name: Update router (add external gateway) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" network: "{{ external_network_name }}" interfaces: - shade_subnet1 - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" filters: is_admin_state_up: true register: info - name: Verify routers info assert: that: - info.routers.0.name == router_name - name: List ports of router openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ router.router.id }}" register: ports - name: Verify router ports assert: that: - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|list|length == 1 - name: Update router (change external fixed ips) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet1 network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 ip: 10.6.6.100 - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" filters: is_admin_state_up: true register: info - name: Verify routers info assert: that: - info.routers.0.name == router_name - (info.routers.0.external_gateway_info.external_fixed_ips|length) == 1 - info.routers.0.external_gateway_info.external_fixed_ips.0.ip_address == "10.6.6.100" - name: Update router (add external fixed ips) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet1 external_gateway_info: network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 ip: 10.6.6.100 - subnet: shade_subnet5 ip: 10.6.6.101 - name: Update router (add external fixed ips) again openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet1 network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 ip: 10.6.6.100 - subnet: shade_subnet5 ip: 10.6.6.101 register: router - name: Assert idempotent module assert: that: router is not changed - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" filters: is_admin_state_up: true register: info - name: Verify routers info assert: that: - info.routers.0.name == router_name - (info.routers.0.external_gateway_info.external_fixed_ips|length) == 2 - info.routers.0.external_gateway_info.external_fixed_ips|map(attribute='ip_address')|sort|list == ["10.6.6.100", "10.6.6.101"] - name: Update router (remove external fixed ips) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet1 network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 ip: 10.6.6.101 - name: Update router (remove external fixed ips) again openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet1 network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 ip: 10.6.6.101 register: router - name: Assert idempotent module assert: that: router is not changed - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" filters: is_admin_state_up: true register: info - name: Verify routers info assert: that: - info.routers.0.name == router_name - (info.routers.0.external_gateway_info.external_fixed_ips|length) == 1 - info.routers.0.external_gateway_info.external_fixed_ips.0.ip_address == "10.6.6.101" - name: Update router (disable external snat) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" enable_snat: false interfaces: - shade_subnet1 network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 ip: 10.6.6.101 - name: Gather routers info openstack.cloud.routers_info: cloud: "{{ cloud }}" name: "{{ router_name }}" filters: is_admin_state_up: true register: info - name: Verify routers info assert: that: - info.routers.0.name == router_name - not info.routers.0.external_gateway_info.enable_snat - name: Update router (disable external snat) again openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" enable_snat: false interfaces: - shade_subnet1 network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 ip: 10.6.6.101 register: router - name: Assert idempotent module assert: that: router is not changed - name: Delete router openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: "{{ router_name }}" - name: Delete router again openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: "{{ router_name }}" register: router - name: Assert idempotent module assert: that: router is not changed - name: Create router without explicit IP address openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" enable_snat: false interfaces: - shade_subnet1 network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 register: router - name: Assert idempotent module assert: that: router is changed - name: Update router without explicit IP address openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" enable_snat: false interfaces: - shade_subnet1 network: "{{ external_network_name }}" external_fixed_ips: - subnet_id: shade_subnet5 register: router - name: Assert idempotent module assert: that: router is not changed - name: Delete router openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: "{{ router_name }}" - name: Create router with simple interface openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - shade_subnet1 register: router - name: Assert changed assert: that: router is changed - name: Set portip in already assigned subnet openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - subnet: shade_subnet1 net: "{{ network_name }}" portip: 10.7.7.42 register: router - name: Assert changed assert: that: router is changed - name: List ports of router openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ router.router.id }}" register: ports - name: Verify router ports assert: that: - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|list|length == 1 - ports.ports|rejectattr('device_owner', 'equalto', 'network:router_gateway')|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|sort|list == ['10.7.7.42'] - name: Unset portip in already assigned subnet openstack.cloud.router: cloud: "{{ cloud }}" state: present name: "{{ router_name }}" interfaces: - subnet: shade_subnet1 net: "{{ network_name }}" register: router - name: Assert not changed assert: that: router is not changed - name: List all routers openstack.cloud.routers_info: cloud: "{{ cloud }}" register: routers - name: List ports of all routers loop: "{{ routers.routers }}" openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ item['id'] }}" register: ports - name: Transform ports for interfaces_info entries loop: "{{ ports.results|map(attribute='ports')|list }}" set_fact: interfaces_info: |- {% for port in item %} {% if port.device_owner != "network:router_gateway" %} {% for fixed_ip in port['fixed_ips'] %} - port_id: {{ port.id }} ip_address: {{ fixed_ip.ip_address }} subnet_id: {{ fixed_ip.subnet_id }} {% endfor %} {% endif %} {% endfor %} register: interfaces - name: Combine router and interfaces_info entries loop: "{{ routers.routers|zip(interfaces.results|map(attribute='ansible_facts'))|list }}" set_fact: # underscore prefix to prevent overwriting facts outside of loop _router: "{{ item.0|combine({'interfaces_info': (item.1.interfaces_info|from_yaml) }) }}" register: routers - name: Remove set_fact artifacts from routers set_fact: routers: "{{ { 'routers': routers.results|map(attribute='ansible_facts._router')|list } }}" - debug: var=routers - name: Assert our router's interfaces_info assert: that: - routers.routers|selectattr('id', 'equalto', router.router.id)|list|length == 1 # Cleanup environment - name: Delete router openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: "{{ router_name }}" - name: Find network openstack.cloud.networks_info: cloud: "{{ cloud }}" name: "{{ network_name }}" register: networks - name: Get ports in internal network openstack.cloud.port_info: cloud: "{{ cloud }}" filters: network_id: "{{ networks.networks.0.id }}" register: existing_ports - name: Clean up ports openstack.cloud.port: cloud: "{{ cloud }}" name: "{{ item.id }}" state: absent loop: "{{ existing_ports.ports }}" - name: Delete subnet5 openstack.cloud.subnet: cloud: "{{ cloud }}" state: absent name: shade_subnet5 - name: Delete subnets 1-4 openstack.cloud.subnet: cloud: "{{ cloud }}" state: absent name: "{{ item.name }}" loop: "{{ test_subnets }}" - name: Delete internal network openstack.cloud.network: cloud: "{{ cloud }}" state: absent name: "{{ network_name }}" - name: Delete external network openstack.cloud.network: cloud: "{{ cloud }}" state: absent name: "{{ external_network_name }}" - include_tasks: shared_network.yml - include_tasks: shared_ext_network.yml