0

In a module I'm working on, I need to check if specific users exist on a machine. The idea was to create a custom fact that contains an array of all users. In the module, it should iterate through the array and check if a specific user is part of the array.

My Custom Fact:

Facter.add("users") do
  setcode do
    IO.readlines("/etc/passwd").collect do |line|
      line.split(":").first
    end
  end
end

The output of the fact is a String like this: ["user1", "user2", "user3"]

Because it is just a string and no array, I'm unable to iterate through it in my puppet module.

I then tried

  shell_split($::users).each |String $user| {
    notify { "$user":}
  }

But now, each user contains a comma after the username.

Do you have an idea for a working and better solution?

Studentus
  • 49
  • 1
  • 10
  • _"The output of the fact is a String like this: ['user1', 'user2', 'user3']"_ - It does not look like a string. It is an array. – Jagdeep Singh Jul 03 '18 at 11:36
  • 1
    @JagdeepSingh Yeah it looks like an array. But the point is, that it is a string with the content of an array. If I use validate_array(), It also tells me that it's not an array but a string. – Studentus Jul 03 '18 at 11:39
  • You will need to elaborate "string with content of an array". Can you paste what you actually have in your terminal? – Jagdeep Singh Jul 03 '18 at 11:48
  • I am unable to reproduce this. That fact code outputs an array for me and not a string. I double checked it with `.instance_of?(Array)` to verify. You will need to post more information to verify that your question matches your situation. – Matthew Schuchard Jul 03 '18 at 11:51
  • @MattSchuchard Yeah inside of the ruby code/fact, it is an array. But the fact doesn't pass it as array to puppet (but as a string). validate_array($::users) tells me "[\"user1\", \"user2\", \"user3\"]" is not an Array. It looks to be a String – Studentus Jul 03 '18 at 11:55
  • 1
    This is pretty much a textbook example of a method that does too much that should be broken up so that you can test and understand the components better individually. – Marc Talbot Jul 03 '18 at 12:08

2 Answers2

2

The output of the fact is a String like this: ["user1", "user2", "user3"]

No, it isn't. The Ruby code you presented in the fact's setcode block evaluates to an array. That expression provides the value of the fact. It is an array.

It is possible, however, that Puppet converts that array to a string after receiving it from Facter. Puppet 3 did this by default, but had a boolean stringify_facts configuration setting that could prevent that behavior. Puppet 4 retained that setting but deprecated it and reversed its default value (to false). Puppet 5 removed the setting, and never stringifies fact values.

Therefore, if you are using (obsolete) Puppet 3 then you can avoid fact stringification by setting

stringify_facts = false

in the [main] section of your puppet.conf files on the master and all agents. You can do the same on Puppet 4, but there you can also just ensure that the stringify_facts setting is not explicitly set at all.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

Assuming, you have this as the output of Factor.add:

output = '["user1", "user2", "user3"]'

You can convert it to an Array with the help of JSON:

require 'json'

JSON.parse output
 => ["user1", "user2", "user3"] 
Jagdeep Singh
  • 4,880
  • 2
  • 17
  • 22
  • Sorry for my wrong output. It is already like ["user1", "user2", "user3"] but the output is just a string with the content of above. I can only pass a string from facter to puppet. Inside the fact, it is an array I guess. – Studentus Jul 03 '18 at 11:48