puppet 4.10.9 → 4.10.10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/lib/puppet/agent.rb +22 -2
  3. data/lib/puppet/application.rb +18 -1
  4. data/lib/puppet/application/agent.rb +9 -2
  5. data/lib/puppet/application/apply.rb +1 -1
  6. data/lib/puppet/application/config.rb +1 -0
  7. data/lib/puppet/application/device.rb +1 -2
  8. data/lib/puppet/application/filebucket.rb +22 -5
  9. data/lib/puppet/application/help.rb +1 -0
  10. data/lib/puppet/application/inspect.rb +2 -0
  11. data/lib/puppet/application/lookup.rb +1 -3
  12. data/lib/puppet/application_support.rb +6 -1
  13. data/lib/puppet/defaults.rb +33 -4
  14. data/lib/puppet/face/config.rb +13 -0
  15. data/lib/puppet/functions/each.rb +10 -4
  16. data/lib/puppet/functions/lookup.rb +2 -2
  17. data/lib/puppet/functions/map.rb +12 -2
  18. data/lib/puppet/functions/reduce.rb +45 -2
  19. data/lib/puppet/interface.rb +1 -0
  20. data/lib/puppet/module_tool/tar/mini.rb +57 -4
  21. data/lib/puppet/network/http/factory.rb +9 -0
  22. data/lib/puppet/network/http/webrick.rb +1 -3
  23. data/lib/puppet/node.rb +10 -0
  24. data/lib/puppet/node/facts.rb +9 -0
  25. data/lib/puppet/parser/functions/sprintf.rb +17 -3
  26. data/lib/puppet/pops/loader/static_loader.rb +2 -2
  27. data/lib/puppet/pops/lookup/hiera_config.rb +2 -2
  28. data/lib/puppet/pops/merge_strategy.rb +16 -1
  29. data/lib/puppet/pops/types/iterable.rb +2 -0
  30. data/lib/puppet/pops/types/type_factory.rb +1 -1
  31. data/lib/puppet/pops/types/type_mismatch_describer.rb +15 -5
  32. data/lib/puppet/pops/types/types.rb +4 -2
  33. data/lib/puppet/provider/service/smf.rb +2 -2
  34. data/lib/puppet/provider/service/systemd.rb +1 -0
  35. data/lib/puppet/provider/service/upstart.rb +1 -1
  36. data/lib/puppet/settings/environment_conf.rb +10 -2
  37. data/lib/puppet/transaction.rb +3 -0
  38. data/lib/puppet/transaction/report.rb +8 -1
  39. data/lib/puppet/type.rb +1 -9
  40. data/lib/puppet/type/user.rb +9 -3
  41. data/lib/puppet/util/http_proxy.rb +14 -6
  42. data/lib/puppet/version.rb +1 -1
  43. data/locales/puppet.pot +29 -13
  44. data/man/man5/puppet.conf.5 +276 -55
  45. data/man/man8/extlookup2hiera.8 +2 -2
  46. data/man/man8/puppet-agent.8 +32 -10
  47. data/man/man8/puppet-apply.8 +21 -6
  48. data/man/man8/puppet-ca.8 +48 -34
  49. data/man/man8/puppet-catalog.8 +4 -4
  50. data/man/man8/puppet-cert.8 +23 -6
  51. data/man/man8/puppet-certificate.8 +44 -28
  52. data/man/man8/puppet-certificate_request.8 +4 -4
  53. data/man/man8/puppet-certificate_revocation_list.8 +4 -4
  54. data/man/man8/puppet-config.8 +5 -5
  55. data/man/man8/puppet-describe.8 +3 -3
  56. data/man/man8/puppet-device.8 +23 -13
  57. data/man/man8/puppet-doc.8 +5 -5
  58. data/man/man8/puppet-epp.8 +16 -10
  59. data/man/man8/puppet-facts.8 +4 -4
  60. data/man/man8/puppet-file.8 +4 -4
  61. data/man/man8/puppet-filebucket.8 +63 -6
  62. data/man/man8/puppet-generate.8 +84 -0
  63. data/man/man8/puppet-help.8 +4 -4
  64. data/man/man8/puppet-inspect.8 +8 -5
  65. data/man/man8/puppet-key.8 +4 -4
  66. data/man/man8/puppet-lookup.8 +87 -0
  67. data/man/man8/puppet-man.8 +5 -5
  68. data/man/man8/puppet-master.8 +5 -5
  69. data/man/man8/puppet-module.8 +22 -13
  70. data/man/man8/puppet-node.8 +4 -4
  71. data/man/man8/puppet-parser.8 +4 -4
  72. data/man/man8/puppet-plugin.8 +4 -4
  73. data/man/man8/puppet-report.8 +4 -4
  74. data/man/man8/puppet-resource.8 +4 -8
  75. data/man/man8/puppet-resource_type.8 +4 -4
  76. data/man/man8/puppet-status.8 +5 -5
  77. data/man/man8/puppet.8 +12 -3
  78. data/spec/fixtures/unit/application/environments/production/data/common.yaml +2 -0
  79. data/spec/integration/agent/logging_spec.rb +2 -0
  80. data/spec/integration/provider/cron/crontab_spec.rb +1 -0
  81. data/spec/unit/agent_spec.rb +33 -0
  82. data/spec/unit/application/config_spec.rb +4 -0
  83. data/spec/unit/application/inspect_spec.rb +11 -0
  84. data/spec/unit/application/lookup_spec.rb +30 -0
  85. data/spec/unit/application_spec.rb +18 -0
  86. data/spec/unit/environments_spec.rb +15 -0
  87. data/spec/unit/face/config_spec.rb +1 -2
  88. data/spec/unit/functions/break_spec.rb +108 -49
  89. data/spec/unit/functions/defined_spec.rb +2 -2
  90. data/spec/unit/functions/lookup_spec.rb +88 -3
  91. data/spec/unit/interface_spec.rb +12 -0
  92. data/spec/unit/module_tool/tar/mini_spec.rb +34 -5
  93. data/spec/unit/network/http/factory_spec.rb +22 -0
  94. data/spec/unit/network/http/webrick_spec.rb +30 -29
  95. data/spec/unit/parser/functions/sprintf_spec.rb +26 -0
  96. data/spec/unit/pops/loaders/static_loader_spec.rb +1 -1
  97. data/spec/unit/pops/types/type_calculator_spec.rb +21 -0
  98. data/spec/unit/pops/types/type_mismatch_describer_spec.rb +9 -0
  99. data/spec/unit/provider/service/smf_spec.rb +2 -4
  100. data/spec/unit/provider/service/systemd_spec.rb +14 -0
  101. data/spec/unit/resource/catalog_spec.rb +10 -0
  102. data/spec/unit/transaction/report_spec.rb +19 -0
  103. data/spec/unit/util/http_proxy_spec.rb +37 -0
  104. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1c19dcf24ffdd82dc67550cce341c1ab7a7eb101
