Careers

Custom Resources in Chef Client 12.5

On October 28, 2015, Chef Principal Engineer John Keiser presented a webinar on Custom Resources in Chef Client 12.5. John introduced the concept of the custom resource, explained why you would want to write one, introduced the language concepts, and walked through a tutorial of how to make your own.

A recording of the webinar is available below. Q&A from the live webinar, including questions we didn’t have time to answer live, is available at the end of this post.

Q&A

Is the “old way” deprecated for future versions of Chef (timeline)?

We have no plans to remove the old way, simply because there are so many cookbooks out there that already use it. Backwards compatibility will be maintained, but the old LWRP/HWRP paradigm is no longer the *recommended* way to create resources.

Do you have any tricks / advice for figuring out map pure ruby back to chef DSL constructs? Sometimes when writing a provider, you find the need to do something like send a notification in pure ruby or instantiate some Chef built-in resource or provider in pure Ruby (or use some other DSL feature like include_recipe) — and then I end up chasing Ruby `require` files all over the chef source code.

If you’re trying to use those features from within a resource, they should already be available to you in the new resources stuff (include_recipe and other resources work inside of resources). In general, I try to stick with the DSL where I can. One trick I’ve learned, though, is to save a reference to the recipe or resource you are being called from, so that you can use it to create resources. For example, recipe = self; ruby_block ‘x’ { block { recipe.file ‘/x.txt’ } }

Is the resource and provider patter seems better encapsulation then writing all the implementation in the resource directory. Am I looking at this wrong?

The biggest reason this is easier is that someone who wants to write resources doesn’t have to learn a new concept. You already know recipes, resources and actions. What’s a provider now? … from a computer science point of view, you can look at this as the difference between a concrete base class, versus an interface / implementation in separate files. You don’t split all your classes into interface / implementation, just the ones you intend to multiply subclass / switch out over time; otherwise your code gets hard to read. That said, there is nothing at all stopping you from putting your implementation in a separate file–just don’t call it a provider! :)

Can you show an example of how the why-run logic has changed?

why-run hasn’t changed–if you use resources in your action, or use converge_by, they will take no action in why-run mode. load_current_value and converge_if_changed (see the chef-docker cookbook) are a new option for more easily handling idempotence that also happen to handle why-run mode.

Will test kitchen and chefspec still work ok?

Yep.

What kind of support is avaiable for custom resources in chefspec?

Same as for normal resources :)

Is there a way to declare that your cookbook requires chef-client 12.5.x?

If you want to ensure backwards compatibility, just add “depends ‘compat_resource'” to your cookbook and all the new resource features will work in 12.0 onwards.

How do you access the previous values for properties then? Does current_resource.x still work?

current_resource still exists, but it’s worth pointing out that when you type “x” in your custom resource it *defaults* to current_resource.x.

What about putting all the code into a library instead of resource/provider?

If you want to declare a resource in libraries, you can just use class MyResource < Chef::Resource.

How do you rspec this new new resource?

chefspec, serverspec, test-kitchen! All the tools you already know and love :)

How do you sublcass the example you showed (myapp_website)?

You can’t subclass a resource declared in the resources/ directory. If you want to subclass, you need to declare it in libraries and do class MyAppWebsite < Chef::Resource

If I have a chef 11.x server can i install the chef 12.5 client on my nodes?

Absolutely!

Can a custom resource and a LWRP co-exist? Can you have the resource work with both 11 and 12/5 clients? If not, how can you det the right resource cookbook on nodes provisioned by chef-provisioning in a mixed pre 12.5 and post 12.5 ecosystem?

Custom resources and LWRPs can co-exist. If you add ‘depends “compat_resource”‘ to your cookbook metadata, you can use the resource features from 12.0 through 12.5. It will not work with chef-client version 11.

What is the major difference between a custom resource and a custom definition?

Custom resources show up in the output and any resources you use inside their actions will show up in the output as well (indented so you can see which resource they came from). Additionally, code in them doesn’t run until converge time, which makes them a lot more natural to understand. Custom definitions act a lot more like macros–the recipe within them compiles immediately when you use the definition, and you won’t see the definition show up in the chef-client output because it isn’t actually a resource.

I wonder if there are any Ruby language limitations you experience when trying to code things with Chef?

Not really. It’s all code :)

Is it possible to have the custom resource effective for more than one cookbook?

Yes, resources are always available to all cookbooks.

Is there an ability to make a property required for on action and not for another?

Not a directly defined one. You’d do this by raising an exception when the action starts, if the required properties are missing.

Off topic: Your bash/zsh config seems to have a setting that shows a suggestion in light gray but still lets you keep typing. That’s cool! How do I enable that?

That’s fish shell :) http://fishshell.com/

Are only_if and not_if conditions apply as for regular resources?

Yep!

There are multiple bug and documentation errors on this feature advanced feature. For example the load_current_value does not work from within an action (which supposed to be supported by the documentation)

load_current_value must be called outside of an action.

Is Chef client 12.5 available today? What is the process for upgrading? What’s the risk?

12.5 is indeed available! The omnibus_updater cookbook can help you keep the client up to date. There are no known backwards compatibility issues upgrading from 12.4.

I read on web documentation that definitions will be depreciated and suggested to use custom resources instead. Definitions were executed in compile time and LWRP/HWRP were executed during converge, what will be situation with custom resources if we want to have something executed in compile time (as definitions)

Custom resources will be executed at converge time. The do block where you *use* the resource (fill in its properties) will be executed at compile time.

What about notification flows? Are defined as for LWRP? For example, what about LWRP use_inline_resources

Yep, they work the same as LWRP use_inline_resources (they use that capability under the covers).

Does Chef has dynamic property?

property :x, default: lazy { <code goes here> } will cause a property to calculate its value (as long as the user doesn’t set the property directly)

The established way to wrap around existing resources without the need to add custom logic on top of that is through definitions. Is this simplified way to define custom resources meant to deprecate definitions?

Yep!

I have never written an lwrp before. Can I have a ruby_block in a chef 12.5 custom resource?

Indeed!

How do you ensure idempotency at the custom resource level (not at each individual resource it includes level)? How do you reference current resource from within the code/actions? e.g. which actions were called? One action to include a subset of other actions, etc.

load_current_value and converge_if_changed will do that (see the chef-docker cookbook for an example). To call an action from another action, you can use new_resource.run_action(:other_action)

How do I share a resource across cookbooks?

Just declare it in a cookbook, and use ‘depends “that_cookbook”‘ on any cookbook where you want to use the resources from.

Can you specify that no action should be the default — i.e. that the caller must specify an action explicitly?

You can specify default_action :nothing, and nothing will happen unless the user specifies an action.

Can I property be extened feature?

property is fully extensible; if you create a class that descends from Chef::Property, and use that class in property :x, MyPropertyClass, that will be used to create the property.

How do you write custom ruby code with a resource? If you do that how do you manage idempotency?Do notifications still work the same way? How to make notifications interact within a resource but not outside of it?