Using databag in recipe

I have been struggling for over a week to solve this issue. Is there anyone who can help me out solving this.

I have a databag called mongo, the contents of the databag are:
{
"firstuser": {
"id": "firstuser",
"password": "123",
"db": "mydb",
"role": "readWrite"
},
"seconduser": {
"id": "seconduser",
"password": "123",
"db": "mydb",
"role": "readWrite"
},
"thirduser": {
"id": "thirduser",
"password": "123",
"db": "mydb",
"role": "read"
},
"id": "users"
}

I want to loop through this databag, in order to create users in MongoDB. How do I access the items for firstuser? For example id, password, db, role etc?
This is what I have come up with (and a lot more fruitless attempts)

data_bag('mongodb').each do |item|
repository = data_bag_item('mongodb', item)
log 'RARARARA: log message' do
if repository['firstuser']
Chef::Log.debug("RARAR DS.repository: #{repository['id']} ")
end
end
end

hi @rajanarkenbout

There are cookbooks out there that already do this, users springs to mind.

The structure in the data bag is the same as a Ruby hash, therefore you can use each_pair

users_databag = data_bag('mongodb', item)
users_databag.each_pair do | user, values |
log "user #{user} id #{values['id']} password #{values['password']}"
end

Hope this helps

1 Like

Cheers mate!

Some minor tweaking and it works

recipe:
data_bag(‘mongodb’).each do | item |
users_databag_item = data_bag_item(‘mongodb’, item)
users_databag_item.each_pair do | user, values |
log "user #{user} id #{values[‘id’]} password #{values[‘password’]}"
end
end

output:
log[user firstuser id firstuser password 123] action write

It seems that this issue is not resolved yet. Right now I am stuck with printing extra empty entries. Any ideas about that?

What´s got me baffled is the fact that I first get 2 empty records, than the 3 expected records and than another empty one…
Check out the output;

  • log[db.createUser( { user: ‘’, pwd: ‘’, roles: [ { role: ‘’, db: ‘db’ } ] } )] action write
  • log[db.createUser( { user: ‘’, pwd: ‘’, roles: [ { role: ‘’, db: ‘db’ } ] } )] action write
  • log[db.createUser( { user: ‘firstuser’, pwd: ‘123’, roles: [ { role: ‘readWrite’, db: ‘mydb’ } ] } )] action write
  • log[db.createUser( { user: ‘seconduser’, pwd: ‘123’, roles: [ { role: ‘readWrite’, db: ‘mydb’ } ] } )] action write
  • log[db.createUser( { user: ‘thirduser’, pwd: ‘123’, roles: [ { role: ‘read’, db: ‘mydb’ } ] } )] action write
  • log[db.createUser( { user: ‘’, pwd: ‘’, roles: [ { role: ‘’, db: ‘’ } ] } )] action write

Please advise

recipe code:

data_bag(‘mongodb’).each do | item |
users_databag_item = data_bag_item(‘mongodb’, item)
users_databag_item.each_pair do | user, values |
log "db.createUser( { user: ‘#{values[‘id’]}’, pwd: ‘#{values[‘password’]}’, roles: [ { role: ‘#{values[‘role’]}’, db: ‘#{values[‘db’]}’ } ] } )"
end
end

Hello @rajanarkenbout

I think your code should work, it’s similar to the code on the Chef data bag page which has two loops, the data bag and item https://docs.chef.io/data_bags.html#create-users

The users community cookbook is slightly different as it performs a search on the data bag to retrieve a list of items, as below

search('mongodb', "user:*") do |user| 
log "id #{user['id']} pwd #{user['password']}"
end

Are you converging using Test Kitchen and Chef Zero or is this a node running against a Chef Server?

If you run the following from the command line

knife data bag show mongodb

Does it show three or five data bags?

Hi @chris_sullivan,

I am using Chef Server.
knife data bag show mongodb keyfile
users
Which means that it loops through the keyfile item as well. Hence the reason for the empty records.

I’ll have a shot at something like this.
data_bag(‘mongodb’, ‘users’) do | item |
or

data_bag(‘mongodb’, ‘users’) do | item |

users_databag_item = data_bag_item(‘mongodb’, users)

Thanks again I really appreciate it.

Hello @rajanarkenbout

Glad you found out where the extra items are coming from.

Just as an aside, you can always use Chef search to filter the data bag items.

Search is available from a Chef recipe and also from the command line via knife search

knife search mongodb "id:users"

or in a recipe

users = search(:mongodb, "id:users")

or you can exclude data bags

knife search mongodb "NOT id:keyfile"

or in a recipe

users = search(:mongodb, "NOT id:keyfile")

Hope this helps.

@chris_sullivan

Using the following code I am faced with one ‘empty’ record… Some progress but not quite enough.

users_databag_item = data_bag_item(‘mongodb’, ‘users’)
users_databag_item.each_pair do | user, values |
log "db.createUser( { user: ‘#{values[‘id’]}’, pwd: ‘#{values[‘password’]}’, roles: [ { role: ‘#{values[‘role’]}’, db: ‘#{values[‘db’]}’ } ] } )"
end

Now I have been trying the search option you mentioned, but can seem to get it to log anything. The result is that the variables are empty. How would approach this? Can you give an example of the code?

Ihave tried to check if not empty,. but to no avail. No recordds are retrieved.

users_databag_item = data_bag_item(‘mongodb’, ‘users’)
users_databag_item.each_pair do | user, values |
if !values.empty? do
log "db.createUser( { user: ‘#{values[‘id’]}’, pwd: ‘#{values[‘password’]}’, roles: [ { role: ‘#{values[‘role’]}’, db: ‘#{values[‘db’]}’ } ] } )"
end
end
end

I believe the culprit is (“id”: “users”) in my databag. Is there a way to filter out this entry?

To prove this I have added

“id”: “users”, “password”: "123"
which resulted in 2 extra empty records.

So, I need to filter out: (“id”: “users”).

Hello @rajanarkenbout,

There are a couple of things you can do

  1. filter your hash and ignore keys with the value of id (using select, reject or just continue loop)
  2. modify the structure of your data bags an add an extra level called “users”

Example of 1.

data_bag('test').each do |item|
   db = data_bag_item('test', item)
   db.each_pair do |k,v|
      next if k == 'id'
      log "id #{v['id']} pwd #{v['password']}"
   end
end

Example of 1. using search


db = search('test', 'NOT id:keyfile')
db.each do |item|
   item.each_pair do |k,v|
      next if k == 'id'
      log "id #{v['id']} pwd #{v['password']}"
   end   
end

Example 2.
Change data bag to add extra layer in hash

{
    "users": {
      "firstuser": {
      "id": "firstuser",
      "password": "123",
      "db": "mydb",
      "role": "readWrite"
    },
      "seconduser": {
      "id": "seconduser",
      "password": "123",
      "db": "mydb",
      "role": "readWrite"
    },
      "thirduser": {
      "id": "thirduser",
      "password": "123",
      "db": "mydb",
      "role": "read"
    }
  },
  "id": "users"
}

Code for extra layer

data_bag('test').each do |item|
   next if item == 'keyfile'
   db = data_bag_item('test', item)
   db['users'].each_pair do |k,v|
      next if k == 'id'
      log "id #{v['id']} pwd #{v['password']}"
   end
end

Hi, When iam using above code in my recipe.Its working fine.
When iam running spec test its saying each is undefined method .Failure.
Can you help on this