Detecting a node's role, acting on it, throws exception

hello,

hopefully not tl;dr :> … i’m approaching a task and i wonder if the
style is appropriate. and if the style is appropriate, why is it
throwing this exception?

i want to take certain actions on a host within a recipe depending on
what kind of role is defined for it. and by “role” i don’t mean a chef
role … necessarily. it’s what role a node plays in the environment.
let’s say i have hosts serving in various roles like: admin, app, proxy,
etc.

in particular, if a node is of role “admin”, then i want to place on
that node AWS credentials of a high privilege level. a node that is of
role “app” i want to place low privileged AWS creds.

in the recipe, i’m trying to create logic that detects the role from
node attr data. maybe this is the wrong approach and i’d like feedback on
that. but i also want to flesh out this approach to ask this question,
which i guess comes down to a question on ruby syntax and the non-presence
of certain node attr data.

(i will note that i just tried this by creating chef roles aws-role-admin
and aws-role-generic, therein setting override attrs, and assigning
those roles to my nodes. if the recipe calls upon attrs set by this
chef role, it works. but is that the right way to solve this?)

an additional data point is we have nodes that were launched with a
legacy form of ec2 userdata, and i want to change the userdata to JSON
going forward.

legacy: “-r rolename -h hostname -e environment -v vol-xxxxxx”

snippet from new JSON style:

"node_name": "test-kallen.dev.wewt.com",
"wewt": {
  "role": "admin",
  "environment": "dev",
  "elip": "xx.xx.xx.xx",
  "vol_list": [
    "vol-xxxxx"
  ]
},
"chef_server": "https://10.xx.xx.xx",
"validation_client_name": "chef-validator",
"run_list": [
  "role[base]",
  "role[postfix-client]",
  "recipe[and_so_on]"
]

my node launch process will take that userdata and populate it
as chef node (normal) attributes.

regardless of the style of userdata we pass in at launch time, that
userdata is in the node attribute data in chef, be it at the top level
under normal attr data or under [:ec2][:userdata]. so i figured i could
test for the values in node attr data in my recipe. but the way i’m
trying it is throwing an exception on legacy hosts for this line in
the recipe:

if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] == "admin"

here’s a small test recipe that tries to detect the role as is present
in node attr data. it tries to be backward compatible for the legacy
userdata style.

if node[:ec2]
if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] == "admin"
Chef::Log.debug(“HIGGS-BOSON: detected role admin”)
elsif node[:ec2][:userdata] =~ /-r app/ || node[:wewt][:role] == "app"
Chef::Log.debug(“HIGGS-BOSON: detected role app”)
else
Chef::Log.debug(“HIGGS-BOSON: no role detected!”)
end
end

successful run on test-kallen.dev.wewt.com which contains the new node
attributes via the new JSON userdata:

