Good example of a lwrp

Hi all -

I’m still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

Also - how can I make some of the parameters mandatory?

OK, found the :required => true for the attributes.

But I'm not sure where to put the actual meat of this provider -
suggestions?

I looked at the database cookbook and am more confused at seeing all the
stuff in lib...

On Fri, Nov 30, 2012 at 11:31 AM, Maven User maven.2.user@gmail.com wrote:

Hi all -

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

Also - how can I make some of the parameters mandatory?

Chef ships with a whole bunch of providers already:
chef/lib/chef/provider at main · chef/chef · GitHub

Check them out for a basic idea of what writing a provider might look like.

Cheers,
Jay

On Fri, Nov 30, 2012 at 11:42 AM, Maven User maven.2.user@gmail.com wrote:

OK, found the :required => true for the attributes.

But I'm not sure where to put the actual meat of this provider -
suggestions?

I looked at the database cookbook and am more confused at seeing all the
stuff in lib...

On Fri, Nov 30, 2012 at 11:31 AM, Maven User maven.2.user@gmail.comwrote:

Hi all -

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

Also - how can I make some of the parameters mandatory?

On Friday, November 30, 2012 at 9:10 AM, Jay Feldblum wrote:

Chef ships with a whole bunch of providers already:
chef/lib/chef/provider at main · chef/chef · GitHub

Check them out for a basic idea of what writing a provider might look like.

Cheers,
Jay

On Fri, Nov 30, 2012 at 11:42 AM, Maven User <maven.2.user@gmail.com (mailto:maven.2.user@gmail.com)> wrote:

OK, found the :required => true for the attributes.

But I'm not sure where to put the actual meat of this provider - suggestions?

I looked at the database cookbook and am more confused at seeing all the stuff in lib...
Here's an example of a LWRP provider that is fairly meaty but contains all the code it runs:
https://github.com/opscode-cookbooks/java/blob/master/providers/ark.rb

You can ignore the converge_by stuff for now, that's required for why-run support, but not necessary otherwise (just don't put the why run_supported?; true stuff in your LWRP if you don't support why-run).

--
Daniel DeLeo

Ohai,

On 11/30/12 9:31 AM, "Maven User" maven.2.user@gmail.com wrote:

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

First, LWRPs are specifically the lightweight DSL that doesn't require the
ruby class structure. "Heavyweight" resources/providers are like the ones
that come with Chef itself. The "database" cookbook implements its
resources/providers as heavyweight due the way that the LWRPs are
automatically named by the cookbook and the filenames, and we wanted to
name

Second, the key is to make your resources idempotent. This is easy if
you're using resources inside the action blocks in the provider, and the
examples (below) have some of that. In some cases, like when you're
chaining together a bunch of command execution, you'll want to use
"load_current_resource" to check the current state of the system.

There are more advanced considerations, such as why-run support, and
handling updated resources, but for now stick to a simple use case.

These LWRPs from Opscode's cookbooks are relatively simple examples:

https://github.com/opscode-cookbooks/cron/blob/master/providers/d.rb

https://github.com/opscode-cookbooks/samba/blob/master/providers/user.rb

https://github.com/opscode-cookbooks/daemontools/blob/master/providers/serv
ice.rb

As an exercise, I'd probably start by doing an LWRP that simply handles
dropping off a "conf.d" style of configuration file.

Hope this helps!

--
Opscode, Inc
Joshua Timberman, Technical Community Manager
IRC, Skype, Twitter, Github: jtimberman

Joshua,

Thanks for providing these examples; I learned a few things from them. One
question for you or anyone else on the list though. This line from the
samba provider's load_current_resource method confuses me:

@smbuser = Chef::Resource::SambaUser.new(new_resource.name)

I assume that Chef::Resource::SambaUser is the class generated from the
LWRP resource. So isn't new_resource already an instance of that class?

Thanks,
Kevin Christen

On Fri, Nov 30, 2012 at 11:32 AM, Joshua Timberman joshua@opscode.comwrote:

Ohai,

On 11/30/12 9:31 AM, "Maven User" maven.2.user@gmail.com wrote:

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

First, LWRPs are specifically the lightweight DSL that doesn't require the
ruby class structure. "Heavyweight" resources/providers are like the ones
that come with Chef itself. The "database" cookbook implements its
resources/providers as heavyweight due the way that the LWRPs are
automatically named by the cookbook and the filenames, and we wanted to
name

Second, the key is to make your resources idempotent. This is easy if
you're using resources inside the action blocks in the provider, and the
examples (below) have some of that. In some cases, like when you're
chaining together a bunch of command execution, you'll want to use
"load_current_resource" to check the current state of the system.

There are more advanced considerations, such as why-run support, and
handling updated resources, but for now stick to a simple use case.

These LWRPs from Opscode's cookbooks are relatively simple examples:

https://github.com/opscode-cookbooks/cron/blob/master/providers/d.rb

https://github.com/opscode-cookbooks/samba/blob/master/providers/user.rb

https://github.com/opscode-cookbooks/daemontools/blob/master/providers/serv
ice.rb

As an exercise, I'd probably start by doing an LWRP that simply handles
dropping off a "conf.d" style of configuration file.

Hope this helps!

--
Opscode, Inc
Joshua Timberman, Technical Community Manager
IRC, Skype, Twitter, Github: jtimberman

Sorry to dredge this old thread back up - but I've followed the examples I
see above and combined that with the docs and I'm struggling a bit (still).

In my lwrp, for now - I have a default provider (default.rb) and a default
resource (default.rb).

Then in the cookbook where I want to leverage this lwrp, I have something
like this:

my-lwrp-name "somename" do
action :install
attributename "somevalue"
end

but this generates an error syntax error, unexpected tSTRING_BEG, expecting
keyword_do or '{' or '(' my-lwrp-name "somename" do

