0

Hello I'm new to Chef and Ruby. I'm trying to make a recipe in Chef To create a cron job on a server based on a value of a variable that I get inside my ruby code.

Gem.clear_paths
node.default["value"] = "nil"
require 'net/http'
ruby_block "do-http-request-with-cutom-header" do
    block do
      Net::HTTP.get('example.com', '/index.html') # => String
      uri = URI('http://example.com/index.html')
      params = { :limit => 10, :page => 3 }
      uri.query = URI.encode_www_form(params)
      res = Net::HTTP.get_response(uri)
      puts res.body if res.is_a?(Net::HTTPSuccess)
      value= res.code
      node["value"] = value
    end
end
if node["value"] == "nil" then
  cron "cassandra repair job" do
    action :delete
  end
else
  cron "cassandra repair job" do
    hour "0"
    minute "55"
    weekday node["value"]
    mailto "root@localhost"
    user "root"
    command "/opt/cassandra/bin/nodetool  repair -par -inc -pr"
  end
end

I know that chef has Lazy Evaluation variable method and ruby code is executing on a converge phase, but I can not figure out the way to modify my code.

How can I use lazy evaluation in my code ?

Tensibai
  • 15,557
  • 1
  • 37
  • 57
  • https://github.com/chef-cookbooks/cron – Rajarshi Das Apr 11 '16 at 08:32
  • @RajarshiDas The Q is not about the cron resource but about lazy evaluation, and when you edit a post you should try to fix it as a whole, not just part :) – Tensibai Apr 11 '16 at 08:42
  • [related if not duplicate](http://stackoverflow.com/questions/30424244/using-a-ruby-block-to-assign-variables-in-chef-recipe?rq=1). – Tensibai Apr 11 '16 at 08:47

1 Answers1

0

node['value'] = value will create an attribute at the normal level, caveat, it is saved on the node object and stay there forever.

As you're using a volatile attribute coming from external source, you should use node.run_state['value'] which purpose is to keep transient value during the run.

Now, as you said it, you need to use lazy evaluation in your later resources for the value and for the action as you wish a different action depending of the external service return.

Example with update use of run_state here, untested code:

node.run_state['value'] = nil
node.run_state['action'] = :delete
require 'net/http'

ruby_block "do-http-request-with-cutom-header" do
    block do
      Net::HTTP.get('example.com', '/index.html') # => String
      uri = URI('http://example.com/index.html')
      params = { :limit => 10, :page => 3 }
      uri.query = URI.encode_www_form(params)
      res = Net::HTTP.get_response(uri)
      puts res.body if res.is_a?(Net::HTTPSuccess)
      value= res.code
      node.run_state['value'] = value
      node.run_state['action'] = :create
    end
end
cron 'cassandra repair job' do
    hour '0'
    minute '55'
    weekday lazy { node.run_state['value'] }
    mailto 'root@localhost'
    user 'root'
    command '/opt/cassandra/bin/nodetool  repair -par -inc -pr'
    action lazy { node.run_state['action'] }
end 

Using lazy on the action parameter is possible since chef 12.4, if you're under this you'll have to craft the resource and run it within the ruby block.

Example crafted from answer here (still untested):

ruby_block "do-http-request-with-cutom-header" do
    block do
      Net::HTTP.get('example.com', '/index.html') # => String
      uri = URI('http://example.com/index.html')
      params = { :limit => 10, :page => 3 }
      uri.query = URI.encode_www_form(params)
      res = Net::HTTP.get_response(uri)
      puts res.body if res.is_a?(Net::HTTPSuccess)
      if res.code.nil? 
        r = Chef::Resource::Cron.new "cassandra repair job"
        r.run_action :delete
      else
        r = Chef::Resource::Cron.new "cassandra repair job"
        r.hour "0"
        r.minute "55"
        r.weekday res.code
        r.mailto "root@localhost"
        r.user "root"
        r.command "/opt/cassandra/bin/nodetool  repair -par -inc -pr"
        r.run_action :create
      end
    end
end

But at this point, it seems you would better get this information from a custom ohai plugin and use your original code without lazy.

Community
  • 1
  • 1
Tensibai
  • 15,557
  • 1
  • 37
  • 57
  • But this only solve a half of a my problem. How do I make a condition check on a node.run_state['value'] If I use this constraction no matter what values I'm assigning inside ruby code It will alwayts stays nill if node.run_state['value'] = "nil" then cron "cassandra repair job" do action :delete end else cron "cassandra repair job" do hour "0" minute "55" weekday lazy { node.run_state['value'] } mailto 'root@localhost' user "root" command "/opt/cassandra/bin/nodetool repair -par -inc -pr" end end – user2784340 Apr 11 '16 at 12:53
  • Indeed, you'll had to make the action a temp attribute too. Set to :delete by default and to :create if there's something to do and then use action lazy { node.run_state['action'] } I think – Tensibai Apr 11 '16 at 13:12
  • @user2784340 Updated answer, should do the trick on chef 12.4 and above. – Tensibai Apr 11 '16 at 14:19