Возврат нескольких пользовательских фактов с помощью Puppet Facter
Я пытаюсь добавить пользователей в систему в качестве фактов марионеток. Я не программист ruby, и следующий код правильно генерирует пользователей, но их uid одинаков (uid последней записи в файле паролей). Если бы uid находился вне области видимости, я ожидал бы неизвестную символьную ошибку, если Facter.add вызывался только один раз в конце, я бы ожидал, что будет только один пользователь, последний, такой же, как uid. Я не понимаю, как можно перебирать, пока другой не делает это...
File.open("/etc/passwd", "r") do |passwords|
while pw_entry = passwords.gets
user, pw, uid, gid, gecos, home, shell = pw_entry.split(/:/)
Facter.add("user_" + user) do
setcode do
uid
end
end
end
end
В поисках я нашел кого-то еще с почти идентичной проблемой, и это было решением (которое также работало для меня):
require 'etc'
Etc.passwd { |user|
Facter.add("user_" + user.name) {
setcode {
user.uid
}
}
}
... однако я не понимаю, в чем разница. Он действует как вызовы к блоку Facter.add, которые буферизуются и запускаются одновременно в конце цикла, и Etc загружает весь passwd, поэтому индексы user.uid в массив и время не имеют значения. Это было бы странно для процедурного языка, хотя...
1 ответ
Вы правы сказать следующее:
File.open("/etc/passwd", "r") do |passwords|
while pw_entry = passwords.gets
user, pw, uid, gid, gecos, home, shell = pw_entry.split(/:/)
print uid
end
end
почти эквивалентно:
require 'etc'
Etc.passwd { |user|
print uid
}
На самом деле эти два фрагмента рубина дадут абсолютно одинаковый результат.
Единственное отличие состоит в том, что последний метод использует другой способ перебора файла passwd. Он использует замыкание, которое получает параметр user
в качестве входа. это user
единственный user
который существует в рамках анонимной функции.
Теперь о вашей проблеме с разницей между вашими двумя методами:
Когда вы ссылаетесь на переменные внутри рубинового замыкания, которые не принадлежат самому замыканию (то есть внешним переменным), ссылка на символ этой переменной в этой (внешней) области видимости сохраняется внутри кода замыкания. Поскольку в первом методе вы повторно используете один и тот же символ в той же области видимости, uid
ссылается на последнее известное значение uid
когда код замыкания вызывается после добавления всех фактов. Это известно как ловушка внешней переменной.
Одним из способов обойти эту проблему является наличие каждого uid
существуют в своем собственном объеме.
def addUserFact(passwd_entry)
user, pw, uid, gid, gecos, home, shell = passwd_entry.split(/:/)
Facter.add("user_" + user) do
setcode do
uid
end
end
end
File.open("C:/cygwin/etc/passwd", "r") do |passwords|
while pw_entry = passwords.gets
addUserFact(pw_entry)
end
end