Я пытаюсь написать марионеточную функцию, которая вызывает мою среду хостинга (облачный атм) для вывода списка серверов, а затем обновляет файл моих хостов.
Моя функция get_hosts сейчас такова:
require 'rubygems'
require 'cloudservers'
module Puppet::Parser::Functions
newfunction(:get_hosts, :type => :rvalue) do |args|
unless args.length == 1
raise Puppet::ParseError, "Must provide the datacenter"
end
DC = args[0]
USERNAME = DC == "us" ? "..." : "..."
API_KEY = DC == "us" ? "..." : "..."
AUTH_URL = DC == "us" ? CloudServers::AUTH_USA : CloudServers::AUTH_UK
DOMAIN = "..."
cs = CloudServers::Connection.new(:username => USERNAME, :api_key => API_KEY, :auth_url => AUTH_URL)
cs.list_servers_detail.map {|server|
server.map {|s| { s[:name] + "." + DC + DOMAIN => {
:ip => s[:addresses][:private][0],
:aliases => s[:name]
}}}
}
end
end
И у меня есть hosts.pp, который вызывает это и «должен» записывать его в / etc / hosts.
class hosts::us {
$hosts = get_hosts("us")
hostentry { $hosts: }
}
define hostentry() {
host{ $name: ip => $name[ip], host_aliases => $name[aliases] }
}
Как вы понимаете, в настоящее время это не работает, и я получаю сообщение об ошибке «Символ как индекс массива в /etc/puppet/manifests/hosts.pp:2». Думаю, как только я пойму, что делаю неправильно, в будущем появятся новые ошибки.
Это хорошая идея? Может ли кто-нибудь помочь мне понять, как это сделать?
Обновить
Наконец-то удалось заставить это работать (с помощью комментариев)! Вот мой get_hosts.rb:
require 'rubygems'
require 'cloudservers'
module Puppet::Parser::Functions
newfunction(:get_hosts, :type => :rvalue) do |args|
unless args.length == 1
raise Puppet::ParseError, "Must provide the datacenter"
end
dc = args[0]
username = dc == "us" ? "..." : "..."
api_key = dc == "us" ? "..." : "..."
auth_url = dc == "us" ? CloudServers::AUTH_USA : CloudServers::AUTH_UK
domain = "...."
cs = CloudServers::Connection.new(:username => username, :api_key => api_key, :auth_url => auth_url)
cs.list_servers_detail.map {|server|
server[:name] + "." + dc + domain + "," +
server[:addresses][:private][0] + "," +
server[:name]
}
end
end
и hosts.pp
class hosts::us {
$hosts = get_hosts("us")
hostentry { $hosts: }
}
define hostentry() {
$parts = split($name, ',')
$address = $parts[0]
$ip = $parts[1]
$aliases = $parts[2]
host{ $address: ip => $ip, host_aliases => $aliases }
}
Довольно неприятно так упорядочивать namevar, но это был единственный способ заставить его работать. Любые улучшения приветствуются.
Я бы не назвал это плохой идеей, но вам действительно нужно прекратить использовать константы повсюду в вашем коде (все, что начинается с заглавной буквы в Ruby, является константой).
Чтобы отладить вашу проблему, вы, вероятно, захотите использовать --trace
в вызове марионеточного мастера, поэтому он напечатает обратную трассировку вместо того, чтобы съесть настоящее исключение и выдать вам бесполезное сообщение об ошибке. У вас есть целая куча разыменований в вашем map
звонки; я предполагаю, что вы неправильно поняли часть структуры данных, исходящую из API, и ваш код спотыкается об этом недоразумении. Запустите отладчик (или обильно посыпьте puts
через ваш код), и вы увидите, что у вас не так, в довольно короткие сроки.
Я бы разделил эту функциональность иначе.
Используйте свою функцию, чтобы создать чистые данные в виде хэша, представляющего список ресурсов хоста.
Затем используйте функцию create_resources для создания фактических ресурсов хоста из этих данных:
https://puppet.com/docs/puppet/latest/function.html#createresources
Пример должен дать вам достаточно, чтобы начать работу:
# A hash of user resources:
$myusers = {
'nick' => { uid => '1330',
group => allstaff,
groups => ['developers', 'operations', 'release'], }
'dan' => { uid => '1308',
group => allstaff,
groups => ['developers', 'prosvc', 'release'], }
}
create_resources(user, $myusers)
Имеет ли это смысл?
Тогда вы можете избежать определенного типа и вы можете выполнять все операции с данными в вызове функции, чтобы получить хеш хэшей, и у вас есть хорошее разделение между функцией, которая собирает данные, и функцией, которая создает экземпляры ресурсов.
Это должно решить любую необходимость в классической итерации, если я правильно понимаю вашу проблему.