How to override node attribute with lazy value?

The chef-server readme
https://github.com/opscode-cookbooks/chef-server/blob/master/attributes/default.rb
shows how to override nginx attributes. However, it doesn’t seem to work
like I want it to when I do:

node.override[“chef-server”][“configuration”][“nginx”][“ssl_certificate”] =
"/etc/pki/tls/certs/#{node[:fqdn]}.pem"

node[:fqdn] is being updated during my chef run using the hostname cookbook
https://github.com/3ofcoins/chef-cookbook-hostname, and so using the
above results in an error because chef-server ends up looking for
/etc/pki/tls/certs/localhost.pem (the old hostname), when it should instead
be using /etc/pki/tls/certs/mynode.mycompany.com.pem.

So I think I want something like the following, but this doesn’t work.
What’s the right way to do it?

node.override[“chef-server”][“configuration”][“nginx”][“ssl_certificate”] =
lazy { “/etc/pki/tls/certs/#{node[:fqdn]}.pem” }

Thanks,
Greg

On Oct 2, 2014, at 3:13 AM, Greg Barker fletch@fletchowns.net wrote:

The chef-server readme shows how to override nginx attributes. However, it doesn't seem to work like I want it to when I do:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] = "/etc/pki/tls/certs/#{node[:fqdn]}.pem"

node[:fqdn] is being updated during my chef run using the hostname cookbook, and so using the above results in an error because chef-server ends up looking for /etc/pki/tls/certs/localhost.pem (the old hostname), when it should instead be using /etc/pki/tls/certs/mynode.mycompany.com.pem.

So I think I want something like the following, but this doesn't work. What's the right way to do it?

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] = lazy { "/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

lazy{} is a feature of resources, not of node attributes. See Derived Attributes in Chef – Noah Kantrowitz for more information about how to handle delayed interpolation in node attributes.

--Noah

Thanks Lamont. I tried using the system
https://github.com/xhost-cookbooks/system cookbook which seems to do as
you have suggested (setting the automatic_attrs
https://github.com/xhost-cookbooks/system/blob/0564b30052923c9e9d5192c52a6dbe9e8f2f9d7b/providers/hostname.rb#L48)
but it still doesn't work.

The system cookbook is first in my run list and then towards the end it
gets to my recipe which contains:
node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] =
"/etc/pki/tls/certs/#{node['fqdn']}.pem"
...but it still thinks node['fqdn'] is localhost, it doesn't get the
updated value.

I guess I will just have to steer clear of relying on node['fqdn'] unless
you have any other ideas, it's a bummer that so many cookbooks use it
though.

Greg

On Sat, Oct 4, 2014 at 10:27 AM, Lamont Granquist lamont@opscode.com
wrote:

On 10/3/14, 5:13 PM, Lamont Granquist wrote:

On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:

How it should be written, i'll look at submitting a PR...

Sorry look like I fell victim to thinking that all problems were like my
last problem.

The hostname is getting set at converge time, fairly late, by the
hostname cookbook. Your node['fqdn'] will be the old hostname throughout
the whole compile phase of the chef-client run. In your case since you
control the code it'll be way easier to use the node['set_fqdn'] attribute
that you're passing to the hostname cookbook to pass to the
chef-server cookbook:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"

If that doesn't work for you then you may have an issue trying to do
that. The attributes are most likely getting passed into the template
variable sometime in compiletime and your node['fqdn'] isn't getting
updated until converge time. Either the hostname cookbook needs to be
changed to do its work at compile-time or else the chef-server cookbook
needs to be converted to be lazy.

A better approach would probably be for the hostname cookbook to expose a
ruby library to call to get the desired hostname (basically sugar around
either returning node['set_fqdn'] or else returning the output of
"/usr/sbin/vmtoolsd --cmd 'info-get guestinfo.hostname'") and then you
could get that value at compile time and set attributes with it just fine.

So, I'd actually suggest doing something more like this than using that
hostname cookbook:

self.class.send(:include, Chef::Mixin::ShellOut)

execute very early

execute "set hostname to nodename" do
command "/bin/hostname #{node.name}"
action :nothing
not_if "shell_out!('hostname').stdout.chomp == node.name"
end.run_action(:run)

fake out ohai data

node.automatic_attrs["hostname"] = node.name[/[^.]/]
node.automatic_attrs["domain"] = node.name[/.(.
)/, 1]
node.automatic_attrs["machinename"] = node.name
node.automatic_attrs["fqdn"] = node.name

case node["platform_family"]
when "rhel", "fedora"
template "/etc/sysconfig/network" do
source "redhat-network.erb"
end
when "debian"
template "/etc/hostname" do
source "ubuntu-hostname.erb"
end
end

That encodes my policy that node names are fqdns and that the fqdn is set
from the node name and that hostnames are fqdns. If you have a different
policy, you can modify that code. The important bit is that I set the
hostname of the box at compile time at the top of my run_list. Then I
override the ohai automatic attrs at compile time so that all later code
will see that. The templates can wait until converge time since those are
only going to be necessary on next boot.

You can quibble with this because clearly there's a problem with
separation of concerns and we "should" be calling ohai to reload the node
data, but if you do that, you need to make sure that you're doing that at
compile time. You could wrap the hostname cookbook's recipe logic in an
LWRP and then simply force that to run at compile time. I don't care about
that because I know what the ohai policy on those attrs are and that we're
unlikely to change it so I'm not too concerned about duplicating the code
and forcing it like that.

And the function of setting the current hostname and fixing the ohai data
is separate from the function of updating the templates. If I was doing
this reusably I'd keep those separate. I'd also keep 'finding the
hostname' separate and probably just put that in a straight up ruby library
function. That would be function or set of functions that you could use to
poke vmware or xenserver or whatever to see what your hostname is set as in
the hypervisor and use that.

"setting the automatic_attrs" wasn't really the point of that code I
pasted there. the point is to execute it at compile time rather than
converge time. the code you point to in the system cookbook is inside
of a provider and will also get executed at converge time. you can call
the system_hostname LWRP yourself and force it to run at compile time by
method chaining .run_action(:set) off of it (and add an action :nothing attribute inside the LWRP).

On 10/9/14, 8:13 PM, Greg Barker wrote:

Thanks Lamont. I tried using the system
https://github.com/xhost-cookbooks/system cookbook which seems to do
as you have suggested (setting the automatic_attrs
https://github.com/xhost-cookbooks/system/blob/0564b30052923c9e9d5192c52a6dbe9e8f2f9d7b/providers/hostname.rb#L48)
but it still doesn't work.

The system cookbook is first in my run list and then towards the end
it gets to my recipe which contains:
node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['fqdn']}.pem"
...but it still thinks node['fqdn'] is localhost, it doesn't get the
updated value.

I guess I will just have to steer clear of relying on node['fqdn']
unless you have any other ideas, it's a bummer that so many cookbooks
use it though.

Greg

On Sat, Oct 4, 2014 at 10:27 AM, Lamont Granquist <lamont@opscode.com
mailto:lamont@opscode.com> wrote:

On 10/3/14, 5:13 PM, Lamont Granquist wrote:

    On Fri Oct  3 16:39:36 2014, Lamont Granquist wrote:


        How it should be written, i'll look at submitting a PR...


    Sorry look like I fell victim to thinking that all problems
    were like my last problem.

    The hostname is getting set at converge time, fairly late, by
    the hostname cookbook.  Your node['fqdn'] will be the old
    hostname throughout the whole compile phase of the chef-client
    run.  In your case since you control the code it'll be way
    easier to use the node['set_fqdn'] attribute that you're
    passing to the hostname cookbook to pass to the
    chef-server cookbook:

    node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
    = "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"

    If that doesn't work for you then you may have an issue trying
    to do that.  The attributes are most likely getting passed
    into the template variable sometime in compiletime and your
    node['fqdn'] isn't getting updated until converge time. 
     Either the hostname cookbook needs to be changed to do its
    work at compile-time or else the chef-server cookbook needs to
    be converted to be lazy.

    A better approach would probably be for the hostname cookbook
    to expose a ruby library to call to get the desired hostname
    (basically sugar around either returning node['set_fqdn'] or
    else returning the output of "/usr/sbin/vmtoolsd --cmd
    'info-get guestinfo.hostname'") and then you could get that
    value at compile time and set attributes with it just fine.


So, I'd actually suggest doing something more like this than using
that hostname cookbook:

self.class.send(:include, Chef::Mixin::ShellOut)

# execute very early
execute "set hostname to nodename" do
  command "/bin/hostname #{node.name <http://node.name>}"
  action :nothing
  not_if "shell_out!('hostname').stdout.chomp == node.name
<http://node.name>"
end.run_action(:run)

# fake out ohai data
node.automatic_attrs["hostname"] = node.name
<http://node.name>[/[^\.]*/]
node.automatic_attrs["domain"] = node.name
<http://node.name>[/\.(.*)/, 1]
node.automatic_attrs["machinename"] = node.name <http://node.name>
node.automatic_attrs["fqdn"] = node.name <http://node.name>

case node["platform_family"]
when "rhel", "fedora"
  template "/etc/sysconfig/network" do
    source "redhat-network.erb"
  end
when "debian"
  template "/etc/hostname" do
    source "ubuntu-hostname.erb"
  end
end

That encodes my policy that node names are fqdns and that the fqdn
is set from the node name and that hostnames are fqdns.  If you
have a different policy, you can modify that code.  The important
bit is that I set the hostname of the box at compile time at the
top of my run_list.  Then I override the ohai automatic attrs at
compile time so that all later code will see that.  The templates
can wait until converge time since those are only going to be
necessary on next boot.

You can quibble with this because clearly there's a problem with
separation of concerns and we "should" be calling ohai to reload
the node data, but if you do that, you need to make sure that
you're doing that at compile time.  You could wrap the hostname
cookbook's recipe logic in an LWRP and then simply force that to
run at compile time.  I don't care about that because I know what
the ohai policy on those attrs are and that we're unlikely to
change it so I'm not too concerned about duplicating the code and
forcing it like that.

And the function of setting the current hostname and fixing the
ohai data is separate from the function of updating the
templates.  If I was doing this reusably I'd keep those separate. 
I'd also keep 'finding the hostname' separate and probably just
put that in a straight up ruby library function.  That would be
function or set of functions that you could use to poke vmware or
xenserver or whatever to see what your hostname is set as in the
hypervisor and use that.

A lot of people also just sidestep all of this fun by setting the hostname
at bootstrap time, before the initial Chef run.

Although the problem comes back in full, if you need to change the hostname
later :slight_smile:

Mat

On Thursday, October 9, 2014, Lamont Granquist lamont@opscode.com wrote:

"setting the automatic_attrs" wasn't really the point of that code I
pasted there. the point is to execute it at compile time rather than
converge time. the code you point to in the system cookbook is inside of a
provider and will also get executed at converge time. you can call the
system_hostname LWRP yourself and force it to run at compile time by method
chaining .run_action(:set) off of it (and add an action :nothing
attribute inside the LWRP).

On 10/9/14, 8:13 PM, Greg Barker wrote:

Thanks Lamont. I tried using the system
https://github.com/xhost-cookbooks/system cookbook which seems to do as
you have suggested (setting the automatic_attrs
https://github.com/xhost-cookbooks/system/blob/0564b30052923c9e9d5192c52a6dbe9e8f2f9d7b/providers/hostname.rb#L48)
but it still doesn't work.

The system cookbook is first in my run list and then towards the end it
gets to my recipe which contains:
node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['fqdn']}.pem"
...but it still thinks node['fqdn'] is localhost, it doesn't get the
updated value.

I guess I will just have to steer clear of relying on node['fqdn'] unless
you have any other ideas, it's a bummer that so many cookbooks use it
though.

Greg

On Sat, Oct 4, 2014 at 10:27 AM, Lamont Granquist <lamont@opscode.com
<javascript:_e(%7B%7D,'cvml','lamont@opscode.com');>> wrote:

On 10/3/14, 5:13 PM, Lamont Granquist wrote:

On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:

How it should be written, i'll look at submitting a PR...

Sorry look like I fell victim to thinking that all problems were like my
last problem.

The hostname is getting set at converge time, fairly late, by the
hostname cookbook. Your node['fqdn'] will be the old hostname throughout
the whole compile phase of the chef-client run. In your case since you
control the code it'll be way easier to use the node['set_fqdn'] attribute
that you're passing to the hostname cookbook to pass to the
chef-server cookbook:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"

If that doesn't work for you then you may have an issue trying to do
that. The attributes are most likely getting passed into the template
variable sometime in compiletime and your node['fqdn'] isn't getting
updated until converge time. Either the hostname cookbook needs to be
changed to do its work at compile-time or else the chef-server cookbook
needs to be converted to be lazy.

A better approach would probably be for the hostname cookbook to expose
a ruby library to call to get the desired hostname (basically sugar around
either returning node['set_fqdn'] or else returning the output of
"/usr/sbin/vmtoolsd --cmd 'info-get guestinfo.hostname'") and then you
could get that value at compile time and set attributes with it just fine.

So, I'd actually suggest doing something more like this than using
that hostname cookbook:

self.class.send(:include, Chef::Mixin::ShellOut)

execute very early

execute "set hostname to nodename" do
command "/bin/hostname #{node.name}"
action :nothing
not_if "shell_out!('hostname').stdout.chomp == node.name"
end.run_action(:run)

fake out ohai data

node.automatic_attrs["hostname"] = node.name[/[^.]/]
node.automatic_attrs["domain"] = node.name[/.(.
)/, 1]
node.automatic_attrs["machinename"] = node.name
node.automatic_attrs["fqdn"] = node.name

case node["platform_family"]
when "rhel", "fedora"
template "/etc/sysconfig/network" do
source "redhat-network.erb"
end
when "debian"
template "/etc/hostname" do
source "ubuntu-hostname.erb"
end
end

That encodes my policy that node names are fqdns and that the fqdn is set
from the node name and that hostnames are fqdns. If you have a different
policy, you can modify that code. The important bit is that I set the
hostname of the box at compile time at the top of my run_list. Then I
override the ohai automatic attrs at compile time so that all later code
will see that. The templates can wait until converge time since those are
only going to be necessary on next boot.

You can quibble with this because clearly there's a problem with
separation of concerns and we "should" be calling ohai to reload the node
data, but if you do that, you need to make sure that you're doing that at
compile time. You could wrap the hostname cookbook's recipe logic in an
LWRP and then simply force that to run at compile time. I don't care about
that because I know what the ohai policy on those attrs are and that we're
unlikely to change it so I'm not too concerned about duplicating the code
and forcing it like that.

And the function of setting the current hostname and fixing the ohai data
is separate from the function of updating the templates. If I was doing
this reusably I'd keep those separate. I'd also keep 'finding the
hostname' separate and probably just put that in a straight up ruby library
function. That would be function or set of functions that you could use to
poke vmware or xenserver or whatever to see what your hostname is set as in
the hypervisor and use that.

--
Rock Solid Ops: development & operations consulting for Ruby on Rails

My 2cts on the subject: don't really on the hostname, use the serial.number as machine hostname and take advantage of dns aliases (cname) which may be filled in an attribute to be used later (maybe overriding the real fun for other cookbooks)

---- Mathieu Martin a écrit ----

A lot of people also just sidestep all of this fun by setting the hostname at bootstrap time, before the initial Chef run.

Although the problem comes back in full, if you need to change the hostname later :slight_smile:

Mat

On Thursday, October 9, 2014, Lamont Granquist lamont@opscode.com wrote:

"setting the automatic_attrs" wasn't really the point of that code I pasted there. the point is to execute it at compile time rather than converge time. the code you point to in the system cookbook is inside of a provider and will also get executed at converge time. you can call the system_hostname LWRP yourself and force it to run at compile time by method chaining .run_action(:set) off of it (and add an action :nothing attribute inside the LWRP).

On 10/9/14, 8:13 PM, Greg Barker wrote:

Thanks Lamont. I tried using the system cookbook which seems to do as you have suggested (setting the automatic_attrs) but it still doesn't work.

The system cookbook is first in my run list and then towards the end it gets to my recipe which contains:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] = "/etc/pki/tls/certs/#{node['fqdn']}.pem"

...but it still thinks node['fqdn'] is localhost, it doesn't get the updated value.

I guess I will just have to steer clear of relying on node['fqdn'] unless you have any other ideas, it's a bummer that so many cookbooks use it though.

Greg

On Sat, Oct 4, 2014 at 10:27 AM, Lamont Granquist lamont@opscode.com wrote:

On 10/3/14, 5:13 PM, Lamont Granquist wrote:

On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:

How it should be written, i'll look at submitting a PR...

Sorry look like I fell victim to thinking that all problems were like my last problem.

The hostname is getting set at converge time, fairly late, by the hostname cookbook. Your node['fqdn'] will be the old hostname throughout the whole compile phase of the chef-client run. In your case since you control the code it'll be way easier to use the node['set_fqdn'] attribute that you're passing to the hostname cookbook to pass to the
chef-server cookbook:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] = "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"

