puppet 3.2.0.rc2 → 3.2.1.rc1
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.
- data/lib/puppet/indirector/catalog/static_compiler.rb +19 -17
- data/lib/puppet/network/http/rack/rest.rb +5 -3
- data/lib/puppet/provider/package/sun.rb +19 -12
- data/lib/puppet/provider/package/windows/package.rb +26 -0
- data/lib/puppet/provider/user/useradd.rb +0 -7
- data/lib/puppet/type/file.rb +38 -41
- data/lib/puppet/type/filebucket.rb +43 -36
- data/lib/puppet/type/user.rb +3 -5
- data/lib/puppet/util/ssl.rb +21 -6
- data/lib/puppet/version.rb +1 -1
- data/spec/unit/network/http/rack/rest_spec.rb +17 -0
- data/spec/unit/provider/package/sun_spec.rb +7 -15
- data/spec/unit/provider/user/useradd_spec.rb +0 -6
- data/spec/unit/util/ssl_spec.rb +62 -21
- metadata +2548 -2548
@@ -15,23 +15,25 @@ class Puppet::Resource::Catalog::StaticCompiler < Puppet::Indirector::Code
|
|
15
15
|
This terminus works today, but cannot be used without additional
|
16
16
|
configuration. Specifically:
|
17
17
|
|
18
|
-
You must create a
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
18
|
+
* You must create a special filebucket resource --- with the title `puppet`
|
19
|
+
and the `path` attribute set to `false` --- in site.pp or somewhere else
|
20
|
+
where it will be added to every node's catalog. Using `puppet` as the title
|
21
|
+
is mandatory; the static compiler treats this title as magical.
|
22
|
+
|
23
|
+
filebucket { puppet:
|
24
|
+
path => false,
|
25
|
+
}
|
26
|
+
|
27
|
+
* You must set `catalog_terminus = static_compiler` in the puppet
|
28
|
+
master's puppet.conf.
|
29
|
+
* The puppet master's auth.conf must allow authenticated nodes to access the
|
30
|
+
`file_bucket_file` endpoint. This is enabled by default (see the
|
31
|
+
`path /file` rule), but if you have made your auth.conf more restrictive,
|
32
|
+
you may need to re-enable it.)
|
33
|
+
* If you are using multiple puppet masters, you must configure load balancer
|
34
|
+
affinity for agent nodes. This is because puppet masters other than the one
|
35
|
+
that compiled a given catalog may not have stored the required file contents
|
36
|
+
in their filebuckets.}
|
35
37
|
|
36
38
|
def compiler
|
37
39
|
@compiler ||= indirection.terminus(:compiler)
|
@@ -111,9 +111,11 @@ class Puppet::Network::HTTP::RackREST < Puppet::Network::HTTP::RackHttpHandler
|
|
111
111
|
# if we find SSL info in the headers, use them to get a hostname from the CN.
|
112
112
|
# try this with :ssl_client_header, which defaults should work for
|
113
113
|
# Apache with StdEnvVars.
|
114
|
-
|
115
|
-
|
116
|
-
|
114
|
+
subj_str = request.env[Puppet[:ssl_client_header]]
|
115
|
+
subject = Puppet::Util::SSL.subject_from_dn(subj_str || "")
|
116
|
+
|
117
|
+
if cn = Puppet::Util::SSL.cn_from_subject(subject)
|
118
|
+
result[:node] = cn
|
117
119
|
result[:authenticated] = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
|
118
120
|
else
|
119
121
|
result[:node] = resolve_node(result)
|
@@ -49,7 +49,7 @@ Puppet::Type.type(:package).provide :sun, :parent => Puppet::Provider::Package d
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def self.instances
|
52
|
-
parse_pkginfo(
|
52
|
+
parse_pkginfo(pkginfo('-l')).collect do |p|
|
53
53
|
hash = namemap(p)
|
54
54
|
hash[:provider] = :sun
|
55
55
|
new(hash)
|
@@ -58,17 +58,24 @@ Puppet::Type.type(:package).provide :sun, :parent => Puppet::Provider::Package d
|
|
58
58
|
|
59
59
|
# Get info on a package, optionally specifying a device.
|
60
60
|
def info2hash(device = nil)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
61
|
+
args = ['-l']
|
62
|
+
args << '-d' << device if device
|
63
|
+
args << @resource[:name]
|
64
|
+
begin
|
65
|
+
pkgs = self.class.parse_pkginfo(pkginfo(*args))
|
66
|
+
errmsg = case pkgs.size
|
67
|
+
when 0
|
68
|
+
'No message'
|
69
|
+
when 1
|
70
|
+
pkgs[0]['ERROR']
|
71
|
+
end
|
72
|
+
return self.class.namemap(pkgs[0]) if errmsg.nil?
|
73
|
+
# according to commit 41356a7 some errors do not raise an exception
|
74
|
+
# so eventhough pkginfo passed, we have to check the actual output
|
75
|
+
raise Puppet::Error, "Unable to get information about package #{@resource[:name]} because of: #{errmsg}"
|
76
|
+
rescue Puppet::ExecutionFailure
|
77
|
+
return {:ensure => :absent}
|
78
|
+
end
|
72
79
|
end
|
73
80
|
|
74
81
|
# Retrieve the version from the current package file.
|
@@ -1,3 +1,29 @@
|
|
1
|
+
# 'puppet/type/package' is being required here to avoid a load order issue that
|
2
|
+
# manifests as 'uninitialized constant Puppet::Util::Windows::MsiPackage' or
|
3
|
+
# 'uninitialized constant Puppet::Util::Windows::Package' (or similar case
|
4
|
+
# where Puppet::Provider::Package::Windows somehow ends up pointing to
|
5
|
+
# Puppet:Util::Windows) if puppet/provider/package/windows/package is loaded
|
6
|
+
# before the puppet/type/package.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# jpartlow@percival:~/work/puppet$ bundle exec rspec spec/unit/provider/package/windows/package_spec.rb spec/unit/provider/package/rpm_spec.rb
|
11
|
+
# Run options: exclude {:broken=>true}
|
12
|
+
# ..F..FFF........................
|
13
|
+
#
|
14
|
+
# Failures:
|
15
|
+
#
|
16
|
+
# 1) Puppet::Util::Package::Windows::Package::each should yield each package it finds
|
17
|
+
# Failure/Error: Puppet::Provider::Package::Windows::MsiPackage.expects(:from_registry).with('Google', {}).returns(package)
|
18
|
+
# NameError:
|
19
|
+
# uninitialized constant Puppet::Util::Windows::MsiPackage
|
20
|
+
# # ./spec/unit/provider/package/windows/package_spec.rb:24:in `block (3 levels) in <top (required)>'
|
21
|
+
#
|
22
|
+
# ---
|
23
|
+
#
|
24
|
+
# Needs more investigation to pinpoint what's going on.
|
25
|
+
#
|
26
|
+
require 'puppet/type/package'
|
1
27
|
require 'puppet/util/windows'
|
2
28
|
|
3
29
|
class Puppet::Provider::Package::Windows
|
@@ -170,13 +170,6 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
|
|
170
170
|
cmd << @resource[:name]
|
171
171
|
end
|
172
172
|
|
173
|
-
def modifycmd(param, value)
|
174
|
-
cmd = super(param, value)
|
175
|
-
cmd += check_manage_home if param == :home
|
176
|
-
|
177
|
-
cmd
|
178
|
-
end
|
179
|
-
|
180
173
|
def deletecmd
|
181
174
|
if @resource.forcelocal?
|
182
175
|
cmd = [command(:localdelete)]
|
data/lib/puppet/type/file.rb
CHANGED
@@ -58,47 +58,44 @@ Puppet::Type.newtype(:file) do
|
|
58
58
|
end
|
59
59
|
|
60
60
|
newparam(:backup) do
|
61
|
-
desc
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
file contents. Eventually, transactional support will be able to
|
100
|
-
automatically restore filebucketed files.
|
101
|
-
"
|
61
|
+
desc <<-EOT
|
62
|
+
Whether (and how) file content should be backed up before being replaced.
|
63
|
+
This attribute works best as a resource default in the site manifest
|
64
|
+
(`File { backup => main }`), so it can affect all file resources.
|
65
|
+
|
66
|
+
* If set to `false`, file content won't be backed up.
|
67
|
+
* If set to a string beginning with `.` (e.g., `.puppet-bak`), Puppet will
|
68
|
+
use copy the file in the same directory with that value as the extension
|
69
|
+
of the backup. (A value of `true` is a synonym for `.puppet-bak`.)
|
70
|
+
* If set to any other string, Puppet will try to back up to a filebucket
|
71
|
+
with that title. See the `filebucket` resource type for more details.
|
72
|
+
(This is the preferred method for backup, since it can be centralized
|
73
|
+
and queried.)
|
74
|
+
|
75
|
+
Default value: `puppet`, which backs up to a filebucket of the same name.
|
76
|
+
(Puppet automatically creates a **local** filebucket named `puppet` if one
|
77
|
+
doesn't already exist.)
|
78
|
+
|
79
|
+
Backing up to a local filebucket isn't particularly useful. If you want
|
80
|
+
to make organized use of backups, you will generally want to use the
|
81
|
+
puppet master server's filebucket service. This requires declaring a
|
82
|
+
filebucket resource and a resource default for the `backup` attribute
|
83
|
+
in site.pp:
|
84
|
+
|
85
|
+
# /etc/puppet/manifests/site.pp
|
86
|
+
filebucket { 'main':
|
87
|
+
path => false, # This is required for remote filebuckets.
|
88
|
+
server => 'puppet.example.com', # Optional; defaults to the configured puppet master.
|
89
|
+
}
|
90
|
+
|
91
|
+
File { backup => main, }
|
92
|
+
|
93
|
+
If you are using multiple puppet master servers, you will want to
|
94
|
+
centralize the contents of the filebucket. Either configure your load
|
95
|
+
balancer to direct all filebucket traffic to a single master, or use
|
96
|
+
something like an out-of-band rsync task to synchronize the content on all
|
97
|
+
masters.
|
98
|
+
EOT
|
102
99
|
|
103
100
|
defaultto "puppet"
|
104
101
|
|
@@ -2,35 +2,44 @@ module Puppet
|
|
2
2
|
require 'puppet/file_bucket/dipper'
|
3
3
|
|
4
4
|
newtype(:filebucket) do
|
5
|
-
@doc =
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
5
|
+
@doc = <<-EOT
|
6
|
+
A repository for storing and retrieving file content by MD5 checksum. Can
|
7
|
+
be local to each agent node, or centralized on a puppet master server. All
|
8
|
+
puppet masters provide a filebucket service that agent nodes can access
|
9
|
+
via HTTP, but you must declare a filebucket resource before any agents
|
10
|
+
will do so.
|
11
|
+
|
12
|
+
Filebuckets are used for the following features:
|
13
|
+
|
14
|
+
- **Content backups.** If the `file` type's `backup` attribute is set to
|
15
|
+
the name of a filebucket, Puppet will back up the _old_ content whenever
|
16
|
+
it rewrites a file; see the documentation for the `file` type for more
|
17
|
+
details. These backups can be used for manual recovery of content, but
|
18
|
+
are more commonly used to display changes and differences in a tool like
|
19
|
+
Puppet Dashboard.
|
20
|
+
- **Content distribution.** The optional static compiler populates the
|
21
|
+
puppet master's filebucket with the _desired_ content for each file,
|
22
|
+
then instructs the agent to retrieve the content for a specific
|
23
|
+
checksum. For more details,
|
24
|
+
[see the `static_compiler` section in the catalog indirection docs](http://docs.puppetlabs.com/references/latest/indirection.html#catalog).
|
25
|
+
|
26
|
+
To use a central filebucket for backups, you will usually want to declare
|
27
|
+
a filebucket resource and a resource default for the `backup` attribute
|
28
|
+
in site.pp:
|
29
|
+
|
30
|
+
# /etc/puppet/manifests/site.pp
|
23
31
|
filebucket { 'main':
|
24
|
-
|
25
|
-
|
26
|
-
# Due to a known issue, path must be set to false for remote filebuckets.
|
32
|
+
path => false, # This is required for remote filebuckets.
|
33
|
+
server => 'puppet.example.com', # Optional; defaults to the configured puppet master.
|
27
34
|
}
|
28
35
|
|
29
|
-
|
30
|
-
File { backup => main }
|
36
|
+
File { backup => main, }
|
31
37
|
|
32
|
-
|
33
|
-
work in a default configuration.
|
38
|
+
Puppet master servers automatically provide the filebucket service, so
|
39
|
+
this will work in a default configuration. If you have a heavily
|
40
|
+
restricted `auth.conf` file, you may need to allow access to the
|
41
|
+
`file_bucket_file` endpoint.
|
42
|
+
EOT
|
34
43
|
|
35
44
|
newparam(:name) do
|
36
45
|
desc "The name of the filebucket."
|
@@ -38,27 +47,25 @@ module Puppet
|
|
38
47
|
end
|
39
48
|
|
40
49
|
newparam(:server) do
|
41
|
-
desc "The server providing the remote filebucket.
|
42
|
-
|
43
|
-
|
44
|
-
in the config or at the commandline is used.
|
50
|
+
desc "The server providing the remote filebucket service. Defaults to the
|
51
|
+
value of the `server` setting (that is, the currently configured
|
52
|
+
puppet master server).
|
45
53
|
|
46
|
-
|
47
|
-
false if you wish to specify a `server` attribute."
|
54
|
+
This setting is _only_ consulted if the `path` attribute is set to `false`."
|
48
55
|
defaultto { Puppet[:server] }
|
49
56
|
end
|
50
57
|
|
51
58
|
newparam(:port) do
|
52
|
-
desc "The port on which the remote server is listening.
|
53
|
-
|
59
|
+
desc "The port on which the remote server is listening. Defaults to the
|
60
|
+
value of the `masterport` setting, which is usually %s." % Puppet[:masterport]
|
54
61
|
|
55
62
|
defaultto { Puppet[:masterport] }
|
56
63
|
end
|
57
64
|
|
58
65
|
newparam(:path) do
|
59
|
-
desc "The path to the
|
60
|
-
|
61
|
-
|
66
|
+
desc "The path to the _local_ filebucket; defaults to the value of the
|
67
|
+
`clientbucketdir` setting. To use a remote filebucket, you _must_ set
|
68
|
+
this attribute to `false`."
|
62
69
|
|
63
70
|
defaultto { Puppet[:clientbucketdir] }
|
64
71
|
|
data/lib/puppet/type/user.rb
CHANGED
@@ -23,7 +23,7 @@ module Puppet
|
|
23
23
|
"The provider supports duplicate users with the same UID."
|
24
24
|
|
25
25
|
feature :manages_homedir,
|
26
|
-
"The provider can create
|
26
|
+
"The provider can create and remove home directories."
|
27
27
|
|
28
28
|
feature :manages_passwords,
|
29
29
|
"The provider can modify user passwords, by accepting a password
|
@@ -303,10 +303,8 @@ module Puppet
|
|
303
303
|
|
304
304
|
newparam(:managehome, :boolean => true) do
|
305
305
|
desc "Whether to manage the home directory when managing the user.
|
306
|
-
This will create the home directory when `ensure => present`,
|
307
|
-
delete the home directory when `ensure => absent`.
|
308
|
-
this will update the user's home directory when the `home` property
|
309
|
-
changes. Defaults to `false`."
|
306
|
+
This will create the home directory when `ensure => present`, and
|
307
|
+
delete the home directory when `ensure => absent`. Defaults to `false`."
|
310
308
|
|
311
309
|
newvalues(:true, :false)
|
312
310
|
|
data/lib/puppet/util/ssl.rb
CHANGED
@@ -4,6 +4,14 @@
|
|
4
4
|
#
|
5
5
|
# @api private
|
6
6
|
module Puppet::Util::SSL
|
7
|
+
NO_NAME = OpenSSL::X509::Name.new
|
8
|
+
|
9
|
+
DN_PARSERS = [
|
10
|
+
OpenSSL::X509::Name.method(:parse_rfc2253),
|
11
|
+
OpenSSL::X509::Name.method(:parse_openssl),
|
12
|
+
lambda { |dn| NO_NAME }
|
13
|
+
]
|
14
|
+
|
7
15
|
# Given a DN string, parse it into an OpenSSL certificate subject. This
|
8
16
|
# method will flexibly handle both OpenSSl and RFC2253 formats, as given by
|
9
17
|
# nginx and Apache, respectively.
|
@@ -12,13 +20,16 @@ module Puppet::Util::SSL
|
|
12
20
|
#
|
13
21
|
# @return [OpenSSL::X509::Name] the certificate subject
|
14
22
|
def self.subject_from_dn(dn)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
if is_possibly_valid_dn?(dn)
|
24
|
+
DN_PARSERS.each do |parser|
|
25
|
+
begin
|
26
|
+
return parser.call(dn)
|
27
|
+
rescue OpenSSL::X509::NameError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
NO_NAME
|
20
32
|
end
|
21
|
-
subject
|
22
33
|
end
|
23
34
|
|
24
35
|
##
|
@@ -35,4 +46,8 @@ module Puppet::Util::SSL
|
|
35
46
|
(subject.to_a.assoc('CN') || [])[1]
|
36
47
|
end
|
37
48
|
end
|
49
|
+
|
50
|
+
def self.is_possibly_valid_dn?(dn)
|
51
|
+
dn =~ /=/
|
52
|
+
end
|
38
53
|
end
|
data/lib/puppet/version.rb
CHANGED
@@ -253,6 +253,23 @@ describe "Puppet::Network::HTTP::RackREST", :if => Puppet.features.rack? do
|
|
253
253
|
@handler.expects(:resolve_node).returns("host.domain.com")
|
254
254
|
@handler.params(req)[:node].should == "host.domain.com"
|
255
255
|
end
|
256
|
+
|
257
|
+
it "should resolve the node name with an ip address look-up if a certificate without a CN is present" do
|
258
|
+
Puppet[:ssl_client_header] = "myheader"
|
259
|
+
req = mk_req('/', "myheader" => "O=no CN")
|
260
|
+
@handler.expects(:resolve_node).returns("host.domain.com")
|
261
|
+
@handler.params(req)[:node].should == "host.domain.com"
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should not allow authentication via the verify header if there is no CN available" do
|
265
|
+
Puppet[:ssl_client_header] = "dn_header"
|
266
|
+
Puppet[:ssl_client_verify_header] = "verify_header"
|
267
|
+
req = mk_req('/', "dn_header" => "O=no CN", "verify_header" => 'SUCCESS')
|
268
|
+
|
269
|
+
@handler.expects(:resolve_node).returns("host.domain.com")
|
270
|
+
|
271
|
+
@handler.params(req)[:authenticated].should be_false
|
272
|
+
end
|
256
273
|
end
|
257
274
|
end
|
258
275
|
end
|
@@ -5,14 +5,6 @@ describe Puppet::Type.type(:package).provider(:sun) do
|
|
5
5
|
let(:resource) { Puppet::Type.type(:package).new(:name => 'dummy', :ensure => :installed, :provider => :sun) }
|
6
6
|
let(:provider) { resource.provider }
|
7
7
|
|
8
|
-
before(:each) do
|
9
|
-
# Stub some provider methods to avoid needing the actual software
|
10
|
-
# installed, so we can test on whatever platform we want.
|
11
|
-
provider.class.stubs(:command).with(:pkginfo).returns('/usr/bin/pkginfo')
|
12
|
-
provider.class.stubs(:command).with(:pkgadd).returns('/usr/sbin/pkgadd')
|
13
|
-
provider.class.stubs(:command).with(:pkgrm).returns('/usr/sbin/pkgrm')
|
14
|
-
end
|
15
|
-
|
16
8
|
describe 'provider features' do
|
17
9
|
it { should be_installable }
|
18
10
|
it { should be_uninstallable }
|
@@ -35,7 +27,7 @@ describe Puppet::Type.type(:package).provider(:sun) do
|
|
35
27
|
end
|
36
28
|
|
37
29
|
it "should install a package if it is not present on update" do
|
38
|
-
|
30
|
+
provider.expects(:pkginfo).with('-l', 'dummy').returns File.read(my_fixture('dummy.server'))
|
39
31
|
provider.expects(:pkgrm).with(['-n', 'dummy'])
|
40
32
|
provider.expects(:install)
|
41
33
|
provider.update
|
@@ -74,7 +66,7 @@ describe Puppet::Type.type(:package).provider(:sun) do
|
|
74
66
|
|
75
67
|
context '#query' do
|
76
68
|
it "should find the package on query" do
|
77
|
-
|
69
|
+
provider.expects(:pkginfo).with('-l', 'dummy').returns File.read(my_fixture('dummy.server'))
|
78
70
|
provider.query.should == {
|
79
71
|
:name => 'SUNWdummy',
|
80
72
|
:category=>"system",
|
@@ -87,19 +79,19 @@ describe Puppet::Type.type(:package).provider(:sun) do
|
|
87
79
|
end
|
88
80
|
|
89
81
|
it "shouldn't find the package on query if it is not present" do
|
90
|
-
|
82
|
+
provider.expects(:pkginfo).with('-l', 'dummy').raises Puppet::ExecutionFailure, "Execution of 'pkginfo -l dummy' returned 3: ERROR: information for \"dummy\" not found."
|
91
83
|
provider.query.should == {:ensure => :absent}
|
92
84
|
end
|
93
85
|
|
94
86
|
it "unknown message should raise error." do
|
95
|
-
|
96
|
-
|
87
|
+
provider.expects(:pkginfo).with('-l', 'dummy').returns 'RANDOM'
|
88
|
+
expect { provider.query }.to raise_error Puppet::Error
|
97
89
|
end
|
98
90
|
end
|
99
91
|
|
100
92
|
context '#instance' do
|
101
93
|
it "should list instances when there are packages in the system" do
|
102
|
-
|
94
|
+
described_class.expects(:pkginfo).with('-l').returns File.read(my_fixture('simple'))
|
103
95
|
instances = provider.class.instances.map { |p| {:name => p.get(:name), :ensure => p.get(:ensure)} }
|
104
96
|
instances.size.should == 2
|
105
97
|
instances[0].should == {
|
@@ -113,7 +105,7 @@ describe Puppet::Type.type(:package).provider(:sun) do
|
|
113
105
|
end
|
114
106
|
|
115
107
|
it "should return empty if there were no packages" do
|
116
|
-
|
108
|
+
described_class.expects(:pkginfo).with('-l').returns ''
|
117
109
|
instances = provider.class.instances
|
118
110
|
instances.size.should == 0
|
119
111
|
end
|