Commit 1042df79 authored by James T. Lee's avatar James T. Lee
Browse files

Move puppet libraries into module for Puppet 7 compat

parent d8c34007
This diff is collapsed.
# Contributing to this module #
* Work in a topic branch
* Submit a github pull request
* Address any comments / feeback
* Merge into main using --no-ff
# Releasing this module #
* This module adheres to http://semver.org/
* Look for API breaking changes using git diff vX.Y.Z..
* If no API breaking changes, the minor version may be bumped.
* If there are API breaking changes, the major version must be bumped.
* If there are only small minor changes, the patch version may be bumped.
* Update the CHANGELOG
* Update the Modulefile
* Commit these changes with a message along the lines of "Update CHANGELOG and
Modulefile for release"
* Create an annotated tag with git tag -a vX.Y.Z -m 'version X.Y.Z' (NOTE the
leading v as per semver.org)
* Push the tag with git push origin --tags
* Build a new package with puppet-module or the rake build task if it exists
* Publish the new package to the forge
* Bonus points for an announcement to puppet-users.
# This is a simple smoke test
# of the file_line resource type.
file { '/tmp/dansfile':
ensure => file,
}
-> file_line { 'dans_line':
line => 'dan is awesome',
path => '/tmp/dansfile',
}
include stdlib
info('has_interface_with(\'lo\'):', has_interface_with('lo'))
info('has_interface_with(\'loX\'):', has_interface_with('loX'))
info('has_interface_with(\'ipaddress\', \'127.0.0.1\'):', has_interface_with('ipaddress', '127.0.0.1'))
info('has_interface_with(\'ipaddress\', \'127.0.0.100\'):', has_interface_with('ipaddress', '127.0.0.100'))
info('has_interface_with(\'network\', \'127.0.0.0\'):', has_interface_with('network', '127.0.0.0'))
info('has_interface_with(\'network\', \'128.0.0.0\'):', has_interface_with('network', '128.0.0.0'))
info('has_interface_with(\'netmask\', \'255.0.0.0\'):', has_interface_with('netmask', '255.0.0.0'))
info('has_interface_with(\'netmask\', \'256.0.0.0\'):', has_interface_with('netmask', '256.0.0.0'))
include stdlib
info('has_ip_address(\'192.168.1.256\'):', has_ip_address('192.168.1.256'))
info('has_ip_address(\'127.0.0.1\'):', has_ip_address('127.0.0.1'))
include stdlib
info('has_ip_network(\'127.0.0.0\'):', has_ip_network('127.0.0.0'))
info('has_ip_network(\'128.0.0.0\'):', has_ip_network('128.0.0.0'))
# @summary function to cast ensure parameter to resource specific value
function stdlib::ensure(
Variant[Boolean, Enum['present', 'absent']] $ensure,
Enum['directory', 'link', 'mounted', 'service', 'file'] $resource,
) >> String {
$_ensure = $ensure ? {
Boolean => $ensure.bool2str('present', 'absent'),
default => $ensure,
}
case $resource {
'service': {
$_ensure ? {
'present' => 'running',
default => 'stopped',
}
}
default: {
$_ensure ? {
'present' => $resource,
default => $_ensure,
}
}
}
}
---
version: 5
defaults: # Used for any hierarchy level that omits these keys.
datadir: data # This path is relative to hiera.yaml's directory.
data_hash: yaml_data # Use the built-in YAML backend.
hierarchy:
- name: "osfamily/major release"
paths:
# Used to distinguish between Debian and Ubuntu
- "os/%{facts.os.name}/%{facts.os.release.major}.yaml"
- "os/%{facts.os.family}/%{facts.os.release.major}.yaml"
# Used for Solaris
- "os/%{facts.os.family}/%{facts.kernelrelease}.yaml"
- name: "osfamily"
paths:
- "os/%{facts.os.name}.yaml"
- "os/%{facts.os.family}.yaml"
- name: 'common'
path: 'common.yaml'
# frozen_string_literal: true
# Fact: package_provider
#
# Purpose: Returns the default provider Puppet will choose to manage packages
# on this system
#
# Resolution: Instantiates a dummy package resource and return the provider
#
# Caveats:
#
require 'puppet/type'
require 'puppet/type/package'
# These will be nil if Puppet is not available.
Facter.add(:package_provider) do
# Instantiates a dummy package resource and return the provider
setcode do
if defined? Gem && Gem::Version.new(Facter.value(:puppetversion).split(' ')[0]) >= Gem::Version.new('3.6')
Puppet::Type.type(:package).newpackage(name: 'dummy', allow_virtual: 'true')[:provider].to_s
else
Puppet::Type.type(:package).newpackage(name: 'dummy')[:provider].to_s
end
end
end
# frozen_string_literal: true
# Fact: is_pe, pe_version, pe_major_version, pe_minor_version, pe_patch_version
#
# Purpose: Return various facts about the PE state of the system
#
# Resolution: Uses a regex match against puppetversion to determine whether the
# machine has Puppet Enterprise installed, and what version (overall, major,
# minor, patch) is installed.
#
# Caveats:
#
# Fact: pe_version
Facter.add('pe_version') do
setcode do
found_version = Facter.value('pe_build')
unless found_version
puppet_ver = Facter.value('puppetversion')
unless puppet_ver.nil?
pe_ver = puppet_ver.match(%r{Puppet Enterprise (\d+\.\d+\.\d+)})
found_version = pe_ver[1] if pe_ver
end
end
found_version
end
end
# Fact: is_pe
Facter.add('is_pe') do
setcode do
if Facter.value(:pe_version).to_s.empty?
false
else
true
end
end
end
# Fact: pe_major_version
Facter.add('pe_major_version') do
confine is_pe: true
setcode do
pe_version = Facter.value(:pe_version)
if pe_version
pe_version.to_s.split('.')[0]
end
end
end
# Fact: pe_minor_version
Facter.add('pe_minor_version') do
confine is_pe: true
setcode do
pe_version = Facter.value(:pe_version)
if pe_version
pe_version.to_s.split('.')[1]
end
end
end
# Fact: pe_patch_version
Facter.add('pe_patch_version') do
confine is_pe: true
setcode do
pe_version = Facter.value(:pe_version)
if pe_version
pe_version.to_s.split('.')[2]
end
end
end
# frozen_string_literal: true
# These facter facts return the value of the Puppet vardir and environment path
# settings for the node running puppet or puppet agent. The intent is to
# enable Puppet modules to automatically have insight into a place where they
# can place variable data, or for modules running on the puppet server to know
# where environments are stored.
#
# The values should be directly usable in a File resource path attribute.
#
begin
require 'facter/util/puppet_settings'
rescue LoadError => e
# puppet apply does not add module lib directories to the $LOAD_PATH (See
# #4248). It should (in the future) but for the time being we need to be
# defensive which is what this rescue block is doing.
rb_file = File.join(File.dirname(__FILE__), 'util', 'puppet_settings.rb')
load rb_file if File.exist?(rb_file) || raise(e)
end
# Facter fact returns the value of the Puppet vardir
Facter.add(:puppet_vardir) do
setcode do
Facter::Util::PuppetSettings.with_puppet do
Puppet[:vardir]
end
end
end
# Facter fact returns the value of the Puppet environment path
Facter.add(:puppet_environmentpath) do
setcode do
Facter::Util::PuppetSettings.with_puppet do
Puppet[:environmentpath]
end
end
end
# Facter fact returns the value of the Puppet server
Facter.add(:puppet_server) do
setcode do
Facter::Util::PuppetSettings.with_puppet do
Puppet[:server]
end
end
end
# frozen_string_literal: true
# root_home.rb
module Facter::Util::RootHome
# @summary
# A facter fact to determine the root home directory.
# This varies on PE supported platforms and may be
# reconfigured by the end user.
class << self
# determines the root home directory
def returnt_root_home
root_ent = Facter::Util::Resolution.exec('getent passwd root')
# The home directory is the sixth element in the passwd entry
# If the platform doesn't have getent, root_ent will be nil and we should
# return it straight away.
root_ent && root_ent.split(':')[5]
end
end
end
Facter.add(:root_home) do
setcode { Facter::Util::RootHome.returnt_root_home }
end
Facter.add(:root_home) do
confine kernel: :darwin
setcode do
str = Facter::Util::Resolution.exec('dscacheutil -q user -a name root')
hash = {}
str.split("\n").each do |pair|
key, value = pair.split(%r{:})
hash[key] = value
end
hash['dir'].strip
end
end
Facter.add(:root_home) do
confine kernel: :aix
root_home = nil
setcode do
str = Facter::Util::Resolution.exec('lsuser -c -a home root')
str&.split("\n")&.each do |line|
next if %r{^#}.match?(line)
root_home = line.split(%r{:})[1]
end
root_home
end
end
# frozen_string_literal: true
# Fact: service_provider
#
# Purpose: Returns the default provider Puppet will choose to manage services
# on this system
#
# Resolution: Instantiates a dummy service resource and return the provider
#
# Caveats:
#
require 'puppet/type'
require 'puppet/type/service'
Facter.add(:service_provider) do
setcode do
Puppet::Type.type(:service).newservice(name: 'dummy')[:provider].to_s
end
end
# frozen_string_literal: true
# A method to evaluate a Facter code block if puppet is loaded.
module Facter::Util::PuppetSettings
# This method is intended to provide a convenient way to evaluate a
# Facter code block only if Puppet is loaded. This is to account for the
# situation where the fact happens to be in the load path, but Puppet is
# not loaded for whatever reason. Perhaps the user is simply running
# facter without the --puppet flag and they happen to be working in a lib
# directory of a module.
def self.with_puppet
Module.const_get('Puppet')
rescue NameError
nil
else
yield
end
end
# frozen_string_literal: true
# Function to print deprecation warnings, Logs a warning once for a given key.
#
# The uniqueness key - can appear once.
# The msg is the message text including any positional information that is formatted by the
# user/caller of the method.
# It is affected by the puppet setting 'strict', which can be set to :error
# (outputs as an error message), :off (no message / error is displayed) and :warning
# (default, outputs a warning) *Type*: String, String.
#
Puppet::Functions.create_function(:deprecation) do
# @param key
# @param message
# @return deprecated warnings
dispatch :deprecation do
param 'String', :key
param 'String', :message
end
def deprecation(key, message)
if defined? Puppet::Pops::PuppetStack.stacktrace
stacktrace = Puppet::Pops::PuppetStack.stacktrace()
file = stacktrace[0]
line = stacktrace[1]
message = "#{message} at #{file}:#{line}"
end
# depending on configuration setting of strict
case Puppet.settings[:strict]
when :off
# do nothing
when :error
raise("deprecation. #{key}. #{message}")
else
unless ENV['STDLIB_LOG_DEPRECATIONS'] == 'false'
Puppet.deprecation_warning(message, key)
end
end
end
end
# frozen_string_literal: true
# @summary
# Digs into the facts hash using dot-notation
#
# Supports the use of dot-notation for referring to structured facts. If a fact requested
# does not exist, returns Undef.
#
# @example Example usage:
# fact('osfamily')
# fact('os.architecture')
#
# @example Array indexing:
# fact('mountpoints."/dev".options.1')
#
# @example Fact containing a "." in the name:
# fact('vmware."VRA.version"')
#
Puppet::Functions.create_function(:fact) do
# @param fact_name
# The name of the fact to check
#
# @return
# All information retrieved on the given fact_name
dispatch :fact do
param 'String', :fact_name
end
def to_dot_syntax(array_path)
array_path.map { |string|
string.include?('.') ? %("#{string}") : string
}.join('.')
end
def fact(fact_name)
facts = closure_scope['facts']
# Transform the dot-notation string into an array of paths to walk. Make
# sure to correctly extract double-quoted values containing dots as single
# elements in the path.
path = fact_name.scan(%r{([^."]+)|(?:")([^"]+)(?:")}).map { |x| x.compact.first }
walked_path = []
path.reduce(facts) do |d, k|
return nil if d.nil? || k.nil?
if d.is_a?(Array)
begin
result = d[Integer(k)]
rescue ArgumentError => e # rubocop:disable Lint/UselessAssignment : Causes errors if assigment is removed.
Puppet.warning("fact request for #{fact_name} returning nil: '#{to_dot_syntax(walked_path)}' is an array; cannot index to '#{k}'")
result = nil
end
elsif d.is_a?(Hash)
result = d[k]
else
Puppet.warning("fact request for #{fact_name} returning nil: '#{to_dot_syntax(walked_path)}' is not a collection; cannot walk to '#{k}'")
result = nil
end
walked_path << k
result
end
end
end
# frozen_string_literal: true
# @summary
# Boolean check to determine whether a variable is of a given data type.
# This is equivalent to the `=~` type checks.
#
# @example Example Usage:
# # check a data type
# foo = 3
# $bar = [1,2,3]
# $baz = 'A string!'
#
# if $foo.is_a(Integer) {
# notify { 'foo!': }
# }
# if $bar.is_a(Array) {
# notify { 'bar!': }
# }
# if $baz.is_a(String) {
# notify { 'baz!': }
# }
#
# See the documentation for "The Puppet Type System" for more information about types.
# See the `assert_type()` function for flexible ways to assert the type of a value.
#
Puppet::Functions.create_function(:is_a) do
# @param value
# The value to be checked
#
# @param type
# The expected type
#
# @return [Boolean]
# Return's `true` or `false`.
dispatch :is_a do
param 'Any', :value
param 'Type', :type
end
def is_a(value, type) # rubocop:disable Naming/PredicateName : Used in to many other places to rename at this time, attempting to refactor caused Rubocop to crash.
# See puppet's lib/puppet/pops/evaluator/evaluator_impl.rb eval_MatchExpression
Puppet::Pops::Types::TypeCalculator.instance?(type, value)
end
end
# frozen_string_literal: true
# @summary
# Wrapper that calls the Puppet 3.x function of the same name.
Puppet::Functions.create_function(:is_absolute_path) do
# @param scope
# The main value that will be passed to the wrapped method
#
# @param args
# Any additional values that are to be passed to the wrapped method
#
# @return [Boolea]
# A boolean value returned from the called 3.x function.
dispatch :deprecation_gen do
param 'Any', :scope
repeated_param 'Any', :args
end
# Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff
# -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1.
def call(scope, *args)
manipulated_args = [scope] + args
self.class.dispatcher.dispatch(self, scope, manipulated_args)
end
def deprecation_gen(scope, *args)
call_function('deprecation', 'is_absolute_path', 'This method is deprecated, please use match expressions with Stdlib::Compat::Absolute_Path instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.')
scope.send('function_is_absolute_path', args)
end
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment