class TerraformInventory::TerraformState

Attributes

resources[R]
state[R]

Public Class Methods

new(stateText) click to toggle source
# File lib/terraform_inventory/terraform_state.rb, line 47
def initialize(stateText)
  @state = split_state(
    YAML.load(
      stateText
        .gsub(/\e\[(\d+)m/, "") # Hack to get rid of ASCII color codes in Terraform output
        .gsub(/\s=\s/, ": ")    # Use colons so we can parse as YAML
        .gsub(/: \n/, ": ''\n") # Need to have quotes in order to parse as YAML
        .split(/\n\n/)          # Grab only text that is related to resource state (exclude outputs)
        .first                  # We only want the first match
    )
  )
end

Public Instance Methods

find_resources(resource_selector) click to toggle source

Find resources given a resource selector.

A resource selector is composed of the following:

resource_type (ex. aws_instance)
resource_name (ex. web)
resource_number (ex. 1)

Here are a few examples of resource selectors:

aws_instance.web.1  -  selects a specific aws_instance resource named web
aws_instance.web    -  selects all aws_instance resources named web

Returns:

[ resource_data ]
# File lib/terraform_inventory/terraform_state.rb, line 23
def find_resources(resource_selector)
  resource_type, resource_name, resource_number = parse_resource_selector(resource_selector)

  if @state[resource_type].nil? || @state[resource_type][resource_name].nil?
    []
  elsif resource_number
    [@state[resource_type][resource_name][resource_number]]
  else
    @state[resource_type][resource_name]
  end
end
group_by_host(resource_host_group_mapping) click to toggle source
# File lib/terraform_inventory/terraform_state.rb, line 35
def group_by_host(resource_host_group_mapping)
  resource_host_group_mapping.reduce({}) do |data, (resource_selector, host_group)| # rubocop:disable Style/EachWithObject
    data[host_group.to_sym] ||= []
    resources = find_resources(resource_selector)

    raise Exception::ResourceNotFoundException, resource_selector if resources.empty?

    data[host_group.to_sym].concat resources
    data
  end
end

Private Instance Methods

parse_resource_selector(resource_selector) click to toggle source
# File lib/terraform_inventory/terraform_state.rb, line 62
def parse_resource_selector(resource_selector)
  resource_selector_regex = /^(\w+)\.([\w@\-]+)(?:\.(\d+))?$/
  matches = resource_selector_regex.match(resource_selector)

  raise Exception::InvalidResourceSelectorException, resource_selector if matches.nil?

  resource_type = matches[1]
  resource_name = matches[2]
  resource_number = if matches[3].nil?
    nil
  else
    matches[3].to_i
  end

  [resource_type, resource_name, resource_number]
end
split_state(state) click to toggle source
# File lib/terraform_inventory/terraform_state.rb, line 79
def split_state(state)
  state.reduce({}) do |data, (resource_selector, resource_attributes)| # rubocop:disable Style/EachWithObject
    resource_type, resource_name, _resource_number = parse_resource_selector(resource_selector)

    data[resource_type] ||= {}
    data[resource_type][resource_name] ||= []
    data[resource_type][resource_name] << resource_attributes

    data
  end
end