puppet 6.11.1 → 6.12.0

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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +1 -1
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +16 -16
  5. data/README.md +1 -1
  6. data/ext/build_defaults.yaml +1 -0
  7. data/ext/windows/service/daemon.rb +22 -17
  8. data/lib/puppet/concurrent.rb +2 -0
  9. data/lib/puppet/concurrent/lock.rb +16 -0
  10. data/lib/puppet/concurrent/synchronized.rb +15 -0
  11. data/lib/puppet/concurrent/thread_local_singleton.rb +14 -0
  12. data/lib/puppet/configurer.rb +45 -31
  13. data/lib/puppet/defaults.rb +42 -3
  14. data/lib/puppet/environments.rb +3 -0
  15. data/lib/puppet/error.rb +9 -1
  16. data/lib/puppet/forge.rb +3 -3
  17. data/lib/puppet/forge/errors.rb +2 -2
  18. data/lib/puppet/forge/repository.rb +30 -86
  19. data/lib/puppet/functions/camelcase.rb +2 -2
  20. data/lib/puppet/functions/epp.rb +4 -4
  21. data/lib/puppet/functions/find_file.rb +9 -9
  22. data/lib/puppet/functions/find_template.rb +63 -0
  23. data/lib/puppet/functions/inline_epp.rb +5 -5
  24. data/lib/puppet/http.rb +2 -0
  25. data/lib/puppet/http/client.rb +89 -17
  26. data/lib/puppet/http/resolver.rb +14 -1
  27. data/lib/puppet/http/resolver/server_list.rb +38 -0
  28. data/lib/puppet/http/resolver/settings.rb +3 -2
  29. data/lib/puppet/http/resolver/srv.rb +10 -4
  30. data/lib/puppet/http/service.rb +32 -0
  31. data/lib/puppet/http/service/ca.rb +11 -10
  32. data/lib/puppet/http/service/report.rb +40 -0
  33. data/lib/puppet/http/session.rb +11 -32
  34. data/lib/puppet/network/http/base_pool.rb +13 -0
  35. data/lib/puppet/node/environment.rb +13 -7
  36. data/lib/puppet/pal/pal_impl.rb +5 -0
  37. data/lib/puppet/parser/functions/epp.rb +3 -3
  38. data/lib/puppet/parser/functions/inline_epp.rb +5 -5
  39. data/lib/puppet/pops/evaluator/runtime3_support.rb +1 -1
  40. data/lib/puppet/pops/lookup/invocation.rb +10 -3
  41. data/lib/puppet/pops/model/pn_transformer.rb +5 -9
  42. data/lib/puppet/pops/parser/evaluating_parser.rb +3 -4
  43. data/lib/puppet/pops/serialization/json_path.rb +3 -3
  44. data/lib/puppet/pops/time/timespan.rb +3 -5
  45. data/lib/puppet/pops/types/string_converter.rb +6 -9
  46. data/lib/puppet/pops/types/type_calculator.rb +6 -10
  47. data/lib/puppet/pops/types/type_formatter.rb +9 -11
  48. data/lib/puppet/pops/types/type_parser.rb +3 -3
  49. data/lib/puppet/provider/package/portage.rb +3 -3
  50. data/lib/puppet/provider/package_targetable.rb +5 -4
  51. data/lib/puppet/provider/service/systemd.rb +1 -1
  52. data/lib/puppet/provider/user/hpux.rb +1 -1
  53. data/lib/puppet/runtime.rb +1 -0
  54. data/lib/puppet/ssl/ssl_provider.rb +20 -0
  55. data/lib/puppet/transaction.rb +33 -11
  56. data/lib/puppet/type.rb +1 -1
  57. data/lib/puppet/type/file/data_sync.rb +5 -1
  58. data/lib/puppet/type/group.rb +3 -2
  59. data/lib/puppet/type/user.rb +3 -2
  60. data/lib/puppet/util.rb +34 -11
  61. data/lib/puppet/util/logging.rb +30 -18
  62. data/lib/puppet/util/windows/adsi.rb +48 -18
  63. data/lib/puppet/version.rb +1 -1
  64. data/lib/puppet/x509/cert_provider.rb +9 -5
  65. data/locales/puppet.pot +155 -141
  66. data/man/man5/puppet.conf.5 +33 -3
  67. data/man/man8/puppet-agent.8 +1 -1
  68. data/man/man8/puppet-apply.8 +1 -1
  69. data/man/man8/puppet-catalog.8 +1 -1
  70. data/man/man8/puppet-config.8 +1 -1
  71. data/man/man8/puppet-describe.8 +1 -1
  72. data/man/man8/puppet-device.8 +1 -1
  73. data/man/man8/puppet-doc.8 +1 -1
  74. data/man/man8/puppet-epp.8 +1 -1
  75. data/man/man8/puppet-facts.8 +1 -1
  76. data/man/man8/puppet-filebucket.8 +1 -1
  77. data/man/man8/puppet-generate.8 +1 -1
  78. data/man/man8/puppet-help.8 +1 -1
  79. data/man/man8/puppet-key.8 +1 -1
  80. data/man/man8/puppet-lookup.8 +1 -1
  81. data/man/man8/puppet-man.8 +1 -1
  82. data/man/man8/puppet-module.8 +1 -1
  83. data/man/man8/puppet-node.8 +1 -1
  84. data/man/man8/puppet-parser.8 +1 -1
  85. data/man/man8/puppet-plugin.8 +1 -1
  86. data/man/man8/puppet-report.8 +1 -1
  87. data/man/man8/puppet-resource.8 +1 -1
  88. data/man/man8/puppet-script.8 +1 -1
  89. data/man/man8/puppet-ssl.8 +1 -1
  90. data/man/man8/puppet-status.8 +1 -1
  91. data/man/man8/puppet.8 +2 -2
  92. data/spec/fixtures/unit/forge/bacula.json +76 -0
  93. data/spec/integration/http/client_spec.rb +144 -0
  94. data/spec/integration/module_tool/forge_spec.rb +64 -0
  95. data/spec/lib/puppet_spec/https.rb +5 -3
  96. data/spec/spec_helper.rb +6 -2
  97. data/spec/unit/concurrent/lock_spec.rb +29 -0
  98. data/spec/unit/configurer_spec.rb +394 -399
  99. data/spec/unit/defaults_spec.rb +15 -4
  100. data/spec/unit/forge/errors_spec.rb +1 -1
  101. data/spec/unit/forge/forge_spec.rb +12 -54
  102. data/spec/unit/forge/module_release_spec.rb +19 -6
  103. data/spec/unit/forge/repository_spec.rb +63 -157
  104. data/spec/unit/forge_spec.rb +46 -116
  105. data/spec/unit/functions/find_template_spec.rb +69 -0
  106. data/spec/unit/http/client_spec.rb +138 -6
  107. data/spec/unit/http/resolver_spec.rb +49 -12
  108. data/spec/unit/http/service/ca_spec.rb +56 -5
  109. data/spec/unit/http/service/report_spec.rb +100 -0
  110. data/spec/unit/http/service_spec.rb +20 -0
  111. data/spec/unit/http/session_spec.rb +53 -18
  112. data/spec/unit/network/http/connection_spec.rb +0 -1
  113. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +8 -3
  114. data/spec/unit/provider/package/portage_spec.rb +4 -4
  115. data/spec/unit/provider/package_targetable_spec.rb +60 -0
  116. data/spec/unit/provider/user/hpux_spec.rb +2 -2
  117. data/spec/unit/ssl/ssl_provider_spec.rb +71 -0
  118. data/spec/unit/transaction_spec.rb +46 -0
  119. data/spec/unit/type/file/content_spec.rb +9 -3
  120. data/spec/unit/util/log_spec.rb +0 -138
  121. data/spec/unit/util/logging_spec.rb +200 -0
  122. data/spec/unit/util/windows/adsi_spec.rb +51 -0
  123. data/spec/unit/x509/cert_provider_spec.rb +24 -4
  124. data/tasks/manpages.rake +1 -0
  125. metadata +24 -5
  126. data/spec/lib/puppet_spec/validators.rb +0 -37
