Created
November 8, 2022 18:18
-
-
Save zealot128/046733a248329e31d43fc9d52fd9040c to your computer and use it in GitHub Desktop.
Obtain hetzner cloud in ansible compatible inventory (script plugin)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'json' | |
require 'bundler/inline' | |
gemfile do | |
source 'https://rubygems.org' | |
# gem 'pry' | |
# gem 'toml' | |
gem 'typhoeus' | |
end | |
api_key = ENV['HCLOUD_TOKEN'] | |
toml_file = File.expand_path("~/.config/hcloud/cli.toml") | |
if !api_key && File.exist?(toml_file) | |
config = TOML.load_file(toml_file) | |
api_key = config['contexts'].find { |i| i['name'] == config['active_context'] }['token'] | |
end | |
unless api_key | |
puts "HCLOUD_TOKEN environment variable not set or hcloud config file not found" | |
exit 1 | |
end | |
api_key = ENV['HCLOUD_TOKEN'] | |
class ApiClient | |
def initialize(token) | |
@token = token | |
end | |
def servers(page: 1, per_page: 50) | |
get "https://api.hetzner.cloud/v1/servers?page=#{page}&per_page=#{per_page}" | |
end | |
def floating_ips(id) | |
get "https://api.hetzner.cloud/v1/floating_ips/#{id}" | |
end | |
private | |
def get(uri) | |
r = Typhoeus.get(uri, headers: headers) | |
unless r.success? | |
puts "Error: #{r.code}" | |
exit 1 | |
end | |
JSON.parse(r.body) | |
end | |
def headers | |
{ 'Authorization' => "Bearer #{@token}" } | |
end | |
end | |
class Inventory | |
def initialize(api_client, public_net_type: 'ipv4') | |
@hosts = [] | |
@host_vars = {} | |
@api_client = api_client | |
@root = { 'hcloud' => { 'hosts' => @hosts }, '_meta' => { 'hostvars' => @host_vars } } | |
@public_net_type = public_net_type | |
end | |
def add(server) | |
server_name = server['name'] | |
@hosts << server_name | |
@host_vars[server_name] = map_host_vars(server) | |
add_to_datacenter(server) | |
add_to_labels(server) | |
end | |
def to_json(*_args) | |
JSON.pretty_generate(@root) | |
end | |
private | |
def map_host_vars(server) | |
ip = server['public_net'][@public_net_type]['ip'] | |
# In case op IPv6, set the IP to the first address of the assigned range. | |
if @public_net_type == "ipv6" | |
raise | |
else | |
ansible_host = ip | |
end | |
public_net = server['public_net'] | |
floating_ips_ids = public_net['floating_ips'] | |
public_net['floating_ips'] = { 'ipv4': [], 'ipv6': [] } | |
floating_ips_ids.each do |id| | |
r = @api_client.floating_ips(id) | |
floating_ip = r['floating_ip'] | |
ip_type = floating_ip['type'] | |
ip = floating_ip['ip'] | |
public_net['floating_ips'][ip_type] << ip | |
end | |
{ | |
'ansible_host': ansible_host, | |
'hcloud_public_net': public_net, | |
'hcloud_server_type': server['server_type'], | |
'hcloud_image': server.dig('image', 'name') || '', | |
'hcloud_datacenter': server['datacenter']['name'], | |
'hcloud_labels': server['labels'], | |
} | |
end | |
def add_to_datacenter(server) | |
dc = server['datacenter']['name'].gsub("-", "_") | |
@root[dc] ||= { 'hosts' => [] } | |
@root[dc]['hosts'] << server['name'] | |
end | |
def add_to_labels(server) | |
server['labels'].each do |label, value| | |
vlabel = "#{label}_#{value}" | |
@root[vlabel] ||= { 'hosts' => [] } | |
@root[vlabel]['hosts'] << server['name'] | |
end | |
end | |
end | |
api_client = ApiClient.new(api_key) | |
inventory = Inventory.new(api_client) | |
page = 1 | |
loop do | |
res = api_client.servers(page: page) | |
res['servers'].each do |server| | |
inventory.add(server) | |
end | |
if res['meta']['pagination']['next_page'] == nil | |
break | |
else | |
page += 1 | |
end | |
end | |
puts inventory.to_json |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment