How do I insert an encrypted data bag item value into a Chef recipe? - ruby

I've created an encrypted data bag value that I'm trying to load into a chef recipe.
knife data bag show foo bar --secret_file secret.key
Encrypted data bag detected, decrypting with provided secret.
id: bar
pass: p4ssw0rd
I'm trying to get the pass value to load up as a variable in a bash resource, and have the encrypted_data_bag_secret in /etc/chef on the client (hence no secret key show, reverting to default /etc/chef location):
dbag = Chef::EncryptedDataBagItem.load("foo", "bar")
foo_pass = dbag["pass"]
I've also tried using the recipe DSL instead of Chef::EncryptedDataBadItem method:
dbag = data_bag_item('foo', 'bar')
foo_pass = dbag["pass"]
And then loading it into a bash resource:
bash 'install_mysql' do
code <<-EOC
...
sudo mysqladmin -u root password {foo_pass}
...
EOC
end
I had a few questions regarding this process.
i) Will Chef::EncryptedDataBagItem.load be deprecated and replaced with data_bag_item; should I use one over the other?
ii) Am I pulling the dbag["pass"] using the correct methods; how would I grab the 'pass' value from inside foo (data bag) => bar (item?)
iii) To call the foo_pass variable inside the bash resource, do I just encapsulate the variable in curly braces {}, or am I missing something here?
iv) Is there a better method than what I am trying out?
I've tried adding the following to see if I can see the variable value printed to screen when running the chef-client, but it's not showing me any of the text or values:
puts "foo_pass equals 1:{foo_pass} 2:#{foo_pass}'
I've been hammering away at this for half the day, and was hoping to get some more experienced responses as how to handle this.

Yes prefer data_bag_item in most cases, it is more correct.
Yes, that is correct.
You need #{foo_pass}, with the leading #.

Related

Ruby Sinatra Upload Form params Disturbed

Upon submitting a form in Sinatra, I'm coming up with the following error:
App 40327 output: 2018-06-28 02:59:17 - NoMethodError - undefined method `[]' for nil:NilClass:
App 40327 output: /Library/WebServer/Documents/blammo/routes/publish.rb:87:in `block in <class:MyApp>'
The form is a file upload form, and a single text field. Simple. The file goes through, as does the text field. They are both captured just fine.
I submit the params to a method, which is ultimately responsible for generating the error on the following line down the page:
fname = params[:s_single_file_upload][:filename]
The method in question returns fine with a boolean. I've rewritten it a couple of ways and flushed out anything that might trip something I'm
unfamiliar with.
So the params is messed up if this method mentioned above is being called. So fname can't be assigned. I expect the params to be intact
at this point in the code. Is there any destruction if the params are perused before this point? In another language, I've seen params destroyed
in one way or another for some reason, but I'm not sure about Ruby.
I'm not finding any nil:NilClass, but that's exactly what it's reporting. Here's the trigger of this method:
result = Alpha::rf_alpha_sniff(params)
And the module::method:
module Alpha
def self.rf_alpha_sniff(incoming)
qualifiers = %w(alpha bravo charlie delta echo foxtrot)
incoming.delete('captures')
incoming.delete('splat') # take out Mustermann's 'captures' and 'splat'
incoming.delete('s_single_file_upload') # non-perusal 'single_file_upload'
incoming.values.each do |item|
item = item.gsub(" ","_")
Dev::hq_log("item: #{ qualifiers.include?(item.downcase) }")
return true if qualifiers.include?(item.downcase)
end
return false
end
end
So the page progresses fine without this method. When the method is induced any way, the params seem to get screwed up, so the file is pretty much
gone.
How is this method interfering with the params so that it's unavailable later on down the script? I'm expecting it to be fully available everywhere.
Turns out, using incoming.delete was deleting items from the params hash, as it was a reference to the original, instead of using a copy.
So, I have to copy the params by using params.dup (duplicate) so they are not the same object.
Having a view of the params hash post-testing-method, showed me that objects were indeed deleted. Another one solved.

How can I conditionally run a block of resources or a recipe in chef?

I've the following recipe used to create some users, add them to a group and set the password to expire at the first login.
search(:users, '*:*').each do |user|
userPassword = "$1$scmdevop$ZDTyqia9RXSrpHGK75FjN/"
user user['id'] do
comment user['comment']
home user['home']
shell user['shell']
manage_home true
password "#{userPassword}"
end
if user['sudo'] then
group "#{node.default["sudogroup"]}" do
action :modify
members user['id']
append true
end
end
if (user['resetPassword'] == nil) || (user['resetPassword']) then
bash 'setExporation' do
code 'chage -d 0 ' + user['id']
user 'root'
end
end
end
The problem is that in this way it will continue to reset the password and set the espiration at every run so I was trying to find how to make it conditionally. I would like to use the following command to check if the user exist
grep -qs #{user["id"]} /etc/passwd
The problem is that I can use the not_if clause only in the first resource because after that the user has been clearly created. Is there a way to get the entire block of three resources being conditional to a shell exit code?
Thanks,
Michele.
What you probably want is a notification from the user resource, but this might be a little hard because that would trigger on any change, not just creation. The underlying problem here is that the desired behavior you stated is expressed in procedural terms, not in terms of convergent state. Best approach is probably to build a custom resource to hide some of this logic, but at heart what you want is an if statement like you already have.

