我正在尝试编写一个 puppet 函数来调用我的托管环境(rackspace cloud atm)来列出服务器,然后更新我的主机文件。
我的 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 相当麻烦,但这似乎是我能让它工作的唯一方法。欢迎任何改进。
答案1
我不会说这是一个坏主意,但你确实需要停止在代码中随处使用常量(Ruby 中以大写字母开头的任何内容都是常量)。
要调试您的问题,您可能希望使用--trace
puppetmaster 调用的选项,这样它就会打印回溯,而不是处理真正的异常并向您提供无用的错误消息。您的map
调用中发生了一大堆取消引用;我猜您误解了 API 中传出的部分数据结构,而您的代码因这种误解而出错。启动调试器(或随意浏览puts
您的代码),您会很快发现您错在哪里。
答案2
我会以不同的方式区分此功能。
使用您的函数在代表主机资源列表的哈希哈希中构建纯数据。
然后使用 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)
那有意义吗?
然后,您可以避免定义的类型,并且可以在函数调用中执行所有数据处理以获取哈希的哈希值,并且您可以在收集数据的函数和实例化资源的函数之间进行良好的分离。
如果我正确理解了您的问题,这应该可以解决任何经典迭代的需求。