@@ -1,5 +1,18 @@
1
1
  class Puppet::HTTP::Resolver
2
- def resolve(session, name, &block)
2
+ def initialize(client)
3
+ @client = client
4
+ end
5
+
6
+ def resolve(session, name, ssl_context: nil)
3
7
  raise NotImplementedError
4
8
  end
9
+
10
+ def check_connection?(session, service, ssl_context: nil)
11
+ service.connect(ssl_context: ssl_context)
12
+ return true
13
+ rescue Puppet::HTTP::ConnectionError => e
14
+ session.add_exception(e)
15
+ Puppet.debug("Connection to #{service.url} failed, trying next route: #{e.message}")
16
+ return false
17
+ end
5
18
  end
@@ -0,0 +1,38 @@
1
+ class Puppet::HTTP::Resolver::ServerList < Puppet::HTTP::Resolver
2
+ def initialize(client, server_list_setting:, default_port:, services: )
3
+ @client = client
4
+ @server_list_setting = server_list_setting
5
+ @default_port = default_port
6
+ @services = services
7
+ end
8
+
9
+ def resolve(session, name, ssl_context: nil)
10
+ if @services.include?(name)
11
+ @server_list_setting.value.each do |server|
12
+ host = server[0]
13
+ port = server[1] || @default_port
14
+ uri = URI("https://#{host}:#{port}/status/v1/simple/master")
15
+ if get_success?(uri, session, ssl_context: ssl_context)
16
+ return Puppet::HTTP::Service.create_service(@client, name, host, port)
17
+ end
18
+ end
19
+ raise Puppet::Error, _("Could not select a functional puppet master from server_list: '%{server_list}'") % { server_list: @server_list_setting.print(@server_list_setting.value) }
20
+ else
21
+ return nil
22
+ end
23
+ end
24
+
25
+ def get_success?(uri, session, ssl_context: nil)
26
+ response = @client.get(uri, ssl_context: ssl_context)
27
+ return true if response.success?
28
+
29
+ Puppet.debug(_("Puppet server %{host}:%{port} is unavailable: %{code} %{reason}") %
30
+ { host: host, port: port, code: response.code, reason: response.message })
31
+ return false
32
+ rescue => detail
33
+ session.add_exception(detail)
34
+ #TRANSLATORS 'server_list' is the name of a setting and should not be translated
35
+ Puppet.debug _("Unable to connect to server from server_list setting: %{detail}") % {detail: detail}
36
+ return false
37
+ end
38
+ end
@@ -1,5 +1,6 @@
1
1
  class Puppet::HTTP::Resolver::Settings < Puppet::HTTP::Resolver
