Module: Chef::ResourceInspector

Defined in:
lib/chef/resource_inspector.rb

Class Method Summary collapse

Class Method Details

.extract_cookbook(path, complete) ⇒ Object



106
107
108
109
110
111
112
113
# File 'lib/chef/resource_inspector.rb', line 106

def self.extract_cookbook(path, complete)
  path = File.expand_path(path)
  dir, name = File.split(path)
  Chef::Cookbook::FileVendor.fetch_from_disk(path)
  loader = Chef::CookbookLoader.new(dir)
  cookbook = loader.load_cookbook(name)
  load_from_resources(cookbook.files_for(:resources), complete)
end

.extract_resource(resource, complete = false) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/chef/resource_inspector.rb', line 44

def self.extract_resource(resource, complete = false)
  data = {}
  data[:description] = resource.description
  data[:default_action] = resource.default_action
  data[:actions] = {}
  resource.allowed_actions.each do |action|
    data[:actions][action] = resource.new(resource.to_s, nil).action_description(action)
  end

  data[:examples] = resource.examples
  data[:introduced] = resource.introduced
  data[:preview] = resource.preview_resource

  properties = unless complete
                 resource.properties.reject { |_, k| k.options[:declared_in] == Chef::Resource || k.options[:skip_docs] }
               else
                 resource.properties.reject { |_, k| k.options[:skip_docs] }
               end

  data[:properties] = properties.each_with_object([]) do |(n, k), acc|
    opts = k.options
    acc << { name: n, description: opts[:description],
             introduced: opts[:introduced], is: opts[:is],
             deprecated: opts[:deprecated] || false,
             required: opts[:required] || false,
             default: opts[:default_description] || get_default(opts[:default]),
             name_property: opts[:name_property] || false,
             equal_to: sort_equal_to(opts[:equal_to]) }
  end
  data
end

.get_default(default) ⇒ Object



33
34
35
36
37
38
39
40
41
42
# File 'lib/chef/resource_inspector.rb', line 33

def self.get_default(default)
  if default.is_a?(Chef::DelayedEvaluator)
    # ideally we'd get the block we pass to `lazy`, but the best we can do
    # is to get the source location, which then results in reparsing the source
    # code for the resource ourselves and just no
    "lazy default"
  else
    default.is_a?(Symbol) ? default.inspect : default # inspect properly returns symbols
  end
end

.inspect(arguments = [], complete: false) ⇒ String

If we’re given no resources, dump all of Chef’s built ins otherwise, if we have a path then extract all the resources from the cookbook or else do a list of built in resources

Parameters:

  • arguments (Array, String) (defaults to: [])

    One of more paths to a cookbook or a resource file to inspect

  • complete (TrueClass, FalseClass) (defaults to: false)

    Whether to show properties defined in the base Resource class

Returns:

  • (String)

    JSON formatting of all resources



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/chef/resource_inspector.rb', line 122

def self.inspect(arguments = [], complete: false)
  output = if arguments.empty?
             ObjectSpace.each_object(Class).select { |k| k < Chef::Resource }.each_with_object({}) { |klass, acc| acc[klass.resource_name] = extract_resource(klass) }
           else
             Array(arguments).each_with_object({}) do |arg, acc|
               if File.directory?(arg)
                 extract_cookbook(arg, complete).each { |k, v| acc[k] = v }
               else
                 r = Chef::ResourceResolver.resolve(arg.to_sym)
                 acc[r.resource_name] = extract_resource(r, complete)
               end
             end
           end

  Chef::JSONCompat.to_json_pretty(output)
end

.load_from_resources(resources, complete) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/chef/resource_inspector.rb', line 82

def self.load_from_resources(resources, complete)
  resources.each_with_object({}) do |r, res|
    pth = r["full_path"]
    # Here we do some magic to extract resources from files where there are multiple resources
    # in a file - to do this, we load the file, and take the delta of which resources
    # exist in object space
    existing_classes = []
    ObjectSpace.each_object(Class).select { |k| k < Chef::Resource }.each { |klass| existing_classes << klass }
    # Load the set of resources from this file
    Chef::Resource::LWRPBase.build_from_file(name, pth, Chef::RunContext.new(Chef::Node.new, nil, nil))
    # Finally, process every new class added to the object space by that
    ObjectSpace.each_object(Class).select { |k| k < Chef::Resource }.each do |klass|
      unless existing_classes.include?(klass)
        # Skip over anything which creates resources that start with exactly this - that happens
        # because if there is no non-classed resource in here, LWRPBase.build_from_file builds a
        # dummy object from it - we don't need that polluting out output!
        next if klass.resource_name.start_with?("Chef__ResourceInspector")

        res[klass.resource_name] = extract_resource(klass, complete)
      end
    end
  end
end

.sort_equal_to(equal_to) ⇒ Object



76
77
78
79
80
# File 'lib/chef/resource_inspector.rb', line 76

def self.sort_equal_to(equal_to)
  Array(equal_to).sort.map(&:inspect)
rescue ArgumentError
  Array(equal_to).map(&:inspect)
end

.startObject



139
140
141
# File 'lib/chef/resource_inspector.rb', line 139

def self.start
  puts inspect(ARGV, complete: true)
end