Skip to content

(PUP-8766) device $LOAD_PATH and environment handling #7242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 45 additions & 29 deletions lib/puppet/application/device.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'puppet/application'
require 'puppet/configurer'
require 'puppet/util/network_device'

class Puppet::Application::Device < Puppet::Application
Expand Down Expand Up @@ -53,6 +54,10 @@ def preinit
options[:detailed_exitcodes] = true
end

option("--libdir LIBDIR") do |arg|
options[:libdir] = arg
end

option("--apply MANIFEST") do |arg|
options[:apply] = arg.to_s
end
Expand Down Expand Up @@ -93,10 +98,11 @@ def help

USAGE
-----
puppet device [-d|--debug] [--detailed-exitcodes] [--deviceconfig <file>]
[-h|--help] [-l|--logdest syslog|<file>|console]
[-v|--verbose] [-w|--waitforcert <seconds>] [-f|--facts]
[-a|--apply <file>] [-r|--resource <type> [name]]
puppet device [-h|--help] [-v|--verbose] [-d|--debug]
[-l|--logdest syslog|<file>|console] [--detailed-exitcodes]
[--deviceconfig <file>] [-w|--waitforcert <seconds>]
[--libdir <directory>]
[-a|--apply <file>] [-f|--facts] [-r|--resource <type> [name]]
[-t|--target <device>] [--user=<user>] [-V|--version]


Expand Down Expand Up @@ -135,9 +141,25 @@ def help
long argument. For example, 'server' is a valid configuration parameter, so
you can specify '--server <servername>' as an argument.

* --debug:
* --help, -h:
Print this help message

* --verbose, -v:
Turn on verbose reporting.

* --debug, -d:
Enable full debugging.

* --logdest, -l:
Where to send log messages. Choose between 'syslog' (the POSIX syslog
service), 'console', or the path to a log file. If debugging or verbosity is
enabled, this defaults to 'console'. Otherwise, it defaults to 'syslog'.

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.

* --detailed-exitcodes:
Provide transaction information via exit codes. If this is enabled, an exit
code of '1' means at least one device had a compile failure, an exit code of
Expand All @@ -149,18 +171,16 @@ def help
Path to the device config file for puppet device.
Default: $confdir/device.conf

* --help:
Print this help message
* --waitforcert, -w:
This option only matters for targets that do not yet have certificates
and it is enabled by default, with a value of 120 (seconds). This causes
+puppet device+ to poll the server every 2 minutes and ask it to sign a
certificate request. This is useful for the initial setup of a target.
You can turn off waiting for certificates by specifying a time of 0.

* --logdest:
Where to send log messages. Choose between 'syslog' (the POSIX syslog
service), 'console', or the path to a log file. If debugging or verbosity is
enabled, this defaults to 'console'. Otherwise, it defaults to 'syslog'.

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.
* --libdir:
Override the per-device libdir with a local directory. Specifying a libdir also
disables pluginsync. This is useful for testing.

* --apply:
Apply a manifest against a remote target. Target must be specified.
Expand All @@ -183,16 +203,6 @@ def help
* --user:
The user to run as.

* --verbose:
Turn on verbose reporting.

* --waitforcert:
This option only matters for daemons that do not yet have certificates
and it is enabled by default, with a value of 120 (seconds). This causes
+puppet agent+ to connect to the server every 2 minutes and ask it to sign a
certificate request. This is useful for the initial setup of a puppet
client. You can turn off waiting for certificates by specifying a time of 0.


EXAMPLE
-------
Expand All @@ -205,7 +215,7 @@ def help

COPYRIGHT
---------
Copyright (c) 2011 Puppet Inc., LLC
Copyright (c) 2011-2018 Puppet Inc., LLC
Licensed under the Apache 2.0 License
HELP
end
Expand All @@ -222,11 +232,12 @@ def main
raise _("missing argument: --target is required when using --apply") if options[:target].nil?
raise _("%{file} does not exist, cannot apply") % { file: options[:apply] } unless File.file?(options[:apply])
end
libdir = Puppet[:libdir]
vardir = Puppet[:vardir]
confdir = Puppet[:confdir]
certname = Puppet[:certname]

env = Puppet.lookup(:environments).get(Puppet[:environment])
env = Puppet::Node::Environment.remote(Puppet[:environment])
returns = Puppet.override(:current_environment => env, :loaders => Puppet::Pops::Loaders.new(env)) do
# find device list
require 'puppet/util/network_device/config'
Expand All @@ -251,9 +262,13 @@ def main

# override local $vardir and $certname
Puppet[:confdir] = ::File.join(Puppet[:devicedir], device.name)
Puppet[:libdir] = options[:libdir] || ::File.join(Puppet[:devicedir], device.name, 'lib')
Puppet[:vardir] = ::File.join(Puppet[:devicedir], device.name)
Puppet[:certname] = device.name

unless options[:resource] || options[:facts] || options[:apply] || options[:libdir]
Puppet::Configurer::PluginHandler.new.download_plugins(env)
end
# this init the device singleton, so that the facts terminus
# and the various network_device provider can use it
Puppet::Util::NetworkDevice.init(device)
Expand Down Expand Up @@ -309,13 +324,14 @@ def main

require 'puppet/configurer'
configurer = Puppet::Configurer.new
configurer.run(:network_device => true, :pluginsync => Puppet::Configurer.should_pluginsync?)
configurer.run(:network_device => true, :pluginsync => Puppet::Configurer.should_pluginsync? && !options[:libdir])
end
rescue => detail
Puppet.log_exception(detail)
# If we rescued an error, then we return 1 as the exit code
1
ensure
Puppet[:libdir] = libdir
Puppet[:vardir] = vardir
Puppet[:confdir] = confdir
Puppet[:certname] = certname
Expand Down
5 changes: 2 additions & 3 deletions lib/puppet/util/command_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def initialize(subcommand_name, command_line)
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, we only want to load pluginsync'ed code from libdir.
# For agent and device, 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
Expand All @@ -116,8 +116,7 @@ def run
# 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.
#
if @subcommand_name != 'master' and @subcommand_name != 'agent'
unless ['master', 'agent', 'device'].include? @subcommand_name
if configured_environment = Puppet.lookup(:environments).get(Puppet[:environment])
configured_environment.each_plugin_directory do |dir|
$LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
Expand Down
5 changes: 4 additions & 1 deletion spec/unit/application/device_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@
@device.options.stubs(:[]).with(:facts).returns(false)
@device.options.stubs(:[]).with(:resource).returns(false)
@device.options.stubs(:[]).with(:to_yaml).returns(false)
@device.options.stubs(:[]).with(:libdir).returns(nil)
@device.options.stubs(:[]).with(:client)
@device.command_line.stubs(:args).returns([])
Puppet::Util::NetworkDevice::Config.stubs(:devices).returns({})
Expand Down Expand Up @@ -504,7 +505,9 @@
expect { @device.main }.to exit_with 1
end

it "should print the device url scheme, host, and port" do
it "should retrieve plugins and print the device url scheme, host, and port" do
Puppet.stubs(:info)
Puppet.expects(:info).with "Retrieving pluginfacts"
Puppet.expects(:info).with "starting applying configuration to device1 at ssh://testhost"
Puppet.expects(:info).with "starting applying configuration to device2 at https://testhost:443/some/path"
expect { @device.main }.to exit_with 1
Expand Down