How to pass command line parameters to capistrano - ruby

I am using Capistrano v2.9.0.
I run this command:
cap deploy:tryout -S testvar=thing
and my deploy.rb contains this:
namespace :deploy do
task :tryout do
if defined? testvar
puts "param: #{testvar}\n"
else
puts "no branch!\n"
end
end
end
The output is "no branch!". How do I pass values from the command line? I tried looking into the code, and I can see options.rb where it adds the passed parameter to options[:pre_vars], but that seems to be an instance variable, and I can't figure out how to access it from my deploy script.

Solution:
The options can be accessed via #parent.variables hash, so if the command line string is testvar=thing, then #parent.variables[:testvar] has the value string.
This seems really ugly and hacky, but it works.
Edit:
Turns out it is also available locally via variables[:testvar]

Related

Rake task selectivly ignoring new code

In a rake task I'm writing some puts statements show changes while others don't. For instance changing
puts model+" | "+id
into
puts model+" * "+id
doesn't change in the output of the script. However in some places changing
puts "Connecting to "+site
into
puts "Connecting to ----"+site
shows the changes that where made.
In the places where any changes to the line doesn't change the output, adding a new puts statement before or after don't show up when the task is run. Commenting out lines of code around the unchanging puts statements that do the actual work cause the script to not execute those lines, just as it should, but changing or adding puts statements there do not change the output of the script.
Removing all other tasks and emacs backup files from the lib/tasks folder doesn't help. I've been bitten before by having a backup copy of a task with the same namespace and task name running instead of the one I was working on.
This is being run with Ruby 2.4.3 on OpenBSD 6.3-stable on a fx-8350. I would post the whole script but the company I'm working for won't allow it.
How about
puts "#{model} +/*/whatever #{site}"
It shouldn't matter to what sounds like a filesystem update issue (reboot), but it's probably better form to put the variables in the string like that instead of + "" them.

action_class.class_eval method not working with execute resource's environment property

I have an interesting problem where I refactored a recipe by creating a Chef resource to handle some tasks I may need in other recipes. For instance, I've created the following action:
resource_name :my_command
action :run do
execute "Execute my command" do
environment ({"SETTINGS_FOLDER" => node['settings']['folder']})
command "#{command_exe} -some -params"
end
end
action_class.class_eval do
def command_exe
"#{node['command']['folder']}\\bin\\command.exe"
end
end
When I call my_command from a recipe it works as expected. However I have several other actions that this resource will implement that'll all use the same environment. So what I did was refactor the resource to look like this:
resource_name :command
action :run do
execute "Execute my command" do
environment env
command "#{command_exe} -some -params"
end
end
action_class.class_eval do
def command_exe
"#{node['command']['folder']}\\bin\\command.exe"
end
def env
{"SETTINGS_FOLDER" => node['settings']['folder']}
end
end
What happens now is, once chef-client executes the my_command resource it appears as though the SETTINGS_FOLDER environment variable on the machine winds up looking like this:
SETTINGS_FOLDER = ""C:\my\settings\folder""
Notice the doubled double-quotes? I'm not sure why this is happening, but it makes my command.exe very angry :(
The ['settings']['folder'] attribute is defined in the cookbook's attributes/default.rblike so:
default['settings']['folder'] = 'C:\\my\\settings\\folder'
My node is running chef-client 13.0.118
EDIT I think the doubled double-quotes was a red herring. I think the logger just represented the hash in that way. My new thought is that perhaps the env method is not being evaluated before being passed to the environment, but rather the function reference itself is being passed. Bear with me, Ruby isn't my first language...
The "env" method name might be a reserved word or is getting stomped later in the run. Try a different name for that method, perhaps?

Ruby - Running rb file from script [duplicate]

