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