4
- data.tar.gz: 7a0d6ea9246d361cbce8c3a317695bbbd3259a11
3
+ metadata.gz: c3f34ce4e9d4760a2970bc95c8c1c36ab05ea177
4
+ data.tar.gz: bfd8fecb20234127dcab39cc295567e8b02670a3
5
5
  SHA512:
6
- metadata.gz: 2414fbc5362e40b5363ae062036ca6ce77865362e11a85291e8e300f35ce34bbe767a3f170db8cbe93445c3af4d349d0be986eca1232099ba0271df75d9e792b
7
- data.tar.gz: e269546a3c53346b599e9d98217cb147b856ae57cd11fedde16cbfe71a93e3db243c53cde6b4f6e4a3ad3354eeb3e4f6cc43b234373a2245210871bbc953d68c
6
+ metadata.gz: 1a20d44ad5b9b2e4e7ce78ad0c408d93b2784879f535d666fab61dc34eb5f614c975014f558f05033e081a957f37abaadbb60a128fb5912ca6b69be7b724a8a3
7
+ data.tar.gz: 884979cbd607689c175759362aab573fc1bbc02f0d7bd78f6c3d975eeb93dd883bca614fa476628455b6123860dceb47ddc2039ca8dbb717ecff83e3fd87c15f
@@ -1,6 +1,8 @@
1
1
  require 'puppet/application'
