List properties of a resource

Viewed 50

I'm implementing a custom resource which is basically a facade to an existing resource (in the example below its the vault_certificate resource).

Using the existing resource this code is valid:

certificate = vault_certificate 'a common name' do
  combine_certificate_and_chain true
  output_certificates false # Just to decrease the chef-client run output
  vault_path "pki/issue/#{node['deployment']}"
end

template "a path" do
  source 'nginx/dummy.conf.erb'
  variables(
    certificate: certificate.certificate_filename
    key: certificate.key_filename
  )
end

Notice I can invoke certificate.certificate_filename or certificate.key_filename. Or more generally I can read any property defined by the vault_certificate resource.

Now with the new resource (sort of a facade to vault_certificate)

provides :vault_certificate_handle_exceptions

unified_mode true

property :common_name, String, name_property: true
property :max_retries, Integer, default: 5

action :create do
  require 'retries'
  # new_resource.max_retries is being used inside the retry_options. I omitted that part as its not relevant for the question
  with_retries(retry_options) do
    begin
      vault_certificate new_resource.common_name do
        combine_certificate_and_chain true
        output_certificates false # Just to decrease the chef-client run output
        vault_path "pki/issue/#{node['deployment']}"
        ignore_failure :quiet
      end
    rescue Vault::HTTPClientError => e
      data = JSON.parse(e.errors)['data']
      if data['error'] == 'Certificate not found locally'
        # This error is one we can recover from (actually we are expecting it). This raise with VaultCertificateError will trigger the with_retries.
        raise VaultCertificateError.new("Waiting for the certificate to appear in the store (because I'm not the leader)", data)
      else
        # Any other error means something really went wrong.
        raise e
      end
    end
  end
end

If I now use this resource and try to invoke .certificate_filename or .key_filename:

certificate = vault_certificate_handle_exceptions 'a common name' do
  action :create
end
template "a path" do
  source 'nginx/dummy.conf.erb'
  variables(
    certificate: certificate.certificate_filename
    key: certificate.key_filename
  )
end

I get an error saying the method certificate_filename (or key_filename) is not defined for vault_certificate_handle_exceptions. To solve it I resorted to this hack:

provides :vault_certificate_handle_exceptions

unified_mode true

property :common_name, String, name_property: true
property :max_retries, Integer, default: 5

action :create do
  require 'retries'
  # new_resource.max_retries is being used inside the retry_options. I omitted that part as its not relevant for the question
  with_retries(retry_options) do
    begin
      cert = vault_certificate new_resource.common_name do
        combine_certificate_and_chain true
        output_certificates false # Just to decrease the chef-client run output
        vault_path "pki/issue/#{node['deployment']}"
        ignore_failure :quiet
      end
      # These lines ensure we can read the vault_certificate properties as if they were properties of this resource (vault_certificate_handle_exceptions)
      Chef::ResourceResolver.resolve(cert.resource_name).properties.keys.each do |name|
        new_resource.send(:define_singleton_method, name.to_sym) do
          cert.send(name.to_sym)
        end
      end
    rescue Vault::HTTPClientError => e
      data = JSON.parse(e.errors)['data']
      if data['error'] == 'Certificate not found locally'
        # This error is one we can recover from (actually we are expecting it). This raise with VaultCertificateError will trigger the with_retries.
        raise VaultCertificateError.new("Waiting for the certificate to appear in the store (because I'm not the leader)", data)
      else
        # Any other error means something really went wrong.
        raise e
      end
    end
  end
end

Is there a cleaner way to achieve this? If not, is there a more direct way to list all the properties of a resource? I thought cert.properties would work, but no luck there.

0 Answers
Related