puppet 0.23.1 → 0.23.2

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 (55) hide show
  1. data/CHANGELOG +31 -0
  2. data/bin/puppetd +2 -1
  3. data/conf/redhat/puppet.spec +9 -6
  4. data/conf/redhat/server.init +4 -5
  5. data/examples/code/mac_dscl.pp +28 -0
  6. data/examples/code/mac_dscl_revert.pp +26 -0
  7. data/examples/code/mac_netinfo.pp +5 -0
  8. data/examples/code/mac_pkgdmg.pp +7 -0
  9. data/ext/puppet-test +69 -2
  10. data/lib/puppet.rb +2 -2
  11. data/lib/puppet/configuration.rb +5 -1
  12. data/lib/puppet/network/server/mongrel.rb +3 -3
  13. data/lib/puppet/parser/ast.rb +2 -2
  14. data/lib/puppet/parser/ast/component.rb +3 -3
  15. data/lib/puppet/parser/ast/node.rb +2 -2
  16. data/lib/puppet/parser/collector.rb +2 -2
  17. data/lib/puppet/parser/interpreter.rb +38 -215
  18. data/lib/puppet/parser/parser.rb +11 -228
  19. data/lib/puppet/parser/parser_support.rb +447 -0
  20. data/lib/puppet/parser/resource/param.rb +2 -2
  21. data/lib/puppet/provider.rb +5 -3
  22. data/lib/puppet/provider/cron/crontab.rb +22 -9
  23. data/lib/puppet/provider/group/directoryservice.rb +23 -0
  24. data/lib/puppet/provider/interface/redhat.rb +251 -0
  25. data/lib/puppet/provider/interface/sunos.rb +116 -0
  26. data/lib/puppet/provider/mount.rb +4 -1
  27. data/lib/puppet/provider/nameservice/directoryservice.rb +341 -0
  28. data/lib/puppet/provider/package/dpkg.rb +2 -2
  29. data/lib/puppet/provider/package/openbsd.rb +2 -2
  30. data/lib/puppet/provider/package/rpm.rb +2 -4
  31. data/lib/puppet/provider/package/sun.rb +2 -2
  32. data/lib/puppet/provider/parsedfile.rb +32 -29
  33. data/lib/puppet/provider/user/directoryservice.rb +116 -0
  34. data/lib/puppet/rails/host.rb +1 -1
  35. data/lib/puppet/reference/configuration.rb +7 -4
  36. data/lib/puppet/type/interface.rb +57 -0
  37. data/lib/puppet/type/pfile/group.rb +2 -2
  38. data/lib/puppet/util/config.rb +10 -3
  39. data/lib/puppet/util/fileparsing.rb +2 -2
  40. data/test/language/ast/hostclass.rb +1 -17
  41. data/test/language/interpreter.rb +18 -388
  42. data/test/language/node.rb +8 -8
  43. data/test/language/parser.rb +444 -45
  44. data/test/lib/puppettest/parsertesting.rb +2 -2
  45. data/test/lib/puppettest/support/collection.rb +2 -2
  46. data/test/network/server/mongrel_test.rb +24 -3
  47. data/test/rails/collection.rb +34 -1
  48. data/test/ral/providers/cron/crontab.rb +198 -40
  49. data/test/ral/providers/mount/parsed.rb +69 -46
  50. data/test/ral/providers/parsedfile.rb +20 -28
  51. data/test/ral/types/cron.rb +20 -24
  52. data/test/ral/types/interface.rb +40 -0
  53. data/test/ral/types/package.rb +6 -2
  54. data/test/util/config.rb +106 -30
  55. metadata +14 -2
@@ -12,7 +12,7 @@ class Puppet::Parser::Resource::Param
12
12
  end
13
13
 
14
14
  def inspect
15
- "#<#{self.class} @name => #{self.name}, @value => #{self.value}, @source => #{self.source.type}>"
15
+ "#<#{self.class} @name => #{self.name}, @value => #{self.value}, @source => #{self.source.name}>"
16
16
  end
17
17
 
18
18
  def line_to_i
@@ -88,4 +88,4 @@ class Puppet::Parser::Resource::Param
88
88
  end
89
89
  end
90
90
 
91
- # $Id: param.rb 2706 2007-07-18 19:47:09Z luke $
91
+ # $Id: param.rb 2742 2007-08-03 23:49:53Z luke $
@@ -337,7 +337,9 @@ class Puppet::Provider
337
337
 