It's like it doesn't want "somename".

Also - its kinda unclear - if the cookbook that is trying to leverage this
lwrp is setting attributes, how do you reference those in your provider,
new_resource.?

On Fri, Nov 30, 2012 at 12:32 PM, Joshua Timberman joshua@opscode.comwrote:

Ohai,

On 11/30/12 9:31 AM, "Maven User" maven.2.user@gmail.com wrote:

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

First, LWRPs are specifically the lightweight DSL that doesn't require the
ruby class structure. "Heavyweight" resources/providers are like the ones
that come with Chef itself. The "database" cookbook implements its
resources/providers as heavyweight due the way that the LWRPs are
automatically named by the cookbook and the filenames, and we wanted to
name

Second, the key is to make your resources idempotent. This is easy if
you're using resources inside the action blocks in the provider, and the
examples (below) have some of that. In some cases, like when you're
chaining together a bunch of command execution, you'll want to use
"load_current_resource" to check the current state of the system.

There are more advanced considerations, such as why-run support, and
handling updated resources, but for now stick to a simple use case.

These LWRPs from Opscode's cookbooks are relatively simple examples:

https://github.com/opscode-cookbooks/cron/blob/master/providers/d.rb

https://github.com/opscode-cookbooks/samba/blob/master/providers/user.rb

https://github.com/opscode-cookbooks/daemontools/blob/master/providers/serv
ice.rb

As an exercise, I'd probably start by doing an LWRP that simply handles
dropping off a "conf.d" style of configuration file.

Hope this helps!

--
Opscode, Inc
Joshua Timberman, Technical Community Manager
IRC, Skype, Twitter, Github: jtimberman

Use underscores instead of dashes in your LWRP name.

On Thursday, December 20, 2012 at 12:53 PM, Maven User wrote:

Sorry to dredge this old thread back up - but I've followed the examples I see above and combined that with the docs and I'm struggling a bit (still).

In my lwrp, for now - I have a default provider (default.rb) and a default resource (default.rb).

Then in the cookbook where I want to leverage this lwrp, I have something like this:

my-lwrp-name "somename" do
action :install
attributename "somevalue"
end

but this generates an error syntax error, unexpected tSTRING_BEG, expecting keyword_do or '{' or '(' my-lwrp-name "somename" do

It's like it doesn't want "somename".

Also - its kinda unclear - if the cookbook that is trying to leverage this lwrp is setting attributes, how do you reference those in your provider, new_resource.?

On Fri, Nov 30, 2012 at 12:32 PM, Joshua Timberman <joshua@opscode.com (mailto:joshua@opscode.com)> wrote:

Ohai,

On 11/30/12 9:31 AM, "Maven User" <maven.2.user@gmail.com (mailto:maven.2.user@gmail.com)> wrote:

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

First, LWRPs are specifically the lightweight DSL that doesn't require the
ruby class structure. "Heavyweight" resources/providers are like the ones
that come with Chef itself. The "database" cookbook implements its
resources/providers as heavyweight due the way that the LWRPs are
automatically named by the cookbook and the filenames, and we wanted to
name

Second, the key is to make your resources idempotent. This is easy if
you're using resources inside the action blocks in the provider, and the
examples (below) have some of that. In some cases, like when you're
chaining together a bunch of command execution, you'll want to use
"load_current_resource" to check the current state of the system.

There are more advanced considerations, such as why-run support, and
handling updated resources, but for now stick to a simple use case.

These LWRPs from Opscode's cookbooks are relatively simple examples:

https://github.com/opscode-cookbooks/cron/blob/master/providers/d.rb

https://github.com/opscode-cookbooks/samba/blob/master/providers/user.rb

https://github.com/opscode-cookbooks/daemontools/blob/master/providers/serv
ice.rb

As an exercise, I'd probably start by doing an LWRP that simply handles
dropping off a "conf.d" style of configuration file.

Hope this helps!

--
Opscode, Inc
Joshua Timberman, Technical Community Manager
IRC, Skype, Twitter, Github: jtimberman

Wow - that was it!

Thank you so much!

On Thu, Dec 20, 2012 at 1:00 PM, Daniel Condomitti daniel@condomitti.comwrote:

Use underscores instead of dashes in your LWRP name.

On Thursday, December 20, 2012 at 12:53 PM, Maven User wrote:

Sorry to dredge this old thread back up - but I've followed the examples I
see above and combined that with the docs and I'm struggling a bit (still).

In my lwrp, for now - I have a default provider (default.rb) and a default
resource (default.rb).

Then in the cookbook where I want to leverage this lwrp, I have something
like this:

my-lwrp-name "somename" do
action :install
attributename "somevalue"
end

but this generates an error syntax error, unexpected tSTRING_BEG,
expecting keyword_do or '{' or '(' my-lwrp-name "somename" do

It's like it doesn't want "somename".

Also - its kinda unclear - if the cookbook that is trying to leverage this
lwrp is setting attributes, how do you reference those in your provider,
new_resource.?

On Fri, Nov 30, 2012 at 12:32 PM, Joshua Timberman joshua@opscode.comwrote:

Ohai,

On 11/30/12 9:31 AM, "Maven User" maven.2.user@gmail.com wrote:

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

First, LWRPs are specifically the lightweight DSL that doesn't require the
ruby class structure. "Heavyweight" resources/providers are like the ones
that come with Chef itself. The "database" cookbook implements its
resources/providers as heavyweight due the way that the LWRPs are
automatically named by the cookbook and the filenames, and we wanted to
name

Second, the key is to make your resources idempotent. This is easy if
you're using resources inside the action blocks in the provider, and the
examples (below) have some of that. In some cases, like when you're
chaining together a bunch of command execution, you'll want to use
"load_current_resource" to check the current state of the system.

