Convert Chef recipe to series of Bash commands? - bash

Typically, one wants to convert Bash scripts to Chef. But sometimes (like, right now) you need to do the opposite. Is there an automatic way to get the list of commands run for a given Chef cookbook on a given configuration?
I'm not trying to end up with something with the full functionality of the Chef cookbook. I want to end up with a small set of commands that reproduce this particular installation on this particular environment. (The reason in this case is I need to separate out the 'sudo' commands and get them run by someone else. I do have sudo access on a machine that I could run Chef on to carry out this task though.)

I doubt you can do that in general, and even if you could, it would likely be more work than implementing what you need in Chef.
For example, even something as simple as creating a configuration file is implemented in Chef as ruby code; you would need to figure out a way to turn that into echo "…" > /etc/whatever.com. Doing that for all resources would be a major undertaking.
It seems to me that what you should actually do is modify any Chef cookbook that you use to run commands as a different user.
Things like template and file are pretty easy: the file will be created as root, and then chown-ed to the correct user. execute resources (which run commands) can be configured to run the command with su simply by specifying the user:
execute "something" do
command "whoami"
user "nobody"
end
It might take you a while to figure out, but once you get the hang of it it's pretty easy; much easier than converting to bash.

Related

pexpect kind of operation with ansible

I am looking to automate an interactive install process with ansible. This install does not have a silent install option or does not take command line arguments for the interactive questions. The question involve setting a folder location, making sure folder location is right etc for which answers might be default or custom.
I looked into the expect module of ansible but seems like it does not solve my purpose.
- expect:
command: passwd username
responses:
(?i)password: "MySekretPa$$word"
I don't need the command but it's required. Instead I am looking for something that could regex Are you sure you want to continue [y|n]? [n]: for which I want to send the default out By sending return or typing n as a response and for example Backup directory [/tmp] for which the response would be Carriage return.
I don't need the command but it's required. Instead I am looking for something that could regex Are you sure you want to continue [y|n]? [n]:
The module requires a command because you have to run something to get any output.
You obviously do have a command in mind, because you've run it manually and seen the output it produces. That's what you should be plugging into the module.
Alternatively, you can write a pexpect script yourself and use the command or shell modules to run it.
I've figured out a way that works for me. I piped in the arguments to the shell script which when run manually needs the answers. Like ./shell.sh <<< 'answer1\nanswer2\n' which works perfectly for me. This I have added to the task.

How to find files in ruby which were edited in some time interval?

How to find files in a directory which were edited in last n minutes?
In unix which is -mmin -60.
In host
ruby /home/ava/test works fine!
Net::SSH.start('host', 'ava') do |ssh|
`ruby /home/ava/test`
end
gives ruby: No such file or directory -- /home/ava/test (LoadError)
You could get a list of files using Dir.[], and use File.mtime on each one to filter them:
Dir["*"].select { |fname| File.mtime(fname) > (Time.now - 60) }
The problem with your code is that Ruby isn't control on the remote system you connect to, instead, the shell on that system is, and you're merely able to issue commands, as if you'd ssh'd into your own local system. Ruby's built-in commands, like Dir.chdir only apply locally, not to the remote session.
Your best bet is to write a script you execute that resides on that system, otherwise the task of executing commands becomes more difficult and you'll need to anticipate prompts and possibly various responses from commands on that system as your code executes things.
The Net::SSH gem includes examples showing how to issue remote commands; You need to remember that once you've connected you're issuing commands to the shell, not to Ruby.
Net::SSH.start('host', 'ava') do |ssh|
`ruby /home/ava/test`
end
gives ruby: No such file or directory -- /home/ava/test (LoadError)
The best way to diagnose this is to start by SSHing to your own local box and executing the code locally, or using surrogate code that only echoes the commands you'd be using in real life on the other machine. Then you can test to see if the actions would be called.
Instead of:
ruby /home/ava/test
issue a command like:
ls -al /home/ava
first, to see what files are visible.
Follow that with something like:
ruby -pe '%x(ls /home/ava)'
to see if Ruby is found and it can execute that command in the path.
Dealing with remote systems isn't the same as running scripts locally. Your environment can be different, meaning your PATH or variables you expect might not be the same.

