Notify service defined in included LWRP recipe

2019-04-10 08:02发布

Is there a way to notify a service to restart which is defined by an included LWRP?

I wrote an LWRP called "sidekiq" which sets up a service, like this, and appears to be working fine on its own.

service "#{new_resource.name}_sidekiq" do
  provider Chef::Provider::Service::Upstart
  action [ :enable ]
  subscribes :restart, "template[/etc/init/#{new_resource.name}_sidekiq.conf]", :immediately
end

The problem is I am using it another recipe which I use for deployments, and need it to notify the service defined in the LWRP. I currently have something this

include_recipe "sidekiq"
deploy_revision my_dir do
  notifies :restart, "service[myapp_sidekiq]"
end

The problem is at compile time, chef looks at this recipe and gives an error

ERROR: resource deploy_revision[my_dir] is configured to notify resource service[myapp_sidekiq] with action restart, but service[myapp_sidekiq] cannot be found in the resource collection.

I can get rid of the error by defining an empty service in my deployment recipe, like service 'myapp_sidekiq', and everything will work fine when first provisioning the machine. However if I run a deployment and nothing changes in the sidekiq LWRP, the myapp_sidekiq service is never redefined and thus cannot be restarted.

2条回答
神经病院院长
2楼-- · 2019-04-10 08:28

To notify a resource to complete an action, that resource must be defined previously in the current Chef run, and as Tensibai notes not defined inline in it's own run_context

Place holder

The simple way is to create a place holder in your deploy script of your non default provider that has an action of :nothing, but you can notify it later.

service "myapp_sidekiq deploy notifier" do
  provider      Chef::Provider::Service::Upstart
  service_name  "myapp_sidekiq"
  action        :nothing
end

You can also modify the overall default provider for a resource in client.rb if you are using Upstart all the time on a platform that Chef has configured as something else, like systemd

Chef::Platform.set :platform => :yours, :resource => :service, :provider => Chef::Provider::Service::Upstart

There are changes coming in Chef 12 that will let Chef evaluate which service provider to use at run time instead of static configuration. This is basically due to systemd coming along and shaking up something on systems that was once very stable and predicatable.

Be careful of the name you use for resources. If you have multiple service resources defined via the same service name you can run into issues due to they way Chef treats them as clones and you may be running something you didn't expect. If you are using multiple service definitions try naming them something unique for the specific purpose. Then in the attributes, specify the service with service_name

LWRP

If you had a particularly complex resource that you are defining repeatedly and you think you should only be specifying all the generic parameters for it once, you could create your own Light Weight Resource and Provider encapsulating all the generic setup so you can define the resource more easily in recipes:

service_myapp_sidekiq "deploy notifier" do
  action      :nothing
end

service_myapp_sidekiq "config subscriber" do
  action      :nothing
  subscribes  :restart, 'blah'
end

That is a lot of work as you have to create an LWRP action for every underlying action you want to support and as you can see, doesn't make your use case much easier.

Library function

You could also do the same sort of thing with a function in a library that defines the basics of the resource and allows you to add any of the customisations you want (like name).

def create_myapp_service name, action, options = {}
  s = Chef::Resource::Service.new "myapp service #{name}"
  s. service_name   "myapp_sidekiq"
  s.provider        Chef::Provider::Service::Upstart
  s.action          action
end

create_myapp_service "deploy", :nothing

Again, these are probably only needed for much more complex resource setups and cases where you repeatedly need to define the same complex resource with small variations.

TLDR: Define a place holder service which does :nothing for the deploy.

查看更多
看我几分像从前
3楼-- · 2019-04-10 08:35

LWRP with use_inline_resources use their own run_context, so resources inside a LWRP are not included in the resource_collection and are not able to be notified outside the LWRP.

LWRP without the inline resources flag add their inner resources to the resource collection, but at converge phase et not at compile, so you'll still have the error you see.

However if I run a deployment and nothing changes in the sidekiq LWRP, the myapp_sidekiq service is never redefined and thus cannot be restarted.

I really don't understand what you mean, unless your deploy_revision should change the enable/disbale state of the service or what it supports (status, restart, reload, etc.), there's no need to re-enable it, just define a service resource for deploy_revision to notify it to restart.

查看更多
登录 后发表回答