2
2
  require 'puppet/error'
3
3
 
4
+ require 'timeout'
5
+
4
6
  # A general class for triggering a run of another
5
7
  # class.
6
8
  class Puppet::Agent
@@ -13,6 +15,10 @@ class Puppet::Agent
13
15
  require 'puppet/util/splayer'
14
16
  include Puppet::Util::Splayer
15
17
 
18
+ # Special exception class used to signal an agent run has timed out.
19
+ class RunTimeoutError < Exception
20
+ end
21
+
16
22
  attr_reader :client_class, :client, :should_fork
17
23
 
18
24
  def initialize(client_class, should_fork=true)
@@ -40,12 +46,26 @@ class Puppet::Agent
40
46
  splay client_options.fetch :splay, Puppet[:splay]
41
47
  result = run_in_fork(should_fork) do
42
48
  with_client(client_options[:transaction_uuid]) do |client|
49
+ client_args = client_options.merge(:pluginsync => Puppet::Configurer.should_pluginsync?)
43
50
  begin
44
- client_args = client_options.merge(:pluginsync => Puppet::Configurer.should_pluginsync?)
45
- lock { client.run(client_args) }
51
+ lock do
52
+ # NOTE: Timeout is pretty heinous as the location in which it
53
+ # throws an error is entirely unpredictable, which means that
54
+ # it can interrupt code blocks that perform cleanup or enforce
55
+ # sanity. The only thing a Puppet agent should do after this
56
+ # error is thrown is die with as much dignity as possible.
57
+ Timeout.timeout(Puppet[:runtimeout], RunTimeoutError) do
58
+ client.run(client_args)
59
+ end
60
+ end
46
61
  rescue Puppet::LockError
47
62
  Puppet.notice "Run of #{client_class} already in progress; skipping (#{lockfile_path} exists)"
48
63
  return
64
+ rescue RunTimeoutError => detail
65
+ Puppet.log_exception(detail, _("Execution of %{client_class} did not complete within %{runtimeout} seconds and was terminated.") %
66
+ {client_class: client_class,
67
+ runtimeout: Puppet[:runtimeout]})
68
+ return 1
49
69
  rescue StandardError => detail
50
70
  Puppet.log_exception(detail, "Could not run #{client_class}: #{detail}")
51
71
  end
@@ -281,6 +281,23 @@ class Application
281
281
  @run_mode = Puppet::Util::RunMode[ mode_name || Puppet.settings.preferred_run_mode ]
282
282
  end
283
283
 
284
+ # Sets environment_mode name
285
+ # @param mode_name [Symbol] The name of the environment mode to run in. May
286
+ # be one of :local, :remote, or :not_required. This impacts where the
287
+ # application looks for its specified environment. If :not_required or
288
+ # :remote are set, the application will not fail if the environment does
289
+ # not exist on the local filesystem.
290
+ def environment_mode(mode_name)
291
+ raise Puppet::Error, _("Invalid environment mode '%{mode_name}'") % { mode_name: mode_name } unless [:local, :remote, :not_required].include?(mode_name)
292
+ @environment_mode = mode_name
293
+ end
294
+
295
+ # Gets environment_mode name. If none is set with `environment_mode=`,
296
+ # default to :local.
297
+ def get_environment_mode
298
+ @environment_mode || :local
299
+ end
300
+
284
301
  # This is for testing only
285
302
  def clear_everything_for_tests
286
303
  @run_mode = @banner = @run_status = @option_parser_commands = nil
@@ -343,7 +360,7 @@ class Application
343
360
  initialize_app_defaults
344
361
  end
345
362
 
346
- Puppet::ApplicationSupport.push_application_context(self.class.run_mode)
363
+ Puppet::ApplicationSupport.push_application_context(self.class.run_mode, self.class.get_environment_mode)
347
364
 
348
365
  exit_on_fail("initialize") { preinit }
349
366
  exit_on_fail("parse application options") { parse_options }
@@ -38,6 +38,7 @@ class Puppet::Application::Agent < Puppet::Application
38
38
  :digest => 'SHA256',
39
39
  :graph => true,
40
40
  :fingerprint => false,
41
+ :sourceaddress => nil,
41
42
  }.each do |opt,val|
42
43
  options[opt] = val
43
44
  end
@@ -59,6 +60,8 @@ class Puppet::Application::Agent < Puppet::Application
59
60
  option("--fingerprint")
60
61
  option("--digest DIGEST")
61
62
 
63
+ option("--sourceaddress IP_ADDRESS")
64
+
62
65
  option("--detailed-exitcodes") do |arg|
63
66
  options[:detailed_exitcodes] = true
64
67
  end
@@ -90,8 +93,8 @@ USAGE
90
93
  -----
91
94
  puppet agent [--certname <NAME>] [-D|--daemonize|--no-daemonize]
92
95
  [-d|--debug] [--detailed-exitcodes] [--digest <DIGEST>] [--disable [MESSAGE]] [--enable]
93
- [--fingerprint] [-h|--help] [-l|--logdest syslog|eventlog|<FILE>|console]
94
- [--masterport <PORT>] [--noop] [-o|--onetime] [-t|--test]
96
+ [--fingerprint] [-h|--help] [-l|--logdest syslog|eventlog|<ABS FILEPATH>|console]
97
+ [--masterport <PORT>] [--noop] [-o|--onetime] [--sourceaddress <IP_ADDRESS>] [-t|--test]
95
98
  [-v|--verbose] [-V|--version] [-w|--waitforcert <SECONDS>]
96
99
 
97
100
 
@@ -261,6 +264,10 @@ generated by running puppet agent with '--genconfig'.
261
264
  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
262
265
  prefix for boolean settings on the command line.)
263
266
 
267
+ * --sourceaddress:
268
+ Set the source IP address for transactions. This defaults to automatically selected.
269
+ (This is a Puppet setting, and can go in puppet.conf.)
270
+
264
271
  * --test:
265
272
  Enable the most common options used for testing. These are 'onetime',
266
273
  'verbose', 'no-daemonize', 'no-usecacheonfailure', 'detailed-exitcodes',
@@ -46,7 +46,7 @@ USAGE
46
46
  -----
47
47
  puppet apply [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
48
48
  [-e|--execute] [--detailed-exitcodes] [-L|--loadclasses]
49
- [-l|--logdest syslog|eventlog|<FILE>|console] [--noop]
49
+ [-l|--logdest syslog|eventlog|<ABS FILEPATH>|console] [--noop]
50
50
  [--catalog <catalog>] [--write-catalog-summary] <file>
51
51
 
52
52
 
@@ -1,4 +1,5 @@
1
1
  require 'puppet/application/face_base'
2
2
 
3
3
  class Puppet::Application::Config < Puppet::Application::FaceBase
4
+ environment_mode :not_required
4
5
  end
@@ -138,8 +138,7 @@ you can specify '--server <servername>' as an argument.
138
138
  valid JSON.
139
139
 
140
140
  * --user:
141
- The user to run as. '--user=root' is required, even when run as root,
142
- for runs that create device certificates or keys.
141
+ The user to run as.
143
142
 
144
143
  * --verbose:
145
144
  Turn on verbose reporting.
@@ -107,38 +107,55 @@ configuration options can also be generated by running puppet with
107
107
  * --version:
108
108
  Print version information.
109
109
 
110
-
111
- EXAMPLE
112
- -------
110
+ EXAMPLES
111
+ --------
112
+ ## Backup a file to the filebucket, then restore it to a temporary directory
113
113
  $ puppet filebucket backup /etc/passwd
114
114
  /etc/passwd: 429b225650b912a2ee067b0a4cf1e949
115
115
  $ puppet filebucket restore /tmp/passwd 429b225650b912a2ee067b0a4cf1e949
116
+
116
117
  ## Diff between two files in the filebucket
117
118
  $ puppet filebucket -l diff d43a6ecaa892a1962398ac9170ea9bf2 7ae322f5791217e031dc60188f4521ef
118
119
  1a2
119
120
  > again
120
- ## Diff between the file in the filebucket and the current one
121
+
122
+ ## Diff between the file in the filebucket and a local file
121
123
  $ puppet filebucket -l diff d43a6ecaa892a1962398ac9170ea9bf2 /tmp/testFile
122
124
  1a2
123
125
  > again
126
+
127
+ ## Backup a file to the filebucket and observe that it keeps each backup separate
124
128
  $ puppet filebucket -l list
125
129
  d43a6ecaa892a1962398ac9170ea9bf2 2015-05-11 09:27:56 /tmp/TestFile
130
+
126
131
  $ echo again >> /tmp/TestFile
132
+
127
133
  $ puppet filebucket -l backup /tmp/TestFile
128
134
  /tmp/TestFile: 7ae322f5791217e031dc60188f4521ef
129
- $ puppet filebucket -l list
135
+
136
+ $ puppet filebucket -l list
130
137
  d43a6ecaa892a1962398ac9170ea9bf2 2015-05-11 09:27:56 /tmp/TestFile
131
138
  7ae322f5791217e031dc60188f4521ef 2015-05-11 09:52:15 /tmp/TestFile
139
+
140
+ ## List files in a filebucket within date ranges
132
141
  $ puppet filebucket -l -f 2015-01-01 -t 2015-01-11 list
133
142
  <Empty Output>
143
+
134
144
  $ puppet filebucket -l -f 2015-05-10 list
135
145
  d43a6ecaa892a1962398ac9170ea9bf2 2015-05-11 09:27:56 /tmp/TestFile
136
146
  7ae322f5791217e031dc60188f4521ef 2015-05-11 09:52:15 /tmp/TestFile
147
+
137
148
  $ puppet filebucket -l -f "2015-05-11 09:30:00" list
138
149
  7ae322f5791217e031dc60188f4521ef 2015-05-11 09:52:15 /tmp/TestFile
150
+
139
151
  $ puppet filebucket -l -t "2015-05-11 09:30:00" list
140
152
  d43a6ecaa892a1962398ac9170ea9bf2 2015-05-11 09:27:56 /tmp/TestFile
141
153
 
154
+ ## From a Puppet master, list files in the master bucketdir
155
+ $ puppet filebucket -b $(puppet config print bucketdir --section master) list
156
+ d43a6ecaa892a1962398ac9170ea9bf2 2015-05-11 09:27:56 /tmp/TestFile
157
+ 7ae322f5791217e031dc60188f4521ef 2015-05-11 09:52:15 /tmp/TestFile
158
+
142
159
  AUTHOR
143
160
  ------
144
161
  Luke Kanies
@@ -1,4 +1,5 @@
1
1
  require 'puppet/application/face_base'
2
2
 
3
3
  class Puppet::Application::Help < Puppet::Application::FaceBase
4
+ environment_mode :not_required
4
5
  end
@@ -170,6 +170,8 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
170
170
 
171
171
  finishtime = Time.now
172
172
  @report.add_times("inspect", finishtime - inspect_starttime)
173
+
174
+ @report.transaction_completed = true
173
175
  @report.finalize_report
174
176
 
175
177
  begin
@@ -323,7 +323,6 @@ Copyright (c) 2015 Puppet Inc., LLC Licensed under the Apache 2.0 License
323
323
  fact_file = options[:fact_file]
324
324
 
325
325
  if fact_file
326
- original_facts = node.parameters
327
326
  if fact_file.end_with?("json")
328
327
  given_facts = JSON.parse(Puppet::FileSystem.read(fact_file, :encoding => 'utf-8'))
329
328
  else
@@ -333,8 +332,7 @@ Copyright (c) 2015 Puppet Inc., LLC Licensed under the Apache 2.0 License
333
332
  unless given_facts.instance_of?(Hash)
334
333
  raise "Incorrect formatted data in #{fact_file} given via the --facts flag"
335
334
  end
336
-
337
- node.parameters = original_facts.merge(given_facts)
335
+ node.add_extra_facts(given_facts)
338
336
  end
339
337
 
340
338
  Puppet[:code] = 'undef' unless options[:compile]
@@ -14,9 +14,11 @@ module Puppet
14
14
  # before being set in a pushed Puppet Context.
15
15
  #
16
16
  # @param run_mode [Puppet::Util::RunMode] Puppet's current Run Mode.
17
+ # @param environment_mode [Symbol] optional, Puppet's
18
+ # current Environment Mode. Defaults to :local
17
19
  # @return [void]
18
20
  # @api private
19
- def self.push_application_context(run_mode)
21
+ def self.push_application_context(run_mode, environment_mode = :local)
20
22
  Puppet.push_context(Puppet.base_context(Puppet.settings), "Update for application settings (#{run_mode})")
21
23
  # This use of configured environment is correct, this is used to establish
22
24
  # the defaults for an application that does not override, or where an override
@@ -25,6 +27,9 @@ module Puppet
25
27
  configured_environment_name = Puppet[:environment]
26
28
  if run_mode.name == :agent
27
29
  configured_environment = Puppet::Node::Environment.remote(configured_environment_name)
30
+ elsif environment_mode == :not_required
31
+ configured_environment =
32
+ Puppet.lookup(:environments).get(configured_environment_name) || Puppet::Node::Environment.remote(configured_environment_name)
28
33
  else
29
34
  configured_environment = Puppet.lookup(:environments).get!(configured_environment_name)
30
35
  end
@@ -296,10 +296,26 @@ module Puppet
296
296
  },