If that doesn't work for you then you may have an issue trying to do that. The attributes are most likely getting passed into the template variable sometime in compiletime and your node['fqdn'] isn't getting updated until converge time. Either the hostname cookbook needs to be changed to do its work at compile-time or else the chef-server cookbook needs to be converted to be lazy.

A better approach would probably be for the hostname cookbook to expose a ruby library to call to get the desired hostname (basically sugar around either returning node['set_fqdn'] or else returning the output of "/usr/sbin/vmtoolsd --cmd 'info-get guestinfo.hostname'") and then you could get that value at compile time and set attributes with it just fine.

So, I'd actually suggest doing something more like this than using that hostname cookbook:

self.class.send(:include, Chef::Mixin::ShellOut)

execute very early

execute "set hostname to nodename" do
command "/bin/hostname #{node.name}"
action :nothing
not_if "shell_out!('hostname').stdout.chomp == node.name"
end.run_action(:run)

fake out ohai data

node.automatic_attrs["hostname"] = node.name[/[^.]/]
node.automatic_attrs["domain"] = node.name[/.(.
)/, 1]
node.automatic_attrs["machinename"] = node.name
node.automatic_attrs["fqdn"] = node.name

case node["platform_family"]
when "rhel", "fedora"
template "/etc/sysconfig/network" do
source "redhat-network.erb"
end
when "debian"
template "/etc/hostname" do
source "ubuntu-hostname.erb"
end
end

