--- - name: List all images openstack.cloud.image_info: cloud: "{{ cloud }}" register: images - name: Identify CirrOS image name set_fact: image_name: "{{ images.images|community.general.json_query(query)|first }}" vars: query: "[?starts_with(name, 'cirros')].name" - name: Gather information about public network openstack.cloud.networks_info: cloud: "{{ cloud }}" name: public register: public_network - name: Assert that public network exists assert: that: public_network.networks|length == 1 - name: Create external network openstack.cloud.network: cloud: "{{ cloud }}" state: present name: ansible_external external: true - name: Create external subnet openstack.cloud.subnet: cloud: "{{ cloud }}" state: present network_name: ansible_external name: ansible_external_subnet cidr: 10.6.6.0/24 - name: Create external port 1 openstack.cloud.port: cloud: "{{ cloud }}" state: present name: ansible_external_port1 network: ansible_external fixed_ips: - ip_address: 10.6.6.50 - name: Create external port 2 openstack.cloud.port: cloud: "{{ cloud }}" state: present name: ansible_external_port2 network: ansible_external fixed_ips: - ip_address: 10.6.6.51 - name: Create internal network openstack.cloud.network: cloud: "{{ cloud }}" state: present name: ansible_internal external: false - name: Create internal subnet openstack.cloud.subnet: cloud: "{{ cloud }}" state: present network_name: ansible_internal name: ansible_internal_subnet cidr: 10.7.7.0/24 - name: Create internal port 1 openstack.cloud.port: cloud: "{{ cloud }}" state: present name: ansible_internal_port1 network: ansible_internal fixed_ips: - ip_address: 10.7.7.100 register: port1 - name: Create internal port 2 openstack.cloud.port: cloud: "{{ cloud }}" state: present name: ansible_internal_port2 network: ansible_internal fixed_ips: - ip_address: 10.7.7.101 register: port2 - name: Create internal port 3 openstack.cloud.port: cloud: "{{ cloud }}" state: present name: ansible_internal_port3 network: ansible_internal fixed_ips: - ip_address: 10.7.7.102 register: port3 - name: Create router 1 openstack.cloud.router: cloud: "{{ cloud }}" state: present name: ansible_router1 network: ansible_external external_fixed_ips: - subnet: ansible_external_subnet ip: 10.6.6.10 interfaces: - net: ansible_internal subnet: ansible_internal_subnet portip: 10.7.7.1 # Router 2 is required for the simplest, first test that assigns a new floating IP to server # from first available external network or nova pool which is DevStack's public network - name: Create router 2 openstack.cloud.router: cloud: "{{ cloud }}" state: present name: ansible_router2 network: public interfaces: - net: ansible_internal subnet: ansible_internal_subnet portip: 10.7.7.10 - name: Get all floating ips openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" register: fips - name: Check if public network has any floating ips set_fact: public_network_had_fips: "{{ fips.floating_ips| selectattr('floating_network_id', '==', public_network.networks.0.id)| list|length > 0 }}" # TODO: Replace with appropriate Ansible module once available - name: Create a floating ip on public network (required for simplest, first floating ip test) command: openstack --os-cloud={{ cloud }} floating ip create public when: not public_network_had_fips # TODO: Replace with appropriate Ansible module once available - name: Create floating ip 1 on external network command: > openstack --os-cloud={{ cloud }} floating ip create --subnet ansible_external_subnet --floating-ip-address 10.6.6.150 ansible_external when: fips.floating_ips|length == 0 or "10.6.6.150" not in fips.floating_ips|map(attribute="floating_ip_address")|list - name: Create server 1 with one nic openstack.cloud.server: cloud: "{{ cloud }}" state: present name: ansible_server1 image: "{{ image_name }}" flavor: m1.tiny nics: # one nic only else simple, first floating ip test does not work - port-name: ansible_internal_port1 auto_ip: false wait: true register: server1 - name: Get server 1 ports openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ server1.server.id }}" register: server1_ports - name: Assert one fixed ip on server 1 # If this assertion fails because server has an public ipv4 address (public_v4) then make sure # that no floating ip on public network is associated with "10.7.7.100" before running this role assert: that: - server1_ports.ports|length == 1 - server1_ports.ports|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|sort|list == ["10.7.7.100"] - name: Create server 2 with two nics openstack.cloud.server: cloud: "{{ cloud }}" state: present name: ansible_server2 image: "{{ image_name }}" flavor: m1.tiny nics: - port-name: ansible_internal_port2 - port-name: ansible_internal_port3 auto_ip: false wait: true register: server2 - name: Get server 2 ports openstack.cloud.port_info: cloud: "{{ cloud }}" filters: device_id: "{{ server2.server.id }}" register: server2_ports - name: Assert two fixed ips on server 2 assert: that: - server2_ports.ports|length == 2 - server2_ports.ports|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|sort|list == ["10.7.7.101", "10.7.7.102"] - name: Assign new floating IP to server from first available external network or nova pool openstack.cloud.floating_ip: cloud: "{{ cloud }}" state: present server: ansible_server1 wait: true - name: Get floating ip attached to server 1 openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" port: "{{ port1.port.id }}" register: server1_fips # openstacksdk has issues with waiting hence we simply retry retries: 10 delay: 3 until: server1_fips.floating_ips|length == 1 - name: Assert fixed ip and floating ip attached to server 1 assert: that: - server1_ports.ports|length == 1 - server1_ports.ports|sum(attribute='fixed_ips', start=[])|map(attribute='ip_address')|sort|list == ["10.7.7.100"] - server1_fips.floating_ips|length == 1 - server1_fips.floating_ips|map(attribute='fixed_ip_address')|sort|list == ["10.7.7.100"] - name: Assert return values of floating_ip_info module assert: that: - server1_fips is success - server1_fips is not changed - server1_fips.floating_ips # allow new fields to be introduced but prevent fields from being removed - expected_fields|difference(server1_fips.floating_ips[0].keys())|length == 0 - name: Assign floating ip to server 1 again openstack.cloud.floating_ip: cloud: "{{ cloud }}" state: present server: ansible_server1 wait: true register: floating_ip - name: Assert floating ip on server 1 has not changed assert: that: floating_ip is not changed - name: Assert return values of floating_ip module assert: that: - floating_ip.floating_ip # allow new fields to be introduced but prevent fields from being removed - expected_fields|difference(floating_ip.floating_ip.keys())|length == 0 - name: Detach floating ip from server 1 openstack.cloud.floating_ip: cloud: "{{ cloud }}" state: absent server: ansible_server1 network: public floating_ip_address: "{{ server1_fips.floating_ips.0.floating_ip_address }}" - name: Wait until floating ip is detached from server 1 openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" port: "{{ port1.port.id }}" register: server1_fips # When detaching a floating ip from an instance there might be a delay until it is not listed anymore retries: 10 delay: 3 until: server1_fips.floating_ips|length == 0 - name: Find all floating ips for debugging openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" register: fips - name: Print all floating ips for debugging debug: var=fips - name: Find all servers for debugging openstack.cloud.server_info: cloud: "{{ cloud }}" register: servers - name: Print all servers for debugging debug: var=servers - name: Assign floating ip to server 2 openstack.cloud.floating_ip: cloud: "{{ cloud }}" state: present reuse: false # else fixed_address will be ignored server: ansible_server2 network: public fixed_address: "{{ port2.port.fixed_ips[0].ip_address }}" wait: true register: server2_fip - name: Assert floating ip attached to server 2 assert: that: - server2_fip.floating_ip - name: Find all floating ips for debugging openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" register: fips - name: Print all floating ips for debugging debug: var=fips - name: Find all servers for debugging openstack.cloud.server_info: cloud: "{{ cloud }}" register: servers - name: Print all servers for debugging debug: var=servers - name: Get floating ip attached to server 2 openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" port: "{{ port2.port.id }}" register: server2_fips - name: Assert floating ip attached to server 2 assert: that: - server2_fips.floating_ips|length == 1 - server2_fips.floating_ips|map(attribute='fixed_ip_address')|sort|list == ["10.7.7.101"] - name: Assign a second, specific floating ip to server 2 openstack.cloud.floating_ip: cloud: "{{ cloud }}" state: present reuse: false # else fixed_address will be ignored server: ansible_server2 network: ansible_external fixed_address: "{{ port3.port.fixed_ips[0].ip_address }}" floating_ip_address: "10.6.6.150" wait: false # does not work anyway and causes issues in local testing - name: Get floating ip attached to server 2 openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" port: "{{ port3.port.id }}" register: server2_fips # We cannot wait for second floating ip to be attached because OpenStackSDK checks only for first floating ip # Ref.: https://github.com/openstack/openstacksdk/blob/e0372b72af8c5f471fc17e53434d7a814ca958bd/openstack/cloud/_floating_ip.py#L733 retries: 10 delay: 3 until: server2_fips.floating_ips|length == 1 - name: Assert second floating ip attached to server 2 assert: that: - server2_fips.floating_ips|length == 1 - server2_fips.floating_ips|map(attribute='fixed_ip_address')|sort|list == ["10.7.7.102"] - name: Detach second floating ip from server 2 openstack.cloud.floating_ip: cloud: "{{ cloud }}" state: absent server: ansible_server2 network: ansible_external floating_ip_address: "10.6.6.150" - name: Wait until second floating ip is detached from server 2 openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" port: "{{ port3.port.id }}" register: server2_fips # When detaching a floating ip from an instance there might be a delay until it is not listed anymore retries: 10 delay: 3 until: server2_fips.floating_ips|length == 0 - name: Get first floating ip attached to server 2 openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" port: "{{ port2.port.id }}" register: server2_fips - name: Detach remaining floating ip from server 2 openstack.cloud.floating_ip: cloud: "{{ cloud }}" state: absent server: ansible_server2 network: public floating_ip_address: "{{ server2_fips.floating_ips.0.floating_ip_address }}" - name: Wait until first floating ip is detached from server 2 openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" port: "{{ port2.port.id }}" register: server2_fips # When detaching a floating ip from an instance there might be a delay until it is not listed anymore retries: 10 delay: 3 until: server2_fips.floating_ips|length == 0 - name: Delete server with two nics openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: ansible_server2 wait: true - name: Delete server with one nic openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: ansible_server1 wait: true - name: Get all floating ips openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" register: fips # TODO: Replace with appropriate Ansible module once available - name: Delete floating ip on public network if we created it when: not public_network_had_fips command: > openstack --os-cloud={{ cloud }} floating ip delete {{ fips.floating_ips|selectattr('floating_network_id', '==', public_network.networks.0.id)| map(attribute="floating_ip_address")|list|join(' ') }} # TODO: Replace with appropriate Ansible module once available - name: Delete floating ip 1 command: openstack --os-cloud={{ cloud }} floating ip delete 10.6.6.150 when: fips.floating_ips|length > 0 and "10.6.6.150" in fips.floating_ips|map(attribute="floating_ip_address")|list - name: Get remaining floating ips on external network openstack.cloud.floating_ip_info: cloud: "{{ cloud }}" floating_network: ansible_external register: fips # TODO: Replace with appropriate Ansible module once available # The first, simple floating ip test might have allocated a floating ip on the external network. # This floating ip must be removed before external network can be deleted. - name: Delete remaining floating ips on external network when: fips.floating_ips|length > 0 command: > openstack --os-cloud={{ cloud }} floating ip delete {{ fips.floating_ips|map(attribute="floating_ip_address")|list|join(' ') }} # Remove routers after floating ips have been detached and disassociated else removal fails with # Error detaching interface from router ***: Client Error for url: ***, # Router interface for subnet *** on router *** cannot be deleted, # as it is required by one or more floating IPs. - name: Delete router 2 openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: ansible_router2 - name: Delete router 1 openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: ansible_router1 - name: Delete internal port 3 openstack.cloud.port: cloud: "{{ cloud }}" state: absent name: ansible_internal_port3 - name: Delete internal port 2 openstack.cloud.port: cloud: "{{ cloud }}" state: absent name: ansible_internal_port2 - name: Delete internal port 1 openstack.cloud.port: cloud: "{{ cloud }}" state: absent name: ansible_internal_port1 - name: Delete internal subnet openstack.cloud.subnet: cloud: "{{ cloud }}" state: absent name: ansible_internal_subnet - name: Delete internal network openstack.cloud.network: cloud: "{{ cloud }}" state: absent name: ansible_internal - name: Delete external port 2 openstack.cloud.port: cloud: "{{ cloud }}" state: absent name: ansible_external_port2 - name: Delete external port 1 openstack.cloud.port: cloud: "{{ cloud }}" state: absent name: ansible_external_port1 - name: Delete external subnet openstack.cloud.subnet: cloud: "{{ cloud }}" state: absent name: ansible_external_subnet - name: Delete external network openstack.cloud.network: cloud: "{{ cloud }}" state: absent name: ansible_external