There are more advanced considerations, such as why-run support, and
handling updated resources, but for now stick to a simple use case.

These LWRPs from Opscode's cookbooks are relatively simple examples:

https://github.com/opscode-cookbooks/cron/blob/master/providers/d.rb

https://github.com/opscode-cookbooks/samba/blob/master/providers/user.rb

https://github.com/opscode-cookbooks/daemontools/blob/master/providers/serv
ice.rb

As an exercise, I'd probably start by doing an LWRP that simply handles
dropping off a "conf.d" style of configuration file.

Hope this helps!

--
Opscode, Inc
Joshua Timberman, Technical Community Manager
IRC, Skype, Twitter, Github: jtimberman

Hmmm - some new weirdness...

I have a block of ruby code like this in the provider:

Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
....

The first time a recipe is run that is using this provider, that evaluates
to nothing, so the subsequent lines are skipped.

It also seems to run some of the steps out of order (right above this block
in the provider is an unzip step which now is run AFTER the Dir bit...).

Am I missing something?

On Thu, Dec 20, 2012 at 1:14 PM, Maven User maven.2.user@gmail.com wrote:

Wow - that was it!

Thank you so much!

On Thu, Dec 20, 2012 at 1:00 PM, Daniel Condomitti daniel@condomitti.comwrote:

Use underscores instead of dashes in your LWRP name.

On Thursday, December 20, 2012 at 12:53 PM, Maven User wrote:

Sorry to dredge this old thread back up - but I've followed the examples
I see above and combined that with the docs and I'm struggling a bit
(still).

In my lwrp, for now - I have a default provider (default.rb) and a
default resource (default.rb).

Then in the cookbook where I want to leverage this lwrp, I have something
like this:

my-lwrp-name "somename" do
action :install
attributename "somevalue"
end

but this generates an error syntax error, unexpected tSTRING_BEG,
expecting keyword_do or '{' or '(' my-lwrp-name "somename" do

It's like it doesn't want "somename".

Also - its kinda unclear - if the cookbook that is trying to leverage
this lwrp is setting attributes, how do you reference those in your
provider, new_resource.?

On Fri, Nov 30, 2012 at 12:32 PM, Joshua Timberman joshua@opscode.comwrote:

Ohai,

On 11/30/12 9:31 AM, "Maven User" maven.2.user@gmail.com wrote:

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

First, LWRPs are specifically the lightweight DSL that doesn't require the
ruby class structure. "Heavyweight" resources/providers are like the ones
that come with Chef itself. The "database" cookbook implements its
resources/providers as heavyweight due the way that the LWRPs are
automatically named by the cookbook and the filenames, and we wanted to
name

Second, the key is to make your resources idempotent. This is easy if
you're using resources inside the action blocks in the provider, and the
examples (below) have some of that. In some cases, like when you're
chaining together a bunch of command execution, you'll want to use
"load_current_resource" to check the current state of the system.

There are more advanced considerations, such as why-run support, and
handling updated resources, but for now stick to a simple use case.

These LWRPs from Opscode's cookbooks are relatively simple examples:

https://github.com/opscode-cookbooks/cron/blob/master/providers/d.rb

https://github.com/opscode-cookbooks/samba/blob/master/providers/user.rb

https://github.com/opscode-cookbooks/daemontools/blob/master/providers/serv
ice.rb

As an exercise, I'd probably start by doing an LWRP that simply handles
dropping off a "conf.d" style of configuration file.

Hope this helps!

--
Opscode, Inc
Joshua Timberman, Technical Community Manager
IRC, Skype, Twitter, Github: jtimberman

On Friday, December 21, 2012 at 2:54 PM, Maven User wrote:

Hmmm - some new weirdness...

I have a block of ruby code like this in the provider:

Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each do |file|
puts "here is the file #{file}"
....

The first time a recipe is run that is using this provider, that evaluates to nothing, so the subsequent lines are skipped.

It also seems to run some of the steps out of order (right above this block in the provider is an unzip step which now is run AFTER the Dir bit...).

Am I missing something?
Short: This is basically the LWRP version of the compile/converge phase issue. Use action :nothing and run_action to make resources execute immediately.

Long:
LWRPs currently handle nested resources by inserting them in the top-level resource collection after the LWRP's position in the resource collection. For a recipe like this:

resource_one
lwrp_resource -> sub_resource_one, sub_resource_two
resource_three

…after lwrp_resource is converged, your resource collection looks like:

resource_one #already executed
lwrp_resource #already executed
sub_resource_one
sub_resource_two
resource_three

This implementation was chosen so that the "sub resources" within an LWRP could notify resources outside of the LWRP. The downside is that the LWRP resource itself cannot properly determine if it was updated or not. See:

http://tickets.opscode.com/browse/CHEF-2336
http://tickets.opscode.com/browse/CHEF-3681

In either of the "insert after" or "inline recipe" implementations, you'll still have the general compile/converge pattern, which means that raw ruby code that's not wrapped in a ruby block will execute before resources, unless you force the issue with #run_action.

Another option for implementing LWRPs would be to scrap the compile/converge distinction altogether, but then notifications are pretty much impossible, which makes anything that wants to trigger an execute resource based on something else being updated (like a config file) much more difficult to write.

--
Daniel DeLeo

WOW - dood - thank you!

I'm a bit overwhelmed by the reply and trying to grock it - so bear with
me....

I'm trying to solve a scenario where we have a dozen recipes that they ALL
do the same 70 lines of code. So I'm trying to refactor that away in to a
lwrp.

I'm also not clear about the "action :nothing" and the run_action bits
you're mentioning above - any usecase links?

The tickets also confused me more >.<

The full block of code I have has ruby wrapping resources:

:Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
if (::File.file?(file))
puts "#{filename} is a file -> #{file}"
filename = ::File.basename(file)
newfilename = ::File.absolute_path(file).split("templates/")
puts "here is the new file name #{newfilename[1]}"

  if (newfilename[1].rindex('/') != nil && newfilename[1].rindex('/') >
  1.    puts "there are directories we need to create"
       dirstocreate = newfilename[1][0, newfilename[1].rindex('/')]
       puts "We need to make #{dirstocreate}"
      directory
    

"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
do
recursive true
action :create
not_if "test -d
/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
end
end
template
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}"
do
local true
source "#{file}"
end
end
end

Could I have put that inside a ruby block or would I lose the resources
inside there?

On Fri, Dec 21, 2012 at 6:19 PM, Daniel DeLeo dan@kallistec.com wrote:

On Friday, December 21, 2012 at 2:54 PM, Maven User wrote:

Hmmm - some new weirdness...

I have a block of ruby code like this in the provider:

Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
....

The first time a recipe is run that is using this provider, that evaluates
to nothing, so the subsequent lines are skipped.

It also seems to run some of the steps out of order (right above this
block in the provider is an unzip step which now is run AFTER the Dir
bit...).

Am I missing something?

Short: This is basically the LWRP version of the compile/converge phase
issue. Use action :nothing and run_action to make resources execute
immediately.

Long:
LWRPs currently handle nested resources by inserting them in the top-level
resource collection after the LWRP's position in the resource collection.
For a recipe like this:

resource_one
lwrp_resource -> sub_resource_one, sub_resource_two
resource_three

…after lwrp_resource is converged, your resource collection looks like:

resource_one #already executed
lwrp_resource #already executed
sub_resource_one
sub_resource_two
resource_three

This implementation was chosen so that the "sub resources" within an LWRP
could notify resources outside of the LWRP. The downside is that the LWRP
resource itself cannot properly determine if it was updated or not. See:

http://tickets.opscode.com/browse/CHEF-2336
http://tickets.opscode.com/browse/CHEF-3681
[CHEF-3681] add inline compilation option for LWRP by danielsdeleo · Pull Request #564 · chef/chef · GitHub

In either of the "insert after" or "inline recipe" implementations, you'll
still have the general compile/converge pattern, which means that raw ruby
code that's not wrapped in a ruby block will execute before resources,
unless you force the issue with #run_action.

Another option for implementing LWRPs would be to scrap the
compile/converge distinction altogether, but then notifications are pretty
much impossible, which makes anything that wants to trigger an execute
resource based on something else being updated (like a config file) much
more difficult to write.

--
Daniel DeLeo

So pardon the indenting:

ruby_block "apply-config" do
block do

::Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
if (::File.file?(file))
puts "#{filename} is a file -> #{file}"
filename = ::File.basename(file)
newfilename = ::File.absolute_path(file).split("templates/")
puts "here is the new file name #{newfilename[1]}"

    if (newfilename[1].rindex('/') != nil && newfilename[1].rindex('/')
        puts "there are directories we need to create"
        dirstocreate = newfilename[1][0, newfilename[1].rindex('/')]
        puts "We need to make #{dirstocreate}"
       directory

"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
do
recursive true
action :create
not_if "test -d
/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
end
end
template
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}"
do
local true
source "#{file}"
end
end
end
end
action :nothing
end.run_action(:run)

??

On Fri, Dec 21, 2012 at 6:40 PM, Maven User maven.2.user@gmail.com wrote:

WOW - dood - thank you!

I'm a bit overwhelmed by the reply and trying to grock it - so bear with
me....

I'm trying to solve a scenario where we have a dozen recipes that they ALL
do the same 70 lines of code. So I'm trying to refactor that away in to a
lwrp.

I'm also not clear about the "action :nothing" and the run_action bits
you're mentioning above - any usecase links?

The tickets also confused me more >.<

The full block of code I have has ruby wrapping resources:

:Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|

puts "here is the file #{file}"
if (::File.file?(file))
  puts "#{filename} is a file  -> #{file}"
  filename = ::File.basename(file)
  newfilename = ::File.absolute_path(file).split("templates/")
  puts "here is the new file name #{newfilename[1]}"

  if (newfilename[1].rindex('/') != nil && newfilename[1].rindex('/')
      puts "there are directories we need to create"
      dirstocreate = newfilename[1][0, newfilename[1].rindex('/')]
      puts "We need to make #{dirstocreate}"
     directory

"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
do
recursive true
action :create
not_if "test -d
/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
end
end
template
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}"
do
local true
source "#{file}"
end
end
end

Could I have put that inside a ruby block or would I lose the resources
inside there?

On Fri, Dec 21, 2012 at 6:19 PM, Daniel DeLeo dan@kallistec.com wrote:

On Friday, December 21, 2012 at 2:54 PM, Maven User wrote:

Hmmm - some new weirdness...

I have a block of ruby code like this in the provider:

Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
....

The first time a recipe is run that is using this provider, that
evaluates to nothing, so the subsequent lines are skipped.

It also seems to run some of the steps out of order (right above this
block in the provider is an unzip step which now is run AFTER the Dir
bit...).

Am I missing something?

Short: This is basically the LWRP version of the compile/converge phase
issue. Use action :nothing and run_action to make resources execute
immediately.

Long:
LWRPs currently handle nested resources by inserting them in the
top-level resource collection after the LWRP's position in the resource
collection. For a recipe like this:

resource_one
lwrp_resource -> sub_resource_one, sub_resource_two
resource_three

…after lwrp_resource is converged, your resource collection looks like:

resource_one #already executed
lwrp_resource #already executed
sub_resource_one
sub_resource_two
resource_three

This implementation was chosen so that the "sub resources" within an LWRP
could notify resources outside of the LWRP. The downside is that the LWRP
resource itself cannot properly determine if it was updated or not. See:

