puppet 6.15.0 → 6.16.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.
- checksums.yaml +4 -4
- data/CODEOWNERS +2 -7
- data/Gemfile.lock +17 -14
- data/lib/puppet.rb +32 -8
- data/lib/puppet/agent.rb +18 -4
- data/lib/puppet/application/agent.rb +1 -2
- data/lib/puppet/application/device.rb +1 -1
- data/lib/puppet/application/plugin.rb +1 -0
- data/lib/puppet/application/ssl.rb +1 -1
- data/lib/puppet/configurer.rb +2 -2
- data/lib/puppet/context/trusted_information.rb +14 -8
- data/lib/puppet/daemon.rb +13 -27
- data/lib/puppet/defaults.rb +19 -0
- data/lib/puppet/face/facts.rb +1 -1
- data/lib/puppet/face/help.rb +29 -3
- data/lib/puppet/face/module/search.rb +5 -0
- data/lib/puppet/face/plugin.rb +1 -1
- data/lib/puppet/file_serving/http_metadata.rb +1 -1
- data/lib/puppet/file_system/uniquefile.rb +4 -0
- data/lib/puppet/forge/repository.rb +7 -6
- data/lib/puppet/functions/filter.rb +1 -0
- data/lib/puppet/http/client.rb +22 -11
- data/lib/puppet/http/external_client.rb +0 -6
- data/lib/puppet/indirector/file_content/http.rb +5 -0
- data/lib/puppet/indirector/file_metadata/http.rb +4 -4
- data/lib/puppet/indirector/rest.rb +7 -1
- data/lib/puppet/network/http/compression.rb +7 -0
- data/lib/puppet/network/http/connection.rb +2 -0
- data/lib/puppet/network/http/connection_adapter.rb +182 -0
- data/lib/puppet/network/http/nocache_pool.rb +1 -0
- data/lib/puppet/network/http_pool.rb +2 -2
- data/lib/puppet/pal/catalog_compiler.rb +5 -0
- data/lib/puppet/pal/pal_impl.rb +4 -1
- data/lib/puppet/parser/compiler.rb +28 -25
- data/lib/puppet/parser/functions/filter.rb +1 -0
- data/lib/puppet/provider/package/aix.rb +17 -2
- data/lib/puppet/provider/package/apt.rb +4 -1
- data/lib/puppet/provider/package/dnfmodule.rb +24 -4
- data/lib/puppet/provider/package/pip.rb +60 -37
- data/lib/puppet/provider/package/portage.rb +2 -2
- data/lib/puppet/provider/package/yum.rb +7 -0
- data/lib/puppet/provider/package/zypper.rb +59 -1
- data/lib/puppet/provider/service/systemd.rb +21 -4
- data/lib/puppet/provider/user/useradd.rb +5 -1
- data/lib/puppet/reports/http.rb +5 -3
- data/lib/puppet/runtime.rb +25 -2
- data/lib/puppet/ssl/state_machine.rb +33 -8
- data/lib/puppet/ssl/verifier_adapter.rb +9 -1
- data/lib/puppet/test/test_helper.rb +1 -1
- data/lib/puppet/type/file/source.rb +1 -1
- data/lib/puppet/type/package.rb +16 -1
- data/lib/puppet/type/service.rb +6 -8
- data/lib/puppet/type/user.rb +1 -7
- data/lib/puppet/util/autoload.rb +1 -18
- data/lib/puppet/util/log/destinations.rb +1 -10
- data/lib/puppet/util/package/version/range.rb +4 -1
- data/lib/puppet/util/package/version/range/eq.rb +14 -0
- data/lib/puppet/version.rb +1 -1
- data/locales/puppet.pot +191 -111
- data/man/man5/puppet.conf.5 +21 -2
- data/man/man8/puppet-agent.8 +1 -1
- data/man/man8/puppet-apply.8 +1 -1
- data/man/man8/puppet-catalog.8 +1 -1
- data/man/man8/puppet-config.8 +1 -1
- data/man/man8/puppet-describe.8 +1 -1
- data/man/man8/puppet-device.8 +1 -1
- data/man/man8/puppet-doc.8 +1 -1
- data/man/man8/puppet-epp.8 +1 -1
- data/man/man8/puppet-facts.8 +1 -1
- data/man/man8/puppet-filebucket.8 +1 -1
- data/man/man8/puppet-generate.8 +1 -1
- data/man/man8/puppet-help.8 +6 -3
- data/man/man8/puppet-key.8 +1 -1
- data/man/man8/puppet-lookup.8 +1 -1
- data/man/man8/puppet-man.8 +1 -1
- data/man/man8/puppet-module.8 +4 -1
- data/man/man8/puppet-node.8 +1 -1
- data/man/man8/puppet-parser.8 +1 -1
- data/man/man8/puppet-plugin.8 +1 -1
- data/man/man8/puppet-report.8 +1 -1
- data/man/man8/puppet-resource.8 +1 -1
- data/man/man8/puppet-script.8 +1 -1
- data/man/man8/puppet-ssl.8 +1 -1
- data/man/man8/puppet-status.8 +1 -1
- data/man/man8/puppet.8 +2 -2
- data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-enabled.txt → dnf-module-list.txt} +6 -0
- data/spec/fixtures/unit/provider/package/zypper/zypper-search-uninstalled.out +13 -0
- data/spec/integration/application/agent_spec.rb +66 -1
- data/spec/integration/application/plugin_spec.rb +23 -0
- data/spec/integration/http/client_spec.rb +6 -1
- data/spec/integration/network/http_pool_spec.rb +56 -0
- data/spec/integration/util/windows/adsi_spec.rb +5 -0
- data/spec/lib/puppet_spec/https.rb +6 -0
- data/spec/unit/agent_spec.rb +47 -1
- data/spec/unit/application/agent_spec.rb +4 -4
- data/spec/unit/context/trusted_information_spec.rb +17 -0
- data/spec/unit/daemon_spec.rb +5 -64
- data/spec/unit/face/module/search_spec.rb +17 -0
- data/spec/unit/file_system/uniquefile_spec.rb +11 -0
- data/spec/unit/http/client_spec.rb +10 -10
- data/spec/unit/http/external_client_spec.rb +9 -9
- data/spec/unit/indirector/catalog/compiler_spec.rb +1 -0
- data/spec/unit/indirector/file_metadata/http_spec.rb +167 -0
- data/spec/unit/indirector/file_metadata/rest_spec.rb +15 -14
- data/spec/unit/indirector/rest_spec.rb +13 -0
- data/spec/unit/network/http/connection_spec.rb +542 -190
- data/spec/unit/network/http/nocache_pool_spec.rb +22 -0
- data/spec/unit/network/http_pool_spec.rb +63 -57
- data/spec/unit/network/http_spec.rb +1 -1
- data/spec/unit/provider/package/aix_spec.rb +29 -0
- data/spec/unit/provider/package/dnfmodule_spec.rb +25 -5
- data/spec/unit/provider/package/pip_spec.rb +42 -16
- data/spec/unit/provider/package/portage_spec.rb +5 -0
- data/spec/unit/provider/package/yum_spec.rb +16 -8
- data/spec/unit/provider/package/zypper_spec.rb +84 -0
- data/spec/unit/provider/service/init_spec.rb +1 -0
- data/spec/unit/provider/service/openbsd_spec.rb +9 -0
- data/spec/unit/provider/service/openwrt_spec.rb +1 -0
- data/spec/unit/provider/service/redhat_spec.rb +9 -0
- data/spec/unit/provider/service/systemd_spec.rb +84 -13
- data/spec/unit/provider/user/useradd_spec.rb +8 -0
- data/spec/unit/puppet_pal_catalog_spec.rb +43 -0
- data/spec/unit/puppet_spec.rb +33 -0
- data/spec/unit/reports/http_spec.rb +1 -1
- data/spec/unit/ssl/state_machine_spec.rb +52 -8
- data/spec/unit/type/service_spec.rb +9 -8
- data/spec/unit/type/user_spec.rb +1 -1
- data/spec/unit/util/autoload_spec.rb +2 -1
- data/spec/unit/util/log/destinations_spec.rb +1 -29
- data/spec/unit/util/package/version/range_spec.rb +22 -1
- data/tasks/manpages.rake +5 -35
- metadata +10 -4
@@ -0,0 +1,182 @@
|
|
1
|
+
class Puppet::Network::HTTP::ConnectionAdapter < Puppet::Network::HTTP::Connection
|
2
|
+
def initialize(host, port, options = {})
|
3
|
+
super(host, port, options)
|
4
|
+
|
5
|
+
@client = Puppet.runtime[:http]
|
6
|
+
end
|
7
|
+
|
8
|
+
def get(path, headers = {}, options = {})
|
9
|
+
headers ||= {}
|
10
|
+
options[:ssl_context] ||= resolve_ssl_context
|
11
|
+
options[:redirect_limit] ||= @redirect_limit
|
12
|
+
|
13
|
+
with_error_handling do
|
14
|
+
resp = @client.get(to_url(path), headers: headers, options: options)
|
15
|
+
resp.nethttp
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def post(path, data, headers = nil, options = {})
|
20
|
+
headers ||= {}
|
21
|
+
headers['Content-Type'] ||= "application/x-www-form-urlencoded"
|
22
|
+
data ||= ''
|
23
|
+
options[:ssl_context] ||= resolve_ssl_context
|
24
|
+
options[:redirect_limit] ||= @redirect_limit
|
25
|
+
|
26
|
+
with_error_handling do
|
27
|
+
resp = @client.post(to_url(path), data, headers: headers, options: options)
|
28
|
+
resp.nethttp
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def head(path, headers = {}, options = {})
|
33
|
+
headers ||= {}
|
34
|
+
options[:ssl_context] ||= resolve_ssl_context
|
35
|
+
options[:redirect_limit] ||= @redirect_limit
|
36
|
+
|
37
|
+
with_error_handling do
|
38
|
+
resp = @client.head(to_url(path), headers: headers, options: options)
|
39
|
+
resp.nethttp
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(path, headers = {'Depth' => 'Infinity'}, options = {})
|
44
|
+
headers ||= {}
|
45
|
+
options[:ssl_context] ||= resolve_ssl_context
|
46
|
+
options[:redirect_limit] ||= @redirect_limit
|
47
|
+
|
48
|
+
with_error_handling do
|
49
|
+
resp = @client.delete(to_url(path), headers: headers, options: options)
|
50
|
+
resp.nethttp
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def put(path, data, headers = nil, options = {})
|
55
|
+
headers ||= {}
|
56
|
+
headers['Content-Type'] ||= "application/x-www-form-urlencoded"
|
57
|
+
data ||= ''
|
58
|
+
options[:ssl_context] ||= resolve_ssl_context
|
59
|
+
options[:redirect_limit] ||= @redirect_limit
|
60
|
+
|
61
|
+
with_error_handling do
|
62
|
+
resp = @client.put(to_url(path), data, headers: headers, options: options)
|
63
|
+
resp.nethttp
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def request_get(*args, &block)
|
68
|
+
path, headers = *args
|
69
|
+
headers ||= {}
|
70
|
+
options = {
|
71
|
+
ssl_context: resolve_ssl_context,
|
72
|
+
redirect_limit: @redirect_limit
|
73
|
+
}
|
74
|
+
|
75
|
+
resp = @client.get(to_url(path), headers: headers, options: options) do |response|
|
76
|
+
yield response.nethttp if block_given?
|
77
|
+
end
|
78
|
+
resp.nethttp
|
79
|
+
end
|
80
|
+
|
81
|
+
def request_head(*args, &block)
|
82
|
+
path, headers = *args
|
83
|
+
headers ||= {}
|
84
|
+
options = {
|
85
|
+
ssl_context: resolve_ssl_context,
|
86
|
+
redirect_limit: @redirect_limit
|
87
|
+
}
|
88
|
+
|
89
|
+
response = @client.head(to_url(path), headers: headers, options: options)
|
90
|
+
yield response.nethttp if block_given?
|
91
|
+
response.nethttp
|
92
|
+
end
|
93
|
+
|
94
|
+
def request_post(*args, &block)
|
95
|
+
path, data, headers = *args
|
96
|
+
headers ||= {}
|
97
|
+
headers['Content-Type'] ||= "application/x-www-form-urlencoded"
|
98
|
+
options = {
|
99
|
+
ssl_context: resolve_ssl_context,
|
100
|
+
redirect_limit: @redirect_limit
|
101
|
+
}
|
102
|
+
|
103
|
+
resp = @client.post(to_url(path), data, headers: headers, options: options) do |response|
|
104
|
+
yield response.nethttp if block_given?
|
105
|
+
end
|
106
|
+
resp.nethttp
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# The old Connection class ignores the ssl_context on the Puppet stack,
|
112
|
+
# and always loads certs/keys based on what is currently in the filesystem.
|
113
|
+
# If the files are missing, it would attempt to bootstrap the certs/keys
|
114
|
+
# while in the process of making a network request, due to the call to
|
115
|
+
# Puppet.lookup(:ssl_host) in Puppet::SSL::Validator::DefaultValidator#setup_connection.
|
116
|
+
# This class doesn't preserve the boostrap behavior because that is handled
|
117
|
+
# outside of this class, and can only be triggered by running `puppet ssl` or
|
118
|
+
# `puppet agent`.
|
119
|
+
def resolve_ssl_context
|
120
|
+
# don't need an ssl context for http connections
|
121
|
+
return nil unless @site.use_ssl?
|
122
|
+
|
123
|
+
# if our verifier has an ssl_context, use that
|
124
|
+
ctx = @verifier.ssl_context
|
125
|
+
return ctx if ctx
|
126
|
+
|
127
|
+
# load available certs
|
128
|
+
cert = Puppet::X509::CertProvider.new
|
129
|
+
ssl = Puppet::SSL::SSLProvider.new
|
130
|
+
begin
|
131
|
+
password = cert.load_private_key_password
|
132
|
+
ssl.load_context(certname: Puppet[:certname], password: password)
|
133
|
+
rescue Puppet::SSL::SSLError => e
|
134
|
+
Puppet.log_exception(e)
|
135
|
+
|
136
|
+
# if we don't have cacerts, then create a root context that doesn't
|
137
|
+
# trust anything. The old code used to fallback to VERIFY_NONE,
|
138
|
+
# which we don't want to emulate.
|
139
|
+
ssl.create_root_context(cacerts: [])
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def to_url(path)
|
144
|
+
if path =~ /^https?:\/\//
|
145
|
+
# The old Connection class accepts a URL as the request path, and sends
|
146
|
+
# it in "absolute-form" in the request line, e.g. GET https://puppet:8140/.
|
147
|
+
# See https://httpwg.org/specs/rfc7230.html#absolute-form. It just so happens
|
148
|
+
# to work because HTTP 1.1 servers are required to accept absolute-form even
|
149
|
+
# though clients are only supposed to send them to proxies, so the proxy knows
|
150
|
+
# what upstream server to CONNECT to. This method creates a URL using the
|
151
|
+
# scheme/host/port that the connection was created with, and appends the path
|
152
|
+
# portion of the absolute-form. The resulting request will use "origin-form"
|
153
|
+
# as it should have done all along.
|
154
|
+
url = URI(path)
|
155
|
+
URI("#{@site.addr}/#{normalize_path(url.path)}")
|
156
|
+
else
|
157
|
+
URI("#{@site.addr}/#{Puppet::Util.uri_encode(normalize_path(path))}")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def normalize_path(path)
|
162
|
+
if path[0] == '/'
|
163
|
+
path[1..-1]
|
164
|
+
else
|
165
|
+
path
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def with_error_handling(&block)
|
170
|
+
yield
|
171
|
+
rescue Puppet::HTTP::TooManyRedirects => e
|
172
|
+
raise Puppet::Network::HTTP::RedirectionLimitExceededException.new(_("Too many HTTP redirections for %{host}:%{port}") % { host: @host, port: @port }, e)
|
173
|
+
rescue Puppet::HTTP::HTTPError => e
|
174
|
+
Puppet.log_exception(e, e.message)
|
175
|
+
case e.cause
|
176
|
+
when Net::OpenTimeout, Net::ReadTimeout, Net::HTTPError, EOFError
|
177
|
+
raise e.cause
|
178
|
+
else
|
179
|
+
raise e
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# @api private
|
4
4
|
class Puppet::Network::HTTP::NoCachePool < Puppet::Network::HTTP::BasePool
|
5
5
|
def initialize(factory = Puppet::Network::HTTP::Factory.new)
|
6
|
+
Puppet.deprecation_warning(_('Puppet::Network::HTTP::NoCachePool is deprecated.'))
|
6
7
|
@factory = factory
|
7
8
|
end
|
8
9
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'puppet/network/http/connection'
|
2
|
+
require 'puppet/network/http/connection_adapter'
|
2
3
|
require 'puppet/util/platform'
|
3
4
|
|
4
5
|
module Puppet::Network; end
|
@@ -12,14 +13,13 @@ module Puppet::Network; end
|
|
12
13
|
#
|
13
14
|
module Puppet::Network::HttpPool
|
14
15
|
|
15
|
-
@http_client_class = Puppet::Network::HTTP::
|
16
|
+
@http_client_class = Puppet::Network::HTTP::ConnectionAdapter
|
16
17
|
|
17
18
|
def self.http_client_class
|
18
19
|
@http_client_class
|
19
20
|
end
|
20
21
|
def self.http_client_class=(klass)
|
21
22
|
@http_client_class = klass
|
22
|
-
Puppet.runtime['http'] = Puppet::HTTP::ExternalClient.new(klass)
|
23
23
|
end
|
24
24
|
|
25
25
|
# Retrieve a connection for the given host and port.
|
@@ -97,6 +97,11 @@ module Pal
|
|
97
97
|
internal_compiler.evaluate_additions
|
98
98
|
end
|
99
99
|
|
100
|
+
# Attempts to evaluate AST for node defnintions https://puppet.com/docs/puppet/latest/lang_node_definitions.html
|
101
|
+
# if there are any.
|
102
|
+
def evaluate_ast_node
|
103
|
+
internal_compiler.evaluate_ast_node
|
104
|
+
end
|
100
105
|
end
|
101
106
|
|
102
107
|
end
|
data/lib/puppet/pal/pal_impl.rb
CHANGED
@@ -424,7 +424,6 @@ module Pal
|
|
424
424
|
begin
|
425
425
|
node.sanitize()
|
426
426
|
compiler = create_internal_compiler(internal_compiler_class, node)
|
427
|
-
add_variables(compiler.topscope, pal_variables)
|
428
427
|
|
429
428
|
case internal_compiler_class
|
430
429
|
when :script
|
@@ -440,6 +439,10 @@ module Pal
|
|
440
439
|
# TRANSLATORS: Do not translate, symbolic name
|
441
440
|
Puppet.override(overrides, "PAL::with_#{internal_compiler_class}_compiler") do
|
442
441
|
compiler.compile do | compiler_yield |
|
442
|
+
# In case the varaibles passed to the compiler are PCore types defined in modules, they
|
443
|
+
# need to be deserialized and added from within the this scope, so that loaders are
|
444
|
+
# available during deserizlization.
|
445
|
+
add_variables(compiler.topscope, Puppet::Pops::Serialization::FromDataConverter.convert(pal_variables))
|
443
446
|
# wrap the internal compiler to prevent it from leaking in the PAL API
|
444
447
|
if block_given?
|
445
448
|
yield(pal_compiler)
|
@@ -348,6 +348,34 @@ class Puppet::Parser::Compiler
|
|
348
348
|
end
|
349
349
|
end
|
350
350
|
|
351
|
+
|
352
|
+
# If ast nodes are enabled, then see if we can find and evaluate one.
|
353
|
+
#
|
354
|
+
# @api private
|
355
|
+
def evaluate_ast_node
|
356
|
+
krt = environment.known_resource_types
|
357
|
+
return unless krt.nodes? #ast_nodes?
|
358
|
+
|
359
|
+
# Now see if we can find the node.
|
360
|
+
astnode = nil
|
361
|
+
@node.names.each do |name|
|
362
|
+
astnode = krt.node(name.to_s.downcase)
|
363
|
+
break if astnode
|
364
|
+
end
|
365
|
+
|
366
|
+
unless (astnode ||= krt.node("default"))
|
367
|
+
raise Puppet::ParseError, _("Could not find node statement with name 'default' or '%{names}'") % { names: node.names.join(", ") }
|
368
|
+
end
|
369
|
+
|
370
|
+
# Create a resource to model this node, and then add it to the list
|
371
|
+
# of resources.
|
372
|
+
resource = astnode.ensure_in_catalog(topscope)
|
373
|
+
|
374
|
+
resource.evaluate
|
375
|
+
|
376
|
+
@node_scope = topscope.class_scope(astnode)
|
377
|
+
end
|
378
|
+
|
351
379
|
# Evaluates each specified class in turn. If there are any classes that
|
352
380
|
# can't be found, an error is raised. This method really just creates resource objects
|
353
381
|
# that point back to the classes, and then the resources are themselves
|
@@ -486,31 +514,6 @@ class Puppet::Parser::Compiler
|
|
486
514
|
krt.capability_mappings.clear # No longer needed
|
487
515
|
end
|
488
516
|
|
489
|
-
# If ast nodes are enabled, then see if we can find and evaluate one.
|
490
|
-
def evaluate_ast_node
|
491
|
-
krt = environment.known_resource_types
|
492
|
-
return unless krt.nodes? #ast_nodes?
|
493
|
-
|
494
|
-
# Now see if we can find the node.
|
495
|
-
astnode = nil
|
496
|
-
@node.names.each do |name|
|
497
|
-
astnode = krt.node(name.to_s.downcase)
|
498
|
-
break if astnode
|
499
|
-
end
|
500
|
-
|
501
|
-
unless (astnode ||= krt.node("default"))
|
502
|
-
raise Puppet::ParseError, _("Could not find node statement with name 'default' or '%{names}'") % { names: node.names.join(", ") }
|
503
|
-
end
|
504
|
-
|
505
|
-
# Create a resource to model this node, and then add it to the list
|
506
|
-
# of resources.
|
507
|
-
resource = astnode.ensure_in_catalog(topscope)
|
508
|
-
|
509
|
-
resource.evaluate
|
510
|
-
|
511
|
-
@node_scope = topscope.class_scope(astnode)
|
512
|
-
end
|
513
|
-
|
514
517
|
# Evaluate our collections and return true if anything returned an object.
|
515
518
|
# The 'true' is used to continue a loop, so it's important.
|
516
519
|
def evaluate_collections
|
@@ -43,6 +43,7 @@ as an array in the form `[key, value]` and returns a hash containing the results
|
|
43
43
|
$data = { "orange" => 0, "blueberry" => 1, "raspberry" => 2 }
|
44
44
|
$filtered_data = $data.filter |$items| { $items[0] =~ /berry$/ }
|
45
45
|
# $filtered_data = {blueberry => 1, raspberry => 2}
|
46
|
+
~~~
|
46
47
|
|
47
48
|
When the first argument is an array and the lambda has two parameters, Puppet passes the
|
48
49
|
array's indexes (enumerated from 0) in the first parameter and its values in the second
|
@@ -29,6 +29,15 @@ Puppet::Type.type(:package).provide :aix, :parent => Puppet::Provider::Package d
|
|
29
29
|
|
30
30
|
attr_accessor :latest_info
|
31
31
|
|
32
|
+
STATE_CODE = {
|
33
|
+
'A' => :applied,
|
34
|
+
'B' => :broken,
|
35
|
+
'C' => :committed,
|
36
|
+
'E' => :efix_locked,
|
37
|
+
'O' => :obsolete,
|
38
|
+
'?' => :inconsistent,
|
39
|
+
}.freeze
|
40
|
+
|
32
41
|
def self.srclistcmd(source)
|
33
42
|
[ command(:installp), "-L", "-d", source ]
|
34
43
|
end
|
@@ -97,6 +106,11 @@ Puppet::Type.type(:package).provide :aix, :parent => Puppet::Provider::Package d
|
|
97
106
|
if output =~ /^#{Regexp.escape(@resource[:name])}\s+.*\s+Already superseded by.*$/
|
98
107
|
self.fail _("aix package provider is unable to downgrade packages")
|
99
108
|
end
|
109
|
+
|
110
|
+
pkg_info = query
|
111
|
+
if pkg_info && [:broken, :inconsistent].include?(pkg_info[:status])
|
112
|
+
self.fail _("Package '%{name}' is in a %{status} state and requires manual intervention") % { name: @resource[:name], status: pkg_info[:status] }
|
113
|
+
end
|
100
114
|
end
|
101
115
|
|
102
116
|
def self.pkglist(hash = {})
|
@@ -108,8 +122,9 @@ Puppet::Type.type(:package).provide :aix, :parent => Puppet::Provider::Package d
|
|
108
122
|
end
|
109
123
|
|
110
124
|
begin
|
111
|
-
list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*)/).collect { |n,e|
|
112
|
-
|
125
|
+
list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*):[^:]*:[^:]*:([^:])/).collect { |n,e,s|
|
126
|
+
e = :absent if [:broken, :inconsistent].include?(STATE_CODE[s])
|
127
|
+
{ :name => n, :ensure => e, :status => STATE_CODE[s], :provider => self.name }
|
113
128
|
}
|
114
129
|
rescue Puppet::ExecutionFailure => detail
|
115
130
|
if hash[:pkgname]
|
@@ -77,7 +77,10 @@ Puppet::Type.type(:package).provide :apt, :parent => :dpkg, :source => :dpkg do
|
|
77
77
|
if should.is_a?(String)
|
78
78
|
begin
|
79
79
|
should_range = VersionRange.parse(should, DebianVersion)
|
80
|
-
|
80
|
+
|
81
|
+
unless should_range.is_a?(VersionRange::Eq)
|
82
|
+
should = best_version(should_range)
|
83
|
+
end
|
81
84
|
rescue VersionRange::ValidationFailure, DebianVersion::ValidationFailure
|
82
85
|
Puppet.debug("Cannot parse #{should} as a debian version range, falling through")
|
83
86
|
end
|
@@ -12,7 +12,7 @@ require 'puppet/provider/package'
|
|
12
12
|
|
13
13
|
Puppet::Type.type(:package).provide :dnfmodule, :parent => :dnf do
|
14
14
|
|
15
|
-
has_feature :installable, :uninstallable, :versionable, :supports_flavors
|
15
|
+
has_feature :installable, :uninstallable, :versionable, :supports_flavors, :disableable
|
16
16
|
#has_feature :upgradeable
|
17
17
|
# it's not (yet) feasible to make this upgradeable since module streams don't
|
18
18
|
# always have matching version types (i.e. idm has streams DL1 and client,
|
@@ -34,10 +34,10 @@ Puppet::Type.type(:package).provide :dnfmodule, :parent => :dnf do
|
|
34
34
|
|
35
35
|
def self.instances
|
36
36
|
packages = []
|
37
|
-
cmd = "#{command(:dnf)} module list
|
37
|
+
cmd = "#{command(:dnf)} module list -d 0 -e #{error_level}"
|
38
38
|
execute(cmd).each_line do |line|
|
39
39
|
# select only lines with actual packages since DNF clutters the output
|
40
|
-
next unless line =~ /\[[
|
40
|
+
next unless line =~ /\[[eix]\][, ]/
|
41
41
|
line.gsub!(/\[d\]/, '') # we don't care about the default flag
|
42
42
|
|
43
43
|
flavor = if line.include?('[i]')
|
@@ -48,7 +48,11 @@ Puppet::Type.type(:package).provide :dnfmodule, :parent => :dnf do
|
|
48
48
|
|
49
49
|
packages << new(
|
50
50
|
name: line.split[0],
|
51
|
-
ensure: line.
|
51
|
+
ensure: if line.include?('[x]')
|
52
|
+
:disabled
|
53
|
+
else
|
54
|
+
line.split[1]
|
55
|
+
end,
|
52
56
|
flavor: flavor,
|
53
57
|
provider: name
|
54
58
|
)
|
@@ -98,6 +102,18 @@ Puppet::Type.type(:package).provide :dnfmodule, :parent => :dnf do
|
|
98
102
|
end
|
99
103
|
end
|
100
104
|
|
105
|
+
# should only get here when @resource[ensure] is :disabled
|
106
|
+
def insync?(is)
|
107
|
+
if resource[:ensure] == :disabled
|
108
|
+
# in sync only if package is already disabled
|
109
|
+
pkg = self.class.instances.find do |package|
|
110
|
+
@resource[:name] == package.name && package.properties[:ensure] == :disabled
|
111
|
+
end
|
112
|
+
return true if pkg
|
113
|
+
end
|
114
|
+
return false
|
115
|
+
end
|
116
|
+
|
101
117
|
def enable(args = @resource[:name])
|
102
118
|
execute([command(:dnf), 'module', 'enable', '-d', '0', '-e', self.class.error_level, '-y', args])
|
103
119
|
end
|
@@ -107,6 +123,10 @@ Puppet::Type.type(:package).provide :dnfmodule, :parent => :dnf do
|
|
107
123
|
reset # reset module to the default stream
|
108
124
|
end
|
109
125
|
|
126
|
+
def disable(args = @resource[:name])
|
127
|
+
execute([command(:dnf), 'module', 'disable', '-d', '0', '-e', self.class.error_level, '-y', args])
|
128
|
+
end
|
129
|
+
|
110
130
|
def reset
|
111
131
|
execute([command(:dnf), 'module', 'reset', '-d', '0', '-e', self.class.error_level, '-y', @resource[:name]])
|
112
132
|
end
|
@@ -79,7 +79,7 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
|
|
79
79
|
command_options << '--all'
|
80
80
|
end
|
81
81
|
|
82
|
-
execpipe [command, command_options] do |process|
|
82
|
+
execpipe [quote(command), command_options] do |process|
|
83
83
|
process.collect do |line|
|
84
84
|
pkg = parse(line)
|
85
85
|
next unless pkg
|
@@ -158,7 +158,7 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
|
|
158
158
|
command = resource_or_provider_command
|
159
159
|
self.class.validate_command(command)
|
160
160
|
|
161
|
-
command_and_options = [command, 'install', "#{@resource[:name]}==versionplease"]
|
161
|
+
command_and_options = [self.class.quote(command), 'install', "#{@resource[:name]}==versionplease"]
|
162
162
|
command_and_options << install_options if @resource[:install_options]
|
163
163
|
execpipe command_and_options do |process|
|
164
164
|
process.collect do |line|
|
@@ -179,7 +179,7 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
|
|
179
179
|
self.class.validate_command(command)
|
180
180
|
|
181
181
|
Dir.mktmpdir("puppet_pip") do |dir|
|
182
|
-
command_and_options = [command, 'install', "#{@resource[:name]}", '-d', "#{dir}", '-v']
|
182
|
+
command_and_options = [self.class.quote(command), 'install', "#{@resource[:name]}", '-d', "#{dir}", '-v']
|
183
183
|
command_and_options << install_options if @resource[:install_options]
|
184
184
|
execpipe command_and_options do |process|
|
185
185
|
process.collect do |line|
|
@@ -211,51 +211,73 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
|
|
211
211
|
should_range
|
212
212
|
end
|
213
213
|
|
214
|
-
|
215
|
-
# latest, a version number, or, in conjunction with the source
|
216
|
-
# parameter, an SCM revision. In that case, the source parameter
|
217
|
-
# gives the fully-qualified URL to the repository.
|
218
|
-
def install
|
219
|
-
command = resource_or_provider_command
|
220
|
-
self.class.validate_command(command)
|
221
|
-
|
214
|
+
def get_install_command_options()
|
222
215
|
should = @resource[:ensure]
|
223
216
|
command_options = %w{install -q}
|
224
|
-
command_options +=
|
217
|
+
command_options += install_options if @resource[:install_options]
|
218
|
+
|
225
219
|
if @resource[:source]
|
226
220
|
if String === should
|
227
221
|
command_options << "#{@resource[:source]}@#{should}#egg=#{@resource[:name]}"
|
228
222
|
else
|
229
223
|
command_options << "#{@resource[:source]}#egg=#{@resource[:name]}"
|
230
224
|
end
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
225
|
+
|
226
|
+
return command_options
|
227
|
+
end
|
228
|
+
|
229
|
+
if should == :latest
|
230
|
+
command_options << "--upgrade" << @resource[:name]
|
231
|
+
|
232
|
+
return command_options
|
233
|
+
end
|
234
|
+
|
235
|
+
unless String === should
|
236
|
+
command_options << @resource[:name]
|
237
|
+
|
238
|
+
return command_options
|
239
|
+
end
|
240
|
+
|
241
|
+
begin
|
242
|
+
should_range = PIP_VERSION_RANGE.parse(should, PIP_VERSION)
|
243
|
+
rescue PIP_VERSION_RANGE::ValidationFailure, PIP_VERSION::ValidationFailure
|
244
|
+
Puppet.debug("Cannot parse #{should} as a pip version range, falling through.")
|
245
|
+
command_options << "#{@resource[:name]}==#{should}"
|
246
|
+
|
247
|
+
return command_options
|
248
|
+
end
|
249
|
+
|
250
|
+
if should_range.is_a?(PIP_VERSION_RANGE::Eq)
|
251
|
+
command_options << "#{@resource[:name]}==#{should}"
|
252
|
+
|
253
|
+
return command_options
|
254
|
+
end
|
255
|
+
|
256
|
+
should = best_version(should_range)
|
257
|
+
|
258
|
+
if should == should_range
|
259
|
+
# when no suitable version for the given range was found, let pip handle
|
260
|
+
if should.is_a?(PIP_VERSION_RANGE::MinMax)
|
261
|
+
command_options << "#{@resource[:name]} #{should.split.join(',')}"
|
254
262
|
else
|
255
|
-
command_options << @resource[:name]
|
263
|
+
command_options << "#{@resource[:name]} #{should}"
|
256
264
|
end
|
265
|
+
else
|
266
|
+
command_options << "#{@resource[:name]}==#{should}"
|
257
267
|
end
|
258
268
|
|
269
|
+
command_options
|
270
|
+
end
|
271
|
+
|
272
|
+
# Install a package. The ensure parameter may specify installed,
|
273
|
+
# latest, a version number, or, in conjunction with the source
|
274
|
+
# parameter, an SCM revision. In that case, the source parameter
|
275
|
+
# gives the fully-qualified URL to the repository.
|
276
|
+
def install
|
277
|
+
command = resource_or_provider_command
|
278
|
+
self.class.validate_command(command)
|
279
|
+
|
280
|
+
command_options = get_install_command_options
|
259
281
|
execute([command, command_options])
|
260
282
|
end
|
261
283
|
|
@@ -298,6 +320,8 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
|
|
298
320
|
should_range.include?(is_version)
|
299
321
|
end
|
300
322
|
|
323
|
+
# Quoting is required if the path to the pip command contains spaces.
|
324
|
+
# Required for execpipe() but not execute(), as execute() already does this.
|
301
325
|
def self.quote(path)
|
302
326
|
if path.include?(" ")
|
303
327
|
"\"#{path}\""
|
@@ -305,5 +329,4 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
|
|
305
329
|
path
|
306
330
|
end
|
307
331
|
end
|
308
|
-
private_class_method :quote
|
309
332
|
end
|