That encodes my policy that node names are fqdns and that the fqdn is set from the node name and that hostnames are fqdns. If you have a different policy, you can modify that code. The important bit is that I set the hostname of the box at compile time at the top of my run_list. Then I override the ohai automatic attrs at compile time so that all later code will see that. The templates can wait until converge time since those are only going to be necessary on next boot.

You can quibble with this because clearly there's a problem with separation of concerns and we "should" be calling ohai to reload the node data, but if you do that, you need to make sure that you're doing that at compile time. You could wrap the hostname cookbook's recipe logic in an LWRP and then simply force that to run at compile time. I don't care about that because I know what the ohai policy on those attrs are and that we're unlikely to change it so I'm not too concerned about duplicating the code and forcing it like that.

And the function of setting the current hostname and fixing the ohai data is separate from the function of updating the templates. If I was doing this reusably I'd keep those separate. I'd also keep 'finding the hostname' separate and probably just put that in a straight up ruby library function. That would be function or set of functions that you could use to poke vmware or xenserver or whatever to see what your hostname is set as in the hypervisor and use that.

--
Rock Solid Ops: development & operations consulting for Ruby on Rails

U,ugu,,ag, uyuxa,qqsdsr

Sent from my BlackBerry 10 smartphone on the Verizon Wireless 4G LTE network.From: Tensibai ZhaoyingSent: Saturday, October 11, 2014 15:13To: chef@lists.opscode.comReply To: chef@lists.opscode.comSubject: [chef] Re: Re: How to override node attribute with lazy value?)()(). , g. Gyv},a‎

My 2cts on the subject: don't really on the hostname, u1se the serial.number as machine hostname and take advantage of dns aliases (cname) which may be filled in an attribute to be used later (maybe ov=erriding the real fun for other cookbooks)

---- Mathieu Martin a écrit ----

A lot of people also just sidestep all of this fun by setting the hostname at bootstrap time, before the initial Chef run.

Although the problem comes back in full, if you need to change the hostname later :slight_smile:

Mat

On Thursday, October 9, 2014, Lamont Granquist <lamont@opscode.com> wrote:

  "setting the automatic_attrs" wasn't really the point of that code
  I pasted there.  the point is to execute it at compile time rather
  than converge time.  the code you point to in the system cookbook
  is inside of a provider and will also get executed at converge
  time.  you can call the system_hostname LWRP yourself and force it
  to run at compile time by method chaining .run_action(:set) off of
  it (and add an `action :nothing` attribute inside the LWRP).




  On 10/9/14, 8:13 PM, Greg Barker wrote:
