Возврат нескольких пользовательских фактов с помощью 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
Другие вопросы по тегам