--- - 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: Create network for server openstack.cloud.network: cloud: "{{ cloud }}" name: "{{ server_network }}" state: present register: network - name: Create subnet for server openstack.cloud.subnet: cidr: 192.168.0.0/24 cloud: "{{ cloud }}" name: "{{ server_subnet }}" network_name: "{{ server_network }}" state: present register: subnet - name: Create second network for server openstack.cloud.network: cloud: "{{ cloud }}" name: "{{ server_alt_network }}" state: present - name: Create second subnet for server openstack.cloud.subnet: cidr: 192.168.1.0/24 cloud: "{{ cloud }}" name: "{{ server_alt_subnet }}" network_name: "{{ server_alt_network }}" state: present - name: Create router 1 (for attaching floating ips) openstack.cloud.router: cloud: "{{ cloud }}" state: present name: ansible_router1 network: public interfaces: - net: "{{ server_network }}" subnet: "{{ server_subnet }}" - net: "{{ server_alt_network }}" subnet: "{{ server_alt_subnet }}" - name: Create security group for server openstack.cloud.security_group: cloud: "{{ cloud }}" state: present name: "{{ server_security_group }}" register: security_group - name: Create second security group for server openstack.cloud.security_group: cloud: "{{ cloud }}" state: present name: "{{ server_alt_security_group }}" register: security_group_alt - name: Create server with meta as CSV openstack.cloud.server: cloud: "{{ cloud }}" state: present name: "{{ server_name }}" image: "{{ image_name }}" flavor: "{{ flavor_name }}" network: "{{ server_network }}" auto_ip: false metadata: "key1=value1,key2=value2" wait: true register: server - debug: var=server - name: assert return values of server module assert: that: # allow new fields to be introduced but prevent fields from being removed - expected_fields|difference(server.server.keys())|length == 0 - name: Assert server assert: that: - server.server.name == server_name - server.server.metadata.keys()|sort == ['key1', 'key2'] - server.server.metadata['key1'] == 'value1' - server.server.metadata['key2'] == 'value2' - server_network in server.server.addresses - server.server.security_groups|map(attribute='name')|list == ['default'] - name: Get info about all servers openstack.cloud.server_info: cloud: "{{ cloud }}" register: info - name: Check info about servers assert: that: - info.servers|length > 0 # allow new fields to be introduced but prevent fields from being removed - expected_fields|difference(info.servers[0].keys())|length == 0 - name: Delete server with meta as CSV openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: "{{ server_name }}" wait: true - name: Get info about all servers openstack.cloud.server_info: cloud: "{{ cloud }}" register: info - name: Check info about no servers assert: that: - info.servers|length == 0 - name: Create server with meta as dict openstack.cloud.server: cloud: "{{ cloud }}" state: present name: "{{ server_name }}" image: "{{ image_name }}" flavor: "{{ flavor_name }}" auto_ip: false network: "{{ server_network }}" metadata: key1: value1 key2: value2 wait: true register: server - debug: var=server - name: Get info about one server openstack.cloud.server_info: cloud: "{{ cloud }}" server: "{{ server_name }}" register: info - name: Check info about server name assert: that: - info.servers[0].name == server_name - info.servers[0].id == server.server.id - name: Filter servers openstack.cloud.server_info: cloud: "{{ cloud }}" filters: id: "{{ server.server.id }}" metadata: key1: value1 key2: value2 register: info - name: Check filter results assert: that: info.servers|map(attribute='id')|list == [server.server.id] - name: Filter servers with partial data openstack.cloud.server_info: cloud: "{{ cloud }}" filters: id: "{{ server.server.id }}" metadata: key1: value1 # intentially left out parts of metadata here register: info - name: Check filter results assert: that: info.servers|map(attribute='id')|list == [server.server.id] - name: Filter servers which should not return results openstack.cloud.server_info: cloud: "{{ cloud }}" filters: id: "THIS_IS_NOT_A_VALID_ID" register: info - name: Check filter results assert: that: info.servers|length == 0 - name: Delete server with meta as dict openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: "{{ server_name }}" wait: true - name: Create server (FIP from pool/network) openstack.cloud.server: cloud: "{{ cloud }}" state: present name: "{{ server_name }}" image: "{{ image_name }}" flavor: "{{ flavor_name }}" network: "private" floating_ip_pools: - "{{ floating_ip_pool_name }}" wait: true register: server - debug: var=server - name: Get detailed info about one server openstack.cloud.server_info: cloud: "{{ cloud }}" server: "{{ server_name }}" detailed: true register: info # TODO: Drop ignore_errors once openstacksdk's bug #2010135 has been solved. # Ref.: https://storyboard.openstack.org/#!/story/2010135 ignore_errors: true - name: Check info about server image name assert: that: - info.servers[0].image.name == image_name # TODO: Drop ignore_errors once openstacksdk's bug #2010135 has been solved. # Ref.: https://storyboard.openstack.org/#!/story/2010135 ignore_errors: true - name: Delete server (FIP from pool/network) openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: "{{ server_name }}" wait: true - name: Create server from volume openstack.cloud.server: cloud: "{{ cloud }}" state: present name: "{{ server_name }}" image: "{{ image_name }}" flavor: "{{ flavor_name }}" network: "{{ server_network }}" auto_ip: false boot_from_volume: true volume_size: "{{ boot_volume_size }}" terminate_volume: true wait: true register: server - debug: var=server - name: Delete server with volume openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: "{{ server_name }}" wait: true - name: Create a minimal server openstack.cloud.server: cloud: "{{ cloud }}" state: present name: "{{ server_name }}" image: "{{ image_name }}" flavor: "{{ flavor_name }}" network: "{{ server_network }}" auto_ip: false wait: true register: server - debug: var=server - name: Get info about servers in all projects openstack.cloud.server_info: cloud: "{{ cloud }}" all_projects: true register: info - name: Check info about servers in all projects assert: that: info.servers|length > 0 - name: Get info about one server in all projects openstack.cloud.server_info: cloud: "{{ cloud }}" server: "{{ server_name }}" all_projects: true register: info - name: Check info about one server in all projects assert: that: info.servers|length > 0 - name: Delete minimal server openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: "{{ server_name }}" wait: true - name: Create server on private network with auto_ip openstack.cloud.server: auto_ip: true cloud: "{{ cloud }}" flavor: "{{ flavor_name }}" image: "{{ image_name }}" name: "{{ server_name }}" nics: - net-name: "{{ server_network }}" reuse_ips: false state: present wait: true register: server - name: Assert server on private network with auto_ip assert: that: - server.server.addresses.values() |flatten(levels=1) |selectattr('OS-EXT-IPS:type', 'equalto', 'floating') |map(attribute='addr') |list|length == 1 - name: Delete server on private network with auto_ip openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: "{{ server_name }}" wait: true - name: Create server on public network openstack.cloud.server: auto_ip: false cloud: "{{ cloud }}" flavor: "{{ flavor_name }}" image: "{{ image_name }}" name: "{{ server_name }}" nics: - net-name: 'public' reuse_ips: false state: present wait: true register: server - debug: var=server - name: Assert server on public network assert: that: - server.server.addresses.values() |flatten(levels=1) |selectattr('OS-EXT-IPS:type', 'equalto', 'floating') |map(attribute='addr') |list|length == 0 - name: Delete server on public network openstack.cloud.server: cloud: "{{ cloud }}" state: absent name: "{{ server_name }}" wait: true - name: Create port to be attached to server openstack.cloud.port: cloud: "{{ cloud }}" state: present name: "{{ server_port }}" network: "{{ server_network }}" no_security_groups: true fixed_ips: - ip_address: 192.168.0.42 register: port - name: Create server which will be updated openstack.cloud.server: auto_ip: false cloud: "{{ cloud }}" # TODO: Uncomment once openstacksdk with support for # description parameter has been released to PyPI. # Ref.: https://review.opendev.org/c/openstack/openstacksdk/+/850671 #description: "This is a server" flavor: "{{ flavor_name }}" image: "{{ image_name }}" metadata: key1: value1 key2: value2 name: "{{ server_name }}" nics: - net-name: "{{ server_network }}" - port-id: "{{ port.port.id }}" reuse_ips: false state: present wait: true register: server - debug: var=server - name: Assert server is not on public network and does not have a floating ip assert: that: - server.server.addresses.keys()|sort == [server_network]|sort - server.server.addresses.values() |flatten(levels=1) |selectattr('OS-EXT-IPS:type', 'equalto', 'floating') |map(attribute='addr') |list|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: Update server openstack.cloud.server: # TODO: Change auto_ip to true once openstacksdk's issue #2010352 has been solved # Ref.: https://storyboard.openstack.org/#!/story/2010352 auto_ip: false cloud: "{{ cloud }}" description: "This server got updated" # flavor cannot be updated but must be present flavor: "{{ flavor_name }}" # image cannot be updated but must be present image: "{{ image_name }}" metadata: key2: value2 key3: value3 name: "{{ server_name }}" # nics cannot be updated nics: - net-name: "{{ server_network }}" - port-id: "{{ port.port.id }}" reuse_ips: false security_groups: - '{{ server_security_group }}' - '{{ server_alt_security_group }}' state: present wait: true register: server_updated - debug: var=server_updated - name: Assert updated server assert: that: - server.server.id == server_updated.server.id - server_updated is changed - server_updated.server.description == "This server got updated" - "'key1' not in server_updated.server.metadata" - server_updated.server.metadata['key2'] == 'value2' - server_updated.server.metadata['key3'] == 'value3' - server_updated.server.security_groups|map(attribute='name')|unique|length == 2 - security_group.security_group.name in server_updated.server.security_groups|map(attribute='name') - security_group_alt.security_group.name in server_updated.server.security_groups|map(attribute='name') - server_network in server_updated.server.addresses.keys()|list|sort - server_updated.server.addresses[server_network]|length == 2 - port.port.fixed_ips[0].ip_address in server_updated.server.addresses[server_network]|map(attribute='addr') # TODO: Verify networks once openstacksdk's issue #2010352 has been solved # Ref.: https://storyboard.openstack.org/#!/story/2010352 #- server_updated.server.addresses.public|length > 0 #- (server_updated.server.addresses.keys()|sort == ([server_network, 'public']|sort)) # or (server_updated.server.addresses.values() # |flatten(levels=1) # |selectattr('OS-EXT-IPS:type', 'equalto', 'floating') # |map(attribute='addr') # |list|length > 0) - name: Update server again openstack.cloud.server: # TODO: Change auto_ip to true once openstacksdk's issue #2010352 has been solved # Ref.: https://storyboard.openstack.org/#!/story/2010352 auto_ip: false cloud: "{{ cloud }}" description: "This server got updated" # flavor cannot be updated but must be present flavor: "{{ flavor_name }}" # image cannot be updated but must be present image: "{{ image_name }}" metadata: key2: value2 key3: value3 name: "{{ server_name }}" # nics cannot be updated nics: - net-name: "{{ server_network }}" - port-id: "{{ port.port.id }}" reuse_ips: false security_groups: - '{{ server_security_group }}' - '{{ server_alt_security_group }}' state: present wait: true register: server_updated_again - name: Assert server did not change assert: that: - server.server.id == server_updated_again.server.id - server_updated_again is not changed # TODO: Drop failure test once openstacksdk's issue #2010352 has been solved # Ref.: https://storyboard.openstack.org/#!/story/2010352 - name: Update server again with auto_ip set to true openstack.cloud.server: auto_ip: true cloud: "{{ cloud }}" description: "This server got updated" # flavor cannot be updated but must be present flavor: "{{ flavor_name }}" # image cannot be updated but must be present image: "{{ image_name }}" metadata: key2: value2 key3: value3 name: "{{ server_name }}" # nics cannot be updated nics: - net-name: "{{ server_network }}" - port-id: "{{ port.port.id }}" reuse_ips: false security_groups: - '{{ server_security_group }}' - '{{ server_alt_security_group }}' state: present wait: true register: server_updated_again ignore_errors: true - name: Assert server update succeeded or failed with expected error assert: that: - not server_updated_again.failed or ('was found matching your NAT destination network' in server_updated_again.msg) - name: Delete updated server openstack.cloud.server: cloud: "{{ cloud }}" delete_ips: true name: "{{ server_name }}" state: absent wait: true - name: Delete port which was attached to server openstack.cloud.port: cloud: "{{ cloud }}" state: absent name: "{{ server_port }}" - name: Delete second security group for server openstack.cloud.security_group: cloud: "{{ cloud }}" state: absent name: "{{ server_alt_security_group }}" - name: Delete security group for server openstack.cloud.security_group: cloud: "{{ cloud }}" state: absent name: "{{ server_security_group }}" - name: Delete router 1 openstack.cloud.router: cloud: "{{ cloud }}" state: absent name: ansible_router1 - name: Delete second subnet for server openstack.cloud.subnet: cloud: "{{ cloud }}" state: absent name: "{{ server_alt_subnet }}" - name: Delete second network for server openstack.cloud.network: cloud: "{{ cloud }}" state: absent name: "{{ server_alt_network }}" - name: Delete subnet for server openstack.cloud.subnet: cloud: "{{ cloud }}" state: absent name: "{{ server_subnet }}" - name: Delete network for server openstack.cloud.network: cloud: "{{ cloud }}" state: absent name: "{{ server_network }}"