Files
ansible-collections-openstack/ci/roles/floating_ip/tasks/main.yml
Austin Jamias f0e0388159 Add ability to allocate floating IP
Currently, you would only use this module to create a floating IP if it
doesn't exist and attempt to attach it to a Nova server. This commit
adds support for creating a standalone floating IP not attached to
anything, and optionally attaching it to a fixed IP in a fixed network.

Change-Id: Id65ce98674b6b9d93dd4cfbbdf2c5c51798fca38
Signed-off-by: Austin Jamias <ajamias@redhat.com>
2025-12-04 15:15:05 -05:00

695 lines
19 KiB
YAML

---
- 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: Gather information about external network
openstack.cloud.networks_info:
cloud: "{{ cloud }}"
name: ansible_external
register: external_network
- 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 internal port 4
openstack.cloud.port:
cloud: "{{ cloud }}"
state: present
name: ansible_internal_port4
network: ansible_internal
fixed_ips:
- ip_address: 10.7.7.103
- ip_address: 10.7.7.104
register: port4
- 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 }}"
- name: Create a floating ip on public network (required for simplest, first floating ip test)
when: not public_network_had_fips
block:
- name: Create a floating ip on public network
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: present
network: public
register: public_fip_result
- name: Verify floating ip got created
assert:
that:
- public_fip_result.floating_ip.floating_network_id == public_network.networks.0.id
- name: Create a floating ip on public network again
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: present
network: public
register: public_fip_result
- name: Verify idempotency
assert:
that: public_fip_result is not changed
# 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 floating ip 2 on external network
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: present
network: ansible_external
floating_ip_address: 10.6.6.151
register: external_fip2_result
- name: Verify floating ip got created
assert:
that:
- external_fip2_result.floating_ip.floating_network_id == external_network.networks.0.id
- name: Update floating ip 2 on external network
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: present
network: ansible_external
floating_ip_address: 10.6.6.151
nat_destination: ansible_internal
fixed_address: 10.7.7.104
register: external_fip2_result
- name: Verify floating ip got updated
assert:
that:
- external_fip2_result is changed
- external_fip2_result.floating_ip.floating_ip_address == "10.6.6.151"
- external_fip2_result.floating_ip.port_id == port4.port.id
- external_fip2_result.floating_ip.fixed_ip_address == "10.7.7.104"
- name: Update floating ip 2 on external network again
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: present
network: ansible_external
floating_ip_address: 10.6.6.151
nat_destination: ansible_internal
fixed_address: 10.7.7.104
register: external_fip2_result
- name: Verify idempotency
assert:
that:
- external_fip2_result is not changed
- name: Detatch floating ip 2 on external network from port
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: absent
network: ansible_external
floating_ip_address: 10.6.6.151
- name: Get floating ip 2 info
openstack.cloud.floating_ip_info:
cloud: "{{ cloud }}"
floating_ip_address: 10.6.6.151
register: external_fip2_result
- name: Verify floating ip got detached
assert:
that:
- external_fip2_result.floating_ips.0.floating_ip_address == "10.6.6.151"
- external_fip2_result.floating_ips.0.fixed_ip_address == none
- external_fip2_result.floating_ips.0.port_id == none
- name: Detatch floating ip 2 on external network from port again
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: absent
network: ansible_external
floating_ip_address: 10.6.6.151
- name: Get floating ip 2 info
openstack.cloud.floating_ip_info:
cloud: "{{ cloud }}"
floating_ip_address: 10.6.6.151
register: external_fip2_result
- name: Verify idempotency
assert:
that:
- external_fip2_result is not changed
- 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|length > 0
# 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|length > 0
# 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|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: 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
- name: Delete floating ip on public network if we created it
when: not public_network_had_fips
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: absent
purge: true
floating_ip_address: "{{ public_fip }}"
network: public
loop: >-
{{
fips.floating_ips |
selectattr('floating_network_id', '==', public_network.networks.0.id) |
map(attribute="floating_ip_address") |
list
}}
loop_control:
loop_var: public_fip
- name: Delete floating ip 1
when: fips.floating_ips|length > 0 and "10.6.6.150" in fips.floating_ips|map(attribute="floating_ip_address")|list
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: absent
purge: true
floating_ip_address: 10.6.6.150
network: ansible_external
- name: Delete floating ip 2
when: fips.floating_ips|length > 0 and "10.6.6.151" in fips.floating_ips|map(attribute="floating_ip_address")|list
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: absent
purge: true
floating_ip_address: 10.6.6.151
network: ansible_external
- name: Get remaining floating ips on external network
openstack.cloud.floating_ip_info:
cloud: "{{ cloud }}"
floating_network: ansible_external
register: fips
# 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
openstack.cloud.floating_ip:
cloud: "{{ cloud }}"
state: absent
purge: true
floating_ip_address: "{{ external_fip }}"
network: ansible_external
loop: >-
{{
fips.floating_ips |
map(attribute="floating_ip_address") |
list
}}
loop_control:
loop_var: external_fip
# 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 4
openstack.cloud.port:
cloud: "{{ cloud }}"
state: absent
name: ansible_internal_port4
- 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