Chef passing revision variable to deploy resource - ruby

I'm trying to pass the git branch that I want to deploy to the Chef deploy resource but it isn't working, I'm guessing it's because the resources are compiled separately and then just executed? But I might be wrong as my understanding of Ruby is limited.
So I'm trying to do this:
ruby_block 'revision' do
block do
# Some code determines the branch to be deployed
branch = 'master'
node.run_state['branch'] = branch
end
end
deploy "#{node['path']['web']}" do
action :deploy
repository "#{node['git']['repository']}"
revision "#{node.run_state['branch']}"
end
However the deploy resource doesn't get passed that variable.
Is this the correct way to go about this? Is there a better or other way?
Thanks in advance!

At the moment chef compiles your deploy resource ruby_block resource is not run yet, so node.run_state['branch'] is not set. You have to move your deploy resource into ruby_block and define it dynamically.
ruby_block 'revision' do
block do
# Some code determines the branch to be deployed
branch = 'master'
node.run_state['branch'] = branch
depl = Chef::Resource::Deploy.new node['path']['web'], run_context
depl.repository node['git']['repository']
depl.revision node.run_state['branch']
depl.run_action :deploy
end
end

Related

Chef - run install block based on variable condition

Background: our systems are setup in a way that I will only be able to see the local chef log and will have no access to the Chef server console or any other sysadmin privileges. Hence I have a need to log locally if I want to see if or why something failed.
I can hear you asking " If you don't trust the pkg or Chef to install it correctly, then..." My answer is that while you are correct, I still want to be covered by the occasional anomaly.
My goal is to install a pkg, check to see that it installed correctly than go on to the next pkg.
On to the question:
I would like to set a variable that checks for the existence of a directory that was created by the first package using the following code:
mycond = ::File.directory?('/opt/MyPkg/conf')
Chef::Log.fatal("MyPkg package not installed ? conf dir is missing") unless mycond
the next stage in the recipee is to run the next install block checking to see if the variable has been set.
yum_package 'OtherPkg' do
action :install
only_if { mycond }
end
My question is since the only_if is failing, I was wondering if there was something wrong with the way I am setting the mycond variable ? perhapes {} braces are needed somewhere in the code ?
Total Chef newbie so please be specific with your answer.
Thanks !
Full code below:
yum_package 'MyPkg' do
flush_cache [ :before ]
action :install
end
mycond = ::File.directory?('/opt/MyPkg/conf')
Chef::Log.fatal("MyPkg package not installed ? conf dir is missing") unless mycond
yum_package 'OtherPkg' do
action :install
only_if { mycond }
end
The problem is Chef's two-pass model. See https://coderanger.net/two-pass/ for the full explanation for for this you just need to move the condition check in to the only_if block itself since that is delayed until converge time: only_if { ::File.directory?('/opt/MyPkg/conf') }.
Using the fatal log level is also probably not a good idea as this isn't actually a fatal error as written.
Chef has an order of precidance that controls the flow of execution.
Code inside resource blocks (e.g. 'yum_package') will execute AFTER any loose code in your recipe.
The following lines are being executed FIRST, before your 'yum_package' blocks:
mycond = ::File.directory?('/opt/MyPkg/conf')
Chef::Log.fatal("MyPkg package not installed ? conf dir is missing") unless mycond
I believe you can nest resource blocks. You cold be able to combind all this code in a 'ruby_block' and it should execute in order as you'd expect.

How to combine a different provider with the Chef deploy resource?

I am trying to create a recipe to deploy an application.
I would like to combine the Chef deploy resource with the Chef Mercurial provider. The readme of this provider suggest that it is easy to use with deploy resource. However, I'm not sure how to do this.
The mercurial resource is working as expected:
mercurial deploy[:deploy_to] do
repository deploy[:scm][:repository]
ssh_key "/home/vagrant/.ssh/authorized_keys"
ssh_ignore true
branch true
revision deploy[:scm][:revision]
user deploy[:user]
group deploy[:group]
action :sync
end
However I'm having trouble with the provider
deploy deploy[:deploy_to] do
repository deploy[:scm][:repository]
user deploy[:user]
group deploy[:group]
revision deploy[:scm][:revision]
environment deploy[:environment].to_hash
scm_provider Chef::Provider::Mercurial
action :deploy
end
The error I'm getting is NoMethodError: undefined method 'ssh_key' for Chef::Resource::Deploy. This is probably due to the fact that the resource requires the ssh_key attribute. I don't know how to pass this attribute through when using the deploy resource.
How can I make this work?
Does anyone have an example of how to use the Chef deploy resource with the Chef Mercurial provider?