297
297
  :environment => {
298
298
  :default => "production",
299
- :desc => "The environment Puppet is running in. For clients
300
- (e.g., `puppet agent`) this determines the environment itself, which
301
- is used to find modules and much more. For servers (i.e., `puppet master`)
302
- this provides the default environment for nodes we know nothing about."
299
+ :desc => "The environment in which Puppet is running. For clients,
300
+ such as `puppet agent`, this determines the environment itself, which
301
+ Puppet uses to find modules and much more. For servers, such as `puppet master`,
302
+ this provides the default environment for nodes that Puppet knows nothing about.
303
+
304
+ When defining an environment in the `[agent]` section, this refers to the
305
+ environment that the agent requests from the master. The environment doesn't
306
+ have to exist on the local filesystem because the agent fetches it from the
307
+ master. This definition is used when running `puppet agent`.
308
+
309
+ When defined in the `[user]` section, the environment refers to the path that
310
+ Puppet uses to search for code and modules related to its execution. This
311
+ requires the environment to exist locally on the filesystem where puppet is
312
+ being executed. Puppet subcommands, including `puppet module` and
313
+ `puppet apply`, use this definition.
314
+
315
+ Given that the context and effects vary depending on the
316
+ [config section](https://puppet.com/docs/puppet/latest/config_file_main.html#config-sections)
317
+ in which the `environment` setting is defined, do not set it globally.",
318
+ :short => "E"
303
319
  },
304
320
  :environmentpath => {
305
321
  :default => "$codedir/environments",
@@ -1102,6 +1118,10 @@ EOT
1102
1118
  and monitoring systems to determine if a puppet process is still in
1103
1119
  the process table.",
1104
1120
  },
1121
+ :sourceaddress => {
1122
+ :default => nil,
1123
+ :desc => "The address the agent should use to initiate requests.",
1124
+ },
1105
1125
  :bindaddress => {
1106
1126
  :default => "0.0.0.0",
1107
1127
  :desc => "The address a listening server should bind to.",
@@ -1352,6 +1372,8 @@ EOT
1352
1372
  :default => "$vardir/devices",
1353
1373
  :type => :directory,
1354
1374
  :mode => "0750",
1375
+ :owner => "service",
1376
+ :group => "service",
1355
1377
  :desc => "The root directory of devices' $vardir.",
1356
1378
  },
1357
1379
  :deviceconfig => {
@@ -1521,6 +1543,13 @@ EOT
1521
1543
  \"never run.\" If you want puppet agent to never run, you should start
1522
1544
  it with the `--no-client` option. #{AS_DURATION}",
1523
1545
  },
1546
+ :runtimeout => {
1547
+ :default => 0,
1548
+ :type => :duration,
1549
+ :desc => "The maximum amount of time an agent run is allowed to take.
1550
+ A Puppet agent run that exceeds this timeout will be aborted.
1551
+ Defaults to 0, which is unlimited. #{AS_DURATION}",
1552
+ },
1524
1553
  :ca_server => {
1525
1554
  :default => "$server",
1526
1555
  :desc => "The server to use for certificate
@@ -106,6 +106,19 @@ Puppet::Face.define(:config, '0.0.1') do
106
106
  EOT
107
107
 
108
108
  when_invoked do |name, value, options|
109
+ if name == 'environment' && options[:section] == 'main'
110
+ Puppet.warning _(<<-EOM).chomp
111
+ The environment should be set in either the `[user]`, `[agent]`, or `[master]`
112
+ section. Variables set in the `[agent]` section are used when running
113
+ `puppet agent`. Variables set in the `[user]` section are used when running
114
+ various other puppet subcommands, like `puppet apply` and `puppet module`; these
115
+ require the defined environment directory to exist locally. Set the config
116
+ section by using the `--section` flag. For example,
117
+ `puppet config --section user set environment foo`. For more information, see
118
+ https://puppet.com/docs/puppet/latest/configuration.html#environment
119
+ EOM
120
+ end
121
+
109
122
  path = Puppet::FileSystem.pathname(Puppet.settings.which_configuration_file)
110
123
  Puppet::FileSystem.touch(path)
111
124
  Puppet::FileSystem.open(path, nil, 'r+:UTF-8') do |file|
@@ -117,8 +117,11 @@ Puppet::Functions.create_function(:each) do
117
117
 
118
118
  def foreach_Hash_1(hash)
119
119
  enumerator = hash.each_pair
120
- hash.size.times do
121
- yield(enumerator.next)
120
+ begin
121
+ hash.size.times do
122
+ yield(enumerator.next)
123
+ end
124
+ rescue StopIteration
122
125
  end
123
126
  # produces the receiver
124
127
  hash
@@ -126,8 +129,11 @@ Puppet::Functions.create_function(:each) do
126
129
 
127
130
  def foreach_Hash_2(hash)
128
131
  enumerator = hash.each_pair
129
- hash.size.times do
130
- yield(*enumerator.next)
132
+ begin
133
+ hash.size.times do
134
+ yield(*enumerator.next)
135
+ end
136
+ rescue StopIteration
131
137
  end
132
138
  # produces the receiver
133
139
  hash
@@ -91,8 +91,8 @@
91
91
  # merged hash. If the same key exists in multiple source hashes, Puppet will
92
92
  # recursively merge hash or array values (with duplicate values removed from
93
93
  # arrays). For conflicting scalar values, the highest-priority value will win.
94
- # * `{'strategy' => 'first|unique|hash'}` --- Same as the string versions of these
95
- # merge behaviors.
94
+ # * `{'strategy' => 'first'}`, `{'strategy' => 'unique'}`,
95
+ # or `{'strategy' => 'hash'}` --- Same as the string versions of these merge behaviors.
96
96
  # * `{'strategy' => 'deep', <DEEP OPTION> => <VALUE>, ...}` --- Same as `'deep'`,
97
97
  # but can adjust the merge with additional options. The available options are:
98
98
  # * `'knockout_prefix'` (string or undef) --- A string prefix to indicate a
@@ -88,11 +88,21 @@ Puppet::Functions.create_function(:map) do
88
88
  end
89
89
 
90
90
  def map_Hash_1(hash)
91
- hash.map {|x, y| yield([x, y]) }
91
+ result = []
92
+ begin
93
+ hash.map {|x, y| result << yield([x, y]) }
94
+ rescue StopIteration
95
+ end
96
+ result
92
97
  end
93
98
 
94
99
  def map_Hash_2(hash)
95
- hash.map {|x, y| yield(x, y) }
100
+ result = []
101
+ begin
102
+ hash.map {|x, y| result << yield(x, y) }
103
+ rescue StopIteration
104
+ end
105
+ result
96
106
  end
97
107
 
98
108
  def map_Enumerable_1(enumerable)
@@ -94,6 +94,37 @@
94
94
  # # $combine contains [dabc, 10]
95
95
  # ~~~
96
96
  #
97
+ # @example Using the `reduce` function to reduce a hash of hashes
98
+ #
99
+ # ~~~ puppet
100
+ # # Reduce a hash of hashes $data, merging defaults into the inner hashes.
101
+ # $data = {
102
+ # 'connection1' => {
103
+ # 'username' => 'user1',
104
+ # 'password' => 'pass1',
105
+ # },
106
+ # 'connection_name2' => {
107
+ # 'username' => 'user2',
108
+ # 'password' => 'pass2',
109
+ # },
110
+ # }
111
+ #
112
+ # $defaults = {
113
+ # 'maxActive' => '20',
114
+ # 'maxWait' => '10000',
115
+ # 'username' => 'defaultuser',
116
+ # 'password' => 'defaultpass',
117
+ # }
118
+ #
119
+ # $merged = $data.reduce( {} ) |$memo, $x| {
120
+ # $memo + { $x[0] => $defaults + $data[$x[0]] }
121
+ # }
122
+ # # At the start of the lambda's first iteration, $memo is set to {}, and $x is set to
123
+ # # the first [key, value] tuple. The key in $data is, therefore, given by $x[0]. In
124
+ # # subsequent rounds, $memo retains the value returned by the expression, i.e.
125
+ # # $memo + { $x[0] => $defaults + $data[$x[0]] }.
126
+ # ~~~
127
+ #
97
128
  # @since 4.0.0
98
129
  #
99
130
  Puppet::Functions.create_function(:reduce) do
@@ -111,11 +142,23 @@ Puppet::Functions.create_function(:reduce) do
111
142
 
112
143
  def reduce_without_memo(enumerable)
113
144
  enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable)
114
- enum.reduce {|memo, x| yield(memo, x) }
145
+ enum.reduce do |memo, x|
146
+ begin
147
+ yield(memo, x)
148
+ rescue StopIteration
149
+ return memo
150
+ end
151
+ end
115
152
  end
116
153
 
117
154
  def reduce_with_memo(enumerable, given_memo)
118
155
  enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable)
119
- enum.reduce(given_memo) {|memo, x| yield(memo, x) }
156
+ enum.reduce(given_memo) do |memo, x|
157
+ begin
158
+ yield(memo, x)
159
+ rescue StopIteration
160
+ return memo
161
+ end
162
+ end
120
163
  end
121
164
  end