Why cant I access a variable outside a Capistrano task - ruby

I have want to set this deferred variable in Capistrano which depends on some variable I set during calling the task
set(:installation_dir) do
if target == "staging"
"/some/path"
else
"/some/other/path"
end
end
task :foo do
p "INSTALLATION_DIR >>> #{installation_dir}"
end
If running the task this error happens
Hector:monitoring-agent robertj$ cap foo -s target=development
/Users/robertj/.rvm/gems/ruby-2.0.0-p0#pf/gems/capistrano-2.15.4/lib/capistrano/configuration/variables.rb:122:in
`method_missing_with_variables': undefined local variable or method `target' for
#<Capistrano::Configuration:0x007fd6a22f9100> (NameError)
This is making me mad. Why doesnt Capistrano 2.x have a simple way to access variables where ever I call.

Looks like, fetch do what you want
p "INSTALLATION_DIR >>> #{fetch(:installation_dir)}"

When you run it like that, you're setting an environment variable. To use it in your Capistrano script you need to set :target, ENV['target'].

Related

Modify Rake Task at test/runtime

Consider the following
class Foo
def bar
1
end
end
And then two rake tasks ...
task :something
InvokeSomething(Foo.new)
end
task :test
do_some_testing
end
def do_some_testing
setup_test
`rake something`
check_if_it_did_everything_correctly
end
After executing setup_test, I want to modify the source for class Foo to return 2 for method bar.
Ideas:
Create a rake task that gets invoked before I define the rake task something and I modify the source code directly. So that something is defined with a different source code.
Somehow modify the Rake task so that that particular method is overridden. At the very least I need a reference to the rake task during runtime.
There are multiple ways to do this.
You can get the reference from Rake::Task["something"] during do_some_testing and re-define a method there.
But there is another even simpler way - which worked for me. Set the value in bar as an environment variable. And modify the environment variable when needed.

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?

Capistrano Ruby: Refactoring Reused String Values

I have a couple tasks within my deploy.rb file that execute within my theme folder.
I currently define them as follows:
namespace :deploy do
desc 'NPM Build Production'
task :npm_build_production do
on roles(:app) do
within "#{release_path}/web/app/themes/example" do
execute :npm, "install --silent --no-progress"
execute :npm, "run build:production"
end;
end
end
end
before 'deploy:updated', 'deploy:npm_build_production'
Everything is working correctly with this implementation, but since there are multiple instances where I use this path, I'd like to extract it to a symbol or variable. I am new to Ruby and am running into some issues.
I have tried using the code below, but for some reason the path ends up being wrong when executed in my tasks.
set :theme_path, -> { "#{release_path}/web/app/themes/example" }
These variables are set on different stages of implementation. for example the release_path variable is not defined in the setting variables section. Move your variable to your execution block for tasking and it will work . for example this snipped will work
namespace :deploy do
desc 'NPM Build Production'
task :npm_build_production do
on roles(:app) do
theme_path = "#{release_path}/web/app/themes/example"
within theme_path do
execute :npm, "install --silent --no-progress"
execute :npm, "run build:production"
end;
end
end
end
also you will be able to fetch some variables using this way while setting other variables like fetch(:varible_name) but I am not sure it is feasible for the release_path since it is a scoped variable
here is how you could do it with a function
def theme_path(release_path)
"#{release_path}/web/app/themes/example"
end
just call this function with your release_path variable and you will have the themepath wherever you want. inside your deployment logic.

How can I lazily set an environment variable using env in Chef?

I put credentials into an s3 bucket and I use a ruby block to grab them. I then want to set an environment variable such that when upstart starts a process it uses this variable. However the block of ruby runs after attributes are set so I thought using lazy would be appropriate, but it's not clear to me how to set env using lazy.
Would it be something like:
ruby_block "get-credentials" do
block do
Chef::Log.info 'Getting sdk.'
require 'aws-sdk'
Chef::Log.info 'Getting making aws s3 instance.'
s3 = AWS::S3.new
Chef::Log.info 'Getting credentials from s3.'
bar = s3.buckets['bucket-name'].objects['bar'].read
Chef::Log.info 'Got bar with length #{bar.length}'
node.set['foo']['bar'] = bar
end
action :run
end
env lazy BAR=node.set['foo']['bar']
service 'foo' do
provider Chef::Provider::Service::Upstart
action [ :enable, :start ]
end
I'm not sure. I am still looking through the documentation and experimenting but maybe someone knows. The turn around on testing different variations is taking a really long time.
The env resource only works on Windows, it has nothing to do with Linux. If you want to define environment variables for an upstart service it has to go in the upstart config, as the environment within Chef has no effect on things spawned from upstart.

Capistrano Checking for undefined variable in Task

In Capistrano using the Multi-stage extension I have two environments: prod and testing.
I need a few variables in testing.rb that are not needed in prod.rb and I want some of my tasks to be able to check if the variable is defined and use it if it is, but ignore it if it is not set.
So, in testing.rb I would have something like:
set :foo, 'bar'
prod.rb wouldn't have any reference to :foo since it doesn't need it. In one of my tasks, I would like to do something like:
if defined?(foo)
# do something with foo
else
# do something without foo
end
But I keep getting the error:
undefined local variable or method 'foo'
Is there a way to test for undefined global variables in the task? Or do I have to do something like:
set :foo, ''
In all my environments that don't need the :foo variable?
Try using exists?(:foo) instead of defined?(foo), as recommended in the Capistrano docs.

Resources