[chef] Re: Re: Re: Re: Re: Re: Re: Introducing the httpd cookbook


Chronological Thread 
  • From: Sean OMeara < >
  • To: " " < >
  • Subject: [chef] Re: Re: Re: Re: Re: Re: Re: Introducing the httpd cookbook
  • Date: Sat, 6 Sep 2014 23:17:09 -0400

<edit>.... "lead madness" =)
-s

On Sat, Sep 6, 2014 at 11:15 PM, Sean OMeara 
< >
 wrote:
> We're in violent agreement here.
>
> The trick to re-usability is to separate what the consumer needs
> control over (usually a configuration file) from what they don't care
> about (directory permissions, package installations, etc).
>
> The http_service provider(s) handle getting the service up and
> listening, then completely offloads the meaningful configuration
> details to the user. The resource *does* write a small configuration
> file, which tweaks a very minimal amount of things (listen ports,
> etc), but its main purpose in life is to include files from the conf.d
> directory.
>
> In the examples I found on the FB Github, the Phil has created an
> "open ended" API that lets users encode a data structure in node
> attributes. Then they're all consumed by a template resource. This is
> a configuration-file-centric view of the world.
>
> https://github.com/facebook/chef-utils/blob/master/cookbooks/fb_cron/recipes/default.rb#L60-L65
>
> The other resource in the recipes are "hard wired" by the cookbook,
> since they're not being driven by node attributes. The minimal amount
> of cross-platform-ness represented in that example is already starting
> to sprawl. There's a giant case statement at the top, and various
> control flow logic around platform_family.
>
> Most of the community cookbooks out there start out looking simple and
> clean... when they're written for a single version of a single
> platform. Then, over time, they descend into the pit of despair that
> is case statements for package names, service names, init systems, and
> filesystem paths. Driving all those details "open ended" will lead to
>
> A Chef resource (implemented with the LWRP DSL or otherwise), creates
> a "closure" around its subject.
>
> This lets you everything the example recipe *other than the template
> resource*, and shove it behind a wall of implementation detail. This
> lets an "httpd_service" become cross platform while hiding all the
> crazy platform details.
>
> The user can then can drop off configuration via httpd_config, which
> is just a thin wrapper around the template resource that calculates a
> file path based on the instance name. The same attribute tricks can be
> used around the contents of the template.
>
> -s
>
>
> On Sat, Sep 6, 2014 at 9:37 PM, Phil Dibowitz 
> < >
>  wrote:
>> On 09/06/2014 06:17 AM, Bráulio Bhavamitra wrote:
>>> Thanks Phil for excelent discussion and examples of how to use node
>>> attributes.
>>>
>>> When LWRP are coded, how do you think both ways to configure can the
>>> connected?
>>
>> Well I think that LWRPs are often the wrong way to provide an API. Not 
>> because
>> LWRPs are themselves bad - they're awesome - but for the same reason we 
>> don't
>> use most of the standard built-in providers. We don't use 'cron' for 
>> example,
>> we built a template and provide a data-api as I described in the last 
>> email.
>> You can see this here:
>>
>>   https://github.com/facebook/chef-utils/tree/master/cookbooks/fb_cron
>>
>> But there are times when an LWRP is what you need. The most common thing we
>> use LWRPs for is when the data we're pulling from the node object cannot be
>> put in a single file, and represents some dynamic set of files - and we 
>> won't
>> know what that set of files is until after everyone has munged the node
>> object. We avoid this wherever possible, because it makes system-level
>> idempotency more difficult, but sometimes you don't have a choice. So the
>> example here might be if the example software I was using *required* every 
>> vip
>> to be in a different file. Now again - often times it's how they set it up,
>> but it's not required. But lets just say it was absolutely required.
>>
>> In this modified example the software requires /etc/foo/foo.conf and then 
>> each
>> site goes in a file like /etc/foo/vips/www.sample.com.conf. And lets 
>> assume,
>> just to make it more interesting that the main configuration doesn't take 
>> that
>> "[global]" header but the other ones do so they know the site name.
>>
>> In this case I'd tweak the attributes slightly and put all the VIPs under
>> their own section:
>>
>>   default['foo']['config_file'] = '/etc/foo/foo.conf'
>>   default['foo']['config']['global'] => {
>>     'logdir' => '/var/log/foo',
>>     'loglevel' => 'DEBUG',
>>   }
>>   default['foo']['config']['vips']['www.sample.com'] => {
>>     'root' => '/var/foo/sample.com',
>>   }
>>
>> Then I'd the recipe to do:
>>
>>   template '/etc/foo/foo.conf' do
>>     source 'foo.conf.erb'
>>     owner 'root'
>>     group 'root'
>>     mode '0644'
>>   end
>>   foo_gen_site_files 'doit'
>>
>> And that would call a 'gen_site_files' LWRP. Notice I'm not passing 
>> anything
>> to it and notice it's not meant for anyone else to call. Now inside the
>> provider I'd have:
>>
>>   action :run do
>>     node['foo']['config']['vips'].keys do |url|
>>       template "/etc/foo/vips/#{url}.conf" do
>>         source 'vip.conf.erb'
>>         user 'root'
>>         group 'root'
>>         mode '0644'
>>         variables({'site' => url})
>>       end
>>     end
>>
>>     # Be idempotent - clean up crap we no longer own
>>     # We have to do this because Foo is too dumb to allow
>>     # all sites in a single file. I hate Foo.
>>     Dir.glob('/etc/foo/vips/*.conf').each do |cfile|
>>       site = File.basename(cfile, '.conf')
>>       next if node['foo']['config']['vips'][site]
>>       file cfile do
>>         action :delete
>>       end
>>     end
>>   end
>>
>> And actually since all this is doing is using built-in resources I'd 
>> actually
>> use notifying_action so I didn't have to deal with notifications myself... 
>> but
>> that's orthogonal to this point.
>>
>> The vip.conf.erb template would now look like:
>>
>>   <% config = 
>> node['foo']['config']['vips'
>>  %>
>>   [<%= @site %>]
>>   <% config.each do |key, val| %>
>>   <%=  key %> = <%= val %>
>>   <% end %>
>>
>> And the foo.conf.erb template would now look like:
>>
>>   <% config = node['foo']'config']['global'].to_hash %>
>>   <% config.each do |key, val| %>
>>   <%=  key %> = <%= val %>
>>   <% end %>
>>
>> There's a a few things to note here: variables to templates are evil and
>> should be avoided at all costs... rather use the node object from within 
>> your
>> template. In this case, I passed in static data that told the template 
>> where
>> to look in the node object and that's it.
>>
>> The other use-case we have for LWRPs is in the relatively-rare case where 
>> we
>> have cookbooks that allow you to both enable *or* disable something. We do
>> this with autofs, so our fb_autofs cookbook's default recipe is included
>> everywhere and looks like this:
>>
>>   fb_autofs 'enable it' do
>>     only_if { node['fb']['fb_autofs']['enable'] }
>>     action :enable
>>   end
>>   fb_autofs 'disable it' do
>>     not_if { node['fb']['fb_autofs']['enable'] }
>>     action :disable
>>   end
>>
>> Since 'lazy' doesn't work on actions, we need two invocations of the LWRP
>> using only_if and not_if which are always lazily-evaluated.
>>
>> The final use-case at FB for LWRPs is basically just a modification of the
>> first one in this email. When we want to deal with things like hardware or
>> mounts or things that require a complicated set of running command, 
>> looking at
>> output, running more commands. But even in these cases it works like the 
>> first
>> example above - the LWRP is just scheduled by it's own cookbook and it's
>> *purely* configured by tweaking the node object and it looks at that at
>> runtime inside the LWRP to decide what to do. This is basically just
>> abstracting what would otherwise be a long ruby_block or some such with
>> bunches of Mixlib::ShellOut calls.
>>
>>
>> --
>> Phil Dibowitz                             
>
>> Open Source software and tech docs        Insanity Palace of Metallica
>http://www.phildev.net/                   http://www.ipom.com/
>>
>> "Be who you are and say what you feel, because those who mind don't matter
>>  and those who matter don't mind."
>>  - Dr. Seuss
>>
>>



Archive powered by MHonArc 2.6.16.

§