Search code examples
rubyimportchef-infralwrp

Adding a provider or extending a LWRP for a wrapped cookbook


(sorry about the links, I can't post more than two..) I am trying to add a provider to a cookbook that wraps another cookbooks which holds a LWRP.

The wrapped cookbook is poise Python supervisor: [github.com/poise/supervisor.git][1] I am using Berkshelf to point Chef to import it:

source "...api.berkshelf.com"
source '....<my chef/berkshelf server>:26200'

cookbook 'supervisor', github: "poise/supervisor"

metadata

In my cookbook:

.
.
    include_recipe 'supervisor'
.
.

..And I wish to add a provider to one of the supervisors resources with a "new" action.

Here are the 'imported' providers: [github.com/poise/supervisor/blob/master/providers/service.rb][1]

I wish to add another provider called action "reload" that will call supervisorctl reread eventually.

I have tried many examples from here and there but with no luck: from gitHub: chef_extend_lwrp

I've tried docs.chef.io lwrp_custom_provider_ruby and neethack.com/2013/10/understand-chef-lwrp-heavy-version/

And tried to emulate Seth Vargo answers and examples from: github.com/opscodecookbooks/jenkins/blob/8a2fae71cd994704b09924e9a14b70b9093963a3/libraries/credentials_password.rb And:

github.com/poise/supervisor/blob/master/providers/service.rb

github.com/poise/supervisor.git

But it looks like Chef is not importing the code correctly:

ERROR: undefined method `action' for Chef::Resource::SupervisorServices:Class

When I writ my library import as: (my_enable_service is defined but I've took it out of this example)

def whyrun_supported?
  true
end


class Chef
  class Resource::MyupervisorService < Resource::SupervisorService
    provides :my_supervisor_service
    actions :reload
    @resource_name = :my_supervisor_service
  end
end


class Chef
  class Provider::MyupervisorService < Provider::SupervisorService
    action :reload do
      converge_by("Enabling #{ new_resource }") do
        my_enable_service
      end
    end



  end
end


Chef::Platform.set(
  resource: :my_supervisor_service,
  provider: Chef::Provider::MyupervisorService
)

My cookbook name is : "my_supervisor" and my library file is "service.rb"

I've tried many answers from stackoverflow too but I can't post it here since I lack reputation points :( I've seen many references from Seth Vargo, I hope he will see my question ;)


Solution

  • Ok, after a while playing with this (sounded interesting to me) I understand what's going wrong here.

    Quoting the documentation:

    Libraries are loaded first to ensure that all language extensions and Ruby classes are available to all resources. Next, attributes are loaded, followed by lightweight resources, and then all definitions (to ensure that any pseudo-resources within definitions are available).

    The files under cookbook/libraries are loaded before the lwrp classes are constructed, that's why you end up with an unknow method, the SupervisorService class is not yet loaded when your library in my_supervisor is compiled, so you end up with a simple Object which has no idea of an actions method.

    Best workaround I can think of is to manage the case in your recipe, calling an execute resource or the lwrp depending on what you do.

    If you really think it should be part of the supervisor actions, clone the cookbook repo, add the action and make a pull request.