This question already has answers here:
Running another ruby script from a ruby script
(7 answers)
Closed 7 years ago.
I'd like to write a ruby script that then calls another ruby script.
Example, I'd like to run the "test1.rb" from my script.
The test1.rb has been simplified to just do this:
print "1"
Then get the result (-> 1).
I tried to complete this problem with backticks or another executing command (%x[#{"test1.rb"}], system("test1.rb") etc.), but it didn't work.
So any idea how I call one script that then calls another script (either relinquishing total control or forking), and get the results?
Thanks
You can simply require the file, which would load the code and execute it:
require_relative "path/test1"
For the sake of having controll over the the run code, I would advice to place your script in a method:
# In test1.rb
def exec_my_script
puts 1
end
# In your main script
require_relative "path/test1"
exec_my_script
EDIT: Ok, since this does not seem to work for your usecase, you can read the file as string and eval the string as so:
result = eval(File.read("path/test1.rb"))
# do something with result
I do NOT like this approach, because it feels kinda "hacky" and is by all means insecure and it will only work if the last thing called in your test1 script returns the result you need...
You may want to use open3
require 'open3'
cmd = 'ruby test1.rb'
#You may change the contents of cmd like you would run it from the command line; like ruby [directory]/filename
Open3.popen3(cmd) do |stdin, stdout|
var = stdout.read
puts var
end
system('ruby test1.rb') # should do the trick
You can also make test1 executable (with chmod) and add the shebang line on top of test1.
You then can call
system("./test1.rb")
Ok, the system('ruby test1.rb') and system("ruby", "test1.rb") command worked.
And now, I like to set the returning value ("1") to a variable.
How I do it? It's possible to do that with backticks?

Passing variables between chef resources

i would like to show you my use case and then discuss possible solutions:
Problem A:
i have 2 recipes, "a" and "b".. "a" installs some program on my file system (say at "/usr/local/bin/stuff.sh" and recipe "b" needs to run this and do something with the output.
so recipe "a" looks something like:
execute "echo 'echo stuff' > /usr/local/bin/stuff.sh"
(the script just echo(es) "stuff" to stdout)
and recipe "b" looks something like:
include_recipe "a"
var=`/usr/local/bin/stuff.sh`
(note the backquotes, var should contain stuff)
and now i need to do something with it, for instance create a user with this username. so at script "b" i add
user "#{node[:var]}"
As it happens, this doesn't work.. apparently chef runs everything that is not a resource and only then runs the resources so as soon as i run the script chef complains that it cannot compile because it first tries to run the "var=..." line at recipe "b" and fails because the "execute ..." at recipe a did not run yet and so the "stuff.sh" script does not exist yet.
Needless to say, this is extremely annoying as it breaks the "Chef runs everything in order from top to bottom" that i was promised when i started using it.
However, i am not very picky so i started looking for alternative solutions to this problem, so:
Problem B: i've run across the idea of "ruby_block". apparently, this is a resource so it will be evaluated along with the other resources. I said ok, then i'd like to create the script, get the output in a "ruby_block" and then pass it to "user". so recipe "b" now looks something like:
include_recipe "a"
ruby_block "a_block" do
block do
node.default[:var] = `/usr/local/bin/stuff.sh`
end
end
user "#{node[:var]}"
However, as it turns out the variable (var) was not passed from "ruby_block" to "user" and it remains empty. No matter what juggling i've tried to do with it i failed (or maybe i just didn't find the correct juggling method)
To the chef/ruby masters around: How do i solve Problem A? How do i solve Problem B?
You have already solved problem A with the Ruby block.
Now you have to solve problem B with a similar approach:
ruby_block "create user" do
block do
user = Chef::Resource::User.new(node[:var], run_context)
user.shell '/bin/bash' # Set parameters using this syntax
user.run_action :create
user.run_action :manage # Run multiple actions (if needed) by declaring them sequentially
end
end
You could also solve problem A by creating the file during the compile phase:
execute "echo 'echo stuff' > /usr/local/bin/stuff.sh" do
action :nothing
end.run_action(:run)
If following this course of action, make sure that:
/usr/local/bin exist during Chef's compile phase;
Either:
stuff.sh is executable; OR
Execute it through a shell (e.g.: var=`sh /usr/local/bin/stuff.sh`
The modern way to do this is to use a custom resource:
in cookbooks/create_script/resources/create_script.rb
provides :create_script
unified_mode true
property :script_name, :name_property: true
action :run do
execute "creating #{script_name}" do
command "echo 'echo stuff' > #{script_name}"
not_if { File.exist?(script_name) }
end
end
Then in recipe code:
create_script "/usr/local/bin/stuff.sh"
For the second case as written I'd avoid the use of a node variable entirely:
script_location = "/usr/local/bin/stuff.sh"
create_script script_location
# note: the user resources takes a username not a file path so the example is a bit
# strange, but that is the way the question was asked.
user script_location
If you need to move it into an attribute and call it from different recipes then there's no need for ruby_blocks or lazy:
some cookbook's attributes/default.rb file (or a policyfile, etc):
default['script_location'] = "/usr/local/bin/stuff.sh"
in recipe code or other custom resources:
create_script node['script_location']
user node['script_location']
There's no need to lazy things or use ruby_block using this approach.
There are actually a few ways to solve the issue that you're having.
The first way is to avoid the scope issues you're having in the passed blocks and do something like ths.
include_recipe "a"
this = self
ruby_block "a_block" do
block do
this.user `/usr/local/bin/stuff.sh`
end
end
Assuming that you plan on only using this once, that would work great. But if you're legitimately needing to store a variable on the node for other uses you can rely on the lazy call inside ruby to do a little work around of the issue.
include_recipe "a"
ruby_block "a_block" do
block do
node.default[:var] = `/usr/local/bin/stuff.sh`.strip
end
end
user do
username lazy { "#{node[:var]}" }
end
You'll quickly notice with Chef that it has an override for all default assumptions for cases just like this.

Mercurial HG_NODE hook variable on windows

I'm currently testing mercurial hooks on windows and it seems like I cannot access hook variables....
here's hgrc content :
[hooks] prechangegroup = ruby prechangegroup.rb test1 test2 $HG_NODE
I also tried with %HG_NODE%
Here's prechangegroup.rb content
ARGV.each do|a|
puts "Argument: #{a}"
end
It prints out:
Argument: test1
Argument: test2
Argument: $HG_NODE$
Followed by the normal push output...
Any idea? (probably something stupid but, I can't seem to find it)
Thanks
HG_NODE is an environmental variable. You don't have to use it as arguments on the command line. Instead, you should be able to use it as puts ENV['HG_NODE'] (found through search engine as I'm not a ruby guy)
OK, I found a good documentation right on mercurial's website.
http://www.selenic.com/mercurial/hgrc.5.html#hooks
I tried with a variable other than %HG_NODE% like %HG_URL% and the variable worked.
So it probably means that the variable is inaccessible from that hook.

Resources