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.

@@ -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 `Filebucket['puppet']` resource in site.pp (or somewhere
19
- else where it will be added to every node's catalog). The title of this
20
- resource **MUST** be "puppet"; the static compiler treats this title as magical.
21
-
22
- # Note: the special $servername var always contains the master's FQDN,
23
- # even if it was reached at a different name.
24
- filebucket { puppet:
25
- server => $servername,
26
- path => false,
27
- }
28
-
29
- You must set `catalog_terminus = static_compiler` in the puppet master's puppet.conf.
30
-
31
- If you are using multiple puppet masters, you must configure load balancer
32
- affinity for agent nodes. This is because puppet masters other than the one
33
- that compiled a given catalog may not have stored the required file contents
34
- in their filebuckets.}
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
- if subj_str = request.env[Puppet[:ssl_client_header]]
115
- subject = Puppet::Util::SSL.subject_from_dn(subj_str)
116
- result[:node] = Puppet::Util::SSL.cn_from_subject(subject)
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(execute([command(:pkginfo), '-l'])).collect do |p|
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
- cmd = [command(:pkginfo), '-l']
62
- cmd << '-d' << device if device
63
- cmd << @resource[:name]
64
- pkgs = self.class.parse_pkginfo(execute(cmd, :failonfail => false, :combine => false))
65
- errmsg = case pkgs.size
66
- when 0; 'No message'
67
- when 1; pkgs[0]['ERROR']
68
- end
69
- return self.class.namemap(pkgs[0]) if errmsg.nil?
70
- return {:ensure => :absent} if errmsg =~ /information for "#{Regexp.escape(@resource[:name])}"/
71
- raise Puppet::Error, "Unable to get information about package #{@resource[:name]} because of: #{errmsg}"
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)]
@@ -58,47 +58,44 @@ Puppet::Type.newtype(:file) do
58
58
  end
59
59
 
60
60
  newparam(:backup) do
61
- desc "Whether files should be backed up before
62
- being replaced. The preferred method of backing files up is via
63
- a `filebucket`, which stores files by their MD5 sums and allows
64
- easy retrieval without littering directories with backups. You
65
- can specify a local filebucket or a network-accessible
66
- server-based filebucket by setting `backup => bucket-name`.
67
- Alternatively, if you specify any value that begins with a `.`
68
- (e.g., `.puppet-bak`), then Puppet will use copy the file in
69
- the same directory with that value as the extension of the
70
- backup. Setting `backup => false` disables all backups of the
71
- file in question.
72
-
73
- Puppet automatically creates a local filebucket named `puppet` and
74
- defaults to backing up there. To use a server-based filebucket,
75
- you must specify one in your configuration.
76
-
77
- filebucket { main:
78
- server => puppet,
79
- path => false,
80
- # The path => false line works around a known issue with the filebucket type.
81
- }
82
-
83
- The `puppet master` daemon creates a filebucket by default,
84
- so you can usually back up to your main server with this
85
- configuration. Once you've described the bucket in your
86
- configuration, you can use it in any file's backup attribute:
87
-
88
- file { \"/my/file\":
89
- source => \"/path/in/nfs/or/something\",
90
- backup => main
91
- }
92
-
93
- This will back the file up to the central server.
94
-
95
- At this point, the benefits of using a central filebucket are that you
96
- do not have backup files lying around on each of your machines, a given
97
- version of a file is only backed up once, you can restore any given file
98
- manually (no matter how old), and you can use Puppet Dashboard to view
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 = "A repository for backing up files. If no filebucket is
6
- defined, then files will be backed up in their current directory,
7
- but the filebucket can be either a host- or site-global repository
8
- for backing up. It stores files and returns the MD5 sum, which
9
- can later be used to retrieve the file if restoration becomes
10
- necessary. A filebucket does not do any work itself; instead,
11
- it can be specified as the value of *backup* in a **file** object.
12
-
13
- Currently, filebuckets are only useful for manual retrieval of
14
- accidentally removed files (e.g., you look in the log for the md5 sum
15
- and retrieve the file with that sum from the filebucket), but when
16
- transactions are fully supported filebuckets will be used to undo
17
- transactions.
18
-
19
- You will normally want to define a single filebucket for your
20
- whole network and then use that as the default backup location:
21
-
22
- # Define the bucket
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
- server => puppet,
25
- path => false,
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
- # Specify it as the default target
30
- File { backup => main }
36
+ File { backup => main, }
31
37
 
32
- Puppetmaster servers create a filebucket by default, so this will
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. If this is not
42
- specified then *path* is checked. If it is set, then the
43
- bucket is local. Otherwise the puppetmaster server specified
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
- Due to a known issue, you currently must set the `path` attribute to
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
- Defaults to the normal Puppet port, %s." % Puppet[:masterport]
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 local filebucket. If this is
60
- unset, then the bucket is remote. The parameter *server* must
61
- can be specified to set the remote server."
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
 
@@ -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, remove, and update home directories."
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`. Linux only:
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
 
@@ -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
- # try to parse both rfc2253 (Apache) and OpenSSL (nginx) formats
16
- begin
17
- subject = OpenSSL::X509::Name.parse_rfc2253(dn)
18
- rescue OpenSSL::X509::NameError
19
- subject = OpenSSL::X509::Name.parse_openssl(dn)
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
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
  module Puppet
10
- PUPPETVERSION = '3.2.0-rc2'
10
+ PUPPETVERSION = '3.2.1-rc1'
11
11
 
12
12
  ##
13
13
  # version is a public API method intended to always provide a fast and
@@ -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
- Puppet::Util::Execution.expects(:execute).with(['/usr/bin/pkginfo', '-l', 'dummy'], {:failonfail => false, :combine => false}).returns File.read(my_fixture('dummy.server'))
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
- Puppet::Util::Execution.expects(:execute).with(['/usr/bin/pkginfo', '-l', 'dummy'], {:failonfail => false, :combine => false}).returns File.read(my_fixture('dummy.server'))
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
- Puppet::Util::Execution.expects(:execute).with(['/usr/bin/pkginfo', '-l', 'dummy'], {:failonfail => false, :combine => false}).returns 'ERROR: information for "dummy" not found.'
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
- Puppet::Util::Execution.expects(:execute).with(['/usr/bin/pkginfo', '-l', 'dummy'], {:failonfail => false, :combine => false}).returns 'RANDOM'
96
- lambda { provider.query }.should raise_error(Puppet::Error)
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
- Puppet::Util::Execution.expects(:execute).with(['/usr/bin/pkginfo', '-l']).returns File.read(my_fixture('simple'))
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
- Puppet::Util::Execution.expects(:execute).with(['/usr/bin/pkginfo', '-l']).returns ''
108
+ described_class.expects(:pkginfo).with('-l').returns ''
117
109
  instances = provider.class.instances
118
110
  instances.size.should == 0
119
111
  end