2
- def resolve(session, name, &block)
3
- yield session.create_service(name)
2
+ def resolve(session, name, ssl_context: nil)
3
+ service = Puppet::HTTP::Service.create_service(@client, name)
4
+ check_connection?(session, service, ssl_context: ssl_context) ? service : nil
4
5
  end
5
6
  end
@@ -1,13 +1,19 @@
1
1
  class Puppet::HTTP::Resolver::SRV < Puppet::HTTP::Resolver
2
- def initialize(domain: srv_domain, dns: Resolv::DNS.new)
2
+ def initialize(client, domain:, dns: Resolv::DNS.new)
3
+ @client = client
3
4
  @srv_domain = domain
4
5
  @delegate = Puppet::Network::Resolver.new(dns)
5
6
  end
6
7
 
7
- def resolve(session, name, &block)
8
- # This assumes the route name is the same as the DNS SRV name
8
+ def resolve(session, name, ssl_context: nil)
9
+ # Here we pass our HTTP service name as the DNS SRV service name
10
+ # This is fine for :ca, but note that :puppet and :file are handled
11
+ # specially in `each_srv_record`.
9
12
  @delegate.each_srv_record(@srv_domain, name) do |server, port|
10
- yield session.create_service(name, server, port)
13
+ service = Puppet::HTTP::Service.create_service(@client, name, server, port)
14
+ return service if check_connection?(session, service, ssl_context: ssl_context)
11
15
  end