Changing directory for User in Ruby script

I'm quite familiar with Dir.chdir("/xyz")
Unfortunately, this changes the directory of the process, but not actually the directory of the user. I'll make the following example to illustrate my need.
$~/: ruby my_script.rb
CHANGING TO PATH FOR USER NOT SCRIPT
$/Projects/Important/Path: pwd
$/Projects/Important/Path
See? I need the script to change the user's path. Performing system/backticks/Dir.chdir all adjust the process path, and end with the user sitting where they started, instead of the path I want them.
From what I've read exec was the way to go, since it takes over the existing process... but to no avail.
You can't, but you can do something which might be good enough. You can invoke another shell from ruby:
Dir.chdir("/xyz")
system("bash")
Running this will create a new bash process, which will start in the /xyz directory. The downside is that changing this process will bring you back to the ruby script, and assuming it ends right away - back to the bash process that started the ruby script.
Another hack that might work is to use the prompt as a hackish hook that will be called after each command. In the ruby script, you can write the new directory's path somewhere that can be read from both bash and ruby(for example a file - but not an environment variable!). In the PROMPT_COMMAND function, you check that file and cd to what's written there. Just make sure you delete that file, so you don't get automatically cded there after every command you run.

Calling Rspec with syntax like ruby -I

I am trying to use https://github.com/rifraf/Vendorize which is run using a command like
D:\projects\SomeLibrary\lib>ruby -I..\..\Vendorize\lib -rvendorize some_lib.rb
It does something clever where it intercepts required files and logs them, but only the ones that get executed in your command line. On it's documentation pages it says
You can run the program several times with different options if the
required files depend on the options.
Or just run your tests…
I want to run all the tests with the -I function from the command line above, so that all the different avenues of code are run, and the libraries loaded (and logged). Given that I can run them like:
D:\projects\SomeLibrary\lib>rspec ..\spec\some_spec.rb
How do I do this? Thanks!
NB: I am a/ a ruby newbie and b/ running windows
I would try writing something like this at the top of some_spec.rb:
require_relative '..\..\Vendorize\lib\vendorize'
You might need to change that a bit depending on what your working directory is.
Then just runs your specs with rspec as you normally do without any extra commands.
If that doesn't work, then locate the rspec.rb executable and run:
ruby -I..\..\Vendorize\lib -rvendorize path/to/rspec.rb ..\spec\some_spec.rb

how to invoke ruby script containing system command with cron job?

I have a ruby script containing system command like http://gist.github.com/235833, while I ran this script from shell, it works correctly, but when I added it to my cron job list, it doesn't work any more, the cron job is like:
10/* * * * * cd /home/hekin; /usr/bin/ruby my_script.rb
any idea what's going wrong with what i've done? Thank you.
Thank you all for your answers.
It's my mistake.
Since I'm using ssh key forwarding on the local machine, while I executed the script from the shell, the ssh key forwarding related environment variables are all sitting there, but from cron job context, those environment variables are missing.
Try to separate the things that might go wrong. The ones I can think of are:
The cron syntax - is the time value given legal and fitting your shell?
Permissions - execute permissions and read permissions for the relevant directory and file
Quoting - what scope does cron cover? Does it run only the first command?
In order to dissect this, I suggest you first run a really simple cron job, like 'ls'. Next run a single-liner script. Next embed your commands in a shell-script file. Somewhere along these lines you should find the problem.
The problem is your environment. While testing in your shell its fully equipped and boosted by your shell environment. While running under cron its very, very stripped down.
Where is the destination "." for your script? I guess it will be "/" and may not "$HOME" thus your script won't be able to write at that location and fails. Try using an absolut path for the destination.

Resources