MNiedzielski
5/31/2017 - 12:33 AM

Load the metadata from an AWS stack into Puppet's Facter. Include all Exports, Outputs, Parameters, Resources and Tags.

Load the metadata from an AWS stack into Puppet's Facter. Include all Exports, Outputs, Parameters, Resources and Tags.

#
# Query AWS for all Exports, Outputs, Parameters, Resources and Tags associated
#   with the named stack and insert them into Facter as facts.
#
# Examples are plentiful for loading Tags into Facter; we load all the metadata
#   related to the stack and its resources.  Optional prefixes for different
#   metadata types are set below.  Use the empty string to remove the prefix.
#
#   Requires: aws-sdk version 2
#   Expects:  'stack_name' to be defined in Facter

require 'facter'
require 'open-uri'
require 'aws-sdk-core'

# Set a prefix for different types of metadata.
prefix          = 'cf_'
prefix_export   = 'cf__export_'
prefix_resource = 'cf__res_'

def aws_metadata(path)
  return open("http://169.254.169.254/latest/meta-data/#{path}").read.split("\n")[0]
end

begin
  Aws.config[:region]      = aws_metadata('placement/availability-zone')[0..-2]
  Aws.config[:credentials] = Aws::InstanceProfileCredentials.new
  cloudformation           = Aws::CloudFormation::Client.new
rescue Exception => e
  p "Failed to query CloudFormation metadata."
  p e
end

stack_id    = Facter.value(:stack_name)

# Stack Outputs
begin
  cloudformation.list_exports().each do |resp|
    resp[:exports].each do |export|
      Facter.add("#{prefix_export}#{export.name}") do
        setcode do
          export.value
        end
      end
    end
  end
rescue Exception => e
  p "Unable to parse AWS CloudFormation Exports."
  p e
end

# Stack Metadata
options    = {stack_name: stack_id}
begin
  cloudformation.describe_stacks(options).each do |resp|
    resp[:stacks][0][:parameters].each do |param|
      Facter.add("#{prefix}#{param.parameter_key}") do
        setcode do
          param.parameter_value
        end
      end
    end

    resp[:stacks][0][:outputs].each do |output|
      Facter.add("#{prefix}#{output.output_key}") do
        setcode do
          output.output_value
        end
      end
    end
    
    resp[:stacks][0][:tags].each do |tag|
      Facter.add("#{prefix}#{tag.key}") do
        setcode do
          tag.value
        end
      end
    end

    Facter.add("#{prefix}stack_id")    { setcode { resp[:stacks][0][:stack_id] } }

    Facter.add("#{prefix}stack_name")  { setcode { resp[:stacks][0][:stack_name] } }

    Facter.add("#{prefix}description") { setcode { resp[:stacks][0][:description] } }

  end
rescue Exception => e
  p "Unable to parse AWS CloudFormation Parameters."
  p e
end

begin
  cloudformation.describe_stack_resources(options).each do |resp|
    resp[:stack_resources].each do |res|
      Facter.add("#{prefix_resource}#{res.logical_resource_id}") do
        setcode do
          res.physical_resource_id
        end
      end
    end
  end
rescue Exception => e
  p "Unable to parse AWS CloudFormation Resources."
  p e
end