http://tickets.opscode.com/browse/CHEF-2336
http://tickets.opscode.com/browse/CHEF-3681
[CHEF-3681] add inline compilation option for LWRP by danielsdeleo · Pull Request #564 · chef/chef · GitHub

In either of the "insert after" or "inline recipe" implementations,
you'll still have the general compile/converge pattern, which means that
raw ruby code that's not wrapped in a ruby block will execute before
resources, unless you force the issue with #run_action.

Another option for implementing LWRPs would be to scrap the
compile/converge distinction altogether, but then notifications are pretty
much impossible, which makes anything that wants to trigger an execute
resource based on something else being updated (like a config file) much
more difficult to write.

--
Daniel DeLeo

Ahh - it needed to be end.run_action(:create) - but this all is resolved
waaay too early it seems (which is what you were saying earlier).

How can I delay the execution of the ruby code?

On Fri, Dec 21, 2012 at 6:55 PM, Maven User maven.2.user@gmail.com wrote:

So pardon the indenting:

ruby_block "apply-config" do
block do

::Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|

  puts "here is the file #{file}"
  if (::File.file?(file))
    puts "#{filename} is a file  -> #{file}"
    filename = ::File.basename(file)
    newfilename = ::File.absolute_path(file).split("templates/")
  puts "here is the new file name #{newfilename[1]}"

    if (newfilename[1].rindex('/') != nil &&

newfilename[1].rindex('/') > 1)
puts "there are directories we need to create"
dirstocreate = newfilename[1][0, newfilename[1].rindex('/')]
puts "We need to make #{dirstocreate}"
directory
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
do
recursive true
action :create
not_if "test -d
/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
end
end
template
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}"
do
local true
source "#{file}"
end
end
end
end
action :nothing
end.run_action(:run)

??

On Fri, Dec 21, 2012 at 6:40 PM, Maven User maven.2.user@gmail.comwrote:

WOW - dood - thank you!

I'm a bit overwhelmed by the reply and trying to grock it - so bear with
me....

I'm trying to solve a scenario where we have a dozen recipes that they
ALL do the same 70 lines of code. So I'm trying to refactor that away in
to a lwrp.

I'm also not clear about the "action :nothing" and the run_action bits
you're mentioning above - any usecase links?

The tickets also confused me more >.<

The full block of code I have has ruby wrapping resources:

:Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|

puts "here is the file #{file}"
if (::File.file?(file))
  puts "#{filename} is a file  -> #{file}"
  filename = ::File.basename(file)
  newfilename = ::File.absolute_path(file).split("templates/")
  puts "here is the new file name #{newfilename[1]}"

  if (newfilename[1].rindex('/') != nil && newfilename[1].rindex('/')
      puts "there are directories we need to create"
      dirstocreate = newfilename[1][0, newfilename[1].rindex('/')]
      puts "We need to make #{dirstocreate}"
     directory

"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
do
recursive true
action :create
not_if "test -d
/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
end
end
template
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}"
do
local true
source "#{file}"
end
end
end

Could I have put that inside a ruby block or would I lose the resources
inside there?

On Fri, Dec 21, 2012 at 6:19 PM, Daniel DeLeo dan@kallistec.com wrote:

On Friday, December 21, 2012 at 2:54 PM, Maven User wrote:

Hmmm - some new weirdness...

I have a block of ruby code like this in the provider:

Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
....

The first time a recipe is run that is using this provider, that
evaluates to nothing, so the subsequent lines are skipped.

It also seems to run some of the steps out of order (right above this
block in the provider is an unzip step which now is run AFTER the Dir
bit...).

Am I missing something?

Short: This is basically the LWRP version of the compile/converge phase
issue. Use action :nothing and run_action to make resources execute
immediately.

Long:
LWRPs currently handle nested resources by inserting them in the
top-level resource collection after the LWRP's position in the resource
collection. For a recipe like this:

resource_one
lwrp_resource -> sub_resource_one, sub_resource_two
resource_three

…after lwrp_resource is converged, your resource collection looks like:

resource_one #already executed
lwrp_resource #already executed
sub_resource_one
sub_resource_two
resource_three

This implementation was chosen so that the "sub resources" within an
LWRP could notify resources outside of the LWRP. The downside is that the
LWRP resource itself cannot properly determine if it was updated or not.
See:

http://tickets.opscode.com/browse/CHEF-2336
http://tickets.opscode.com/browse/CHEF-3681
[CHEF-3681] add inline compilation option for LWRP by danielsdeleo · Pull Request #564 · chef/chef · GitHub

In either of the "insert after" or "inline recipe" implementations,
you'll still have the general compile/converge pattern, which means that
raw ruby code that's not wrapped in a ruby block will execute before
resources, unless you force the issue with #run_action.

Another option for implementing LWRPs would be to scrap the
compile/converge distinction altogether, but then notifications are pretty
much impossible, which makes anything that wants to trigger an execute
resource based on something else being updated (like a config file) much
more difficult to write.

--
Daniel DeLeo

actually - I'm a BIT further now (maybe).

So removing the action and end.run_action items, I can see now it's
executing the ruby code when it should.

BUT - now it doesn't understand what a "directory" or a "template" is - how
do I import these things?

On Fri, Dec 21, 2012 at 7:02 PM, Maven User maven.2.user@gmail.com wrote:

Ahh - it needed to be end.run_action(:create) - but this all is resolved
waaay too early it seems (which is what you were saying earlier).

How can I delay the execution of the ruby code?

On Fri, Dec 21, 2012 at 6:55 PM, Maven User maven.2.user@gmail.comwrote:

So pardon the indenting:

ruby_block "apply-config" do
block do

::Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|

  puts "here is the file #{file}"
  if (::File.file?(file))
    puts "#{filename} is a file  -> #{file}"
    filename = ::File.basename(file)
    newfilename = ::File.absolute_path(file).split("templates/")
  puts "here is the new file name #{newfilename[1]}"

    if (newfilename[1].rindex('/') != nil &&

newfilename[1].rindex('/') > 1)
puts "there are directories we need to create"
dirstocreate = newfilename[1][0, newfilename[1].rindex('/')]
puts "We need to make #{dirstocreate}"
directory
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
do
recursive true
action :create
not_if "test -d
/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
end
end
template
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}"
do
local true
source "#{file}"
end
end
end
end
action :nothing
end.run_action(:run)

??

On Fri, Dec 21, 2012 at 6:40 PM, Maven User maven.2.user@gmail.comwrote:

WOW - dood - thank you!

I'm a bit overwhelmed by the reply and trying to grock it - so bear with
me....

I'm trying to solve a scenario where we have a dozen recipes that they
ALL do the same 70 lines of code. So I'm trying to refactor that away in
to a lwrp.

I'm also not clear about the "action :nothing" and the run_action bits
you're mentioning above - any usecase links?

The tickets also confused me more >.<

The full block of code I have has ruby wrapping resources:

:Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|

puts "here is the file #{file}"
if (::File.file?(file))
  puts "#{filename} is a file  -> #{file}"
  filename = ::File.basename(file)
  newfilename = ::File.absolute_path(file).split("templates/")
  puts "here is the new file name #{newfilename[1]}"

  if (newfilename[1].rindex('/') != nil &&

newfilename[1].rindex('/') > 1)
puts "there are directories we need to create"
dirstocreate = newfilename[1][0, newfilename[1].rindex('/')]
puts "We need to make #{dirstocreate}"
directory
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
do
recursive true
action :create
not_if "test -d
/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}"
end
end
template
"/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}"
do
local true
source "#{file}"
end
end
end

Could I have put that inside a ruby block or would I lose the resources
inside there?

On Fri, Dec 21, 2012 at 6:19 PM, Daniel DeLeo dan@kallistec.com wrote:

On Friday, December 21, 2012 at 2:54 PM, Maven User wrote:

Hmmm - some new weirdness...

I have a block of ruby code like this in the provider:

Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
....

The first time a recipe is run that is using this provider, that
evaluates to nothing, so the subsequent lines are skipped.

It also seems to run some of the steps out of order (right above this
block in the provider is an unzip step which now is run AFTER the Dir
bit...).

Am I missing something?

Short: This is basically the LWRP version of the compile/converge phase
issue. Use action :nothing and run_action to make resources execute
immediately.

Long:
LWRPs currently handle nested resources by inserting them in the
top-level resource collection after the LWRP's position in the resource
collection. For a recipe like this:

resource_one
lwrp_resource -> sub_resource_one, sub_resource_two
resource_three

…after lwrp_resource is converged, your resource collection looks like:

resource_one #already executed
lwrp_resource #already executed
sub_resource_one
sub_resource_two
resource_three

This implementation was chosen so that the "sub resources" within an
LWRP could notify resources outside of the LWRP. The downside is that the
LWRP resource itself cannot properly determine if it was updated or not.
See:

http://tickets.opscode.com/browse/CHEF-2336
http://tickets.opscode.com/browse/CHEF-3681
[CHEF-3681] add inline compilation option for LWRP by danielsdeleo · Pull Request #564 · chef/chef · GitHub

In either of the "insert after" or "inline recipe" implementations,
you'll still have the general compile/converge pattern, which means that
raw ruby code that's not wrapped in a ruby block will execute before
resources, unless you force the issue with #run_action.

Another option for implementing LWRPs would be to scrap the
compile/converge distinction altogether, but then notifications are pretty
much impossible, which makes anything that wants to trigger an execute
resource based on something else being updated (like a config file) much
more difficult to write.

--
Daniel DeLeo

On Friday, December 21, 2012 at 4:15 PM, Maven User wrote:

actually - I'm a BIT further now (maybe).

So removing the action and end.run_action items, I can see now it's executing the ruby code when it should.

BUT - now it doesn't understand what a "directory" or a "template" is - how do I import these things?

You went a bit in the wrong direction. I'd recommend either:

  1. use resources like normal, and put raw ruby code into ruby blocks:

action :something do
directory "path" do
#stuff
end
ruby_block "arbitrary_code" do
block do
# some code
end
end
file "path/file" do
#stuff
end
end

OR

  1. Use action :nothing plus run_action, but no ruby blocks

action :something do
directory "path" do
#stuff
action :nothing
run_action(:create) # this works if it's very last
end # or you can put .run_action() here, it'll be the same result

random ruby code, NO ruby_block resource

r = file "path/file" do
#stuff
action :nothing
end
r.run_action(:create) # this is the other way to use run_action(): assign resource to a variable
end

This example is a little complicated, but you should be able to see the general pattern:

--
Daniel DeLeo

Gotcha - your rewrite of my example is a bit wrong - I'm using any files
found in a given directory as templates and recreating the entire folder
structure up one directory expanding the templates as I go.

The trick was to get the directory provider working within the ruby block.

I'm not sure this is the right thing to do or not (but it cleaned up my
code slightly), but I created two defs - one for directories and one for
the templates that are needed.

I'm also using the ruby_block syntax too:

def mkdir (dirname)
directory "#{dirname}" do
recursive true
action :create
end
end

def mktemplate (templatename, sourcefile)
template "#{templatename}" do
local true
source "#{sourcefile}"
end
end

ruby_block "apply-config" do
block do

::Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
if (::File.file?(file))
puts "#{filename} is a file -> #{file}"
filename = ::File.basename(file)
newfilename = ::File.absolute_path(file).split("templates/")
puts "here is the new file name #{newfilename[1]}"
if (newfilename[1].rindex('/') != nil &&
newfilename[1].rindex('/') > 1)
puts "there are directories we need to create"
dirstocreate = newfilename[1][0,
newfilename[1].rindex('/')]
puts "We need to make #{dirstocreate}"

mkdir("/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}")
end

mktemplate("/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}",
"#{file}")
end
end
end
end

This is working (for now).

On Fri, Dec 21, 2012 at 8:29 PM, Daniel DeLeo dan@kallistec.com wrote:

On Friday, December 21, 2012 at 4:15 PM, Maven User wrote:

actually - I'm a BIT further now (maybe).

So removing the action and end.run_action items, I can see now it's
executing the ruby code when it should.

BUT - now it doesn't understand what a "directory" or a "template" is -
how do I import these things?

You went a bit in the wrong direction. I'd recommend either:

  1. use resources like normal, and put raw ruby code into ruby blocks:

action :something do
directory "path" do
#stuff
end
ruby_block "arbitrary_code" do
block do
# some code
end
end
file "path/file" do
#stuff
end
end

OR

  1. Use action :nothing plus run_action, but no ruby blocks

action :something do
directory "path" do
#stuff
action :nothing
run_action(:create) # this works if it's very last
end # or you can put .run_action() here, it'll be the same result

random ruby code, NO ruby_block resource

r = file "path/file" do
#stuff
action :nothing
end
r.run_action(:create) # this is the other way to use run_action():
assign resource to a variable
end

This example is a little complicated, but you should be able to see the
general pattern:

java/providers/ark.rb at 1.6.0 · sous-chefs/java · GitHub

--
Daniel DeLeo

ok - to the why - I had an earlier post on this but here goes...

We're using maven and embedded jetty. ALL of our embedded jetty artifacts
produce a zip file that contains (at least):

war - the directory that holds the war file
conf - any ssl keys
templates - any templates

Inside templates, there are directories that need to be moved one directory
higher and in them, templates - for example:

|_templates |_bin |_control.sh (our start/stop init script)

Inside the control.sh file, maven replaces the ${foo} with <%=node[:foo]%>.

This way, we build ONE artifact for EVERY environment and let chef
determine how that artifact is configured at deploy time.

SO - why the lwrp - well, because we have a ton of apps that are getting
deployed this way and I'm one to enjoy copy/pasting recipes all over the
place. NOW - I can put a dependency on my lwrp via the depends inside the
metadata file and now all of our apps go from having 100+ lines of code in
their recipes (depending on the different resources getting moved around),
to having about 10.

On Fri, Dec 21, 2012 at 8:41 PM, Maven User maven.2.user@gmail.com wrote:

Gotcha - your rewrite of my example is a bit wrong - I'm using any files
found in a given directory as templates and recreating the entire folder
structure up one directory expanding the templates as I go.

The trick was to get the directory provider working within the ruby block.

I'm not sure this is the right thing to do or not (but it cleaned up my
code slightly), but I created two defs - one for directories and one for
the templates that are needed.

I'm also using the ruby_block syntax too:

def mkdir (dirname)
directory "#{dirname}" do
recursive true
action :create
end
end

def mktemplate (templatename, sourcefile)
template "#{templatename}" do
local true
source "#{sourcefile}"
end
end

ruby_block "apply-config" do
block do

::Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
if (::File.file?(file))
puts "#{filename} is a file -> #{file}"
filename = ::File.basename(file)
newfilename = ::File.absolute_path(file).split("templates/")
puts "here is the new file name #{newfilename[1]}"
if (newfilename[1].rindex('/') != nil &&
newfilename[1].rindex('/') > 1)
puts "there are directories we need to create"
dirstocreate = newfilename[1][0,
newfilename[1].rindex('/')]
puts "We need to make #{dirstocreate}"

mkdir("/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}")
end

mktemplate("/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}",
"#{file}")
end
end
end
end

This is working (for now).

On Fri, Dec 21, 2012 at 8:29 PM, Daniel DeLeo dan@kallistec.com wrote:

On Friday, December 21, 2012 at 4:15 PM, Maven User wrote:

actually - I'm a BIT further now (maybe).

So removing the action and end.run_action items, I can see now it's
executing the ruby code when it should.

BUT - now it doesn't understand what a "directory" or a "template" is -
how do I import these things?

You went a bit in the wrong direction. I'd recommend either:

  1. use resources like normal, and put raw ruby code into ruby blocks:

action :something do
directory "path" do
#stuff
end
ruby_block "arbitrary_code" do
block do
# some code
end
end
file "path/file" do
#stuff
end
end

OR

  1. Use action :nothing plus run_action, but no ruby blocks

action :something do
directory "path" do
#stuff
action :nothing
run_action(:create) # this works if it's very last
end # or you can put .run_action() here, it'll be the same result

random ruby code, NO ruby_block resource

r = file "path/file" do
#stuff
action :nothing
end
r.run_action(:create) # this is the other way to use run_action():
assign resource to a variable
end

This example is a little complicated, but you should be able to see the
general pattern:

java/providers/ark.rb at 1.6.0 · sous-chefs/java · GitHub

--
Daniel DeLeo

and thank everyone so much for helping me get this far - I really
appreciate it!!!

On Fri, Dec 21, 2012 at 8:51 PM, Maven User maven.2.user@gmail.com wrote:

ok - to the why - I had an earlier post on this but here goes...

We're using maven and embedded jetty. ALL of our embedded jetty artifacts
produce a zip file that contains (at least):

war - the directory that holds the war file
conf - any ssl keys
templates - any templates

Inside templates, there are directories that need to be moved one
directory higher and in them, templates - for example:

|_templates |_bin |_control.sh (our start/stop init script)

Inside the control.sh file, maven replaces the ${foo} with <%=node[:foo]%>.