Thanks Lamont. I tried using the system cookbook which seems to do as you have suggested (setting the automatic_attrs) but it still doesn't work.
        The system cookbook is first in my run list and then towards
        the end it gets to my recipe which contains:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['fqdn']}.pem"

        ...but it still thinks node['fqdn'] is localhost, it doesn't
        get the updated value.




      I guess I will just have to steer clear of relying on
      node['fqdn'] unless you have any other ideas, it's a bummer
      that so many cookbooks use it though.




    Greg

On Sat, Oct 4, 2014 at 10:27 AM, Lamont
Granquist <lamont@opscode.com>
wrote:

On 10/3/14, 5:13 PM, Lamont Granquist wrote:
On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:
                How it should be written, i'll look at submitting a
                PR...
              Sorry look like I fell victim to thinking that all
              problems were like my last problem.




              The hostname is getting set at converge time, fairly
              late, by the hostname cookbook.  Your node['fqdn']
              will be the old hostname throughout the whole compile
              phase of the chef-client run.  In your case since you
              control the code it'll be way easier to use the
              node['set_fqdn'] attribute that you're passing to the
              hostname cookbook to pass to the


              chef-server cookbook:




              node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
              = "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"




              If that doesn't work for you then you may have an
              issue trying to do that.  The attributes are most
              likely getting passed into the template variable
              sometime in compiletime and your node['fqdn'] isn't
              getting updated until converge time.   Either the
              hostname cookbook needs to be changed to do its work
              at compile-time or else the chef-server cookbook needs
              to be converted to be lazy.




              A better approach would probably be for the hostname
              cookbook to expose a ruby library to call to get the
              desired hostname (basically sugar around either
              returning node['set_fqdn'] or else returning the
              output of "/usr/sbin/vmtoolsd --cmd 'info-get
              guestinfo.hostname'") and then you could get that
              value at compile time and set attributes with it just
              fine.
So, I'd actually suggest doing something more like this than using that hostname cookbook:
        self.class.send(:include, Chef::Mixin::ShellOut)




        # execute very early


        execute "set hostname to nodename" do


          command "/bin/hostname #{<a href="http://node.name" target="_blank">node.name</a>}"


          action :nothing


          not_if "shell_out!('hostname').stdout.chomp == <a href="http://node.name" target="_blank">node.name</a>"


        end.run_action(:run)




        # fake out ohai data


        node.automatic_attrs["hostname"] = <a href="http://node.name" target="_blank">node.name</a>[/[^\.]*/]


        node.automatic_attrs["domain"] = <a href="http://node.name" target="_blank">node.name</a>[/\.(.*)/,
        1]


        node.automatic_attrs["machinename"] = <a href="http://node.name" target="_blank">node.name</a>


        node.automatic_attrs["fqdn"] = <a href="http://node.name" target="_blank">node.name</a>




        case node["platform_family"]


        when "rhel", "fedora"


          template "/etc/sysconfig/network" do


            source "redhat-network.erb"


          end


        when "debian"


          template "/etc/hostname" do


            source "ubuntu-hostname.erb"


          end


        end




        That encodes my policy that node names are fqdns and that
        the fqdn is set from the node name and that hostnames are
        fqdns.  If you have a different policy, you can modify that
        code.  The important bit is that I set the hostname of the
        box at compile time at the top of my run_list.  Then I
        override the ohai automatic attrs at compile time so that
        all later code will see that.  The templates can wait until
        converge time since those are only going to be necessary on
        next boot.




        You can quibble with this because clearly there's a problem
        with separation of concerns and we "should" be calling ohai
        to reload the node data, but if you do that, you need to
        make sure that you're doing that at compile time.  You could
        wrap the hostname cookbook's recipe logic in an LWRP and
        then simply force that to run at compile time.  I don't care
        about that because I know what the ohai policy on those
        attrs are and that we're unlikely to change it so I'm not
        too concerned about duplicating the code and forcing it like
        that.




        And the function of setting the current hostname and fixing
        the ohai data is separate from the function of updating the
        templates.  If I was doing this reusably I'd keep those
        separate.  I'd also keep 'finding the hostname' separate and
        probably just put that in a straight up ruby library
        function.  That would be function or set of functions that
        you could use to poke vmware or xenserver or whatever to see
        what your hostname is set as in the hypervisor and use that.

--

Rock Solid Ops: development & operations consulting for Ruby on Rails

Sent from my BlackBerry 10 smartphone on the Verizon Wireless 4G LTE network.From: Mathieu MartinuuGac‎Sent: Saturday, October 11, 2014 14:34To: chef@lists.opscode.com‎Reply To: chef@lists.opscode.comCc: Greg BarkerSubject: [chef] Re: How to override node attribute with lazy value?

A lot of people also just sidestep all of this fun by setting the hostname at bootstrap time, before the initial Chef run.

Although the problem comes back in full, if you need to change the hostname later :slight_smile:

Mat

On Thursday, October 9, 2014, Lamont Granquist <lamont@opscode.com> wrote:

  "setting the automatic_attrs" wasn't really the point of that code
  I pasted there.  the point is to execute it at compile time rather
  than converge time.  the code you point to in the system cookbook
  is inside of a provider and will also get executed at converge
  time.  you can call the system_hostname LWRP yourself and force it
  to run at compile time by method chaining .run_action(:set) off of
  it (and add an `action :nothing` attribute inside the LWRP).




  On 10/9/14, 8:13 PM, Greg Barker wrote:
Thanks Lamont. I tried using the system cookbook which seems to do as you have suggested (setting the automatic_attrs) but it still doesn't work.
        The system cookbook is first in my run list and then towards
        the end it gets to my recipe which contains:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['fqdn']}.pem"

        ...but it still thinks node['fqdn'] is localhost, it doesn't
        get the updated value.




      I guess I will just have to steer clear of relying on
      node['fqdn'] unless you have any other ideas, it's a bummer
      that so many cookbooks use it though.




    Greg

On Sat, Oct 4, 2014 at 10:27 AM, Lamont
Granquist <lamont@opscode.com>
wrote:

