Project: Chef InSpec (Provisioning / Security & Compliance)
File: custom_resources.md

+++ title = "InSpec Custom Resources" draft = false gh_repo = "inspec" [menu] [menu.inspec] title = "Custom Resources" identifier = "inspec/profiles/libraries" parent = "inspec/profiles" weight = 40 +++ You can extend the functionality of Chef InSpec profiles by creating custom resources. For hands-on examples, check out on Learn Chef. Create custom resources in a profile's libraries directory. ```bash examples/profile ... libraries example_config.rb ``` The smallest possible resource takes this form: ```ruby class Tiny < Inspec.resource(1) name 'tiny' end ``` Resources are written as a regular Ruby class which inherits from Inspec.resource. The number (1) specifies the version this resource plugin targets. As Chef InSpec evolves, this interface may change and may require a higher version. Use the following attributes to configure a resource. `name` : Identifier of the resource. Required `desc` : Description of the resource Optional `example` : Example usage of the resource Optional `supports` : Platform restrictions of the resource Optional The following methods are available to the resource. `inspec` : Contains a registry of all other resources to interact with the operating system or target in general. `skip_resource` : A resource may call this method to indicate that requirements aren't met. All tests that use this resource will be marked as skipped. The additional methods may be defined within the resource: `resource_id` : An instance method. Place logic here to determine the unique identifier for a resource, and set it using the superclass method. Following is an example of its usage in an InSpec test: ```ruby describe example_config do its("resourceid") { should eq PATHOFCONFFILE } end ``` The following example shows a full resource using attributes and methods to provide simple access to a configuration file: ```ruby class ExampleConfig < Inspec.resource(1) name 'example_config' supports platform_family: 'fedora' supports platform: 'centos', release: '6.9' supports platform: 'centos', release: '7.*' desc ' Resource description ... ' example ' describe example_config do its("signal") { should eq "on" } end ' def initialize(path = nil) @path = path ||

@params = SimpleConfig.new( read_content ) end def method_missing(name) @params[name] end def resource_id value = examplemethodtodetermineresourceid # define logic to determine resourceid value super(value) end private def read_content f = inspec.file(@path) if f.file? f.content else raise Inspec::Exceptions::ResourceSkipped, "Can't read config at #{@path}" end end end ``` For a full example, see our . If you have a profile that includes another profile with custom resources as a dependency, the custom resources from the dependent profile are included by default. If two custom resource names conflict, you can use the `require_resource` InSpec DSL function to rename a custom resource in control code. ```ruby require_resource( profile: '<DEPENDENCY_NAME>', resource: '<RESOURCE_NAME>', as: '<ALTERNATERESOURCENAME>' ) ``` where: `<DEPENDENCY_NAME>` is the dependent profile `<RESOURCE_NAME>` is the resource name in the dependent profile `<ALTERNATERESOURCENAME>` is an alternate name for that resource Prior to InSpec v4.16, resources were pre-loaded for every invocation of `inspec`. This was a heavy and unnecessary burden on the system and exacerbated startup times (especially on Windows). As of InSpec v4.16, resources are lazily loaded into the `inspec` process upon use. This greatly speeds up the initial startup costs of the `inspec` process and only loads what you need to use. For example, `inspec --version` no longer runs for 10 seconds!. Lazy loading does change the way the resource registry is handled in ways that might break some assumptions. Specifically, `inspec.<resource>` isn't pre-populated with the core resources that InSpec ships with. If you make a local/custom resource of the same name, referring to the core resource via `inspec.<resource>` will not resolve to the core resource. As such, overriding core resources is not recommended best practice. If you really do need to do this, it is easiest to make a local resource with a new name and refer to the core resource directly. Otherwise, you need to ensure that the core resource you want is registered (via `require "inspec/resource/<name>"`) before your profile is run to ensure it is eagerly loaded and in the global resource registry.