Setting node attributes with a knife plugin


#1

Hi,

I was wondering if anyone has an idea how to decently change a single attribute
of a node when that attribute is passed on the command line as an argument for
a knife plugin.

Let’s say the plugin’s name is 'node set_attr’
E.g. if I run
knife node set_attr NODENAME apache.dir "/tmp"
I want to achieve that node[‘apache’][‘dir’] == “/tmp”.

The only way I came up with is something along the lines of:

@nodename = @name_args[0]
@attribute = @name_args[1]
@new_value = @name_args[2]

@node = Chef::Node.load(@nodename)

ruby_command = “@node.” + @attribute + “=” + @new_value
eval(ruby_command)
@node.save

However imo eval’ing this is kind of ugly, are there any better ways?

My actual use case is the creation of encrypted attribute values via [1] and
applying them directly to a node, however the encryption stuff itself is
trivial. The only thing I am not very happy about* - as mentioned above - is
using eval to set the attribute.

If this is not the right place to ask ruby questions about non-chef-core
related things, I apologize sincerely.

Kind regards,

Oscar

  • besides not having tests for the plugin and catching all sorts of errors that
    could occur

[1] https://github.com/oscarschneider/openssldemo/blob/master/node_secret.rb


#2

On Tue, Jan 24, 2012 at 6:29 PM, os4839@googlemail.com wrote:

Hi,

I was wondering if anyone has an idea how to decently change a single
attribute
of a node when that attribute is passed on the command line as an argument
for
a knife plugin.

Let’s say the plugin’s name is 'node set_attr’
E.g. if I run
knife node set_attr NODENAME apache.dir "/tmp"
I want to achieve that node[‘apache’][‘dir’] == “/tmp”.

The only way I came up with is something along the lines of:

@nodename = @name_args[0]
@attribute = @name_args[1]
@new_value = @name_args[2]

@node = Chef::Node.load(@nodename)

ruby_command = “@node.” + @attribute + “=” + @new_value
eval(ruby_command)
@node.save

So the only constraint is that @attribute is a dot-separated hierarchy of
hash keys?

This should do it (but I haven’t actually tried running it in Chef, so
YMMV)

*parts, last = @attribute.split(’.’)
hash = parts.inject(@node) { |h,attr| h[attr] }
hash[last] = @new_value

Andrea


#3

I’ve added a work item for us to explore doing this efficiently (i.e.
not requiring a full node save) and perhaps as a beginning to general
node delta / diff rather than full node change. Can’t promise
anything on what this will look like, or when, only that we are
considering it too and that it’s an interesting case.

Cheers,
Chris

Christopher Brown, Chief Technical Officer, Opscode, Inc.
T: (425) 502-5522, E: cb@opscode.com
IRC, Github: skeptomai
Twitter: @skeptomai

On Tue, Jan 24, 2012 at 9:29 AM, os4839@googlemail.com wrote:

Hi,

I was wondering if anyone has an idea how to decently change a single attribute
of a node when that attribute is passed on the command line as an argument for
a knife plugin.

Let’s say the plugin’s name is 'node set_attr’
E.g. if I run
knife node set_attr NODENAME apache.dir "/tmp"
I want to achieve that node[‘apache’][‘dir’] == “/tmp”.

The only way I came up with is something along the lines of:

@nodename = @name_args[0]
@attribute = @name_args[1]
@new_value = @name_args[2]

@node = Chef::Node.load(@nodename)

ruby_command = “@node.” + @attribute + “=” + @new_value
eval(ruby_command)
@node.save

However imo eval’ing this is kind of ugly, are there any better ways?

My actual use case is the creation of encrypted attribute values via [1] and
applying them directly to a node, however the encryption stuff itself is
trivial. The only thing I am not very happy about* - as mentioned above - is
using eval to set the attribute.

If this is not the right place to ask ruby questions about non-chef-core
related things, I apologize sincerely.

Kind regards,

Oscar

  • besides not having tests for the plugin and catching all sorts of errors that
    could occur

[1] https://github.com/oscarschneider/openssldemo/blob/master/node_secret.rb