[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Loading Recipe test_recipe via include_recipe
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Found recipe default in cookbook test_recipe
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: HIGGS-BOSON: detected role dev
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Converging node test-kallen.dev.wewt.com
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Saving the current state of node test-kallen.dev.wewt.com

failed run on webapp01b.dev.wewt.com which does not contain the new
node attributes:

[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Loading Recipe test_recipe via include_recipe
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Found recipe default in cookbook test_recipe
[Thu, 02 Feb 2012 02:16:28 +0000] ERROR: Running exception handlers
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: Saving node information to /var/cache/chef/failed-run-data.json
[Thu, 02 Feb 2012 02:16:28 +0000] ERROR: Exception handlers complete
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Re-raising exception: NoMethodError - undefined method []' for nil:NilClass /var/cache/chef/cookbooks/test_recipe/recipes/default.rb:34:infrom_file’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/cookbook_version.rb:578:in load_recipe' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:40:ininclude_recipe’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/mixin/language_include_recipe.rb:27:in each' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:ininclude_recipe’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/run_context.rb:72:in load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:ineach’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/run_context.rb:69:in load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:195:insetup_run_context’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/client.rb:159:in run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:239:inrun_application’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/application/client.rb:229:in loop' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:inrun_application’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/application.rb:67:in run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/chef-client:26 /usr/bin/chef-client:19:inload’
/usr/bin/chef-client:19
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: Stacktrace dumped to /var/cache/chef/chef-stacktrace.out
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: NoMethodError: undefined method []' for nil:NilClass /var/cache/chef/cookbooks/test_recipe/recipes/default.rb:34:infrom_file’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/cookbook_version.rb:578:in load_recipe' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:40:ininclude_recipe’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/mixin/language_include_recipe.rb:27:in each' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:ininclude_recipe’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/run_context.rb:72:in load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:ineach’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/run_context.rb:69:in load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:195:insetup_run_context’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/client.rb:159:in run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:239:inrun_application’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/application/client.rb:229:in loop' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:inrun_application’
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/…/lib/chef/application.rb:67:in run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/chef-client:26 /usr/bin/chef-client:19:inload’
/usr/bin/chef-client:19
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: NoMethodError: undefined method `[]’ for nil:NilClass

so… why does this throw the exception? i’m not a savvy ruby coder,
but shouldn’t the “or” in that line address the fact that node[:wewt][:role]
doesn’t exist for this node?

if i edit this node’s attr data and add in the new-style attributes, the
run will succeed.

i could go back and populate this node attr data for all legacy hosts,
but i don’t want to if i don’t have to, if there’s a better answer.

thanks y’all,
kallen

Le 02.02.2012 04:10, kallen@groknaut.net a écrit :

hello,

Hello

regardless of the style of userdata we pass in at launch time, that
userdata is in the node attribute data in chef, be it at the top
level
under normal attr data or under [:ec2][:userdata]. so i figured i
could
test for the values in node attr data in my recipe. but the way i'm
trying it is throwing an exception on legacy hosts for this line in
the recipe:

if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] ==
"admin"

Indeed trying to call [:role] on something not existing at all ( the
[:wewt] part on "legagy" hosts ) throw an execption:

I'd probably write your test like this:

admorapp = "no"

if node[:ec2]
if node[:ec2][:userdata] =~ /-r admin/
admorapp = "admin"
elsif node[:ec2][:userdata] =~ /-r app/
admorapp ="app"
end
elsif node[:wewt]
if node[:wewt][:role] == "admin"
admorapp = "admin"
elsif node[:wewt][:role] == "app"
admorapp = "app"
end
end

Chef::Log.debug("HIGGS-BOSON: #{admorapp} role detected")

You may add a if to check if role is detected or not checking admorapp
== "no" to throw a message/do something if no role is detected ...

I'm catching up on email and seeing that nobody has replied.

"i want to take certain actions on a host within a recipe depending on
what kind of role is defined for it. and by "role" i don't mean a chef
role .. necessarily. it's what role a node plays in the environment.
let's say i have hosts serving in various roles like: admin, app, proxy,
etc."
Er...... why not?
This would be exactly what a chef role is for - and by far the easiest way
to do it.

Cheers,
Edawrd

On Wed, Feb 1, 2012 at 7:10 PM, kallen@groknaut.net wrote:

hello,

hopefully not tl;dr :> .. i'm approaching a task and i wonder if the
style is appropriate. and if the style is appropriate, why is it
throwing this exception?

i want to take certain actions on a host within a recipe depending on
what kind of role is defined for it. and by "role" i don't mean a chef
role .. necessarily. it's what role a node plays in the environment.
let's say i have hosts serving in various roles like: admin, app, proxy,
etc.

in particular, if a node is of role "admin", then i want to place on
that node AWS credentials of a high privilege level. a node that is of
role "app" i want to place low privileged AWS creds.

in the recipe, i'm trying to create logic that detects the role from
node attr data. maybe this is the wrong approach and i'd like feedback on
that. but i also want to flesh out this approach to ask this question,
which i guess comes down to a question on ruby syntax and the non-presence
of certain node attr data.

(i will note that i just tried this by creating chef roles aws-role-admin
and aws-role-generic, therein setting override attrs, and assigning
those roles to my nodes. if the recipe calls upon attrs set by this
chef role, it works. but is that the right way to solve this?)

an additional data point is we have nodes that were launched with a
legacy form of ec2 userdata, and i want to change the userdata to JSON
going forward.

legacy: "-r rolename -h hostname -e environment -v vol-xxxxxx"

snippet from new JSON style:

"node_name": "test-kallen.dev.wewt.com",
"wewt": {
"role": "admin",
"environment": "dev",
"elip": "xx.xx.xx.xx",
"vol_list": [
"vol-xxxxx"
]
},
"chef_server": "https://10.xx.xx.xx",
"validation_client_name": "chef-validator",
"run_list": [
"role[base]",
"role[postfix-client]",
"recipe[and_so_on]"
]

my node launch process will take that userdata and populate it
as chef node (normal) attributes.

regardless of the style of userdata we pass in at launch time, that
userdata is in the node attribute data in chef, be it at the top level
under normal attr data or under [:ec2][:userdata]. so i figured i could
test for the values in node attr data in my recipe. but the way i'm
trying it is throwing an exception on legacy hosts for this line in
the recipe:

if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] == "admin"

here's a small test recipe that tries to detect the role as is present
in node attr data. it tries to be backward compatible for the legacy
userdata style.

if node[:ec2]
if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] == "admin"
Chef::Log.debug("HIGGS-BOSON: detected role admin")
elsif node[:ec2][:userdata] =~ /-r app/ || node[:wewt][:role] == "app"
Chef::Log.debug("HIGGS-BOSON: detected role app")
else
Chef::Log.debug("HIGGS-BOSON: no role detected!")
end
end

successful run on test-kallen.dev.wewt.com which contains the new node
attributes via the new JSON userdata:

[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Loading Recipe test_recipe via
include_recipe
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Found recipe default in cookbook
test_recipe
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: HIGGS-BOSON: detected role dev
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Converging node
test-kallen.dev.wewt.com
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Saving the current state of node
test-kallen.dev.wewt.com

failed run on webapp01b.dev.wewt.com which does not contain the new
node attributes:

[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Loading Recipe test_recipe via
include_recipe
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Found recipe default in cookbook
test_recipe
[Thu, 02 Feb 2012 02:16:28 +0000] ERROR: Running exception handlers
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: Saving node information to
/var/cache/chef/failed-run-data.json
[Thu, 02 Feb 2012 02:16:28 +0000] ERROR: Exception handlers complete
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Re-raising exception:
NoMethodError - undefined method []' for nil:NilClass /var/cache/chef/cookbooks/test_recipe/recipes/default.rb:34:in from_file'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/cookbook_version.rb:578:in
load_recipe' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:40:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in
each' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:72:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in each'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:195:in setup_run_context'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:159:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:239:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in
loop' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application.rb:67:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/chef-client:26 /usr/bin/chef-client:19:in load'
/usr/bin/chef-client:19
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: Stacktrace dumped to
/var/cache/chef/chef-stacktrace.out
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: NoMethodError: undefined method
[]' for nil:NilClass /var/cache/chef/cookbooks/test_recipe/recipes/default.rb:34:in from_file'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/cookbook_version.rb:578:in
load_recipe' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:40:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in
each' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:72:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in each'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:195:in setup_run_context'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:159:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:239:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in
loop' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application.rb:67:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/chef-client:26 /usr/bin/chef-client:19:in load'
/usr/bin/chef-client:19
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: NoMethodError: undefined method
`' for nil:NilClass

so.. why does this throw the exception? i'm not a savvy ruby coder,
but shouldn't the "or" in that line address the fact that
node[:wewt][:role]
doesn't exist for this node?

if i edit this node's attr data and add in the new-style attributes, the
run will succeed.

i could go back and populate this node attr data for all legacy hosts,
but i don't want to if i don't have to, if there's a better answer.

thanks y'all,
kallen

On Mon, 06 Feb 2012, Edward Sargisson wrote:

I'm catching up on email and seeing that nobody has replied.

"i want to take certain actions on a host within a recipe depending on
what kind of role is defined for it. and by "role" i don't mean a chef
role .. necessarily. it's what role a node plays in the environment.
let's say i have hosts serving in various roles like: admin, app, proxy,
etc."
Er...... why not?
This would be exactly what a chef role is for - and by far the easiest way
to do it.

yeah, you're probably right. i'm still getting a feel for how i want to
describe my infrastructure in code using chef's tools. i'll try to
revisit this. in the meantime, i chose to solve it like so:

x_privs = data_bag_item("hush", "x-perm-matrix")
if node[:wewt] && node[:wewt][:role]
if node[:wewt][:role].match /#{x_privs['roles_that_get_this']}/
grab_this = "X_SERVERCERT"
grab_that = "X_PRIVATEKEY"
end
else
if node[:ec2][:userdata].match /#{x_privs['roles_that_get_this_legacy']}/
grab_this = "X_SERVERCERT"
grab_that = "X_PRIVATEKEY"
end
end

and i think i might get what's up with the error

NoMethodError - undefined method `[]' for nil:NilClass

because i happened to read Chef Infra (archive) log a few nites ago. if i may paraphrase
erikh:

when i try to reference node[:wewt][:role] on a node that doesn't have
those attrs, it tries to apply the method # to nil, which isn't defined
for NilClass (the class representation of the nil object).

is that it?

::handwave:: i'm not a ruby coder .. yet

kallen

On Wed, Feb 1, 2012 at 7:10 PM, kallen@groknaut.net wrote:

hello,

hopefully not tl;dr :> .. i'm approaching a task and i wonder if the
style is appropriate. and if the style is appropriate, why is it
throwing this exception?

i want to take certain actions on a host within a recipe depending on
what kind of role is defined for it. and by "role" i don't mean a chef
role .. necessarily. it's what role a node plays in the environment.
let's say i have hosts serving in various roles like: admin, app, proxy,
etc.

in particular, if a node is of role "admin", then i want to place on
that node AWS credentials of a high privilege level. a node that is of
role "app" i want to place low privileged AWS creds.

in the recipe, i'm trying to create logic that detects the role from
node attr data. maybe this is the wrong approach and i'd like feedback on
that. but i also want to flesh out this approach to ask this question,
which i guess comes down to a question on ruby syntax and the non-presence
of certain node attr data.

(i will note that i just tried this by creating chef roles aws-role-admin
and aws-role-generic, therein setting override attrs, and assigning
those roles to my nodes. if the recipe calls upon attrs set by this
chef role, it works. but is that the right way to solve this?)

an additional data point is we have nodes that were launched with a
legacy form of ec2 userdata, and i want to change the userdata to JSON
going forward.

legacy: "-r rolename -h hostname -e environment -v vol-xxxxxx"

snippet from new JSON style:

"node_name": "test-kallen.dev.wewt.com",
"wewt": {
"role": "admin",
"environment": "dev",
"elip": "xx.xx.xx.xx",
"vol_list": [
"vol-xxxxx"
]
},
"chef_server": "https://10.xx.xx.xx",
"validation_client_name": "chef-validator",
"run_list": [
"role[base]",
"role[postfix-client]",
"recipe[and_so_on]"
]

my node launch process will take that userdata and populate it
as chef node (normal) attributes.

regardless of the style of userdata we pass in at launch time, that
userdata is in the node attribute data in chef, be it at the top level
under normal attr data or under [:ec2][:userdata]. so i figured i could
test for the values in node attr data in my recipe. but the way i'm
trying it is throwing an exception on legacy hosts for this line in
the recipe:

if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] == "admin"

here's a small test recipe that tries to detect the role as is present
in node attr data. it tries to be backward compatible for the legacy
userdata style.

if node[:ec2]
if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] == "admin"
Chef::Log.debug("HIGGS-BOSON: detected role admin")
elsif node[:ec2][:userdata] =~ /-r app/ || node[:wewt][:role] == "app"
Chef::Log.debug("HIGGS-BOSON: detected role app")
else
Chef::Log.debug("HIGGS-BOSON: no role detected!")
end
end

successful run on test-kallen.dev.wewt.com which contains the new node
attributes via the new JSON userdata:

[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Loading Recipe test_recipe via
include_recipe
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Found recipe default in cookbook
test_recipe
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: HIGGS-BOSON: detected role dev
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Converging node
test-kallen.dev.wewt.com
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Saving the current state of node
test-kallen.dev.wewt.com

failed run on webapp01b.dev.wewt.com which does not contain the new
node attributes:

[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Loading Recipe test_recipe via
include_recipe
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Found recipe default in cookbook
test_recipe
[Thu, 02 Feb 2012 02:16:28 +0000] ERROR: Running exception handlers
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: Saving node information to
/var/cache/chef/failed-run-data.json
[Thu, 02 Feb 2012 02:16:28 +0000] ERROR: Exception handlers complete
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Re-raising exception:
NoMethodError - undefined method []' for nil:NilClass /var/cache/chef/cookbooks/test_recipe/recipes/default.rb:34:in from_file'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/cookbook_version.rb:578:in
load_recipe' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:40:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in
each' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:72:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in each'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:195:in setup_run_context'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:159:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:239:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in
loop' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application.rb:67:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/chef-client:26 /usr/bin/chef-client:19:in load'
/usr/bin/chef-client:19
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: Stacktrace dumped to
/var/cache/chef/chef-stacktrace.out
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: NoMethodError: undefined method
[]' for nil:NilClass /var/cache/chef/cookbooks/test_recipe/recipes/default.rb:34:in from_file'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/cookbook_version.rb:578:in
load_recipe' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:40:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in
each' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:72:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in each'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:195:in setup_run_context'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:159:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:239:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in
loop' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application.rb:67:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/chef-client:26 /usr/bin/chef-client:19:in load'
/usr/bin/chef-client:19
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: NoMethodError: undefined method
`' for nil:NilClass

so.. why does this throw the exception? i'm not a savvy ruby coder,
but shouldn't the "or" in that line address the fact that
node[:wewt][:role]
doesn't exist for this node?

if i edit this node's attr data and add in the new-style attributes, the
run will succeed.

i could go back and populate this node attr data for all legacy hosts,
but i don't want to if i don't have to, if there's a better answer.

thanks y'all,
kallen

I like to use:

if node.has_key? 'foo' and node['foo'].has_key? 'bar' and
node['foo']['bar] =~ /bong/

It is the least gross when testing for the presence of like, three or
four nested keys. :slight_smile:

Cheers,

AJ

On 7 February 2012 21:32, kallen@groknaut.net wrote:

On Mon, 06 Feb 2012, Edward Sargisson wrote:

I'm catching up on email and seeing that nobody has replied.

"i want to take certain actions on a host within a recipe depending on
what kind of role is defined for it. and by "role" i don't mean a chef
role .. necessarily. it's what role a node plays in the environment.
let's say i have hosts serving in various roles like: admin, app, proxy,
etc."
Er...... why not?
This would be exactly what a chef role is for - and by far the easiest way
to do it.

yeah, you're probably right. i'm still getting a feel for how i want to
describe my infrastructure in code using chef's tools. i'll try to
revisit this. in the meantime, i chose to solve it like so:

x_privs = data_bag_item("hush", "x-perm-matrix")
if node[:wewt] && node[:wewt][:role]
if node[:wewt][:role].match /#{x_privs['roles_that_get_this']}/
grab_this = "X_SERVERCERT"
grab_that = "X_PRIVATEKEY"
end
else
if node[:ec2][:userdata].match /#{x_privs['roles_that_get_this_legacy']}/
grab_this = "X_SERVERCERT"
grab_that = "X_PRIVATEKEY"
end
end

and i think i might get what's up with the error

NoMethodError - undefined method `' for nil:NilClass

because i happened to read Chef Infra (archive) log a few nites ago. if i may paraphrase
erikh:

when i try to reference node[:wewt][:role] on a node that doesn't have
those attrs, it tries to apply the method # to nil, which isn't defined
for NilClass (the class representation of the nil object).

is that it?

::handwave:: i'm not a ruby coder .. yet

kallen

On Wed, Feb 1, 2012 at 7:10 PM, kallen@groknaut.net wrote:

hello,

hopefully not tl;dr :> .. i'm approaching a task and i wonder if the
style is appropriate. and if the style is appropriate, why is it
throwing this exception?

i want to take certain actions on a host within a recipe depending on
what kind of role is defined for it. and by "role" i don't mean a chef
role .. necessarily. it's what role a node plays in the environment.
let's say i have hosts serving in various roles like: admin, app, proxy,
etc.

in particular, if a node is of role "admin", then i want to place on
that node AWS credentials of a high privilege level. a node that is of
role "app" i want to place low privileged AWS creds.

in the recipe, i'm trying to create logic that detects the role from
node attr data. maybe this is the wrong approach and i'd like feedback on
that. but i also want to flesh out this approach to ask this question,
which i guess comes down to a question on ruby syntax and the non-presence
of certain node attr data.

(i will note that i just tried this by creating chef roles aws-role-admin
and aws-role-generic, therein setting override attrs, and assigning
those roles to my nodes. if the recipe calls upon attrs set by this
chef role, it works. but is that the right way to solve this?)

an additional data point is we have nodes that were launched with a
legacy form of ec2 userdata, and i want to change the userdata to JSON
going forward.

legacy: "-r rolename -h hostname -e environment -v vol-xxxxxx"

snippet from new JSON style:

"node_name": "test-kallen.dev.wewt.com",
"wewt": {
"role": "admin",
"environment": "dev",
"elip": "xx.xx.xx.xx",
"vol_list": [
"vol-xxxxx"
]
},
"chef_server": "https://10.xx.xx.xx",
"validation_client_name": "chef-validator",
"run_list": [
"role[base]",
"role[postfix-client]",
"recipe[and_so_on]"
]

my node launch process will take that userdata and populate it
as chef node (normal) attributes.

regardless of the style of userdata we pass in at launch time, that
userdata is in the node attribute data in chef, be it at the top level
under normal attr data or under [:ec2][:userdata]. so i figured i could
test for the values in node attr data in my recipe. but the way i'm
trying it is throwing an exception on legacy hosts for this line in
the recipe:

if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] == "admin"

here's a small test recipe that tries to detect the role as is present
in node attr data. it tries to be backward compatible for the legacy
userdata style.

if node[:ec2]
if node[:ec2][:userdata] =~ /-r admin/ || node[:wewt][:role] == "admin"
Chef::Log.debug("HIGGS-BOSON: detected role admin")
elsif node[:ec2][:userdata] =~ /-r app/ || node[:wewt][:role] == "app"
Chef::Log.debug("HIGGS-BOSON: detected role app")
else
Chef::Log.debug("HIGGS-BOSON: no role detected!")
end
end

successful run on test-kallen.dev.wewt.com which contains the new node
attributes via the new JSON userdata:

[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Loading Recipe test_recipe via
include_recipe
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Found recipe default in cookbook
test_recipe
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: HIGGS-BOSON: detected role dev
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Converging node
test-kallen.dev.wewt.com
[Thu, 02 Feb 2012 02:16:26 +0000] DEBUG: Saving the current state of node
test-kallen.dev.wewt.com

failed run on webapp01b.dev.wewt.com which does not contain the new
node attributes:

[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Loading Recipe test_recipe via
include_recipe
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Found recipe default in cookbook
test_recipe
[Thu, 02 Feb 2012 02:16:28 +0000] ERROR: Running exception handlers
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: Saving node information to
/var/cache/chef/failed-run-data.json
[Thu, 02 Feb 2012 02:16:28 +0000] ERROR: Exception handlers complete
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: Re-raising exception:
NoMethodError - undefined method []' for nil:NilClass /var/cache/chef/cookbooks/test_recipe/recipes/default.rb:34:in from_file'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/cookbook_version.rb:578:in
load_recipe' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:40:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in
each' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:72:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in each'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:195:in setup_run_context'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:159:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:239:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in
loop' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application.rb:67:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/chef-client:26 /usr/bin/chef-client:19:in load'
/usr/bin/chef-client:19
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: Stacktrace dumped to
/var/cache/chef/chef-stacktrace.out
[Thu, 02 Feb 2012 02:16:28 +0000] DEBUG: NoMethodError: undefined method
[]' for nil:NilClass /var/cache/chef/cookbooks/test_recipe/recipes/default.rb:34:in from_file'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/cookbook_version.rb:578:in
load_recipe' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:40:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in
each' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/mixin/language_include_recipe.rb:27:in include_recipe'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:72:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in each'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/run_context.rb:69:in
load' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:195:in setup_run_context'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/client.rb:159:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:239:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in
loop' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application/client.rb:229:in run_application'
/usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/../lib/chef/application.rb:67:in
run' /usr/lib/ruby/gems/1.8/gems/chef-0.10.4/bin/chef-client:26 /usr/bin/chef-client:19:in load'
/usr/bin/chef-client:19
[Thu, 02 Feb 2012 02:16:28 +0000] FATAL: NoMethodError: undefined method
`' for nil:NilClass

so.. why does this throw the exception? i'm not a savvy ruby coder,
but shouldn't the "or" in that line address the fact that
node[:wewt][:role]
doesn't exist for this node?

if i edit this node's attr data and add in the new-style attributes, the
run will succeed.

i could go back and populate this node attr data for all legacy hosts,
but i don't want to if i don't have to, if there's a better answer.

thanks y'all,
kallen