Rspec test on method that yields control

I am currently writing rspec tests for already written code of a project.
The code I am trying to test is something like the following:
def foo (ip, user)
#[...]
result = ""
Net::SSH.start(ip, user) do |session|
result = session.exec!('some_command_in_linux')
end
#[...]
end
What I am trying to accomplish is effectively decouple the assignment of the result from the execution of the remote command via SSH assign a fake string to the result variable.
I have read about yield matchers, but have not succeeded in applying them to my scenario.
More specifically, I was thinking something like:
expect {|block| Net::SSH::start(ip, user, &block).to receive(ip, user, &block).and_return(sample_output)}
Any ideas?
If you don't need the block to actually run - simply ignore it. It won't run, but it would be safely ignored:
expect(Net::SSH).to receive(:start).with(ip, user).and_return(sample_output)
If you do want the block to run, use and_yield:
session = double(:session).as_null_object
expect(Net::SSH).to receive(:start).with(ip, user).and_yield(session).and_return(sample_output)
If you want the session object to behave in a certain way, you can expect it to do stuff:
session = double(:session)
expect(Net::SSH).to receive(:start).with(ip, user).and_yield(session)
expect(session).to receive(:exec!).with('some_command_in_linux').and_return(sample_output)

Accessing Ruby Threads

Probably not even a valid question but how can I see what this block contains:
spec = Thread.current[:spec]
print spec # gives => #<RSpec::Core::ExampleGroup::Nested_1:0x7f61991d90c8>
Can I see any of the methods assigned to this or whatever is in it?
If more context is needed, I'm trying to understand what spec is doing here in function here but not being used anywhere (at least directly)
https://github.com/amfranz/rspec-hiera-puppet/blob/master/lib/rspec-hiera-puppet/puppet.rb#L7
To view properties do:
spec.inspect
If you want to access those properties:
spec.propertyyouwant

PageObject with Ruby - set text in a text field only works in the main file

I'm automating a site that has a page with a list of options selected by a radio button. When selecting one of the radios, a text field and a select list are presented.
I created a file (test_contracting.rb) that is the one through which I execute the test (ruby test_contracting.rb) and some other classes to represent my page.
On my class ContractPage, I have the following element declaration:
checkbox(:option_sub_domain, :id => "option_sub_domain")
text_field(:domain, :id => "domain_text")
select_list(:tld, :id => "domain_tld")
I've created in the ContractPage a method that sets the configuration of the domain like this:
def configure_domain(config={})
check_option_sub_domain
domain = config[:domain]
tld = config[:tld]
end
When I call the method configure_domain from the test_contracting.rb, it selects the radio button, but it doesn't fill the field with the values. The params are getting into the method correctly. I've checked it using "puts". Even if I change the params to a general string like "bla" it doesnt work. The annoying point is that if on test_contracting.rb I call the exact same components, it works.
my_page_instance = ContractPage.new(browser)
my_page_instance.domain = "bla"
my_page_instance.tld = ".com"
What I found to work was to in the configure_domain method, implement the following:
domain_element.value = config[:domain]
tld_element.send_keys config[:locaweb_domain]
Then it worked.
The documentation for the PageObjects module that I'm using as reference can be found here: http://rubydoc.info/github/cheezy/page-object/master/PageObject/Accessors#select_list-instance_method
Do you guys have any explation on why the method auto generated by the pageobject to set the value of the object didnt work in this scope/context ?
By the way, a friend tried the same thing with Java and it failed as well.
In ruby all equals methods (methods that end with the = sign) need to have a receiver. Let me show you some code that will demonstrate why. Here is the code that sets a local variable to a value:
domain = "blah"
and here is the code that calls the domain= method:
domain = "blah"
In order for ruby to know that you are calling a method instead of setting a local variable you need to add a receiver. Simply change your method above to this and it will work:
def configure_domain(config={})
check_option_sub_domain
self.domain = config[:domain]
self.tld = config[:tld]
end
I'm pretty new to this world of Selenium and page objects but maybe one of my very recent discoveries might help you.
I found that that assignment methods for the select_list fields only worked for me once I started using "self" in front. This is what I have used to access it within my page object code. e.g., self.my_select_list="my select list value"
Another note - The send_keys workaround you mention is clever and might do the trick for a number of uses, but in my case the select list values are variable and may have several options starting with the same letter.
I hope something in here is useful to you.
UPDATE (Jan 3/12)
On diving further into the actual Ruby code for the page object I discovered that the select_list set is also using send_keys, so in actuality I still have the same limitation here as the one I noted using the send_keys workaround directly. sigh So much to learn, so little time!

Resources