Current File : //opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/application/script.rb |
require_relative '../../puppet/application'
require_relative '../../puppet/configurer'
require_relative '../../puppet/util/profiler/aggregate'
require_relative '../../puppet/parser/script_compiler'
class Puppet::Application::Script < Puppet::Application
option("--debug","-d")
option("--execute EXECUTE","-e") do |arg|
options[:code] = arg
end
option("--test","-t")
option("--verbose","-v")
option("--logdest LOGDEST", "-l") do |arg|
handle_logdest_arg(arg)
end
def summary
_("Run a puppet manifests as a script without compiling a catalog")
end
def help
<<-HELP
puppet-script(8) -- #{summary}
========
SYNOPSIS
--------
Runs a puppet language script without compiling a catalog.
USAGE
-----
puppet script [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
[-e|--execute]
[-l|--logdest syslog|eventlog|<FILE>|console] [--noop]
<file>
DESCRIPTION
-----------
This is a standalone puppet script runner tool; use it to run puppet code
without compiling a catalog.
When provided with a modulepath, via command line or config file, puppet
script can load functions, types, tasks and plans from modules.
OPTIONS
-------
Note that any setting that's valid in the configuration
file is also a valid long argument. For example, 'environment' is a
valid setting, so you can specify '--environment mytest'
as an argument.
See the configuration file documentation at
https://puppet.com/docs/puppet/latest/configuration.html for the
full list of acceptable parameters. A commented list of all
configuration options can also be generated by running puppet with
'--genconfig'.
* --debug:
Enable full debugging.
* --help:
Print this help message
* --logdest:
Where to send log messages. Choose between 'syslog' (the POSIX syslog
service), 'eventlog' (the Windows Event Log), 'console', or the path to a log
file. Defaults to 'console'.
Multiple destinations can be set using a comma separated list
(eg: `/path/file1,console,/path/file2`)"
A path ending with '.json' will receive structured output in JSON format. The
log file will not have an ending ']' automatically written to it due to the
appending nature of logging. It must be appended manually to make the content
valid JSON.
A path ending with '.jsonl' will receive structured output in JSON Lines
format.
* --noop:
Use 'noop' mode where Puppet runs in a no-op or dry-run mode. This
is useful for seeing what changes Puppet will make without actually
executing the changes. Applies to tasks only.
* --execute:
Execute a specific piece of Puppet code
* --verbose:
Print extra information.
EXAMPLE
-------
$ puppet script -l /tmp/manifest.log manifest.pp
$ puppet script --modulepath=/root/dev/modules -e 'notice("hello world")'
AUTHOR
------
Henrik Lindberg
COPYRIGHT
---------
Copyright (c) 2017 Puppet Inc., LLC Licensed under the Apache 2.0 License
HELP
end
def app_defaults
super.merge({
:default_file_terminus => :file_server,
})
end
def run_command
if Puppet.features.bolt?
Puppet.override(:bolt_executor => Bolt::Executor.new) do
main
end
else
raise _("Bolt must be installed to use the script application")
end
end
def main
# The tasks feature is always on
Puppet[:tasks] = true
# Set the puppet code or file to use.
if options[:code] || command_line.args.length == 0
Puppet[:code] = options[:code] || STDIN.read
else
manifest = command_line.args.shift
raise _("Could not find file %{manifest}") % { manifest: manifest } unless Puppet::FileSystem.exist?(manifest)
Puppet.warning(_("Only one file can be used per run. Skipping %{files}") % { files: command_line.args.join(', ') }) if command_line.args.size > 0
end
unless Puppet[:node_name_fact].empty?
# Collect the facts specified for that node
facts = Puppet::Node::Facts.indirection.find(Puppet[:node_name_value])
raise _("Could not find facts for %{node}") % { node: Puppet[:node_name_value] } unless facts
Puppet[:node_name_value] = facts.values[Puppet[:node_name_fact]]
facts.name = Puppet[:node_name_value]
end
# Find the Node
node = Puppet::Node.indirection.find(Puppet[:node_name_value])
raise _("Could not find node %{node}") % { node: Puppet[:node_name_value] } unless node
configured_environment = node.environment || Puppet.lookup(:current_environment)
apply_environment = manifest ?
configured_environment.override_with(:manifest => manifest) :
configured_environment
# Modify the node descriptor to use the special apply_environment.
# It is based on the actual environment from the node, or the locally
# configured environment if the node does not specify one.
# If a manifest file is passed on the command line, it overrides
# the :manifest setting of the apply_environment.
node.environment = apply_environment
# TRANSLATION, the string "For puppet script" is not user facing
Puppet.override({:current_environment => apply_environment}, "For puppet script") do
# Merge in the facts.
node.merge(facts.values) if facts
# Add server facts so $server_facts[environment] exists when doing a puppet script
# SCRIPT TODO: May be needed when running scripts under orchestrator. Leave it for now.
#
node.add_server_facts({})
begin
# Compile the catalog
# When compiling, the compiler traps and logs certain errors
# Those that do not lead to an immediate exit are caught by the general
# rule and gets logged.
#
begin
# support the following features when evaluating puppet code
# * $facts with facts from host running the script
# * $settings with 'settings::*' namespace populated, and '$settings::all_local' hash
# * $trusted as setup when using puppet apply
# * an environment
#
# fixup trusted information
node.sanitize()
compiler = Puppet::Parser::ScriptCompiler.new(node.environment, node.name)
topscope = compiler.topscope
# When scripting the trusted data are always local, but set them anyway
topscope.set_trusted(node.trusted_data)
# Server facts are always about the local node's version etc.
topscope.set_server_facts(node.server_facts)
# Set $facts for the node running the script
facts_hash = node.facts.nil? ? {} : node.facts.values
topscope.set_facts(facts_hash)
# create the $settings:: variables
topscope.merge_settings(node.environment.name, false)
compiler.compile()
rescue Puppet::Error
# already logged and handled by the compiler, including Puppet::ParseErrorWithIssue
exit(1)
end
exit(0)
rescue => detail
Puppet.log_exception(detail)
exit(1)
end
end
ensure
if @profiler
Puppet::Util::Profiler.remove_profiler(@profiler)
@profiler.shutdown
end
end
def setup
exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
handle_logdest_arg(Puppet[:logdest])
Puppet::Util::Log.newdestination(:console) unless options[:setdest]
Signal.trap(:INT) do
$stderr.puts _("Exiting")
exit(1)
end
# TODO: This skips applying the settings catalog for these settings, but
# the effect of doing this is unknown. It may be that it only works if there is a puppet
# installed where a settings catalog have already been applied...
# This saves 1/5th of the startup time
# Puppet.settings.use :main, :agent, :ssl
# When running a script, the catalog is not relevant, and neither is caching of it
Puppet::Resource::Catalog.indirection.cache_class = nil
# we do not want the last report to be persisted
Puppet::Transaction::Report.indirection.cache_class = nil
set_log_level
if Puppet[:profile]
@profiler = Puppet::Util::Profiler.add_profiler(Puppet::Util::Profiler::Aggregate.new(Puppet.method(:info), "script"))
end
end
end