Bash output to variable


I need to store the IP which is the result of a bash resource into a variable that I can use later.

My code looks like this:

sentinel_ip=" "
sentinel_hostname=" "
sentinel_machine = search(:node, "role:redis AND chef_environment:#{chef_env} AND team:#{team} AND node_type:sentinel")
sentinel_machine.each do |nodeobj_sentinel|
  sentinel_ip << nodeobj_sentinel['ipaddress']
  sentinel_hostname <<

execute 'get master' do
  command = "redis-cli -h #{sentinel_hostname} -p 26379 info | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' "
  action :run
# I'll store the result of the above command in master_ip variable
  master_ip << node['ipaddress']

#here I need to use the master_ip to connect to it
bash 'update config in runtime' do
  code <<-EOH
redis-cli -h #{master_ip} -p #{defaultport} -a #{auth} config set #{runtime_config}
redis-cli -h #{master_ip} -p #{defaultport} -a #{auth} config rewrite
  not_if { runtime_config.empty?}

Basically, if I get any master_ip from “get_master” execute resource, I pass it to the bash block below to use it, in order to update redis at runtime.

When I get something in master_ip, I’ll continue the rest of my recipe.

Anyway, the result of running ‘get master’ execute block above ends with

Compiling Cookbooks...
[2017-10-29T10:26:58+00:00] WARN: nodeobj_sentinel: node[clj-lc-tstrds03]
[2017-10-29T10:26:58+00:00] WARN: nodeobj_sentinel ip:
[2017-10-29T10:26:58+00:00] WARN: nodeobj_sentinel name: clj-lc-tstrds03
[2017-10-29T10:26:58+00:00] WARN: Sentinel is  clj-lc-tstrds03
[2017-10-29T10:26:59+00:00] WARN: master ip is {}

So the master_ip is empty.
Any ideea how to do this better?
Thank you!

P.S. running everything by hand in the machine, i get the IP.


There isn’t really such a thing as a “return value” from a resource. From the looks of things you probably want to restructure this to be a Custom Resource1 or write a library helper to do the shelling out for you. In short, don’t use execute for this as that’s getting a value that really has no place being a resource in your run.


I’ve done it like this:

ruby_block "get master" do
    block do
      Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut)
      command1 = "redis-cli -h #{sentinel_ip} -p 26379 info | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' && redis-cli -h #{sentinel_ip} -p #{defaultport} -a #{auth} config set #{runtime_config} && redis-cli -h #{sentinel_ip} -p #{defaultport} -a #{auth} config rewrite"
      command_out = shell_out(command1)
      node.run_state['master_ip'] = command_out1.stdout
    action :create

  template "redis.conf" do
    path "/etc/redis.conf"
    source "redis.conf.erb"
    owner node['redis']['user']
    group node['redis']['group']
    mode "0600"
        :node_type => node_type,
        :masterport => node['redis']['defaultport'],
        :masterip => lazy { node.run_state['master_ip'].chomp },
        :maxmemory => node['redis']['maxmemory'],
        :maxmemory_policy => node['redis']['maxmemory_policy'],
        :secret => auth,
        :runtime_config => runtime_config



This solution is workable but that mess of code is exactly why a Custom Resource or Helper method is recommended. Any sufficiently overly complicated ruby_block is a code smell.