Puppet模板[Ruby]中的嵌套迭代



我本周开始学习Puppet,并努力实现/etc/ssh/sudo_authorized_keys的用户密钥。

我有一本sudo_users.yaml:中有密钥的用户词典

core::sudo_users_keys:
kate:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC3N..."
john:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC..."
marvin:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC3Nza..."

然后我在sudokeys.pp文件中创建这个:

class core::sudokeys {
file { "/etc/ssh/sudo_authorized_keys":
ensure  => file,
mode    => "0440",
content => template("core/sudo_authorized_keys.erb"),
}

正如您所看到的,我想通过迭代来实现模板。这是我当前的模板:

<%- scope['core::sudo_users_keys'].each | user | -%>
{
<%- if user[1] -%>
<%- $user[1]['keys'].each do | key | -%>
<%= $key[1]['type'] $key[1]['key'] -%> 
<%- end end -%>
}
<%- end -%>

我有相同的字典,其中包含ssh的id_rsa键,并使用如下交互。它非常适用于ssh_authorized_key,但在这种情况下,我可以通过向/etc/ssh/sudo_authorized_keys添加密钥来使用它。这就是为什么我决定使用模板,只在sudo_authorized_keys文件中注入密钥。

class core::sshkeys {
lookup("core::sudo_users_keys").each | $user | {
if $user[1] {
$user[1]["keys"].each | $key | {
ssh_authorized_key { "${user[0]}-${key[0]}":
ensure => present,
user   => $user[0],
type   => $key[1]["type"],
key    => $key[1]["key"],
}
}
}
}
}

Puppet文档不包括这种更复杂的迭代,我觉得自己在迷雾中徘徊。

目前,我在部署模板时遇到了这个错误,但我觉得我准备模板的方式不会像我想要的那样工作。

Internal Server Error: org.jruby.exceptions.SyntaxError: (SyntaxError) /etc/puppetlabs/code/environments/test/modules/core/templates/sudo_authorized_keys.erb:2: syntax error, unexpected tSTRING_BEG
_erbout.<< "    {n".freeze
^

我将感谢任何关于模板建设的建议。我应该更改什么以使其工作并仅提取typekey值?

您的方法是可行的,但您的代码存在多个问题,其中包括

  • 模板中的scope对象提供对Puppet变量的访问,而不是对Hiera数据的访问。可能最简单的解决方法是

    1. core::sudokeys类一个类参数来与数据关联(比如$userkeys(
    2. 更改数据的Hiera键,使其自动绑定到新的类参数,以及
    3. 在模板中,通过类参数访问数据(在这种情况下甚至不需要使用scope对象(
  • 在该模板中,您似乎为数据假设了与Hiera中实际结构不同的结构。你的数据是一个散列的散列,但你访问它的一部分,就好像在某个地方有数组一样(user[1]key[1](。此外,如果有一个或多个数组,请注意Ruby数组索引从0开始,而不是从1开始。

  • ERB模板中的Scriptlet代码是(仅(Ruby。您的scriptlet代码似乎混合了Ruby和Puppet语法。特别是,Ruby变量名没有前缀$,Ruby块参数出现在块内部,而不是块外部。

  • <%= ... %>标记a,用于分别输出一个Ruby表达式的值。您似乎正在尝试发射具有相同标记的多个表达式。

此外,值得注意的是,scriptlet代码可以跨越多行。这可以让事情变得更清楚。此外,您可能需要注意模板中的空白和换行符,以获得所需的输出。如果需要的话,ERB可以选择在scriptlet标记周围使用不需要的空白,但有时至少可以很容易地避免添加您不想要的空白。另一方面,请确保不要抑制您实际想要的空白。

所以,这里有一种以上所有可能采取的形式:

sudo_users.yaml

core::sudokeys::users_keys:
kate:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC3N..."
john:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC..."
marvin:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC3Nza..."

sudokeys.pp

class core::sudokeys($users_keys) {
file { "/etc/ssh/sudo_authorized_keys":
ensure  => file,
mode    => "0440",
content => template("core/sudo_authorized_keys.erb"),
}
}

sudo_authorized_keys.erb

<% @users_keys.each do | user |
if user.has_key?('keys') do
user['keys'].each do |key|
%><%= key['type'] %> <%= key['key'] %>
<%        # don't consume preceding whitespace here
end
end
end
%>

我使用了John Bollinger的答案,但在我的情况下,模板并不完美,因为我经常出现错误,例如syntax error, unexpected end-of-file _erbout

适合我的sudo_authorized_keys.erb文件是这样的:

<%- @users_keys.each do | user, config | -%>
<%- if config.has_key?('keys') -%>
<%- config['keys'].each do | name, value | -%>
<%= value['type'] %> <%= value['key'] %> <%= user %>
<%- end -%>
<%- end -%>
<%- end -%>

最新更新