Chef - Read a file from git repo at runtime and use parse value in recipe

I would like to read a file from a checkout git repository to parse a config file and use this data to perform few resources commands.
git "/var/repository" do
action :sync
end
config = JSON.parse(File.read("/var/repository/config.json" ))
config.each do |job, flags|
#do some resources stuff here
end
This will not work because the file doesn't exist at compile time:
================================================================================
Recipe Compile Error in /var/chef/cache/cookbooks/...
================================================================================
Errno::ENOENT
No such file or directory - /var/repository/config.json
I where trying to load the file in ruby_block and perform the Chef resource actions there, but this didn't worked. Also setting the parsed config to a variable and use it outside of the ruby_block didn't work.
ruby_block "load config" do
block do
config = JSON.parse(File.read("/var/repository/config.json"))
#node["config"] = config doesn't work - node["config"] will not be set
config.each do |job, flags|
#do some stuff - will not work because Chef context is missing
end
end
end
Any idea how I could read the file at runtime and used the parsed values in my recipe?
You may also find it helpful to use lazy evaluation in scenarios like this.
In some cases, the value for an attribute cannot be known until the execution phase of a chef-client run. In this situation, using lazy evaluation of attribute values can be helpful. Instead of an attribute being assigned a value, it may instead be assigned a code block.

Mina deployment : invoke task once `current` symlink is updated

I'm using Mina (a simpler alternative to Capistrano) to deploy my ruby websites, and I am trying to run some tasks once the current symlink has been updated.
So far, here's what I have in my deploy.rb file:
desc "Deploys the current version to the server."
task :deploy => :environment do
deploy do
invoke :'git:clone'
invoke :'deploy:link_shared_paths'
invoke :'bundle:install'
to :launch do
invoke :restart
end
end
end
desc "Manually restart Thin web server"
task :restart do
in_directory "#{deploy_to}/current" do
queue! %[bundle exec thin restart -C "#{thin_yml}"]
end
end
My problem is that when Mina hits the to :launch block, the current symlink has not yet been updated, so either it does not exist (if it is the 1st deployment for this project) or it's still pointing to the n-1 release (and thus, the server uses an outdated version of the project).
So I'd like to be able to invoke my :restart task once the new release has been moved to the release directory and the current symlink has been updated.
I think it's a bug of Mina. in_directory seems to not work properly when used inside a to context. A quick and dirty workaround would be adding #commands[:default] = commands(#to) at the end of the in_directory block.
desc "Manually restart Thin web server"
task :restart do
in_directory "#{deploy_to}/current" do
queue! %[bundle exec thin restart -C "#{thin_yml}"]
#commands[:default] = commands(#to)
end
end

Chef-solo: deploy: access to release_path

I have following Chef cookbook:
deploy "/home/prj" do
repo "https://path_to_repo"
user node.project_owner
group node.project_owner
symlink_before_migrate({})
end
How can I access to the provider's release path? In my case in will be: /home/prj/releases/20120506125222/ .
It depends on where you want to access the release path. "Inside" the resource, i.e. the callbacks, that's easily possible using something iike
deploy "/home/prj" do
before_migrate do
gemfile = File.read("#{release_path}/Gemfile")
end
end
Outside of the resource, you don't have the release_path variable available. You can however use the current symlink which points to the currently deployed version, i.e. the last release:
current_path = "home/prj/current"
release_path = File.readlink(current_path)
Most of the time, you can to things directly in the current_path without having to resort to resolving the symlink target.
That said, you typically don't want to actually do things in there directly. Instead, you are encouraged to generate additional files in the shared directory (i.e. /home/prk/shared) and let chef symlink those files into the release during deployment. That's exactly what symlink_before_migrate is for. That way, you don't need to actually know the release path yourself but can let chef handle that for you.

Resources