This way, we build ONE artifact for EVERY environment and let chef
determine how that artifact is configured at deploy time.

SO - why the lwrp - well, because we have a ton of apps that are getting
deployed this way and I'm one to enjoy copy/pasting recipes all over the
place. NOW - I can put a dependency on my lwrp via the depends inside the
metadata file and now all of our apps go from having 100+ lines of code in
their recipes (depending on the different resources getting moved around),
to having about 10.

On Fri, Dec 21, 2012 at 8:41 PM, Maven User maven.2.user@gmail.comwrote:

Gotcha - your rewrite of my example is a bit wrong - I'm using any files
found in a given directory as templates and recreating the entire folder
structure up one directory expanding the templates as I go.

The trick was to get the directory provider working within the ruby block.

I'm not sure this is the right thing to do or not (but it cleaned up my
code slightly), but I created two defs - one for directories and one for
the templates that are needed.

I'm also using the ruby_block syntax too:

def mkdir (dirname)
directory "#{dirname}" do
recursive true
action :create
end
end

def mktemplate (templatename, sourcefile)
template "#{templatename}" do
local true
source "#{sourcefile}"
end
end

ruby_block "apply-config" do
block do

::Dir["/srv/#{new_resource.artifactid}-#{new_resource.version}/templates/**/*"].each
do |file|
puts "here is the file #{file}"
if (::File.file?(file))
puts "#{filename} is a file -> #{file}"
filename = ::File.basename(file)
newfilename = ::File.absolute_path(file).split("templates/")
puts "here is the new file name #{newfilename[1]}"
if (newfilename[1].rindex('/') != nil &&
newfilename[1].rindex('/') > 1)
puts "there are directories we need to create"
dirstocreate = newfilename[1][0,
newfilename[1].rindex('/')]
puts "We need to make #{dirstocreate}"

mkdir("/srv/#{new_resource.artifactid}-#{new_resource.version}/#{dirstocreate}")
end

mktemplate("/srv/#{new_resource.artifactid}-#{new_resource.version}/#{newfilename[1]}",
"#{file}")
end
end
end
end

This is working (for now).

On Fri, Dec 21, 2012 at 8:29 PM, Daniel DeLeo dan@kallistec.com wrote:

On Friday, December 21, 2012 at 4:15 PM, Maven User wrote:

actually - I'm a BIT further now (maybe).

So removing the action and end.run_action items, I can see now it's
executing the ruby code when it should.

BUT - now it doesn't understand what a "directory" or a "template" is -
how do I import these things?

You went a bit in the wrong direction. I'd recommend either:

  1. use resources like normal, and put raw ruby code into ruby blocks:

action :something do
directory "path" do
#stuff
end
ruby_block "arbitrary_code" do
block do
# some code
end
end
file "path/file" do
#stuff
end
end

OR

  1. Use action :nothing plus run_action, but no ruby blocks

action :something do
directory "path" do
#stuff
action :nothing
run_action(:create) # this works if it's very last
end # or you can put .run_action() here, it'll be the same result

random ruby code, NO ruby_block resource

r = file "path/file" do
#stuff
action :nothing
end
r.run_action(:create) # this is the other way to use run_action():
assign resource to a variable
end

This example is a little complicated, but you should be able to see the
general pattern:

java/providers/ark.rb at 1.6.0 · sous-chefs/java · GitHub

--
Daniel DeLeo

Kevin,

Providers typically detect the current state of the system (the "current
resource"), compare that state to the state declared in the recipe (the
"new resource"), and figure out what actions it needs to take to modify the
system to bring it into compliance with the new resource.

Cheers,
Jay

On Sat, Dec 1, 2012 at 9:00 AM, Kevin Christen kevin.christen@gmail.comwrote:

Joshua,

Thanks for providing these examples; I learned a few things from them. One
question for you or anyone else on the list though. This line from the
samba provider's load_current_resource method confuses me:

@smbuser = Chef::Resource::SambaUser.new(new_resource.name)

I assume that Chef::Resource::SambaUser is the class generated from the
LWRP resource. So isn't new_resource already an instance of that class?

Thanks,
Kevin Christen

On Fri, Nov 30, 2012 at 11:32 AM, Joshua Timberman joshua@opscode.comwrote:

Ohai,

On 11/30/12 9:31 AM, "Maven User" maven.2.user@gmail.com wrote:

I'm still on my quest to simplify our deployments and was wondering if
there is a good demo/example/sample I can look at to create my own LWRP?

I can see how to create the resource, but the provider bit is kinda
confusing.

First, LWRPs are specifically the lightweight DSL that doesn't require the
ruby class structure. "Heavyweight" resources/providers are like the ones
that come with Chef itself. The "database" cookbook implements its
resources/providers as heavyweight due the way that the LWRPs are
automatically named by the cookbook and the filenames, and we wanted to
name

Second, the key is to make your resources idempotent. This is easy if
you're using resources inside the action blocks in the provider, and the
examples (below) have some of that. In some cases, like when you're
chaining together a bunch of command execution, you'll want to use
"load_current_resource" to check the current state of the system.

There are more advanced considerations, such as why-run support, and
handling updated resources, but for now stick to a simple use case.

These LWRPs from Opscode's cookbooks are relatively simple examples:

https://github.com/opscode-cookbooks/cron/blob/master/providers/d.rb

https://github.com/opscode-cookbooks/samba/blob/master/providers/user.rb

https://github.com/opscode-cookbooks/daemontools/blob/master/providers/serv
ice.rb

As an exercise, I'd probably start by doing an LWRP that simply handles
dropping off a "conf.d" style of configuration file.

Hope this helps!

--
Opscode, Inc
Joshua Timberman, Technical Community Manager
IRC, Skype, Twitter, Github: jtimberman