Open germebl opened 1 week ago
The API does not yet support this, in the meantime here is a workaround: https://github.com/ansible-collections/hetzner.hcloud/blob/ecaeac117563cf0c070e442938feb68976374381/examples/server-assign-to-subnetwork.yml
I wrote myself another workaround, so i just get the real next free ip to simulate the DHCP assignment:
following need to be passed to it: {{ network_name }} e.g. nat-network {{ hetzner_api_token }} {{ subnet }} e.g. 10.1.100.0/24
get_ip.yaml
---
- name: Retrieve the Hetzner network information
hosts: localhost
tasks:
- name: Get all networks from Hetzner Cloud
uri:
url: https://api.hetzner.cloud/v1/networks
method: GET
headers:
Authorization: "Bearer {{ hetzner_api_token }}"
register: networks_response
- name: Find the network with the specified name
set_fact:
target_network: "{{ networks_response.json.networks | selectattr('name', 'equalto', network_name) | list | first }}"
- name: Find the subnet in the specified network
set_fact:
target_subnet: "{{ target_network.subnets | selectattr('ip_range', 'equalto', subnet) | list | first }}"
- name: Get all servers from Hetzner Cloud
uri:
url: https://api.hetzner.cloud/v1/servers
method: GET
headers:
Authorization: "Bearer {{ hetzner_api_token }}"
register: servers_response
- name: Extract server IPs in the target subnet
set_fact:
server_ips_in_subnet: >-
{{
servers_response.json.servers |
map(attribute='private_net') |
sum(start=[]) |
selectattr('network', 'equalto', target_network.id) |
map(attribute='ip') |
select('match', '^' + target_subnet.ip_range.split('/')[0] | regex_replace('\.[0-9]+$', '')) |
list
}}
- name: Extract server alias IPs in the target subnet
set_fact:
main_ips_in_subnet: >-
{{
servers_response.json.servers |
map(attribute='private_net') |
sum(start=[]) |
selectattr('network', 'equalto', target_network.id) |
map(attribute='ip') |
select('match', '^' + target_subnet.ip_range.split('/')[0] | regex_replace('\.[0-9]+$', '')) |
list
}}
- name: Extract alias IPs in the target subnet
set_fact:
alias_ips_in_subnet: >-
{{
servers_response.json.servers |
map(attribute='private_net') |
sum(start=[]) |
selectattr('network', 'equalto', target_network.id) |
map(attribute='alias_ips') |
sum(start=[]) |
select('match', '^' + target_subnet.ip_range.split('/')[0] | regex_replace('\.[0-9]+$', '')) |
list
}}
- name: Combine main and alias IPs in the target subnet
set_fact:
server_ips_in_subnet: "{{ main_ips_in_subnet + alias_ips_in_subnet }}"
- name: Calculate all IPs in the subnet range using Python script
command: "python3 ip_range.py {{ target_subnet.ip_range }}"
register: all_ips_in_subnet_output
- name: Set fact for all IPs in subnet range
set_fact:
all_ips_in_subnet: "{{ all_ips_in_subnet_output.stdout.split(',') }}"
- name: Remove used IPs from the list of all IPs in the subnet
set_fact:
available_ips_in_subnet: >-
{{
(all_ips_in_subnet | difference(server_ips_in_subnet))
| map('split', '.') | map('map', 'int') | sort | map('join', '.') | list
}}
- name: Find the smallest available IP in the subnet
set_fact:
smallest_available_ip: >-
{{
(available_ips_in_subnet | first)
}}
ip_range.py
# ip_range.py
import sys
from ipaddress import ip_network
network = ip_network(sys.argv[1])
ips = [str(ip) for ip in network.hosts()]
print(",".join(ips))
Really dirty, but works.
SUMMARY
It would be beneficial to have the ability to assign a server to a specific subnet during its creation using the Ansible hcloud collection. Currently, servers can be added to a private network, but the subnet is automatically chosen. This feature would allow for more precise network configurations.
ISSUE TYPE
COMPONENT NAME
hcloud_server module
ADDITIONAL INFORMATION
The feature would allow users to specify a subnet within a private network when creating a server. This capability is needed to better manage network resources and ensure that servers are placed in the correct subnet according to predefined network architecture.
Example usage in a playbook:
If there is already a way to achieve this, please hint me and close the request.