1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
# Bundler and rubygems maintain a set of directories from which to
# load gems. If Bundler is loaded, let it determine what can be
# loaded. If it's not loaded, then use rubygems. But do this before
# loading any puppet code, so that our gem loading system is sane.
if not defined? ::Bundler
begin
require 'rubygems'
rescue LoadError
end
end
require_relative '../../puppet'
require_relative '../../puppet/util'
require_relative '../../puppet/util/rubygems'
require_relative '../../puppet/util/limits'
require_relative '../../puppet/util/colors'
require_relative '../../puppet/gettext/module_translations'
module Puppet
module Util
# This is the main entry point for all puppet applications / faces; it
# is basically where the bootstrapping process / lifecycle of an app
# begins.
class CommandLine
include Puppet::Util::Limits
OPTION_OR_MANIFEST_FILE = /^-|\.pp$/
# @param zero [String] the name of the executable
# @param argv [Array<String>] the arguments passed on the command line
# @param stdin [IO] (unused)
def initialize(zero = $0, argv = ARGV, stdin = STDIN)
@command = File.basename(zero, '.rb')
@argv = argv
end
# @return [String] name of the subcommand is being executed
# @api public
def subcommand_name
return @command if @command != 'puppet'
if @argv.first =~ OPTION_OR_MANIFEST_FILE
nil
else
@argv.first
end
end
# @return [Array<String>] the command line arguments being passed to the subcommand
# @api public
def args
return @argv if @command != 'puppet'
if subcommand_name.nil?
@argv
else
@argv[1..-1]
end
end
# Run the puppet subcommand. If the subcommand is determined to be an
# external executable, this method will never return and the current
# process will be replaced via {Kernel#exec}.
#
# @return [void]
def execute
require_config = true
if @argv.first =~ /help|-h|--help|-V|--version/
require_config = false
end
Puppet::Util.exit_on_fail(_("Could not initialize global default settings")) do
Puppet.initialize_settings(args, require_config)
end
setpriority(Puppet[:priority])
find_subcommand.run
end
# @api private
def external_subcommand
Puppet::Util.which("puppet-#{subcommand_name}")
end
private
def find_subcommand
if subcommand_name.nil?
if args.include?("--help") || args.include?("-h")
ApplicationSubcommand.new("help", CommandLine.new("puppet", ["help"]))
else
NilSubcommand.new(self)
end
elsif Puppet::Application.available_application_names.include?(subcommand_name)
ApplicationSubcommand.new(subcommand_name, self)
else
path_to_subcommand = external_subcommand
if path_to_subcommand
ExternalSubcommand.new(path_to_subcommand, self)
else
UnknownSubcommand.new(subcommand_name, self)
end
end
end
# @api private
class ApplicationSubcommand
def initialize(subcommand_name, command_line)
@subcommand_name = subcommand_name
@command_line = command_line
end
def run
# For most applications, we want to be able to load code from the modulepath,
# such as apply, describe, resource, and faces.
# For agent and device in agent mode, we only want to load pluginsync'ed code from libdir.
# For master, we shouldn't ever be loading per-environment code into the master's
# ruby process, but that requires fixing (#17210, #12173, #8750). So for now
# we try to restrict to only code that can be autoloaded from the node's
# environment.
# PUP-2114 - at this point in the bootstrapping process we do not
# have an appropriate application-wide current_environment set.
# If we cannot find the configured environment, which may not exist,
# we do not attempt to add plugin directories to the load path.
unless @subcommand_name == 'master' || @subcommand_name == 'agent' || (@subcommand_name == 'device' && (['--apply', '--facts', '--resource'] - @command_line.args).empty?)
configured_environment = Puppet.lookup(:environments).get(Puppet[:environment])
if configured_environment
configured_environment.each_plugin_directory do |dir|
$LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
end
Puppet::ModuleTranslations.load_from_modulepath(configured_environment.modules)
Puppet::ModuleTranslations.load_from_vardir(Puppet[:vardir])
# Puppet requires Facter, which initializes its lookup paths. Reset Facter to
# pickup the new $LOAD_PATH.
Puppet.runtime[:facter].reset
end
end
app = Puppet::Application.find(@subcommand_name).new(@command_line)
app.run
end
end
# @api private
class ExternalSubcommand
def initialize(path_to_subcommand, command_line)
@path_to_subcommand = path_to_subcommand
@command_line = command_line
end
def run
Kernel.exec(@path_to_subcommand, *@command_line.args)
end
end
# @api private
class NilSubcommand
include Puppet::Util::Colors
def initialize(command_line)
@command_line = command_line
end
def run
args = @command_line.args
if args.include? "--version" or args.include? "-V"
puts Puppet.version
elsif @command_line.subcommand_name.nil? && args.count > 0
# If the subcommand is truly nil and there is an arg, it's an option; print out the invalid option message
puts colorize(:hred, _("Error: Could not parse application options: invalid option: %{opt}") % { opt: args[0] })
exit 1
else
puts _("See 'puppet help' for help on available puppet subcommands")
end
end
end
# @api private
class UnknownSubcommand < NilSubcommand
def initialize(subcommand_name, command_line)
@subcommand_name = subcommand_name
super(command_line)
end
def run
puts colorize(:hred, _("Error: Unknown Puppet subcommand '%{cmd}'") % { cmd: @subcommand_name })
super
exit 1
end
end
end
end
end
|