class Puppet::Application::Device
Attributes
agent[RW]
args[RW]
host[RW]
Public Instance Methods
app_defaults()
click to toggle source
Calls superclass method
Puppet::Application#app_defaults
# File lib/puppet/application/device.rb 13 def app_defaults 14 super.merge({ 15 :catalog_terminus => :rest, 16 :catalog_cache_terminus => :json, 17 :node_terminus => :rest, 18 :facts_terminus => :network_device, 19 }) 20 end
find_resources(type, name)
click to toggle source
# File lib/puppet/application/device.rb 398 def find_resources(type, name) 399 key = [type, name].join('/') 400 401 if name 402 [ Puppet::Resource.indirection.find( key ) ] 403 else 404 Puppet::Resource.indirection.search( key, {} ) 405 end 406 end
help()
click to toggle source
# File lib/puppet/application/device.rb 87 def help 88 <<-HELP 89 90 puppet-device(8) -- #{summary} 91 ======== 92 93 SYNOPSIS 94 -------- 95 Retrieves catalogs from the Puppet master and applies them to remote devices. 96 97 This subcommand can be run manually; or periodically using cron, 98 a scheduled task, or a similar tool. 99 100 101 USAGE 102 ----- 103 puppet device [-h|--help] [-v|--verbose] [-d|--debug] 104 [-l|--logdest syslog|<file>|console] [--detailed-exitcodes] 105 [--deviceconfig <file>] [-w|--waitforcert <seconds>] 106 [--libdir <directory>] 107 [-a|--apply <file>] [-f|--facts] [-r|--resource <type> [name]] 108 [-t|--target <device>] [--user=<user>] [-V|--version] 109 110 111 DESCRIPTION 112 ----------- 113 Devices require a proxy Puppet agent to request certificates, collect facts, 114 retrieve and apply catalogs, and store reports. 115 116 117 USAGE NOTES 118 ----------- 119 Devices managed by the puppet-device subcommand on a Puppet agent are 120 configured in device.conf, which is located at $confdir/device.conf by default, 121 and is configurable with the $deviceconfig setting. 122 123 The device.conf file is an INI-like file, with one section per device: 124 125 [<DEVICE_CERTNAME>] 126 type <TYPE> 127 url <URL> 128 debug 129 130 The section name specifies the certname of the device. 131 132 The values for the type and url properties are specific to each type of device. 133 134 The optional debug property specifies transport-level debugging, 135 and is limited to telnet and ssh transports. 136 137 See https://puppet.com/docs/puppet/latest/config_file_device.html for details. 138 139 140 OPTIONS 141 ------- 142 Note that any setting that's valid in the configuration file is also a valid 143 long argument. For example, 'server' is a valid configuration parameter, so 144 you can specify '--server <servername>' as an argument. 145 146 * --help, -h: 147 Print this help message 148 149 * --verbose, -v: 150 Turn on verbose reporting. 151 152 * --debug, -d: 153 Enable full debugging. 154 155 * --logdest, -l: 156 Where to send log messages. Choose between 'syslog' (the POSIX syslog 157 service), 'console', or the path to a log file. If debugging or verbosity is 158 enabled, this defaults to 'console'. Otherwise, it defaults to 'syslog'. 159 Multiple destinations can be set using a comma separated list 160 (eg: `/path/file1,console,/path/file2`)" 161 162 A path ending with '.json' will receive structured output in JSON format. The 163 log file will not have an ending ']' automatically written to it due to the 164 appending nature of logging. It must be appended manually to make the content 165 valid JSON. 166 167 * --detailed-exitcodes: 168 Provide transaction information via exit codes. If this is enabled, an exit 169 code of '1' means at least one device had a compile failure, an exit code of 170 '2' means at least one device had resource changes, and an exit code of '4' 171 means at least one device had resource failures. Exit codes of '3', '5', '6', 172 or '7' means that a bitwise combination of the preceding exit codes happened. 173 174 * --deviceconfig: 175 Path to the device config file for puppet device. 176 Default: $confdir/device.conf 177 178 * --waitforcert, -w: 179 This option only matters for targets that do not yet have certificates 180 and it is enabled by default, with a value of 120 (seconds). This causes 181 +puppet device+ to poll the server every 2 minutes and ask it to sign a 182 certificate request. This is useful for the initial setup of a target. 183 You can turn off waiting for certificates by specifying a time of 0. 184 185 * --libdir: 186 Override the per-device libdir with a local directory. Specifying a libdir also 187 disables pluginsync. This is useful for testing. 188 189 A path ending with '.jsonl' will receive structured output in JSON Lines 190 format. 191 192 * --apply: 193 Apply a manifest against a remote target. Target must be specified. 194 195 * --facts: 196 Displays the facts of a remote target. Target must be specified. 197 198 * --resource: 199 Displays a resource state as Puppet code, roughly equivalent to 200 `puppet resource`. Can be filtered by title. Requires --target be specified. 201 202 * --target: 203 Target a specific device/certificate in the device.conf. Doing so will perform a 204 device run against only that device/certificate. 205 206 * --to_yaml: 207 Output found resources in yaml format, suitable to use with Hiera and 208 create_resources. 209 210 * --user: 211 The user to run as. 212 213 214 EXAMPLE 215 ------- 216 $ puppet device --target remotehost --verbose 217 218 AUTHOR 219 ------ 220 Brice Figureau 221 222 223 COPYRIGHT 224 --------- 225 Copyright (c) 2011-2018 Puppet Inc., LLC 226 Licensed under the Apache 2.0 License 227 HELP 228 end
main()
click to toggle source
# File lib/puppet/application/device.rb 231 def main 232 if options[:resource] and !options[:target] 233 raise _("resource command requires target") 234 end 235 if options[:facts] and !options[:target] 236 raise _("facts command requires target") 237 end 238 unless options[:apply].nil? 239 raise _("missing argument: --target is required when using --apply") if options[:target].nil? 240 raise _("%{file} does not exist, cannot apply") % { file: options[:apply] } unless File.file?(options[:apply]) 241 end 242 libdir = Puppet[:libdir] 243 vardir = Puppet[:vardir] 244 confdir = Puppet[:confdir] 245 ssldir = Puppet[:ssldir] 246 certname = Puppet[:certname] 247 248 env = Puppet::Node::Environment.remote(Puppet[:environment]) 249 returns = Puppet.override(:current_environment => env, :loaders => Puppet::Pops::Loaders.new(env)) do 250 # find device list 251 require_relative '../../puppet/util/network_device/config' 252 devices = Puppet::Util::NetworkDevice::Config.devices.dup 253 if options[:target] 254 devices.select! { |key, value| key == options[:target] } 255 end 256 if devices.empty? 257 if options[:target] 258 raise _("Target device / certificate '%{target}' not found in %{config}") % { target: options[:target], config: Puppet[:deviceconfig] } 259 else 260 Puppet.err _("No device found in %{config}") % { config: Puppet[:deviceconfig] } 261 exit(1) 262 end 263 end 264 devices.collect do |devicename,device| 265 # TODO when we drop support for ruby < 2.5 we can remove the extra block here 266 begin 267 device_url = URI.parse(device.url) 268 # Handle nil scheme & port 269 scheme = "#{device_url.scheme}://" if device_url.scheme 270 port = ":#{device_url.port}" if device_url.port 271 272 # override local $vardir and $certname 273 Puppet[:ssldir] = ::File.join(Puppet[:deviceconfdir], device.name, 'ssl') 274 Puppet[:confdir] = ::File.join(Puppet[:devicedir], device.name) 275 Puppet[:libdir] = options[:libdir] || ::File.join(Puppet[:devicedir], device.name, 'lib') 276 Puppet[:vardir] = ::File.join(Puppet[:devicedir], device.name) 277 Puppet[:certname] = device.name 278 ssl_context = nil 279 280 # create device directory under $deviceconfdir 281 Puppet::FileSystem.dir_mkpath(Puppet[:ssldir]) unless Puppet::FileSystem.dir_exist?(Puppet[:ssldir]) 282 283 # this will reload and recompute default settings and create device-specific sub vardir 284 Puppet.settings.use :main, :agent, :ssl 285 286 # Workaround for PUP-8736: store ssl certs outside the cache directory to prevent accidental removal and keep the old path as symlink 287 optssldir = File.join(Puppet[:confdir], 'ssl') 288 Puppet::FileSystem.symlink(Puppet[:ssldir], optssldir) unless Puppet::FileSystem.exist?(optssldir) 289 290 unless options[:resource] || options[:facts] || options[:apply] 291 # Since it's too complicated to fix properly in the default settings, we workaround for PUP-9642 here. 292 # See https://github.com/puppetlabs/puppet/pull/7483#issuecomment-483455997 for details. 293 # This has to happen after `settings.use` above, so the directory is created and before `setup_host` below, where the SSL 294 # routines would fail with access errors 295 if Puppet.features.root? && !Puppet::Util::Platform.windows? 296 user = Puppet::Type.type(:user).new(name: Puppet[:user]).exists? ? Puppet[:user] : nil 297 group = Puppet::Type.type(:group).new(name: Puppet[:group]).exists? ? Puppet[:group] : nil 298 Puppet.debug("Fixing perms for #{user}:#{group} on #{Puppet[:confdir]}") 299 FileUtils.chown(user, group, Puppet[:confdir]) if user || group 300 end 301 302 ssl_context = setup_context 303 304 unless options[:libdir] 305 Puppet.override(ssl_context: ssl_context) do 306 Puppet::Configurer::PluginHandler.new.download_plugins(env) if Puppet::Configurer.should_pluginsync? 307 end 308 end 309 end 310 311 # this inits the device singleton, so that the facts terminus 312 # and the various network_device provider can use it 313 Puppet::Util::NetworkDevice.init(device) 314 315 if options[:resource] 316 type, name = parse_args(command_line.args) 317 Puppet.info _("retrieving resource: %{resource} from %{target} at %{scheme}%{url_host}%{port}%{url_path}") % { resource: type, target: device.name, scheme: scheme, url_host: device_url.host, port: port, url_path: device_url.path } 318 resources = find_resources(type, name) 319 if options[:to_yaml] 320 data = resources.map do |resource| 321 resource.prune_parameters(:parameters_to_include => @extra_params).to_hiera_hash 322 end.inject(:merge!) 323 text = YAML.dump(type.downcase => data) 324 else 325 text = resources.map do |resource| 326 resource.prune_parameters(:parameters_to_include => @extra_params).to_manifest.force_encoding(Encoding.default_external) 327 end.join("\n") 328 end 329 (puts text) 330 0 331 elsif options[:facts] 332 Puppet.info _("retrieving facts from %{target} at %{scheme}%{url_host}%{port}%{url_path}") % { resource: type, target: device.name, scheme: scheme, url_host: device_url.host, port: port, url_path: device_url.path } 333 remote_facts = Puppet::Node::Facts.indirection.find(name, :environment => env) 334 # Give a proper name to the facts 335 remote_facts.name = remote_facts.values['clientcert'] 336 renderer = Puppet::Network::FormatHandler.format(:console) 337 puts renderer.render(remote_facts) 338 0 339 elsif options[:apply] 340 # avoid reporting to server 341 Puppet::Transaction::Report.indirection.terminus_class = :yaml 342 Puppet::Resource::Catalog.indirection.cache_class = nil 343 344 require_relative '../../puppet/application/apply' 345 begin 346 Puppet[:node_terminus] = :plain 347 Puppet[:catalog_terminus] = :compiler 348 Puppet[:catalog_cache_terminus] = nil 349 Puppet[:facts_terminus] = :network_device 350 Puppet.override(:network_device => true) do 351 Puppet::Application::Apply.new(Puppet::Util::CommandLine.new('puppet', ["apply", options[:apply]])).run_command 352 end 353 end 354 else 355 Puppet.info _("starting applying configuration to %{target} at %{scheme}%{url_host}%{port}%{url_path}") % { target: device.name, scheme: scheme, url_host: device_url.host, port: port, url_path: device_url.path } 356 357 overrides = {} 358 overrides[:ssl_context] = ssl_context if ssl_context 359 Puppet.override(overrides) do 360 configurer = Puppet::Configurer.new 361 configurer.run(:network_device => true, :pluginsync => false) 362 end 363 end 364 rescue => detail 365 Puppet.log_exception(detail) 366 # If we rescued an error, then we return 1 as the exit code 367 1 368 ensure 369 Puppet[:libdir] = libdir 370 Puppet[:vardir] = vardir 371 Puppet[:confdir] = confdir 372 Puppet[:ssldir] = ssldir 373 Puppet[:certname] = certname 374 end 375 end 376 end 377 378 if ! returns or returns.compact.empty? 379 exit(1) 380 elsif options[:detailed_exitcodes] 381 # Bitwise OR the return codes together, puppet style 382 exit(returns.compact.reduce(:|)) 383 elsif returns.include? 1 384 exit(1) 385 else 386 exit(0) 387 end 388 end
parse_args(args)
click to toggle source
# File lib/puppet/application/device.rb 390 def parse_args(args) 391 type = args.shift or raise _("You must specify the type to display") 392 Puppet::Type.type(type) or raise _("Could not find type %{type}") % { type: type } 393 name = args.shift 394 395 [type, name] 396 end
preinit()
click to toggle source
# File lib/puppet/application/device.rb 22 def preinit 23 # Do an initial trap, so that cancels don't get a stack trace. 24 Signal.trap(:INT) do 25 $stderr.puts _("Cancelling startup") 26 exit(0) 27 end 28 29 { 30 :apply => nil, 31 :waitforcert => nil, 32 :detailed_exitcodes => false, 33 :verbose => false, 34 :debug => false, 35 :centrallogs => false, 36 :setdest => false, 37 :resource => false, 38 :facts => false, 39 :target => nil, 40 :to_yaml => false, 41 }.each do |opt,val| 42 options[opt] = val 43 end 44 45 @args = {} 46 end
setup()
click to toggle source
# File lib/puppet/application/device.rb 414 def setup 415 setup_logs 416 417 Puppet::SSL::Oids.register_puppet_oids 418 419 # setup global device-specific defaults; creates all necessary directories, etc 420 Puppet.settings.use :main, :agent, :device, :ssl 421 422 if options[:apply] || options[:facts] || options[:resource] 423 Puppet::Util::Log.newdestination(:console) 424 else 425 args[:Server] = Puppet[:server] 426 if options[:centrallogs] 427 logdest = args[:Server] 428 429 logdest += ":" + args[:Port] if args.include?(:Port) 430 Puppet::Util::Log.newdestination(logdest) 431 end 432 433 Puppet::Transaction::Report.indirection.terminus_class = :rest 434 435 if Puppet[:catalog_cache_terminus] 436 Puppet::Resource::Catalog.indirection.cache_class = Puppet[:catalog_cache_terminus].intern 437 end 438 end 439 end
setup_context()
click to toggle source
# File lib/puppet/application/device.rb 408 def setup_context 409 waitforcert = options[:waitforcert] || (Puppet[:onetime] ? 0 : Puppet[:waitforcert]) 410 sm = Puppet::SSL::StateMachine.new(waitforcert: waitforcert) 411 sm.ensure_client_certificate 412 end
summary()
click to toggle source
# File lib/puppet/application/device.rb 83 def summary 84 _("Manage remote network devices") 85 end