class OctocatalogDiff::Catalog::Computed
Represents a Puppet catalog that is computed (via `puppet master –compile …`) By instantiating this class, the catalog is computed.
Public Class Methods
Constructor @param :node [String] REQUIRED: Node name @param :basedir [String] Directory in which to compile the catalog @param :pass_env_vars [Array<String>] Environment variables to pass when compiling catalog @param :retry_failed_catalog [Integer] Number of retries if a catalog compilation fails @param :tag [String] For display purposes, the catalog being compiled @param :puppet_binary [String] Full path to Puppet @param :puppet_version [String] Puppet version (optional; if not supplied, it is calculated) @param :puppet_command [String] Full command to run Puppet (optional; if not supplied, it is calculated)
OctocatalogDiff::Catalog::new
# File lib/octocatalog-diff/catalog/computed.rb, line 30 def initialize(options) super raise ArgumentError, 'Node name must be passed to OctocatalogDiff::Catalog::Computed' unless options[:node].is_a?(String) raise ArgumentError, 'Branch is undefined' unless options[:branch] # Additional class variables @pass_env_vars = options.fetch(:pass_env_vars, []) @retry_failed_catalog = options.fetch(:retry_failed_catalog, 0) @tag = options.fetch(:tag, 'catalog') @puppet_binary = options[:puppet_binary] @puppet_version = options[:puppet_version] @puppet_command = options[:puppet_command] @builddir = nil @facts_terminus = options.fetch(:facts_terminus, 'yaml') end
Public Instance Methods
Private method: Make sure that the Puppet environment directory exists.
# File lib/octocatalog-diff/catalog/computed.rb, line 194 def assert_that_puppet_environment_directory_exists target_dir = File.join(@builddir.tempdir, 'environments', environment) return if File.directory?(target_dir) raise Errno::ENOENT, "Environment directory #{target_dir} does not exist" end
Private method: Bootstrap
a directory
# File lib/octocatalog-diff/catalog/computed.rb, line 74 def bootstrap(logger) return if @builddir # Fill options for creating and populating the temporary directory tmphash = @options.dup # Bootstrap directory if needed if !@options[:bootstrapped_dir].nil? raise Errno::ENOENT, "Invalid dir #{@options[:bootstrapped_dir]}" unless File.directory?(@options[:bootstrapped_dir]) tmphash[:basedir] = @options[:bootstrapped_dir] elsif @options[:branch] == '.' if @options[:bootstrap_current] tmphash[:basedir] = OctocatalogDiff::Util::Util.temp_dir('ocd-bootstrap-basedir-') FileUtils.cp_r File.join(@options[:basedir], '.'), tmphash[:basedir] o = @options.reject { |k, _v| k == :branch }.merge(path: tmphash[:basedir]) OctocatalogDiff::CatalogUtil::Bootstrap.bootstrap_directory(o, logger) else tmphash[:basedir] = @options[:basedir] end else tmphash[:basedir] = OctocatalogDiff::Util::Util.temp_dir('ocd-bootstrap-checkout-') OctocatalogDiff::CatalogUtil::Bootstrap.bootstrap_directory(@options.merge(path: tmphash[:basedir]), logger) end # Create and populate the temporary directory @builddir ||= OctocatalogDiff::CatalogUtil::BuildDir.new(tmphash, logger) end
Private method: Build catalog by running Puppet @param logger [Logger] Logger object
# File lib/octocatalog-diff/catalog/computed.rb, line 105 def build_catalog(logger) if @facts_terminus != 'facter' facts_obj = OctocatalogDiff::CatalogUtil::Facts.new(@options, logger) logger.debug "Start retrieving facts for #{@node} from #{self.class}" @options[:facts] = facts_obj.facts logger.debug "Success retrieving facts for #{@node} from #{self.class}" end bootstrap(logger) result = run_puppet(logger) @retries = result[:retries] if (result[:exitcode]).zero? begin @catalog = ::JSON.parse(result[:stdout]) @catalog_json = result[:stdout] @error_message = nil rescue ::JSON::ParserError => exc @catalog = nil @catalog_json = nil @error_message = "Catalog has invalid JSON: #{exc.message}" end else @error_message = result[:stderr] @catalog = nil @catalog_json = nil end end
Compilation directory @return [String] Compilation directory
# File lib/octocatalog-diff/catalog/computed.rb, line 56 def compilation_dir raise 'Catalog was not built' if @builddir.nil? @builddir.tempdir end
Convert file resources source => “puppet:///…” to content => “actual content of file”.
# File lib/octocatalog-diff/catalog/computed.rb, line 67 def convert_file_resources(dry_run = false) return @options.key?(:basedir) if dry_run return false unless @options[:basedir] OctocatalogDiff::CatalogUtil::FileResources.convert_file_resources(self, environment) end
Environment used to compile catalog
# File lib/octocatalog-diff/catalog/computed.rb, line 62 def environment @options.fetch(:environment, 'production') end
Private method: Actually execute puppet @return [Hash] { stdout, stderr, exitcode }
# File lib/octocatalog-diff/catalog/computed.rb, line 159 def exec_puppet(logger) # This is the environment provided to the puppet command. env = {} @pass_env_vars.each { |var| env[var] ||= ENV[var] } # This is the Puppet command itself env['OCD_PUPPET_BINARY'] = @puppet_command_obj.puppet_binary # Additional passed-in options sr_run_opts = env.merge( logger: logger, working_dir: @builddir.tempdir, argv: @puppet_command_obj.puppet_argv ) # Set up the ScriptRunner scriptrunner = OctocatalogDiff::Util::ScriptRunner.new( default_script: 'puppet/puppet.sh', override_script_path: @options[:override_script_path] ) begin scriptrunner.run(sr_run_opts) rescue OctocatalogDiff::Util::ScriptRunner::ScriptException => exc logger.warn "Puppet command failed: #{exc.message}" if logger end { stdout: scriptrunner.stdout, stderr: scriptrunner.stderr, exitcode: scriptrunner.exitcode } end
Get the command to compile the catalog @return [String] Puppet command line
# File lib/octocatalog-diff/catalog/computed.rb, line 135 def puppet_command puppet_command_obj.puppet_command end
# File lib/octocatalog-diff/catalog/computed.rb, line 139 def puppet_command_obj @puppet_command_obj ||= begin raise ArgumentError, '"puppet_binary" was not passed to OctocatalogDiff::Catalog::Computed' unless @puppet_binary command_opts = @options.merge( node: @node, compilation_dir: @builddir.tempdir, parser: @options.fetch(:parser, :default), puppet_binary: @puppet_binary, fact_file: @builddir.fact_file, dir: @builddir.tempdir, enc: @builddir.enc, puppet_version: puppet_version ) OctocatalogDiff::CatalogUtil::Command.new(command_opts) end end
Get the Puppet version @return [String] Puppet version
# File lib/octocatalog-diff/catalog/computed.rb, line 49 def puppet_version raise ArgumentError, '"puppet_binary" was not passed to OctocatalogDiff::Catalog::Computed' unless @puppet_binary @puppet_version ||= OctocatalogDiff::Util::PuppetVersion.puppet_version(@puppet_binary, @options) end
Private method: Runs puppet on the command line to compile the catalog Exit code is 0 if catalog generation was successful, non-zero otherwise. @param logger [Logger] Logger object @return [Hash] { stdout: <catalog as JSON>, stderr: <error messages>, exitcode: <hopefully 0> }
# File lib/octocatalog-diff/catalog/computed.rb, line 204 def run_puppet(logger) assert_that_puppet_environment_directory_exists # Run 'cmd' with environment 'env' from directory 'dir' # First line of a successful result needs to be stripped off. It will look like: # Notice: Compiled catalog for xxx in environment production in 27.88 seconds retval = {} 0.upto(@retry_failed_catalog) do |retry_num| @retries = retry_num time_begin = Time.now logger.debug("(#{@tag}) Try #{1 + retry_num} executing Puppet #{puppet_version}: #{puppet_command}") result = exec_puppet(logger) # Success if (result[:exitcode]).zero? logger.debug("(#{@tag}) Catalog succeeded on try #{1 + retry_num} in #{Time.now - time_begin} seconds") first_brace = result[:stdout].index('{') || 0 retval = { stdout: result[:stdout][first_brace..-1], stderr: nil, exitcode: 0, retries: retry_num } break end # Failure logger.debug("(#{@tag}) Catalog failed on try #{1 + retry_num} in #{Time.now - time_begin} seconds") retval = result.merge(retries: retry_num) end retval end