16
+
17
+ return nil
12
18
  end
13
19
  end
@@ -1,6 +1,23 @@
1
1
  class Puppet::HTTP::Service
2
2
  attr_reader :url
3
3
 
4
+ SERVICE_NAMES = [:ca, :report].freeze
5
+
6
+ def self.create_service(client, name, server = nil, port = nil)
7
+ case name
8
+ when :ca
9
+ Puppet::HTTP::Service::Ca.new(client, server, port)
10
+ when :report
11
+ Puppet::HTTP::Service::Report.new(client, server, port)
12
+ else
13
+ raise ArgumentError, "Unknown service #{name}"
14
+ end
15
+ end
16
+
17
+ def self.valid_name?(name)
18
+ SERVICE_NAMES.include?(name)
19
+ end
20
+
4
21
  def initialize(client, url)
5
22
  @client = client
6
23
  @url = url
@@ -15,4 +32,19 @@ class Puppet::HTTP::Service
15
32
  def connect(ssl_context: nil)
16
33
  @client.connect(@url, ssl_context: ssl_context)
17
34
  end
35
+
36
+ protected
37
+
38
+ def add_puppet_headers(headers)
39
+ modified_headers = headers.dup
40
+ modified_headers['X-Puppet-Profiling'] = 'true' if Puppet[:profile]
41
+ modified_headers
42
+ end
43
+
44
+ def build_url(api, server, port)
45
+ URI::HTTPS.build(host: server,
46
+ port: port,
47
+ path: api
48
+ ).freeze
49
+ end
18
50
  end
@@ -1,10 +1,16 @@
1
1
  class Puppet::HTTP::Service::Ca < Puppet::HTTP::Service
2
2
  HEADERS = { 'Accept' => 'text/plain' }.freeze
3
+ API = '/puppet-ca/v1'.freeze
4
+
5
+ def initialize(client, server, port)
6
+ url = build_url(API, server || Puppet[:ca_server], port || Puppet[:ca_port])
7
+ super(client, url)
8
+ end
3
9
 
4
10
  def get_certificate(name, ssl_context: nil)
5
11
  response = @client.get(
6
12
  with_base_url("/certificate/#{name}"),
7
- headers: HEADERS,
13
+ headers: add_puppet_headers(HEADERS),
8
14
  ssl_context: ssl_context
9
15
  )
10
16
 
@@ -14,17 +20,12 @@ class Puppet::HTTP::Service::Ca < Puppet::HTTP::Service
14
20
  end
15
21
 
16
22
  def get_certificate_revocation_list(if_modified_since: nil, ssl_context: nil)
17
- request_headers = if if_modified_since
18
- h = HEADERS.dup
19
- h['If-Modified-Since'] = if_modified_since.httpdate
20
- h
21
- else
22
- HEADERS
23
- end
23
+ headers = add_puppet_headers(HEADERS)
24
+ headers['If-Modified-Since'] = if_modified_since.httpdate if if_modified_since
24
25
 
25
26
  response = @client.get(
26
27
  with_base_url("/certificate_revocation_list/ca"),
27
- headers: request_headers,
28
+ headers: headers,
28
29
  ssl_context: ssl_context
29
30
  )
30
31
 
@@ -36,7 +37,7 @@ class Puppet::HTTP::Service::Ca < Puppet::HTTP::Service
36
37
  def put_certificate_request(name, csr, ssl_context: nil)
