Help with error in bootstrapping a node

I set up a Virtual box with RHEL 5.11 (for now) and installed chef-client v12.5.1, and logged in as root. I setup my knife.rb file and am able to do knife commands, like knife node list for example. I set up a user “Jenkins” and associated pem file for communication with the Chef server, which is v12.0.3

Now when I bootstrap a node, ex

Ø knife bootsrap myNode -N myNode -x root -P pw

I get

“You authenticated successfully to https://chef-server.domain.com/organization/myOrg as jenkins but you are not authorized for this action
Response: missing create permission”

Any clues?

Chef 12 uses RBAC for clients. This document might hero shed light on what
is going on.

https://docs.chef.io/auth_authorization.html

Basically, you need to just grant the user the required permissions.

Thanks. I guess this in new in chef-client v12.5.1?

Chris

IIRC a regular user cannot create clients, you have to be an admin. This may have changed in a more recent version of Chef Server to accommodate the “validatorless” bootstrapping feature but I am not sure.

I have a java cookbook that installs Java, among other things, in a RHEL6 distro. How can I set JAVA_HOME so it persists in the environment, that is, when the cookbook finishes, I can go to my command line I can type echo $JAVA_HOME and see the setting. I do

bash ‘Set JAVA_HOME’ do
code <<-EOF
export JAVA_HOME=/etc/alternatives/java
EOF
end

But I don’t get anything when I do echo $JAVA_HOME from command line

Chris

In *nix OSes, environment variables are inherited from the parent process when a new process is created, and from there processes may set environment variables for themselves and any processes they create in the future. In the case of a shell, this is handled by various profile and rc scripts that provide system-wide and per-user customization. A good thing to read is the "invocation" section of the bash manual page: http://linux.die.net/man/1/bash In any case, the recommended way to make modifications to these files can vary by distro and I don't remember off-hand how you're supposed to do it for EL, but you should be able to google some combo of these terms and get an answer.

So, what your code is doing is, Chef Client creates a bash process; that bash process sets an environment variable for itself (which can only affect processes that it creates); then it exits, having changed nothing that would affect the environment variables of existing or future processes.

HTH

How about adding the environment variable to the user’s profile file (for example .bash_profile if user’s default shell is bash) via chef?

ruby_block "Update user's profile file" do
  block do
    file = Chef::Util::FileEdit.new("/home/<user>/.profile")
    file.insert_line_if_no_match("export JAVA_HOME=/usr/bin/java", "export JAVA_HOME=/usr/bin/java")   
    file.write_file
  end
end

I have a cookbook with default attributes defined in my attributes/default.rb file, like so

default[:my_cookbook][:attr1] = ‘value1’

Now I want to use this in my libraries/default.rb file. However, the following gives a compile error during the compile phase of my chef-client run

some_value = node[:my_cookbook][:attr1]

…that is, I get “node is undefined variable or object” (or the like)

I’m guessing I need to use this
http://www.rubydoc.info/gems/chef/11.4.4/Chef/Node

my_node = Chef::Node.load(name)
some_value = my_node[:my_cookbook][:attr1]

What value should the “name” have? Is the name I gave the node when I bootstrapped it? So if I did

knife bootstrap node1 -N node1 -x root -P pw

I should do

my_node = Chef::Node.load(‘node1’)

Thanks,
Chris

Libraries are evaluated as regular ruby code, whereas Attributes files and Recipes are evaluated inside a DSL.

Your suggested solution for loading the node object from the server won't work, because it creates a second copy of the node object, which won't affect the primary copy.

What you need to do is create a module and define a method on it, then use that elsewhere. The simplest way is to use module functions which take a node as an argument. That looks like:

module MyHelperFunctions
  def self.compute_a_value(node)
    node[:my_cookbook][:attr1]
  end
end

You would access that with code like MyHelperFucntions.compute_a_value(node)

The other way to go is to mix your module in to the recipe DSL. The tricky part about that is that when you create a resource, the part between the do and end is actually a DSL for just that resource, so you have to mix your module into both the recipe and resource to make it work everywhere.

To illustrate:

# in recipes/whatever.rb

# this area here is the **recipe** DSL

file "/tmp/foo.rb" do
  # this area here is a DSL for just the file resource
  mode "0755"
  # etc.
end

# now you're back in the recipe DSL

So if you want to define a method that can implicitly use the node object, you have to do something like this:

module MyHelpers
  def computed_value
    node[:my_cookbook][:attr1]
  end
end

Chef::Recipe.send(:include, MyHelpers)
Chef::Resource.send(:include, MyHelpers)

HTH.

Thanks!

Making a “second copy” of the node maybe all I want since, in this particular case, I want to “read” from the node and not write to it.

Also, I understand now that libraries are evaluated as straight ruby code except inside functions, that is code between def function…end.

Chris