Custom function for not_if block


#1

I would like to use a custom function to read the existence of a registry value for a not_if block of a chef resource. I am unsure how I can do this.
I have attempted to use the the ENV chef resources. Unfortunately the settings I have to use to bootstrap the node, which requires the proxy to be defined, means that when I pass the not_if statements, it reads the ENV settings that exist within the client.rb :frowning: - So this is why I am using a batch block rather than an existing resource as it literally does not work how I need it to and I am unsure how to get around that.

Here is the function:

# This is used as a custom test for a reg value used in the not_if blocks of the registry additions
    def value_exists?(path,key)
      reg_type = Win32::Registry::KEY_READ
      Win32::Registry::HKEY_LOCAL_MACHINE.open(path, reg_type) do |reg|
          begin
            regkey = reg[key]
            return true
          rescue
            return false
          end
        end
      end
    end

Here is how I want to the use the function (see not_if block) within the batch resource.

no_proxy = 'localhost,127.0.0.1,sv.local' # List of names where the proxy is not to be used
  # Proxy exceptions list
  batch 'NO_PROXY' do
    code <<-EOH
      setx -m NO_PROXY "#{no_proxy}"
    EOH
    not_if { (value_exists?("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment","NO_PROXY")) == true }
  end

The error that is returning is as follows when running chef-client on the node (Windows 10).

================================================================================
Error executing action `run` on resource 'batch[NO_PROXY]'
================================================================================

NoMethodError
-------------
undefined method `value_exists?' for Chef::Resource::Batch

Cookbook Trace:
---------------
c:/chef/cache/cookbooks/my_bootstrap/recipes/default.rb:47:in `block (2 levels) in from_file'

Resource Declaration:
---------------------
# In c:/chef/cache/cookbooks/my_bootstrap/recipes/default.rb

 43:   batch 'NO_PROXY' do
 44:     code <<-EOH
 45:       setx -m NO_PROXY "#{no_proxy}"
 46:     EOH
 47:     not_if { (value_exists?("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment","no_proxy")) == true }
 48:   end
 49:

Compiled Resource:
------------------
# Declared in c:/chef/cache/cookbooks/my_bootstrap/recipes/default.rb:43:in `from_file'

batch("NO_PROXY") do
  action [:run]
  retries 0
  retry_delay 2
  default_guard_interpreter :batch
  command "NO_PROXY"
  backup 5
  returns 0
  user nil
  code "      setx -m NO_PROXY \"localhost,127.0.0.1,sv.local,my_solution.local\"\n"
  interpreter "cmd.exe"
  declared_type :batch
  cookbook_name "my_bootstrap"
  recipe_name "default"
  not_if { #code block }
end

Platform:
---------
x64-mingw32

[2017-03-03T10:17:01+13:00] INFO: Running queued delayed notifications before re-raising exception

Running handlers:
[2017-03-03T10:17:01+13:00] ERROR: Running exception handlers
Running handlers complete
[2017-03-03T10:17:01+13:00] ERROR: Exception handlers complete
Chef Client failed. 0 resources updated in 05 seconds
[2017-03-03T10:17:01+13:00] INFO: Sending resource update report (run-id: 7080fb08-e23d-4ca5-a90f-ab2e6af0e658)
[2017-03-03T10:17:02+13:00] FATAL: Stacktrace dumped to c:/chef/cache/chef-stacktrace.out
[2017-03-03T10:17:02+13:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2017-03-03T10:17:02+13:00] FATAL: NoMethodError: batch[NO_PROXY] (my_bootstrap::default line 43) had an     error: NoMethodError: undefined method `value_exists?' for Chef::Resource::Batch

#2

Which version of Chef-Client are you using? Are you using test kitchen?

Have you written your value_exists? method in a file in the libraries folder?
If so the method should be added to Ruby’s base Object and be available in the batch class.

If you have added the value_exists? to the recipe then the method will be part of the recipe class.

I’ve just taken your code and it works for me.

Library file registry_stuff

def value_exists?(path,key)
  true
end

Single recipe test_registry.rb, run list of cookbook::test_registry

batch 'NO_PROXY' do
  code 'echo hello world'
  not_if { (value_exists?('', '') == true }
end

output

Recipe: test_cookbook::test_registry
  * batch[NO_PROXY] action run[2017-03-03T11:16:43+00:00] INFO: Processing batch
[NO_PROXY] action run (test_cookbook::test_registry line 1)
 (skipped due to not_if)

#3

The Registry DSL Methods may be helpful for you: https://docs.chef.io/resource_registry_key.html#recipe-dsl-methods

I think you could use registry_get_subkeys to collect the key value to determine if your resource should converge.


#4

Thanks Seth, I was really replying to the custom function not working for not_if block rather than deal with the specific code or registry key methods in Chef.

As MW pointed out here: Windows registry_key > only_if/not_if > registry_value_exists help
And mentioned here: https://github.com/chef/chef/issues/2733#issuecomment-209703920

The use of registry_value_exists? and registry_data_exists? can be confusing but I agree using existing Chef functionality is best.


#5

I GOT IT TO WORK!!!

Embarrassing solution, but I had named my library folder within the cookbook with a capital letter. So ‘Libraries’ when it should have been ‘libraries’ the whole time…