On 10/3/14, 5:13 PM, Lamont Granquist wrote:
On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:
                How it should be written, i'll look at submitting a
                PR...
              Sorry look like I fell victim to thinking that all
              problems were like my last problem.




              The hostname is getting set at converge time, fairly
              late, by the hostname cookbook.  Your node['fqdn']
              will be the old hostname throughout the whole compile
              phase of the chef-client run.  In your case since you
              control the code it'll be way easier to use the
              node['set_fqdn'] attribute that you're passing to the
              hostname cookbook to pass to the


              chef-server cookbook:




              node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
              = "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"




              If that doesn't work for you then you may have an
              issue trying to do that.  The attributes are most
              likely getting passed into the template variable
              sometime in compiletime and your node['fqdn'] isn't
              getting updated until converge time.   Either the
              hostname cookbook needs to be changed to do its work
              at compile-time or else the chef-server cookbook needs
              to be converted to be lazy.




              A better approach would probably be for the hostname
              cookbook to expose a ruby library to call to get the
              desired hostname (basically sugar around either
              returning node['set_fqdn'] or else returning the
              output of "/usr/sbin/vmtoolsd --cmd 'info-get
              guestinfo.hostname'") and then you could get that
              value at compile time and set attributes with it just
              fine.
So, I'd actually suggest doing something more like this than using that hostname cookbook:
        self.class.send(:include, Chef::Mixin::ShellOut)




        # execute very early


        execute "set hostname to nodename" do


          command "/bin/hostname #{<a href="http://node.name" target="_blank">node.name</a>}"


          action :nothing


          not_if "shell_out!('hostname').stdout.chomp == <a href="http://node.name" target="_blank">node.name</a>"


        end.run_action(:run)




        # fake out ohai data


        node.automatic_attrs["hostname"] = <a href="http://node.name" target="_blank">node.name</a>[/[^\.]*/]


        node.automatic_attrs["domain"] = <a href="http://node.name" target="_blank">node.name</a>[/\.(.*)/,
        1]


        node.automatic_attrs["machinename"] = <a href="http://node.name" target="_blank">node.name</a>


        node.automatic_attrs["fqdn"] = <a href="http://node.name" target="_blank">node.name</a>




        case node["platform_family"]


        when "rhel", "fedora"


          template "/etc/sysconfig/network" do


            source "redhat-network.erb"


          end


        when "debian"


          template "/etc/hostname" do


            source "ubuntu-hostname.erb"


          end


        end




        That encodes my policy that node names are fqdns and that
        the fqdn is set from the node name and that hostnames are
        fqdns.  If you have a different policy, you can modify that
        code.  The important bit is that I set the hostname of the
        box at compile time at the top of my run_list.  Then I
        override the ohai automatic attrs at compile time so that
        all later code will see that.  The templates can wait until
        converge time since those are only going to be necessary on
        next boot.




        You can quibble with this because clearly there's a problem
        with separation of concerns and we "should" be calling ohai
        to reload the node data, but if you do that, you need to
        make sure that you're doing that at compile time.  You could
        wrap the hostname cookbook's recipe logic in an LWRP and
        then simply force that to run at compile time.  I don't care
        about that because I know what the ohai policy on those
        attrs are and that we're unlikely to change it so I'm not
        too concerned about duplicating the code and forcing it like
        that.




        And the function of setting the current hostname and fixing
        the ohai data is separate from the function of updating the
        templates.  If I was doing this reusably I'd keep those
        separate.  I'd also keep 'finding the hostname' separate and
        probably just put that in a straight up ruby library
        function.  That would be function or set of functions that
        you could use to poke vmware or xenserver or whatever to see
        what your hostname is set as in the hypervisor and use that.

--

Rock Solid Ops: development & operations consulting for Ruby on Rails

On 10/11/14, 11:33 AM, Mathieu Martin wrote:

A lot of people also just sidestep all of this fun by setting the
hostname at bootstrap time, before the initial Chef run.

Although the problem comes back in full, if you need to change the
hostname later :slight_smile:

Yeah setting the identity of the server (in general) needs to be pushed
as early as possible (in general), or you're going to have a bad time.

Thanks Noah. I tried it out but I don't think I'm doing it right.

node["chef-server"]["configuration"]["nginx"] % { ssl_certificate:
"/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

This resulted in:

NoMethodError - undefined method `%' for nil:NilClass

So before that line I added:

node.default["chef-server"]["configuration"]["nginx"] = {}

But now I get the error:

NoMethodError - Undefined node attribute or method %' on node'

Any ideas?

On Thu, Oct 2, 2014 at 7:55 AM, Noah Kantrowitz noah@coderanger.net wrote:

On Oct 2, 2014, at 3:13 AM, Greg Barker fletch@fletchowns.net wrote:

The chef-server readme shows how to override nginx attributes. However,
it doesn't seem to work like I want it to when I do:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] =
"/etc/pki/tls/certs/#{node[:fqdn]}.pem"

node[:fqdn] is being updated during my chef run using the hostname
cookbook, and so using the above results in an error because chef-server
ends up looking for /etc/pki/tls/certs/localhost.pem (the old hostname),
when it should instead be using /etc/pki/tls/certs/mynode.mycompany.com.pem.

So I think I want something like the following, but this doesn't work.
What's the right way to do it?

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] =
lazy { "/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

lazy{} is a feature of resources, not of node attributes. See
Derived Attributes in Chef – Noah Kantrowitz for more information about
how to handle delayed interpolation in node attributes.

--Noah

Greg,

Using Noah's approach, you'd have something like this in your attribute
file, to establish the pattern for the derived attribute:

node["chef-server"]["configuration"]["nginx"][ "ssl_certificate"] =
"/etc/pki/tls/certs/%{fqdn}.pem" }

And then this in your recipe where actually wanted to realize the value:

node["chef-server"]["configuration"]["nginx"][ "ssl_certificate"] % { fqdn
: node[:fqdn] }

Hope this helps.
Christine

"/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

On Thu, Oct 2, 2014 at 11:18 AM, Greg Barker fletch@fletchowns.net wrote:

Thanks Noah. I tried it out but I don't think I'm doing it right.

node["chef-server"]["configuration"]["nginx"] % { ssl_certificate:
"/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

This resulted in:

NoMethodError - undefined method `%' for nil:NilClass

So before that line I added:

node.default["chef-server"]["configuration"]["nginx"] = {}

But now I get the error:

NoMethodError - Undefined node attribute or method %' on node'

Any ideas?

On Thu, Oct 2, 2014 at 7:55 AM, Noah Kantrowitz noah@coderanger.net
wrote:

On Oct 2, 2014, at 3:13 AM, Greg Barker fletch@fletchowns.net wrote:

The chef-server readme shows how to override nginx attributes. However,
it doesn't seem to work like I want it to when I do:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] =
"/etc/pki/tls/certs/#{node[:fqdn]}.pem"

node[:fqdn] is being updated during my chef run using the hostname
cookbook, and so using the above results in an error because chef-server
ends up looking for /etc/pki/tls/certs/localhost.pem (the old hostname),
when it should instead be using /etc/pki/tls/certs/mynode.mycompany.com.pem.

So I think I want something like the following, but this doesn't work.
What's the right way to do it?

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"] =
lazy { "/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

lazy{} is a feature of resources, not of node attributes. See
Derived Attributes in Chef – Noah Kantrowitz for more information about
how to handle delayed interpolation in node attributes.

--Noah

Just move that into a computation in recipe code that is stored in a
variable and not in a node attribute:

in default.rb:

ssl_certificate = node["chef-server"]["configuration"]["nginx"][
"ssl_certificate"] ||=
"/etc/pki/tls/certs/%{node["fqdn"]}.pem"

then don't set that attribute in the attribute file, leave it only as a
hook for someone to override the computation with.

See GitHub - lamont-cookbooks/erlang_one: Example computed attributes without using an attribute repo for an example
cookbook I wrote last night, with tests showing that you can wrap the
cookbook the way that people want to. Works without computed attributes
directly in the attributes file, it exposes the kind of behavior so that
what the recipe does is computed from the input attributes. Since it
uses a ruby variable instead of setting node attributes in recipe code
there's no attribute precedence issues.

On Fri Oct 3 07:21:32 2014, Christine Draper wrote:

Greg,

Using Noah's approach, you'd have something like this in your
attribute file, to establish the pattern for the derived attribute:

node["chef-server"]["configuration"]["nginx"][ "ssl_certificate"] =
"/etc/pki/tls/certs/%{fqdn}.pem" }

And then this in your recipe where actually wanted to realize the value:

node["chef-server"]["configuration"]["nginx"][ "ssl_certificate"] % {
fqdn : node[:fqdn] }

Hope this helps.
Christine

"/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

On Thu, Oct 2, 2014 at 11:18 AM, Greg Barker <fletch@fletchowns.net
mailto:fletch@fletchowns.net> wrote:

Thanks Noah. I tried it out but I don't think I'm doing it right.

node["chef-server"]["configuration"]["nginx"] % { ssl_certificate:
"/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

This resulted in:

NoMethodError - undefined method `%' for nil:NilClass

So before that line I added:

node.default["chef-server"]["configuration"]["nginx"] = {}

But now I get the error:

NoMethodError - Undefined node attribute or method %' on node'

Any ideas?

On Thu, Oct 2, 2014 at 7:55 AM, Noah Kantrowitz
<noah@coderanger.net mailto:noah@coderanger.net> wrote:

On Oct 2, 2014, at 3:13 AM, Greg Barker <fletch@fletchowns.net
mailto:fletch@fletchowns.net> wrote:

The chef-server readme shows how to override nginx
attributes. However, it doesn't seem to work like I want it to
when I do:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node[:fqdn]}.pem"

node[:fqdn] is being updated during my chef run using the
hostname cookbook, and so using the above results in an error
because chef-server ends up looking for
/etc/pki/tls/certs/localhost.pem (the old hostname), when it
should instead be using
/etc/pki/tls/certs/mynode.mycompany.com.pem.

So I think I want something like the following, but this
doesn't work. What's the right way to do it?

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= lazy { "/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

lazy{} is a feature of resources, not of node attributes. See
Derived Attributes in Chef – Noah Kantrowitz for more
information about how to handle delayed interpolation in node
attributes.

--Noah

Thanks for the additional responses. Unfortunately I still wasn't able to
get it working.

I put the following in my attributes/default.rb:

default["chef-server"]["configuration"]["nginx"]["ssl_certificate"] =
"/etc/pki/tls/certs/%{fqdn}.pem"
default["chef-server"]["configuration"]["nginx"]["ssl_certificate_key"] =
"/etc/pki/tls/private/%{fqdn}.key"

Then in my recipe I have:

node["chef-server"]["configuration"]["nginx"]["ssl_certificate"] % { fqdn:
node[:fqdn] }
node["chef-server"]["configuration"]["nginx"]["ssl_certificate_key"] % {
fqdn: node[:fqdn] }

include_recipe "chef-server::default"

This resulted in a /var/opt/chef-server/nginx/etc/chef_https_lb.conf with:

ssl_certificate /etc/pki/tls/certs/%{fqdn}.pem;
ssl_certificate_key /etc/pki/tls/private/%{fqdn}.key;

Which of course nginx did not like:

2014-10-03_21:59:37.09937 nginx: [emerg] directive "ssl_certificate" is not
terminated by ";"

I also tried setting those attributes in my role instead of the
attributes/default.rb file:

"configuration": {
"nginx": {
"ssl_certificate": "/etc/pki/tls/certs/%{fqdn}.pem",
"ssl_certificate_key": "/etc/pki/tls/private/%{fqdn}.key"
}
}

This resulted in the same error.

Lamont - I'm not sure I understand your response. Does that actually set
the node["chef-server"]["configuration"]["nginx"][ "ssl_certificate"]
attribute that the chef-server cookbook is expecting? Or is that how the
chef-server cookbook should have been written?

Thanks,
Greg

On Fri, Oct 3, 2014 at 8:02 AM, Lamont Granquist lamont@opscode.com wrote:

Just move that into a computation in recipe code that is stored in a
variable and not in a node attribute:

in default.rb:

ssl_certificate = node["chef-server"]["configuration"]["nginx"][
"ssl_certificate"] ||=
"/etc/pki/tls/certs/%{node["fqdn"]}.pem"

then don't set that attribute in the attribute file, leave it only as a
hook for someone to override the computation with.

See GitHub - lamont-cookbooks/erlang_one: Example computed attributes without using an attribute repo for an example
cookbook I wrote last night, with tests showing that you can wrap the
cookbook the way that people want to. Works without computed attributes
directly in the attributes file, it exposes the kind of behavior so that
what the recipe does is computed from the input attributes. Since it uses
a ruby variable instead of setting node attributes in recipe code there's
no attribute precedence issues.

On Fri Oct 3 07:21:32 2014, Christine Draper wrote:

Greg,

Using Noah's approach, you'd have something like this in your
attribute file, to establish the pattern for the derived attribute:

node["chef-server"]["configuration"]["nginx"][ "ssl_certificate"] =
"/etc/pki/tls/certs/%{fqdn}.pem" }

And then this in your recipe where actually wanted to realize the value:

node["chef-server"]["configuration"]["nginx"][ "ssl_certificate"] % {
fqdn : node[:fqdn] }

Hope this helps.
Christine

"/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

On Thu, Oct 2, 2014 at 11:18 AM, Greg Barker <fletch@fletchowns.net
mailto:fletch@fletchowns.net> wrote:

Thanks Noah. I tried it out but I don't think I'm doing it right.

node["chef-server"]["configuration"]["nginx"] % { ssl_certificate:
"/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

This resulted in:

NoMethodError - undefined method `%' for nil:NilClass

So before that line I added:

node.default["chef-server"]["configuration"]["nginx"] = {}

But now I get the error:

NoMethodError - Undefined node attribute or method %' on node'

Any ideas?

On Thu, Oct 2, 2014 at 7:55 AM, Noah Kantrowitz
<noah@coderanger.net mailto:noah@coderanger.net> wrote:

On Oct 2, 2014, at 3:13 AM, Greg Barker <fletch@fletchowns.net
mailto:fletch@fletchowns.net> wrote:

The chef-server readme shows how to override nginx
attributes. However, it doesn't seem to work like I want it to
when I do:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node[:fqdn]}.pem"

node[:fqdn] is being updated during my chef run using the
hostname cookbook, and so using the above results in an error
because chef-server ends up looking for
/etc/pki/tls/certs/localhost.pem (the old hostname), when it
should instead be using
/etc/pki/tls/certs/mynode.mycompany.com.pem.

So I think I want something like the following, but this
doesn't work. What's the right way to do it?

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= lazy { "/etc/pki/tls/certs/#{node[:fqdn]}.pem" }

lazy{} is a feature of resources, not of node attributes. See
Derived Attributes in Chef – Noah Kantrowitz for more
information about how to handle delayed interpolation in node
attributes.

--Noah

How it should be written, i'll look at submitting a PR...

On Fri Oct 3 15:05:03 2014, Greg Barker wrote:

Thanks for the additional responses. Unfortunately I still wasn't able
to get it working.

I put the following in my attributes/default.rb:

default["chef-server"]["configuration"]["nginx"]["ssl_certificate"] =
"/etc/pki/tls/certs/%{fqdn}.pem"
default["chef-server"]["configuration"]["nginx"]["ssl_certificate_key"] =
"/etc/pki/tls/private/%{fqdn}.key"

Then in my recipe I have:

node["chef-server"]["configuration"]["nginx"]["ssl_certificate"] % {
fqdn: node[:fqdn] }
node["chef-server"]["configuration"]["nginx"]["ssl_certificate_key"] %
{ fqdn: node[:fqdn] }

include_recipe "chef-server::default"

This resulted in a /var/opt/chef-server/nginx/etc/chef_https_lb.conf with:

ssl_certificate /etc/pki/tls/certs/%{fqdn}.pem;
ssl_certificate_key /etc/pki/tls/private/%{fqdn}.key;

Which of course nginx did not like:

2014-10-03_21:59:37.09937 nginx: [emerg] directive "ssl_certificate"
is not terminated by ";"

I also tried setting those attributes in my role instead of the
attributes/default.rb file:

"configuration": {
"nginx": {
"ssl_certificate": "/etc/pki/tls/certs/%{fqdn}.pem",
"ssl_certificate_key": "/etc/pki/tls/private/%{fqdn}.key"
}
}

This resulted in the same error.

Lamont - I'm not sure I understand your response. Does that actually
set the node["chef-server"]["configuration"]["nginx"][
"ssl_certificate"] attribute that the chef-server cookbook is
expecting? Or is that how the chef-server cookbook should have been
written?

Thanks,
Greg

On Fri, Oct 3, 2014 at 8:02 AM, Lamont Granquist <lamont@opscode.com
mailto:lamont@opscode.com> wrote:

Just move that into a computation in recipe code that is stored in
a variable and not in a node attribute:

in default.rb:

ssl_certificate = node["chef-server"]["__configuration"]["nginx"][
"ssl_certificate"] ||=
  "/etc/pki/tls/certs/%{node["__fqdn"]}.pem"

then don't set that attribute in the attribute file, leave it only
as a hook for someone to override the computation with.

See https://github.com/lamont-__granquist/erlang_one
<https://github.com/lamont-granquist/erlang_one> for an example
cookbook I wrote last night, with tests showing that you can wrap
the cookbook the way that people want to.  Works without computed
attributes directly in the attributes file, it exposes the kind of
behavior so that what the recipe does is computed from the input
attributes.  Since it uses a ruby variable instead of setting node
attributes in recipe code there's no attribute precedence issues.

On Fri Oct 3 07:21:32 2014, Christine Draper wrote:


    Greg,

    Using Noah's approach, you'd have something like this in your
    attribute file, to establish the pattern for the derived
    attribute:

    node["chef-server"]["__configuration"]["nginx"][
    "ssl_certificate"] =
    "/etc/pki/tls/certs/%{fqdn}.__pem" }

    And then this in your recipe where actually wanted to realize
    the value:

    node["chef-server"]["__configuration"]["nginx"][
    "ssl_certificate"] % {
    fqdn : node[:fqdn] }

    Hope this helps.
    Christine



    "/etc/pki/tls/certs/#{node[:__fqdn]}.pem" }


    On Thu, Oct 2, 2014 at 11:18 AM, Greg Barker
    <fletch@fletchowns.net <mailto:fletch@fletchowns.net>
    <mailto:fletch@fletchowns.net
    <mailto:fletch@fletchowns.net>>__> wrote:

    Thanks Noah. I tried it out but I don't think I'm doing it right.

    node["chef-server"]["__configuration"]["nginx"] % {
    ssl_certificate:
    "/etc/pki/tls/certs/#{node[:__fqdn]}.pem" }

    This resulted in:

    NoMethodError - undefined method `%' for nil:NilClass

    So before that line I added:

    node.default["chef-server"]["__configuration"]["nginx"] = {}

    But now I get the error:

    NoMethodError - Undefined node attribute or method `%' on `node'

    Any ideas?

    On Thu, Oct 2, 2014 at 7:55 AM, Noah Kantrowitz
    <noah@coderanger.net <mailto:noah@coderanger.net>
    <mailto:noah@coderanger.net <mailto:noah@coderanger.net>>> wrote:


    On Oct 2, 2014, at 3:13 AM, Greg Barker <fletch@fletchowns.net
    <mailto:fletch@fletchowns.net>
    <mailto:fletch@fletchowns.net
    <mailto:fletch@fletchowns.net>>__> wrote:

    > The chef-server readme shows how to override nginx
    attributes. However, it doesn't seem to work like I want it to
    when I do:
    >
    >
    node.override["chef-server"]["__configuration"]["nginx"]["ssl___certificate"]
    = "/etc/pki/tls/certs/#{node[:__fqdn]}.pem"
    >
    > node[:fqdn] is being updated during my chef run using the
    hostname cookbook, and so using the above results in an error
    because chef-server ends up looking for
    /etc/pki/tls/certs/localhost.__pem (the old hostname), when it
    should instead be using
    /etc/pki/tls/certs/mynode.__mycompany.com.pem.
    >
    > So I think I want something like the following, but this
    doesn't work. What's the right way to do it?
    >
    >
    node.override["chef-server"]["__configuration"]["nginx"]["ssl___certificate"]
    = lazy { "/etc/pki/tls/certs/#{node[:__fqdn]}.pem" }

    lazy{} is a feature of resources, not of node attributes. See
    https://coderanger.net/__derived-attributes/
    <https://coderanger.net/derived-attributes/> for more
    information about how to handle delayed interpolation in node
    attributes.

    --Noah

