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


Chronological Thread 
  • From: Ranjib Dey < >
  • To: " " < >
  • Subject: [chef] Re: Re: Re: Re: Re: Re: Re: Re: Introducing the httpd cookbook
  • Date: Sun, 7 Sep 2014 00:23:55 -0700

i dont like the attribute driven lwrps. they couple your code with attribute. historically the customization via chef's attribute system has painful. They are extremely powerful to create flatter hierarchies, but recipes, wrapper recipes etc is a pain. This is partially due to chef's elaborate attribute precedence level, and also having a single attribute system to represent ohai's related data.
note. attributes are public read only data. that means any attribute you define is available for reads to the entire fleet. This also means you are storing more data in chef server. this also means all the nodes that searches for this node will fetch more data (unless you use partial search) which will take more time and cpu to decompress at the client side. And finally remember each attribute applied to N nodes will increase this N times. 
Most of the lwrps that I have find easy to use, extend and maintain are less heavy on attributes (user_account, apt_repository, sudo, ruby_build are some of those) ... 
I still prefer to use attributes, to customize the recipe driven logic, that are not offered via lwrp, but include_recipe.
cheers
ranjib


On Sat, Sep 6, 2014 at 9:02 PM, Bráulio Bhavamitra < " target="_blank"> > wrote:
I really like the design of fb_cron! It is simple and very powerful in terms of what you can achieve with a simple hash (in JSON).

Also, I really agree that LWRP should be used when more complicated logic is necessary, and so ruby code can really help.

Thanks for sharing some of the usecase of Facebook, a very important use case of Chef.

But after this discussion, I also "agreed" to configure everything first by LWRP and then build a node attributes interface around it.

Sean, it is important to note that the cross-platform issue will rise and will be complicated to handle in both models (configuration by node attributes and by LWRP).

It is important to note that I'm not critizing the httpd cookbook, but the trend to do everything by LWRP and ignore node attributes.

cheers,
bráulio


On Sat, Sep 6, 2014 at 10:37 PM, Phil Dibowitz < " target="_blank"> > 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                              " target="_blank">
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





--
"Lute pela sua ideologia. Seja um com sua ideologia. Viva pela sua ideologia. Morra por sua ideologia" P.R. Sarkar

EITA - Educação, Informação e Tecnologias para Autogestão
http://cirandas.net/brauliobo
http://eita.org.br

"Paramapurusha é meu pai e Parama Prakriti é minha mãe. O universo é meu lar e todos nós somos cidadãos deste cosmo. Este universo é a imaginação da Mente Macrocósmica, e todas as entidades estão sendo criadas, preservadas e destruídas nas fases de extroversão e introversão do fluxo imaginativo cósmico. No âmbito pessoal, quando uma pessoa imagina algo em sua mente, naquele momento, essa pessoa é a única proprietária daquilo que ela imagina, e ninguém mais. Quando um ser humano criado mentalmente caminha por um milharal também imaginado, a pessoa imaginada não é a propriedade desse milharal, pois ele pertence ao indivíduo que o está imaginando. Este universo foi criado na imaginação de Brahma, a Entidade Suprema, por isso a propriedade deste universo é de Brahma, e não dos microcosmos que também foram criados pela imaginação de Brahma. Nenhuma propriedade deste mundo, mutável ou imutável, pertence a um indivíduo em particular; tudo é o patrimônio comum de todos."
Restante do texto em http://cirandas.net/brauliobo/blog/a-problematica-de-hoje-em-dia




Archive powered by MHonArc 2.6.16.

§