class Object

Constants

EASY_FACTS

These facts have a one to one correlation between a legacy fact and a new structured fact.

HASH_KEY_TYPES

A list of valid hash key token types

LEGACY_FACTS_VAR_TYPES
REGEX_FACTS

These facts will depend on how a system is set up and can't just be enumerated like the EASY_FACTS below.

For example a server might have two block devices named 'sda' and 'sdb' so there would be a $blockdeivce_sda_vendor and $blockdeivce_sdb_vendor fact for each device. Or it could have 26 block devices going all the way up to 'sdz'. There is no way to know what the possibilities are so we have to use a regex to match them.

UNCONVERTIBLE_FACTS

These facts that can't be converted to new facts for reasons documented at github.com/mmckinst/puppet-lint-legacy_facts-check#limitations

Public Instance Methods

check() click to toggle source
# File lib/puppet-lint/plugins/legacy_facts.rb, line 107
def check
  tokens.select { |x| LEGACY_FACTS_VAR_TYPES.include?(x.type) }.each do |token|
    fact_name = ''

    # Get rid of the top scope before we do our work. We don't need to
    # preserve it because it won't work with the new structured facts.
    if token.value.start_with?('::') then
      fact_name = token.value.sub(/^::/, '')

    # This matches using legacy facts in a the new structured fact. For
    # example this would match 'uuid' in $facts['uuid'] so it can be converted
    # to facts['dmi']['product']['uuid']"
    elsif token.value == 'facts' then
      fact_name = hash_key_for(token)

    elsif token.value.start_with?("facts['")
      fact_name = token.value.match(/facts\['(.*)'\]/)[1]
    end

    if EASY_FACTS.include?(fact_name) or UNCONVERTIBLE_FACTS.include?(fact_name) or fact_name.match(Regexp.union(REGEX_FACTS)) then
      notify :warning, {
        :message   => 'legacy fact',
        :line      => token.line,
        :column    => token.column,
        :token     => token,
        :fact_name => fact_name,
      }
    end
  end
end
fix(problem) click to toggle source
# File lib/puppet-lint/plugins/legacy_facts.rb, line 150
def fix(problem)
  fact_name = problem[:fact_name]

  # Check if the variable is using the $facts hash represented internally by
  # multiple tokens and remove the tokens for the old legacy key if so.
  if problem[:token].value == 'facts'
    loop do
      t = problem[:token].next_token
      remove_token(t)
      break if t.type == :RBRACK
    end
  end

  if EASY_FACTS.include?(fact_name)
    problem[:token].value = EASY_FACTS[fact_name]
  elsif fact_name.match(Regexp.union(REGEX_FACTS))
    if m = fact_name.match(/^blockdevice_(?<devicename>.*)_(?<attribute>model|size|vendor)$/)
      problem[:token].value = "facts['disks']['"<< m['devicename'] << "']['" << m['attribute'] << "']"
    elsif m = fact_name.match(/^(?<attribute>ipaddress|ipaddress6|macaddress|mtu|netmask|netmask6|network|network6)_(?<interface>.*)$/)
      problem[:token].value = "facts['networking']['interfaces']['"<< m['interface'] << "']['" << m['attribute'].sub('address', '') << "']"
    elsif m = fact_name.match(/^processor(?<id>[0-9]+)$/)
      problem[:token].value = "facts['processors']['models'][" << m['id'] << "]"
    elsif m = fact_name.match(/^sp_(?<name>.*)$/)
      problem[:token].value = "facts['system_profiler']['" << m['name'] << "']"
    elsif m = fact_name.match(/^ssh(?<algorithm>dsa|ecdsa|ed25519|rsa)key$/)
      problem[:token].value = "facts['ssh']['" << m['algorithm'] << "']['key']"
    elsif m = fact_name.match(/^ldom_(?<name>.*)$/)
      problem[:token].value = "facts['ldom']['" << m['name'] << "']"
    elsif m = fact_name.match(/^zone_(?<name>.*)_(?<attribute>brand|iptype|name|uuid|id|path|status)$/)
      problem[:token].value = "facts['solaris_zones']['zones']['" << m['name'] << "']['" << m['attribute'] << "']"
    end
  end
end
hash_key_for(token) click to toggle source

If the variable is using the $facts hash represented internally by multiple tokens, this helper simplifies accessing the hash key.

# File lib/puppet-lint/plugins/legacy_facts.rb, line 140
def hash_key_for(token)
  lbrack_token = token.next_code_token
  return '' unless lbrack_token && lbrack_token.type == :LBRACK

  key_token = lbrack_token.next_code_token
  return '' unless key_token && HASH_KEY_TYPES.include?(key_token.type)

  key_token.value
end