class AbideDataProcessor::Parser::ResourceDataParser
Parser
class for resource Hiera data. rubocop:disable Metrics/ClassLength
Attributes
Public Class Methods
# File lib/abide-data-processor/parser.rb, line 78 def initialize(hiera_data, control_maps, control_configs: {}, ignore: [], only: []) @hiera_data = validate_hiera_data(hiera_data) @control_maps = validate_control_maps(control_maps) @control_configs = control_configs @ignore = ignore @only = only @resources = RGL::DirectedAdjacencyGraph.new @controls = Set.new @filtered = Set.new @dependent = {} end
Public Instance Methods
Parse the Hiera data into a Hash used by Puppet to create the resources. The way this works is by first creating a DAG and adding all resources to the graph as vertices, with an edge for each resource pointing from a dummy node, :root, to the resource. We then add edges to the graph based on the ‘before_me` and `after_me` lists of each resource and remove the :root-connected edges for each resource that has a `before_me` list, and remove the :root-connected edges for each resource in a `after_me` list. Finally, we sort the graph into an Array populated with a single Hash of ordered resources and return that Hash. @return [Array] A sorted array of resource hashes. rubocop:disable Metrics/MethodLength
# File lib/abide-data-processor/parser.rb, line 100 def parse @hiera_data.each do |name, data| resource = AbideDataProcessor::Parser.new_resource(name, data, @control_maps) add_control_names(resource) add_dependent_mapping(resource) # Map any controls this resource depends on @resources.add_vertex(resource) # Add all the resources to the graph @resources.add_edge(:root, resource) # Establish the root -> resource edges add_edge_ordering(resource) # Add resource ordering edges end # If the resource should be filtered (i.e. only or ignore), remove it from the graph. filter_resources! # Verify that all dependent resources are in the graph, remove them if not. remove_unsatisfied_dependents! # Sort the graph and return the array of ordered resource hashes sort_resources.map do |r| r.add_control_configs(@control_configs) resource_data(r) end end
Private Instance Methods
Adds edges to the graph based on the given Resource’s ‘after_me` list. @param resource [Resource] The Resource
to add edges for.
# File lib/abide-data-processor/parser.rb, line 250 def add_after_me_edge(resource) resource.after_me.flatten.each do |after| next unless after # Skip if this `after` is nil, empty, or falsy (e.g. false, 0, etc.) next if after.equal?(resource) # Skip if this `after` is the same as the current resource # We remove the edge from root to the `after` resource if it exists because the `after` resource # is no longer attached to the root of the graph as this resources comes before it. @resources.remove_edge(:root, after) if @resources.has_edge?(:root, after) # Add the edge from this resource to the after resource @resources.add_edge(resource, after) unless @resources.has_edge?(resource, after) end end
Adds edges to the graph based on the given Resource’s ‘before_me` list. @param resource [Resource] The Resource
to add edges for.
# File lib/abide-data-processor/parser.rb, line 235 def add_before_me_edge(resource) resource.before_me.flatten.each do |before| next unless before # Skip if this `before` is nil, empty, or falsy (e.g. false, 0, etc.) next if before.equal?(resource) # Skip if this `before` is the same as the current resource # We remove the edge from root to this resource if it exists because this resource is no longer # attached to the root of the graph as it has other resources before it. @resources.remove_edge(:root, resource) if @resources.has_edge?(:root, resource) # Add the edge from the before resource to this resource @resources.add_edge(before, resource) unless @resources.has_edge?(before, resource) end end
Adds control neames for the given resource to the @controls set. @param resource [Resource] The resource to add control names for.
# File lib/abide-data-processor/parser.rb, line 125 def add_control_names(resource) return unless resource.controls @controls.merge(resource.control_names).flatten! @controls.merge(resource.mapped_control_names).flatten! end
Adds a mapping for a dependent control and the resources that depend on it. @param resource [Resource] The resource to add the mapping for.
# File lib/abide-data-processor/parser.rb, line 177 def add_dependent_mapping(resource) return unless resource.dependent resource.dependent.each do |control_name| @dependent[control_name] = [] unless @dependent.key?(control_name) @dependent[control_name] << resource end end
Adds edges to the graph based on the given Resource’s ‘before_me` and `after_me` lists. @param resource [Resource] The Resource
to add edges for.
# File lib/abide-data-processor/parser.rb, line 228 def add_edge_ordering(resource) add_before_me_edge(resource) add_after_me_edge(resource) end
Gets all verticies in the graph that have the associated control @param control_name [String] The name of the control to check. @return [Array] The verticies that have the associated control.
# File lib/abide-data-processor/parser.rb, line 209 def collect_verticies_by_control(control_name) @resources.vertices.select { |r| r.control?(control_name) } end
Checks if the given Resource
has a control in the given list. @param resource [Resource] The resource to check. @param control_list [Array] The list of controls to check against. @return [Boolean] True if the resource is in the control list, false otherwise.
# File lib/abide-data-processor/parser.rb, line 217 def control_in?(resource, control_list) return false if control_list.empty? control_list.each do |ignored_control| return true if resource.control?(ignored_control) end false end
Checks whether the resource should be filtered out based on the ignore and only lists. @param resource [Resource] The resource to check. @return [Boolean] True if the resource should be filtered out, false otherwise.
# File lib/abide-data-processor/parser.rb, line 168 def filter_resource?(resource) return true if control_in?(resource, @ignore) return true unless @only.empty? || control_in?(resource, @only) false end
Removes Resources from the graph if they should be filtered.
# File lib/abide-data-processor/parser.rb, line 154 def filter_resources! @resources.depth_first_search do |resource| next if resource == :root if filter_resource?(resource) @resources.remove_vertex(resource) # Remove resource's graph vertex @filtered.add(resource) # Add resource to filtered set end end end
Checks the dependent controls against all controls after filtered resource controls are removed and removes any dependent resources that are not satisfied. rubocop:disable Metrics/MethodLength, Metrics/AbcSize
# File lib/abide-data-processor/parser.rb, line 189 def remove_unsatisfied_dependents! dependent_set = Set.new(@dependent.keys) filtered_set = Set.new(@filtered.to_a.map(&:control_names)).flatten filtered_mapped = Set.new(@filtered.to_a.map(&:mapped_control_names)).flatten all_controls = @controls.subtract(filtered_set + filtered_mapped) return if dependent_set.proper_subset?(all_controls) # All dependent controls exist in the graph (dependent_set - all_controls).each do |control_name| @dependent[control_name].each do |resource| @resources.remove_vertex(resource) @filtered.add(resource) end end end
Calls the given Resource’s ‘resource_data` method, filters out any resource references in metaparameters that references filtered resources, and returns the result. @param resource [Resource] The resource to be filtered. @return [Hash] The filtered resource data. rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
# File lib/abide-data-processor/parser.rb, line 137 def resource_data(resource) data = resource.resource_data.dup data.each do |_, res_data| res_data.each do |_, params| METAPARAMS.each do |param| next unless params.key?(param) params[param].reject! { |r| @filtered.to_a.map(&:resource_reference).include?(r) } params.delete(param) if params[param].empty? end end end data end
This method validates that the resources graph has no cycles and then returns a topological sort of the graph as an Array of Resource
objects. @return [Array] The sorted Resources. @raise [ArgumentError] If the resources graph has any cycles.
# File lib/abide-data-processor/parser.rb, line 267 def sort_resources raise "Resource cyclic ordering detected: #{@resources.cycles}" unless @resources.acyclic? # We call topsort on the graph to get the sorted list of resources, convert it to an array, and # remove the root node. @resources.topsort_iterator.to_a.flatten.uniq.reject { |r| r == :root } end