338
338
  def initialize(resource = nil)
339
339
  if resource.is_a?(Hash)
340
- @property_hash = resource.dup
340
+ # We don't use a duplicate here, because some providers (ParsedFile, at least)
341
+ # use the hash here for later events.
342
+ @property_hash = resource
341
343
  elsif resource
342
344
  @resource = resource if resource
343
345
  # LAK 2007-05-09: Keep the model stuff around for backward compatibility
@@ -354,7 +356,7 @@ class Puppet::Provider
354
356
  elsif self.resource
355
357
  resource.name
356
358
  else
357
- raise Puppet::DevError, "No resource and no name in property hash"
359
+ raise Puppet::DevError, "No resource and no name in property hash in %s instance" % self.class.name
358
360
  end
359
361
  end
360
362
 
@@ -370,4 +372,4 @@ class Puppet::Provider
370
372
  end
371
373
  end
372
374
 
373
- # $Id: provider.rb 2588 2007-06-15 14:05:10Z luke $
375
+ # $Id: provider.rb 2753 2007-08-07 02:38:45Z luke $
@@ -78,10 +78,10 @@ Puppet::Type.type(:cron).provide(:crontab,
78
78
  # Return the header placed at the top of each generated file, warning
79
79
  # users that modifying this file manually is probably a bad idea.
80
80
  def self.header
81
- %{# HEADER This file was autogenerated at #{Time.now} by puppet.
82
- # HEADER While it can still be managed manually, it is definitely notrecommended.
83
- # HEADER Note particularly that the comments starting with 'Puppet Name' should
84
- # HEADER not be deleted, as doing so could cause duplicate cron jobs.\n}
81
+ %{# HEADER: This file was autogenerated at #{Time.now} by puppet.
82
+ # HEADER: While it can still be managed manually, it is definitely not recommended.
83
+ # HEADER: Note particularly that the comments starting with 'Puppet Name' should
84
+ # HEADER: not be deleted, as doing so could cause duplicate cron jobs.\n}
85
85
  end
86
86
 
87
87
  # See if we can match the record against an existing cron job.
@@ -134,31 +134,44 @@ Puppet::Type.type(:cron).provide(:crontab,
134
134
  # Collapse name and env records.
135
135
  def self.prefetch_hook(records)
136
136
  name = nil
137
- envs = []
138
- records.each { |record|
137
+ envs = nil
138
+ result = records.each { |record|
139
139
  case record[:record_type]
140
140
  when :comment:
141
141
  if record[:name]
142
142
  name = record[:name]
143
143
  record[:skip] = true
144
+
145
+ # Start collecting env values
146
+ envs = []
144
147
  end
145
148
  when :environment:
146
- if name
149
+ # If we're collecting env values (meaning we're in a named cronjob),
150
+ # store the line and skip the record.
151
+ if envs
147
152
  envs << record[:line]
148
153
  record[:skip] = true
149
154
  end
155
+ when :blank:
156
+ # nothing
150
157
  else
151
158
  if name
152
159
  record[:name] = name
153
160
  name = nil
154
161
  end
155
- if envs.empty?
162
+ if envs.nil? or envs.empty?
156
163
  record[:environment] = :absent
157
164
  else
165
+ # Collect all of the environment lines, and mark the records to be skipped,
166
+ # since their data is included in our crontab record.
158
167
  record[:environment] = envs
168
+
169
+ # And turn off env collection again
170
+ envs = nil
159
171
  end
160
172
  end
161
173
  }.reject { |record| record[:skip] }
174
+ result
162
175
  end
163
176
 
164
177
  def self.to_file(records)
@@ -185,4 +198,4 @@ Puppet::Type.type(:cron).provide(:crontab,
185
198
  end
186
199
  end
187
200
 
188
- # $Id: crontab.rb 2697 2007-07-14 21:13:04Z luke $
201
+ # $Id: crontab.rb 2750 2007-08-06 17:59:37Z luke $
@@ -0,0 +1,23 @@
1
+ # Created by Jeff McCune on 2007-07-22
2
+ # Copyright (c) 2007. All rights reserved.
3
+ #
4
+ # This program is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU General Public License
6
+ # as published by the Free Software Foundation (version 2 of the License)
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ # You should have received a copy of the GNU General Public License
12
+ # along with this program; if not, write to the Free Software
13
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA
14
+
15
+ require 'puppet/provider/nameservice/directoryservice'
16
+
17
+ Puppet::Type.type(:group).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do
18
+ desc "Group management using DirectoryService on OS X."
19
+
20
+ commands :dscl => "/usr/bin/dscl"
21
+ confine :operatingsystem => :darwin
22
+ #defaultfor :operatingsystem => :darwin
23
+ end
@@ -0,0 +1,251 @@
1
+ require 'puppet/provider/parsedfile'
2
+ require 'erb'
3
+
4
+ Puppet::Type.type(:interface).provide(:redhat) do
5
+ INTERFACE_DIR = "/etc/sysconfig/network-scripts"
6
+ confine :exists => INTERFACE_DIR
7
+ defaultfor :operatingsystem => [:fedora, :centos, :redhat]
8
+
9
+ # Create the setter/gettor methods to match the model.
10
+ mk_resource_methods
11
+
12
+ ALIAS_TEMPLATE = ERB.new <<-ALIAS
13
+ DEVICE=<%= self.device %>
14
+ ONBOOT=<%= self.on_boot %>
15
+ BOOTPROTO=<%= self.bootproto %>
16
+ IPADDR=<%= self.name %>
17
+ NETMASK=<%= self.netmask %>
18
+ BROADCAST=
19
+ ALIAS
20
+
21
+
22
+ LOOPBACK_TEMPLATE = ERB.new <<-LOOPBACKDUMMY
23
+ DEVICE=<%= self.device %>
24
+ ONBOOT=<%= self.on_boot %>
25
+ BOOTPROTO=static
26
+ IPADDR=<%= self.name %>
27
+ NETMASK=255.255.255.255
28
+ BROADCAST=
29
+ LOOPBACKDUMMY
30
+
31
+ # maximum number of dummy interfaces
32
+ MAX_DUMMIES = 10
33
+
34
+ # maximum number of aliases per interface
35
+ MAX_ALIASES_PER_IFACE = 10
36
+
37
+
38
+ @@dummies = []
39
+ @@aliases = Hash.new { |hash, key| hash[key] = [] }
40
+
41
+ # calculate which dummy interfaces are currently already in
42
+ # use prior to needing to call self.next_dummy later on.
43
+ def self.instances
44
+ # parse all of the config files at once
45
+ Dir.glob("%s/ifcfg-*" % INTERFACE_DIR).collect do |file|
46
+
47
+ record = parse(file)
48
+
49
+ # store the existing dummy interfaces
50
+ if record[:interface_type] == :dummy
51
+ @@dummies << record[:ifnum] unless @@dummies.include?(record[:ifnum])
52
+ end
53
+
54
+ if record[:interface_type] == :alias
55
+ @@aliases[record[:interface]] << record[:ifnum]
56
+ end
57
+ new(record)
58
+ end
59
+ end
60
+
61
+ # return the next avaliable dummy interface number, in the case where
62
+ # ifnum is not manually specified
63
+ def self.next_dummy
64
+ MAX_DUMMIES.times do |i|
65
+ unless @@dummies.include?(i.to_s)
66
+ @@dummies << i.to_s
67
+ return i.to_s
68
+ end
69
+ end
70
+ end
71
+
72
+ # return the next available alias on a given interface, in the case
73
+ # where ifnum if not manually specified
74
+ def self.next_alias(interface)
75
+ MAX_ALIASES_PER_IFACE.times do |i|
76
+ unless @@aliases[interface].include?(i.to_s)
77
+ @@aliases[interface] << i.to_s
78
+ return i.to_s
79
+ end
80
+ end
81
+ end
82
+
83
+ # base the ifnum, for dummy / loopback interface in linux
84
+ # on the last octect of the IP address
85
+
86
+ # Parse the existing file.
87
+ def self.parse(file)
88
+
89
+ opts = {}
90
+ return opts unless FileTest.exists?(file)
91
+
92
+ File.open(file) do |f|
93
+ f.readlines.each do |line|
94
+ if line =~ /^(\w+)=(.+)$/
95
+ opts[$1.downcase.intern] = $2
96
+ end
97
+ end
98
+ end
99
+
100
+ # figure out the "real" device information
101
+ case opts[:device]
102
+ when /:/:
103
+ if opts[:device].include?(":")
104
+ opts[:interface], opts[:ifnum] = opts[:device].split(":")
105
+ end
106
+
107
+ opts[:interface_type] = :alias
108
+ when /^dummy/:
109
+ opts[:interface_type] = :loopback
110
+ opts[:interface] = "dummy"
111
+
112
+ # take the number of the dummy interface, as this is used
113
+ # when working out whether to call next_dummy when dynamically
114
+ # creating these
115
+ opts[:ifnum] = opts[:device].sub("dummy",'')
116
+
117
+ @@dummies << opts[:ifnum].to_s unless @@dummies.include?(opts[:ifnum].to_s)
118
+ else
119
+ opts[:interface_type] = :normal
120
+ opts[:interface] = opts[:device]
121
+ end
122
+
123
+ # translate whether we come up on boot to true/false
124
+ case opts[:onboot].downcase
125
+ when "yes":
126
+ opts[:onboot] = :true
127
+ when "no":
128
+ opts[:onboot] = :false
129
+ else
130
+ # this case should never happen, but just in case
131
+ opts[:onboot] = false
132
+ end
133
+
134
+
135
+ # Remove any attributes we don't want. These would be
136
+ # pretty easy to support.
137
+ [:bootproto, :broadcast, :netmask, :device].each do |opt|
138
+ if opts.include?(opt)
139
+ opts.delete(opt)
140
+ end
141
+ end
142
+
143
+ if opts.include?(:ipaddr)
144
+ opts[:name] = opts[:ipaddr]
145
+ opts.delete(:ipaddr)
146
+ end
147
+
148
+ return opts
149
+
150
+ end
151
+
152
+ # Prefetch our interface list, yo.
153
+ def self.prefetch(resources)
154
+ instances.each do |prov|
155
+ if resource = resources[prov.name]
156
+ resource.provider = prov
157
+ end
158
+ end
159
+ end
160
+
161
+ def create
162
+ @resource.class.validproperties.each do |property|
163
+ if value = @resource.should(property)
164
+ @property_hash[property] = value
165
+ end
166
+ end
167
+ @property_hash[:name] = @resource.name
168
+
169
+ return (@resource.class.name.to_s + "_created").intern
170
+ end
171
+
172
+ def destroy
173
+ File.unlink(@resource[:target])
174
+ end
175
+
176
+ def exists?
177
+ FileTest.exists?(@resource[:target])
178
+ end
179
+
180
+ # generate the content for the interface file, so this is dependent
181
+ # on whether we are adding an alias to a real interface, or a loopback
182
+ # address (also dummy) on linux. For linux it's quite involved, and we
183
+ # will use an ERB template
184
+ def generate
185
+ # choose which template to use for the interface file, based on
186
+ # the interface type
187
+ case @resource.should(:interface_type)
188
+ when :loopback
189
+ return LOOPBACK_TEMPLATE.result(binding)
190
+ when :alias
191
+ return ALIAS_TEMPLATE.result(binding)
192
+ end
193
+ end
194
+
195
+ # Where should the file be written out?
196
+ # This defaults to INTERFACE_DIR/ifcfg-<namevar>, but can have a
197
+ # more symbolic name by setting interface_desc in the type.
198
+ def file_path
199
+ @resource[:interface_desc] ||= @resource[:name]
200
+ return File.join(INTERFACE_DIR, "ifcfg-" + @resource[:interface_desc])
201
+
202
+ end
203
+
204
+ # create the device name, so this based on the IP, and interface + type
205
+ def device
206
+ case @resource.should(:interface_type)
207
+ when :loopback
208
+ @property_hash[:ifnum] ||= self.class.next_dummy
209
+ return "dummy" + @property_hash[:ifnum]
210
+ when :alias
211
+ @property_hash[:ifnum] ||= self.class.next_alias(@resource[:interface])
212
+ return @resource[:interface] + ":" + @property_hash[:ifnum]
213
+ end
214
+ end
215
+
216
+ # whether the device is to be brought up on boot or not. converts
217
+ # the true / false of the type, into yes / no values respectively
218
+ # writing out the ifcfg-* files
219
+ def on_boot
220
+ case @property_hash[:onboot].to_s
221
+ when "true"
222
+ return "yes"
223
+ when "false"
224
+ return "no"
225
+ else
226
+ return "neither"
227
+ end
228
+ end
229
+
230
+ # Write the new file out.
231
+ def flush
232
+ # Don't flush to disk if we're removing the config.
233
+ return if @resource.should(:ensure) == :absent
234
+
235
+ @property_hash.each do |name, val|
236
+ if val == :absent
237
+ raise ArgumentError, "Propety %s must be provided" % val
238
+ end
239
+ end
240
+
241
+ File.open(@resource[:target], "w") do |f|
242
+ f.puts generate()
243
+ end
244
+ end
245
+
246
+ def prefetch
247
+ @property_hash = self.class.parse(@resource[:target])
248
+ end
249
+ end
250
+
251
+ # $Id: redhat.rb 2747 2007-08-05 19:01:39Z luke $
@@ -0,0 +1,116 @@
1
+ require 'puppet/provider/parsedfile'
2
+ require 'erb'
3
+
4
+ Puppet::Type.type(:interface).provide(:sunos,
5
+ :default_target => "/etc/hostname.lo0",
6
+ :parent => Puppet::Provider::ParsedFile,
7
+ :filetype => :flat
8
+ ) do
9
+
10
+ confine :kernel => "SunOS"
11
+
12
+ # Two types of lines:
13
+ # the first line does not start with 'addif'
14
+ # the rest do
15
+ record_line :sunos, :fields => %w{interface_type name ifopts onboot}, :rts => true, :absent => "", :block_eval => :instance do
16
+ # Parse our interface line
17
+ def process(line)
18
+ details = {:ensure => :present}
19
+
20
+ values = line.split(/\s+/)
21
+
22
+ # Are we the primary interface?
23
+ if values[0] == "addif"
24
+ details[:interface_type] = :alias
25
+ values.shift
26
+ else
27
+ details[:interface_type] = :normal
28
+ end
29
+
30
+ # Should the interface be up by default?
31
+ if values[-1] == "up"
32
+ details[:onboot] = :true
33
+ values.pop
34
+ else
35
+ details[:onboot] = :false
36
+ end
37
+
38
+ # Set the interface name.
39
+ details[:name] = values.shift
40
+
41
+ # Handle any interface options
42
+ unless values.empty?
43
+ details[:ifopts] = values.join(" ")
44
+ end
45
+
46
+ return details
47
+ end
48
+
49
+ # Turn our record into a line.
50
+ def to_line(details)
51
+ ret = []
52
+ if details[:interface_type] != :normal
53
+ ret << "addif"
54
+ end
55
+ ret << details[:name]
56
+
57
+ if details[:ifopts] and details[:ifopts] != :absent
58
+ if details[:ifopts].is_a?(Array)
59
+ ret << details[:ifopts].join(" ")
60
+ else
61
+ ret << details[:ifopts]
62
+ end
63
+ end
64
+
65
+ if details[:onboot] and details[:onboot] != :false
66
+ ret << "up"
67
+ end
68
+
69
+ return ret.join(" ")
70
+ end
71
+ end
72
+
73
+ def self.header
74
+ # over-write the default puppet behaviour of adding a header
75
+ # because on further investigation this breaks the solaris
76
+ # init scripts
77
+ %{}
78
+ end
79
+
80
+ # Get a list of interface instances.
81
+ def self.instances
82
+ Dir.glob("/etc/hostname.*").collect do |file|
83
+ # We really only expect one record from each file
84
+ parse(file).shift
85
+ end.collect { |record| new(record) }
86
+ end
87
+
88
+ def self.match(hash)
89
+ # see if we can match the has against an existing object
90
+ if model.find { |obj| obj.value(:name) == hash[:name] }
91
+ return obj
92
+ else
93
+ return false
94
+ end
95
+ end
96
+
97
+ # Prefetch our interface list, yo.
98
+ def self.prefetch(resources)
99
+ instances.each do |prov|
100
+ if resource = resources[prov.name]
101
+ resource.provider = prov
102
+ end
103
+ end
104
+ end
105
+
106
+ # Where should the file be written out? Can be overridden by setting
107
+ # :target in the model.
108
+ def file_path
109
+ unless @resource[:interface]
110
+ raise ArgumentError, "You must provide the interface name on Solaris"
111
+ end
112
+ return File.join("/etc", "hostname." + @resource[:interface])
113
+ end
114
+ end
115
+
116
+ # $Id: sunos.rb 2747 2007-08-05 19:01:39Z luke $