37
38
  response = @client.put(
38
39
  with_base_url("/certificate_request/#{name}"),
39
- headers: HEADERS,
40
+ headers: add_puppet_headers(HEADERS),
40
41
  content_type: 'text/plain',
41
42
  body: csr.to_pem,
42
43
  ssl_context: ssl_context
@@ -0,0 +1,40 @@
1
+ class Puppet::HTTP::Service::Report < Puppet::HTTP::Service
2
+ API = '/puppet/v3'.freeze
3
+ EXCLUDED_FORMATS = [:yaml, :b64_zlib_yaml, :dot]
4
+
5
+ # puppet major version where JSON is enabled by default
6
+ MAJOR_VERSION_JSON_DEFAULT = 5
7
+
8
+ def initialize(client, server, port)
9
+ url = build_url(API, server || Puppet[:report_server], port || Puppet[:report_port])
10
+ super(client, url)
11
+ end
12
+
13
+ def put_report(name, report, environment:, ssl_context: nil)
14
+ formatter = Puppet::Network::FormatHandler.format_for(Puppet[:preferred_serialization_format])
15
+
16
+ model = Puppet::Transaction::Report
17
+ network_formats = model.supported_formats - EXCLUDED_FORMATS
18
+ mime_types = network_formats.map { |f| model.get_format(f).mime }
19
+
20
+ response = @client.put(
21
+ with_base_url("/report/#{name}"),
22
+ headers: add_puppet_headers('ACCEPT' => mime_types.join(', ')),
23
+ params: { :environment => environment },
24
+ content_type: formatter.mime,
25
+ body: formatter.render(report),
26
+ ssl_context: ssl_context
27
+ )
28
+
29
+ return response.body.to_s if response.success?
30
+
31
+ server_version = response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION]
32
+ if server_version && SemanticPuppet::Version.parse(server_version).major < MAJOR_VERSION_JSON_DEFAULT &&
33
+ Puppet[:preferred_serialization_format] != 'pson'
34
+ #TRANSLATORS "pson", "preferred_serialization_format", and "puppetserver" should not be translated
35
+ raise Puppet::HTTP::ProtocolError.new(_("To submit reports to a server running puppetserver %{server_version}, set preferred_serialization_format to pson") % { server_version: server_version })
36
+ end
37
+
38
+ raise Puppet::HTTP::ResponseError.new(response)
39
+ end
40
+ end
@@ -1,55 +1,34 @@
1
1
  class Puppet::HTTP::Session
2
- Route = Struct.new(:service_class, :api, :server_setting, :port_setting)
3
-
4
- ROUTES = {
5
- ca: Route.new(Puppet::HTTP::Service::Ca, '/puppet-ca/v1', :ca_server, :ca_port),
6
- }.freeze
7
-
8
2
  def initialize(client, resolvers)
9
3
  @client = client
10
4
  @resolvers = resolvers
11
5
  @resolved_services = {}
6
+ @resolution_exceptions = []
12
7
  end
13
8
 
14
9
  def route_to(name, ssl_context: nil)
15
- route = ROUTES[name]
16
- raise ArgumentError, "Unknown service #{name}" unless route
10
+ raise ArgumentError, "Unknown service #{name}" unless Puppet::HTTP::Service.valid_name?(name)
17
11
 
18
12
  cached = @resolved_services[name]
19
13
  return cached if cached
20
14
 
21
- errors = []
15
+ @resolution_exceptions = []
22
16
 
23
17
  @resolvers.each do |resolver|
24
18
  Puppet.debug("Resolving service '#{name}' using #{resolver.class}")
25
- resolver.resolve(self, name) do |service|
26
- begin
27
- service.connect(ssl_context: ssl_context)
28
- @resolved_services[name] = service
29
- Puppet.debug("Resolved service '#{name}' to #{service.url}")
30
- return service
31
- rescue Puppet::HTTP::ConnectionError => e
32
- errors << e
33
- Puppet.debug("Connection to #{service.url} failed, trying next route: #{e.message}")
34
- end
19
+ service = resolver.resolve(self, name, ssl_context: ssl_context)
20
+ if service
21
+ @resolved_services[name] = service
22
+ Puppet.debug("Resolved service '#{name}' to #{service.url}")
23
+ return service
35
24
  end
36
25
  end
37
26
 
38
- errors.each { |e| Puppet.log_exception(e) }
39
-
27
+ @resolution_exceptions.each { |e| Puppet.log_exception(e) }
40
28
  raise Puppet::HTTP::RouteError, "No more routes to #{name}"
41
29
  end
42
30
 
