Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(inventory): handle servers that dont work with connect_with setting [2/3] #187

Merged
merged 1 commit into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- inventory plugin - Log warning instead of crashing when some servers do not work with global connect_with setting.
63 changes: 46 additions & 17 deletions plugins/inventory/hcloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@
type: str
required: false
connect_with:
description: Connect to the server using the value from this field.
description: |
Connect to the server using the value from this field. This sets the `ansible_host`
variable to the value indicated, if that value is available. If you need further
customization, like falling back to private ipv4 if the server has no public ipv4,
you can use `compose` top-level key.
default: public_ipv4
type: str
choices:
Expand Down Expand Up @@ -237,22 +241,14 @@ def _set_server_attributes(self, server):
if server_private_network.network.id == self.network.id:
self.inventory.set_variable(server.name, "private_ipv4", to_native(server_private_network.ip))

if self.get_option("connect_with") == "public_ipv4":
self.inventory.set_variable(server.name, "ansible_host", to_native(server.public_net.ipv4.ip))
if self.get_option("connect_with") == "public_ipv6":
self.inventory.set_variable(server.name, "ansible_host", to_native(self._first_ipv6_address(server.public_net.ipv6.ip)))
elif self.get_option("connect_with") == "hostname":
self.inventory.set_variable(server.name, "ansible_host", to_native(server.name))
elif self.get_option("connect_with") == "ipv4_dns_ptr":
self.inventory.set_variable(server.name, "ansible_host", to_native(server.public_net.ipv4.dns_ptr))
elif self.get_option("connect_with") == "private_ipv4":
if self.get_option("network"):
for server_private_network in server.private_net:
if server_private_network.network.id == self.network.id:
self.inventory.set_variable(server.name, "ansible_host", to_native(server_private_network.ip))
else:
raise AnsibleError(
"You can only connect via private IPv4 if you specify a network")
try:
self.inventory.set_variable(server.name, "ansible_host", self._get_server_ansible_host(server))
except AnsibleError as e:
# Log warning that for this host can not be connected to, using the
# method specified in `connect_with`. Users might use `compose` to
# override the connection method, or implement custom logic, so we
# do not need to abort if nothing matched.
self.display.v("[hcloud] %s" % e, server.name)

# Server Type
if server.server_type is not None:
Expand All @@ -278,6 +274,39 @@ def _set_server_attributes(self, server):
# Labels
self.inventory.set_variable(server.name, "labels", dict(server.labels))

def _get_server_ansible_host(self, server):
if self.get_option("connect_with") == "public_ipv4":
if server.public_net.ipv4:
return to_native(server.public_net.ipv4.ip)
else:
raise AnsibleError("Server has no public ipv4, but connect_with=public_ipv4 was specified")

if self.get_option("connect_with") == "public_ipv6":
if server.public_net.ipv6:
return to_native(self._first_ipv6_address(server.public_net.ipv6.ip))
else:
raise AnsibleError("Server has no public ipv6, but connect_with=public_ipv6 was specified")

elif self.get_option("connect_with") == "hostname":
# every server has a name, no need to guard this
return to_native(server.name)

elif self.get_option("connect_with") == "ipv4_dns_ptr":
if server.public_net.ipv4:
return to_native(server.public_net.ipv4.dns_ptr)
else:
raise AnsibleError("Server has no public ipv4, but connect_with=ipv4_dns_ptr was specified")

elif self.get_option("connect_with") == "private_ipv4":
if self.get_option("network"):
for server_private_network in server.private_net:
if server_private_network.network.id == self.network.id:
return to_native(server_private_network.ip)

else:
raise AnsibleError(
"You can only connect via private IPv4 if you specify a network")

def _first_ipv6_address(self, network):
return next(IPv6Network(network).hosts())

Expand Down