On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:

How it should be written, i'll look at submitting a PR...

Sorry look like I fell victim to thinking that all problems were like
my last problem.

The hostname is getting set at converge time, fairly late, by the
hostname cookbook. Your node['fqdn'] will be the old hostname
throughout the whole compile phase of the chef-client run. In your
case since you control the code it'll be way easier to use the
node['set_fqdn'] attribute that you're passing to the hostname cookbook
to pass to the
chef-server cookbook:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"

If that doesn't work for you then you may have an issue trying to do
that. The attributes are most likely getting passed into the template
variable sometime in compiletime and your node['fqdn'] isn't getting
updated until converge time. Either the hostname cookbook needs to be
changed to do its work at compile-time or else the chef-server cookbook
needs to be converted to be lazy.

A better approach would probably be for the hostname cookbook to expose
a ruby library to call to get the desired hostname (basically sugar
around either returning node['set_fqdn'] or else returning the output
of "/usr/sbin/vmtoolsd --cmd 'info-get guestinfo.hostname'") and then
you could get that value at compile time and set attributes with it
just fine.

Greg, just to make sure, since we don't see how you're using that
interpolation:

node["chef-server"]["configuration"]["nginx"]["ssl_certificate"] % { fqdn:
node[:fqdn] }

This ^ line of Ruby code returns the string you're looking for. It doesn't
modify the string stored in your attribute.