43
- def create_service(name, server = nil, port = nil)
44
- route = ROUTES[name]
45
- raise ArgumentError, "Unknown service #{name}" unless route
46
-
47
- server ||= Puppet[route.server_setting]
48
- port ||= Puppet[route.port_setting]
49
- url = URI::HTTPS.build(host: server,
50
- port: port,
51
- path: route.api
52
- ).freeze
53
- route.service_class.new(@client, url)
31
+ def add_exception(exception)
32
+ @resolution_exceptions << exception
54
33
  end
55
34
  end
@@ -8,6 +8,7 @@ class Puppet::Network::HTTP::BasePool
8
8
  verifier.setup_connection(http)
9
9
  begin
10
10
  http.start
11
+ print_ssl_info(http) if Puppet::Util::Log.sendlevel?(:debug)
11
12
  rescue OpenSSL::SSL::SSLError => error
12
13
  verifier.handle_connection_error(http, error)
13
14
  end
@@ -15,4 +16,16 @@ class Puppet::Network::HTTP::BasePool
15
16
  http.start
16
17
  end
17
18
  end
19
+
20
+ private
21
+
22
+ def print_ssl_info(http)
23
+ buffered_io = http.instance_variable_get(:@socket)
24
+ return unless buffered_io
25
+
26
+ socket = buffered_io.io
27
+ return unless socket
28
+
29
+ Puppet.debug("Using #{socket.ssl_version} with cipher #{socket.cipher.first}")
30
+ end
18
31
  end
@@ -1,6 +1,7 @@
1
1
  require 'puppet/util'
2
2
  require 'monitor'
3
3
  require 'puppet/parser/parser_factory'
4
+ require 'puppet/concurrent/lock'
4
5
 
5
6
  # Just define it, so this class has fewer load dependencies.
6
7
  class Puppet::Node
@@ -70,6 +71,7 @@ class Puppet::Node::Environment
70
71
  #
71
72
  # @param name [Symbol] The environment name
72
73
  def initialize(name, modulepath, manifest, config_version)
74
+ @lock = Puppet::Concurrent::Lock.new
73
75
  @name = name.intern
74
76
  @modulepath = self.class.expand_dirs(self.class.extralibs() + modulepath)
75
77
  @manifest = manifest == NO_MANIFEST ? manifest : Puppet::FileSystem.expand_path(manifest)
@@ -232,11 +234,13 @@ class Puppet::Node::Environment
232
234
  # @api public
233
235
  # @return [Puppet::Resource::TypeCollection] The current global TypeCollection
234
236
  def known_resource_types
235
- if @known_resource_types.nil?
236
- @known_resource_types = Puppet::Resource::TypeCollection.new(self)
237
- @known_resource_types.import_ast(perform_initial_import(), '')
237
+ @lock.synchronize do
238
+ if @known_resource_types.nil?
239
+ @known_resource_types = Puppet::Resource::TypeCollection.new(self)
240
+ @known_resource_types.import_ast(perform_initial_import(), '')
241
+ end
242
+ @known_resource_types
238
243
  end
239
- @known_resource_types
240
244
  end
241
245
 
242
246
  # Yields each modules' plugin directory if the plugin directory (modulename/lib)
@@ -429,9 +433,11 @@ class Puppet::Node::Environment
429
433
  # Checks if a reparse is required (cache of files is stale).
430
434
  #
431
435
  def check_for_reparse
432
- if (Puppet[:code] != @parsed_code || @known_resource_types.parse_failed?)
433
- @parsed_code = nil
434
- @known_resource_types = nil
436
+ @lock.synchronize do
437
+ if (Puppet[:code] != @parsed_code || @known_resource_types.parse_failed?)
438
+ @parsed_code = nil
439
+ @known_resource_types = nil
440
+ end
435
441
  end
436
442
  end
437
443
 
@@ -83,6 +83,8 @@ module Pal
83
83
  end
84
84
  end
85
85
 
86
+ previous_tasks_value = Puppet[:tasks]
87
+ previous_code_value = Puppet[:code]
86
88
  Puppet[:tasks] = true
87
89
  # After the assertions, if code_string is non nil - it has the highest precedence
88
90
  Puppet[:code] = code_string unless code_string.nil?
@@ -90,6 +92,9 @@ module Pal
90
92
  # If manifest_file is nil, the #main method will use the env configured manifest
