1

I have a small application installed on a few servers, I wanted to write a quick recipe that will allow me to gather the version number from these servers.

This is what I've written:

bash "Get app version" do
    code <<-EOH
    cat /var/lib/myapp/node_modules/myapp/package.json | grep version
    EOH
end

However when I run the knife bootstrap command, I don't see the output in my console, even if I run it with -VV the output is not there.

I have two questions:

  1. Is this the best way for me to collect the version numbers?
  2. Why doesn't the cat results appear in my console?
Or W
  • 99
  • 3
  • 10

2 Answers2

1

Save the version number as a node attribute. This way you have a central store of the versions and you can use the node attribute elsewhere in Chef easily.

Something like:

ruby_block "myapp installed version check" do
  block do
    # file setup
    file = "/var/lib/myapp/node_modules/myapp/package.json"
    raise "File doesn't exist [#{file}]" unless File.exists?( file )

    # get the version line
    versions = open( file ).grep(/version/)
    raise "No versions in file [#{file}]" unless versions.length > 0
    Chef::Log.warn "Too many versions [#{versions.length}] in file [#{file}]" unless versions.length == 1

    # some regex to match your version number
    version = versions[0].match(/\d+\.\d+/).to_s

    # set the attribute
    node.set[:installed][:myapp][:version] = version

    # optionally reload node so attribute is available during this chef-client run
    node.from_file( run_context.resolve_attribute('myapp-cookbook', 'default') )

    # and log it. 
    Chef::Log.info( "myapp version is [#{node[:installed][:myapp][:version]}]" )
  end
end

raise will fail the Chef run with an exception. Use Chef::Log and return instead for the errors that aren't critical and you want to continue on processing recipes.

You can remove the node attribute bits and just log the information so it appears in the chef-client log. This is a bit better than relying on stdout/stderr which disappears when chef-client is not running interactively (i.e as a service). But why just log it when you can have it stored in a central location and query the value across your infra??

note it's generally better to implement the ruby in a library and use it via a custom lightweight resource if you ever think you'll re use the feature for myapp-b.

Machavity
  • 834
  • 10
  • 26
Matt
  • 1,537
  • 8
  • 11
0

First, to see the output in your knife output, you may need to redirect the stdout output to stderr, which is a reverse of the usual idiom:

cat /var/lib/myapp/node_modules/myapp/package.json | grep version 1>&2

But if you just ran your original command using ssh (or distributed with a tool like dsh) instead of knife, you would get the output you want without the overhead or extra output of a knife run.

As to the "best way" to collect the data, that entirely depends on what you want to use it for. If it's just informational and want to see it when you do a manual bootstrap operation, then using knife in this way may be fine. But if you wanted to do something systematically with the data, like collect it and use it in another program, then using knife would not likely be the best way to do it.

platforms
  • 1,118
  • 10
  • 23
  • Thank you for answering my question! What would you consider to be a better way to collect the data for in a way that will allow me to take actions or store it? – Or W Aug 18 '13 at 10:33
  • The simplest way is to run your original command using ssh instead: `ssh user@host 'cat /var/lib/myapp/node_modules/myapp/package.json | grep version' > version.txt`. But the thing is, you are using knife to bootstrap this server, right? So you should already have a high degree of confidence in which version of the software is on that server, because ensuring that is Chef's job. – platforms Aug 18 '13 at 14:57