In other words, this whole line should either be assigned to a variable, or
be right in your template, like:

ssl_certificate <%=
node["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
% { fqdn: node[:fqdn] } %>;

Is that how you were using this?

Mat

On Fri, Oct 3, 2014 at 8:13 PM, Lamont Granquist lamont@opscode.com wrote:

On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:

How it should be written, i'll look at submitting a PR...

Sorry look like I fell victim to thinking that all problems were like my
last problem.

The hostname is getting set at converge time, fairly late, by the hostname
cookbook. Your node['fqdn'] will be the old hostname throughout the whole
compile phase of the chef-client run. In your case since you control the
code it'll be way easier to use the node['set_fqdn'] attribute that you're
passing to the hostname cookbook to pass to the
chef-server cookbook:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"

If that doesn't work for you then you may have an issue trying to do
that. The attributes are most likely getting passed into the template
variable sometime in compiletime and your node['fqdn'] isn't getting
updated until converge time. Either the hostname cookbook needs to be
changed to do its work at compile-time or else the chef-server cookbook
needs to be converted to be lazy.

A better approach would probably be for the hostname cookbook to expose a
ruby library to call to get the desired hostname (basically sugar around
either returning node['set_fqdn'] or else returning the output of
"/usr/sbin/vmtoolsd --cmd 'info-get guestinfo.hostname'") and then you
could get that value at compile time and set attributes with it just fine.

--

Organizer of DevOpsMtl http://www.devopsmtl.com. @webmat
http://twitter.com/webmat, LinkedIn
http://ca.linkedin.com/in/mathieumartin/, blog
http://www.programblings.com?utm_source=email+signature.

Mathieu, it's the opacide chef-server cookbook that ends up using this
attribute. That's the problem. :slight_smile:

On Friday, October 3, 2014, Mathieu Martin webmat@gmail.com wrote:

Greg, just to make sure, since we don't see how you're using that
interpolation:

node["chef-server"]["configuration"]["nginx"]["ssl_certificate"] % {
fqdn: node[:fqdn] }

This ^ line of Ruby code returns the string you're looking for. It doesn't
modify the string stored in your attribute.

In other words, this whole line should either be assigned to a variable,
or be right in your template, like:

ssl_certificate <%= node["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
% { fqdn: node[:fqdn] } %>;

Is that how you were using this?

Mat

On Fri, Oct 3, 2014 at 8:13 PM, Lamont Granquist <lamont@opscode.com
<javascript:_e(%7B%7D,'cvml','lamont@opscode.com');>> wrote:

On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:

How it should be written, i'll look at submitting a PR...

Sorry look like I fell victim to thinking that all problems were like my
last problem.

The hostname is getting set at converge time, fairly late, by the
hostname cookbook. Your node['fqdn'] will be the old hostname throughout
the whole compile phase of the chef-client run. In your case since you
control the code it'll be way easier to use the node['set_fqdn'] attribute
that you're passing to the hostname cookbook to pass to the
chef-server cookbook:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"

If that doesn't work for you then you may have an issue trying to do
that. The attributes are most likely getting passed into the template
variable sometime in compiletime and your node['fqdn'] isn't getting
updated until converge time. Either the hostname cookbook needs to be
changed to do its work at compile-time or else the chef-server cookbook
needs to be converted to be lazy.

A better approach would probably be for the hostname cookbook to expose a
ruby library to call to get the desired hostname (basically sugar around
either returning node['set_fqdn'] or else returning the output of
"/usr/sbin/vmtoolsd --cmd 'info-get guestinfo.hostname'") and then you
could get that value at compile time and set attributes with it just fine.

--

Organizer of DevOpsMtl http://www.devopsmtl.com. @webmat
http://twitter.com/webmat, LinkedIn
http://ca.linkedin.com/in/mathieumartin/, blog
http://www.programblings.com?utm_source=email+signature.

On 10/3/14, 5:13 PM, Lamont Granquist wrote:

On Fri Oct 3 16:39:36 2014, Lamont Granquist wrote:

How it should be written, i'll look at submitting a PR...

Sorry look like I fell victim to thinking that all problems were like
my last problem.

The hostname is getting set at converge time, fairly late, by the
hostname cookbook. Your node['fqdn'] will be the old hostname
throughout the whole compile phase of the chef-client run. In your
case since you control the code it'll be way easier to use the
node['set_fqdn'] attribute that you're passing to the hostname
cookbook to pass to the
chef-server cookbook:

node.override["chef-server"]["configuration"]["nginx"]["ssl_certificate"]
= "/etc/pki/tls/certs/#{node['set_fqdn']}.pem"

If that doesn't work for you then you may have an issue trying to do
that. The attributes are most likely getting passed into the template
variable sometime in compiletime and your node['fqdn'] isn't getting
updated until converge time. Either the hostname cookbook needs to
be changed to do its work at compile-time or else the chef-server
cookbook needs to be converted to be lazy.

A better approach would probably be for the hostname cookbook to
expose a ruby library to call to get the desired hostname (basically
sugar around either returning node['set_fqdn'] or else returning the
output of "/usr/sbin/vmtoolsd --cmd 'info-get guestinfo.hostname'")
and then you could get that value at compile time and set attributes
with it just fine.

So, I'd actually suggest doing something more like this than using that
hostname cookbook:

self.class.send(:include, Chef::Mixin::ShellOut)

execute very early

execute "set hostname to nodename" do
command "/bin/hostname #{node.name}"
action :nothing
not_if "shell_out!('hostname').stdout.chomp == node.name"
end.run_action(:run)

fake out ohai data

node.automatic_attrs["hostname"] = node.name[/[^.]/]
node.automatic_attrs["domain"] = node.name[/.(.
)/, 1]
node.automatic_attrs["machinename"] = node.name
node.automatic_attrs["fqdn"] = node.name

case node["platform_family"]
when "rhel", "fedora"
template "/etc/sysconfig/network" do
source "redhat-network.erb"
end
when "debian"
template "/etc/hostname" do
source "ubuntu-hostname.erb"
end
end

That encodes my policy that node names are fqdns and that the fqdn is
set from the node name and that hostnames are fqdns. If you have a
different policy, you can modify that code. The important bit is that I
set the hostname of the box at compile time at the top of my run_list.
Then I override the ohai automatic attrs at compile time so that all
later code will see that. The templates can wait until converge time
since those are only going to be necessary on next boot.

You can quibble with this because clearly there's a problem with
separation of concerns and we "should" be calling ohai to reload the
node data, but if you do that, you need to make sure that you're doing
that at compile time. You could wrap the hostname cookbook's recipe
logic in an LWRP and then simply force that to run at compile time. I
don't care about that because I know what the ohai policy on those attrs
are and that we're unlikely to change it so I'm not too concerned about
duplicating the code and forcing it like that.

And the function of setting the current hostname and fixing the ohai
data is separate from the function of updating the templates. If I was
doing this reusably I'd keep those separate. I'd also keep 'finding the
hostname' separate and probably just put that in a straight up ruby
library function. That would be function or set of functions that you
could use to poke vmware or xenserver or whatever to see what your
hostname is set as in the hypervisor and use that.