91
93
  # to do things in the block while a Script Compiler is in effect
92
94
  main(manifest_file, facts, variables, :script, &block)
95
+ ensure
96
+ Puppet[:tasks] = previous_tasks_value
97
+ Puppet[:code] = previous_code_value
93
98
  end
94
99
 
95
100
  # Evaluates a Puppet Language script string.
@@ -7,12 +7,12 @@ result as a String.
7
7
  The first argument to this function should be a `<MODULE NAME>/<TEMPLATE FILE>`
8
8
  reference, which loads `<TEMPLATE FILE>` from `<MODULE NAME>`'s `templates`
9
9
  directory. In most cases, the last argument is optional; if used, it should be a
10
- [hash](/puppet/latest/reference/lang_data_hash.html) that contains parameters to
10
+ [hash](https://puppet.com/docs/puppet/latest/lang_data_hash.html) that contains parameters to
11
11
  pass to the template.
12
12
 
13
- - See the [template](/puppet/latest/reference/lang_template.html) documentation
13
+ - See the [template](https://puppet.com/docs/puppet/latest/lang_template.html) documentation
14
14
  for general template usage information.
15
- - See the [EPP syntax](/puppet/latest/reference/lang_template_epp.html)
15
+ - See the [EPP syntax](https://puppet.com/docs/puppet/latest/lang_template_epp.html)
16
16
  documentation for examples of EPP.
17
17
 
18
18
  For example, to call the apache module's `templates/vhost/_docroot.epp`
@@ -6,12 +6,12 @@ text result as a String.
6
6
 
7
7
  The first argument to this function should be a string containing an EPP
8
8
  template. In most cases, the last argument is optional; if used, it should be a
9
- [hash](/puppet/latest/reference/lang_data_hash.html) that contains parameters to
9
+ [hash](https://puppet.com/docs/puppet/latest/lang_data_hash.html) that contains parameters to
10
10
  pass to the template.
11
11
 
12
- - See the [template](/puppet/latest/reference/lang_template.html) documentation
12
+ - See the [template](https://puppet.com/docs/puppet/latest/lang_template.html) documentation
13
13
  for general template usage information.
14
- - See the [EPP syntax](/puppet/latest/reference/lang_template_epp.html)
14
+ - See the [EPP syntax](https://puppet.com/docs/puppet/latest/lang_template_epp.html)
15
15
  documentation for examples of EPP.
16
16
 
17
17
  For example, to evaluate an inline EPP template and pass it the `docroot` and
@@ -29,7 +29,7 @@ parameter tag without default values. Puppet produces an error if the
29
29
  `inline_epp` function fails to pass any required parameter.
30
30
 
31
31
  An inline EPP template should be written as a single-quoted string or
32
- [heredoc](/puppet/latest/reference/lang_data_string.html#heredocs).
32
+ [heredoc](https://puppet.com/docs/puppet/latest/lang_data_string.html#heredocs).
33
33
  A double-quoted string is subject to expression interpolation before the string
34
34
  is parsed as an EPP template.
35
35
 
@@ -45,7 +45,7 @@ END
45
45
  ~~~
46
46
 
47
47
  - Since 3.5
48
- - Requires [future parser](/puppet/3.8/reference/experiments_future.html) in Puppet 3.5 to 3.8") do |arguments|
48
+ - Requires [future parser](https://puppet.com/docs/puppet/3.8/experiments_future.html) in Puppet 3.5 to 3.8") do |arguments|
49
49
 
50
50
  Puppet::Parser::Functions::Error.is4x('inline_epp')
51
51
  end
@@ -33,7 +33,7 @@ module Runtime3Support
33
33
  # @raise [Puppet::ParseError] an evaluation error initialized from the arguments (TODO: Change to EvaluationError?)
34
34
  #
35
35
  def optionally_fail(issue, semantic, options={}, except=nil)
36
- if except.nil?
36
+ if except.nil? && diagnostic_producer.severity_producer[issue] == :error
37
37
  # Want a stacktrace, and it must be passed as an exception
38
38
  begin
39
39
  raise EvaluationError.new()