puppet 0.9.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 (182) hide show
  1. data/CHANGELOG +0 -0
  2. data/COPYING +340 -0
  3. data/LICENSE +17 -0
  4. data/README +24 -0
  5. data/Rakefile +294 -0
  6. data/TODO +4 -0
  7. data/bin/cf2puppet +186 -0
  8. data/bin/puppet +176 -0
  9. data/bin/puppetca +213 -0
  10. data/bin/puppetd +246 -0
  11. data/bin/puppetdoc +184 -0
  12. data/bin/puppetmasterd +258 -0
  13. data/examples/code/allatonce +13 -0
  14. data/examples/code/assignments +11 -0
  15. data/examples/code/classing +35 -0
  16. data/examples/code/components +73 -0
  17. data/examples/code/execs +16 -0
  18. data/examples/code/failers/badclassnoparam +10 -0
  19. data/examples/code/failers/badclassparam +10 -0
  20. data/examples/code/failers/badcompnoparam +9 -0
  21. data/examples/code/failers/badcompparam +9 -0
  22. data/examples/code/failers/badtypeparam +3 -0
  23. data/examples/code/file.bl +11 -0
  24. data/examples/code/filedefaults +10 -0
  25. data/examples/code/fileparsing +116 -0
  26. data/examples/code/filerecursion +15 -0
  27. data/examples/code/functions +3 -0
  28. data/examples/code/groups +7 -0
  29. data/examples/code/head +30 -0
  30. data/examples/code/importing +8 -0
  31. data/examples/code/nodes +20 -0
  32. data/examples/code/one +8 -0
  33. data/examples/code/relationships +34 -0
  34. data/examples/code/selectors +28 -0
  35. data/examples/code/simpletests +11 -0
  36. data/examples/code/snippets/argumentdefaults +14 -0
  37. data/examples/code/snippets/casestatement +39 -0
  38. data/examples/code/snippets/classheirarchy.pp +15 -0
  39. data/examples/code/snippets/classincludes.pp +17 -0
  40. data/examples/code/snippets/classpathtest +11 -0
  41. data/examples/code/snippets/dirchmod +19 -0
  42. data/examples/code/snippets/failmissingexecpath.pp +13 -0
  43. data/examples/code/snippets/falsevalues.pp +3 -0
  44. data/examples/code/snippets/filecreate +11 -0
  45. data/examples/code/snippets/implicititeration +15 -0
  46. data/examples/code/snippets/multipleinstances +7 -0
  47. data/examples/code/snippets/namevartest +9 -0
  48. data/examples/code/snippets/scopetest +13 -0
  49. data/examples/code/snippets/selectorvalues.pp +22 -0
  50. data/examples/code/snippets/simpledefaults +5 -0
  51. data/examples/code/snippets/simpleselector +38 -0
  52. data/examples/code/svncommit +13 -0
  53. data/examples/root/bin/sleeper +69 -0
  54. data/examples/root/etc/configfile +0 -0
  55. data/examples/root/etc/debian-passwd +29 -0
  56. data/examples/root/etc/debian-syslog.conf +71 -0
  57. data/examples/root/etc/init.d/sleeper +65 -0
  58. data/examples/root/etc/otherfile +0 -0
  59. data/examples/root/etc/puppet/fileserver.conf +3 -0
  60. data/examples/root/etc/puppet/puppetmasterd.conf +10 -0
  61. data/ext/module:puppet +195 -0
  62. data/install.rb +270 -0
  63. data/lib/puppet.rb +249 -0
  64. data/lib/puppet/base64.rb +19 -0
  65. data/lib/puppet/client.rb +519 -0
  66. data/lib/puppet/config.rb +49 -0
  67. data/lib/puppet/daemon.rb +208 -0
  68. data/lib/puppet/element.rb +71 -0
  69. data/lib/puppet/event.rb +259 -0
  70. data/lib/puppet/log.rb +321 -0
  71. data/lib/puppet/metric.rb +250 -0
  72. data/lib/puppet/parsedfile.rb +38 -0
  73. data/lib/puppet/parser/ast.rb +1560 -0
  74. data/lib/puppet/parser/interpreter.rb +150 -0
  75. data/lib/puppet/parser/lexer.rb +226 -0
  76. data/lib/puppet/parser/parser.rb +1354 -0
  77. data/lib/puppet/parser/scope.rb +755 -0
  78. data/lib/puppet/server.rb +170 -0
  79. data/lib/puppet/server/authstore.rb +227 -0
  80. data/lib/puppet/server/ca.rb +140 -0
  81. data/lib/puppet/server/filebucket.rb +147 -0
  82. data/lib/puppet/server/fileserver.rb +477 -0
  83. data/lib/puppet/server/logger.rb +43 -0
  84. data/lib/puppet/server/master.rb +103 -0
  85. data/lib/puppet/server/servlet.rb +247 -0
  86. data/lib/puppet/sslcertificates.rb +737 -0
  87. data/lib/puppet/statechange.rb +150 -0
  88. data/lib/puppet/storage.rb +95 -0
  89. data/lib/puppet/transaction.rb +179 -0
  90. data/lib/puppet/transportable.rb +151 -0
  91. data/lib/puppet/type.rb +1354 -0
  92. data/lib/puppet/type/component.rb +141 -0
  93. data/lib/puppet/type/cron.rb +543 -0
  94. data/lib/puppet/type/exec.rb +316 -0
  95. data/lib/puppet/type/group.rb +152 -0
  96. data/lib/puppet/type/nameservice.rb +3 -0
  97. data/lib/puppet/type/nameservice/netinfo.rb +173 -0
  98. data/lib/puppet/type/nameservice/objectadd.rb +146 -0
  99. data/lib/puppet/type/nameservice/posix.rb +200 -0
  100. data/lib/puppet/type/package.rb +420 -0
  101. data/lib/puppet/type/package/apt.rb +70 -0
  102. data/lib/puppet/type/package/dpkg.rb +108 -0
  103. data/lib/puppet/type/package/rpm.rb +81 -0
  104. data/lib/puppet/type/package/sun.rb +117 -0
  105. data/lib/puppet/type/package/yum.rb +58 -0
  106. data/lib/puppet/type/pfile.rb +569 -0
  107. data/lib/puppet/type/pfile/checksum.rb +219 -0
  108. data/lib/puppet/type/pfile/create.rb +108 -0
  109. data/lib/puppet/type/pfile/group.rb +129 -0
  110. data/lib/puppet/type/pfile/mode.rb +131 -0
  111. data/lib/puppet/type/pfile/source.rb +264 -0
  112. data/lib/puppet/type/pfile/type.rb +31 -0
  113. data/lib/puppet/type/pfile/uid.rb +166 -0
  114. data/lib/puppet/type/pfilebucket.rb +80 -0
  115. data/lib/puppet/type/pprocess.rb +97 -0
  116. data/lib/puppet/type/service.rb +347 -0
  117. data/lib/puppet/type/service/base.rb +17 -0
  118. data/lib/puppet/type/service/debian.rb +50 -0
  119. data/lib/puppet/type/service/init.rb +145 -0
  120. data/lib/puppet/type/service/smf.rb +29 -0
  121. data/lib/puppet/type/state.rb +182 -0
  122. data/lib/puppet/type/symlink.rb +183 -0
  123. data/lib/puppet/type/tidy.rb +183 -0
  124. data/lib/puppet/type/typegen.rb +149 -0
  125. data/lib/puppet/type/typegen/filerecord.rb +243 -0
  126. data/lib/puppet/type/typegen/filetype.rb +316 -0
  127. data/lib/puppet/type/user.rb +290 -0
  128. data/lib/puppet/util.rb +138 -0
  129. data/test/certmgr/certmgr.rb +265 -0
  130. data/test/client/client.rb +203 -0
  131. data/test/executables/puppetbin.rb +53 -0
  132. data/test/executables/puppetca.rb +79 -0
  133. data/test/executables/puppetd.rb +71 -0
  134. data/test/executables/puppetmasterd.rb +153 -0
  135. data/test/executables/puppetmodule.rb +60 -0
  136. data/test/language/ast.rb +412 -0
  137. data/test/language/interpreter.rb +71 -0
  138. data/test/language/scope.rb +412 -0
  139. data/test/language/snippets.rb +445 -0
  140. data/test/other/events.rb +111 -0
  141. data/test/other/log.rb +195 -0
  142. data/test/other/metrics.rb +92 -0
  143. data/test/other/overrides.rb +115 -0
  144. data/test/other/parsedfile.rb +31 -0
  145. data/test/other/relationships.rb +113 -0
  146. data/test/other/state.rb +106 -0
  147. data/test/other/storage.rb +39 -0
  148. data/test/other/transactions.rb +235 -0
  149. data/test/parser/lexer.rb +120 -0
  150. data/test/parser/parser.rb +180 -0
  151. data/test/puppet/conffiles.rb +104 -0
  152. data/test/puppet/defaults.rb +100 -0
  153. data/test/puppet/error.rb +23 -0
  154. data/test/puppet/utiltest.rb +120 -0
  155. data/test/puppettest.rb +774 -0
  156. data/test/server/authstore.rb +209 -0
  157. data/test/server/bucket.rb +227 -0
  158. data/test/server/ca.rb +201 -0
  159. data/test/server/fileserver.rb +710 -0
  160. data/test/server/logger.rb +175 -0
  161. data/test/server/master.rb +150 -0
  162. data/test/server/server.rb +130 -0
  163. data/test/tagging/tagging.rb +80 -0
  164. data/test/test +51 -0
  165. data/test/types/basic.rb +119 -0
  166. data/test/types/component.rb +272 -0
  167. data/test/types/cron.rb +261 -0
  168. data/test/types/exec.rb +273 -0
  169. data/test/types/file.rb +616 -0
  170. data/test/types/filebucket.rb +167 -0
  171. data/test/types/fileignoresource.rb +287 -0
  172. data/test/types/filesources.rb +587 -0
  173. data/test/types/filetype.rb +162 -0
  174. data/test/types/group.rb +271 -0
  175. data/test/types/package.rb +205 -0
  176. data/test/types/query.rb +101 -0
  177. data/test/types/service.rb +100 -0
  178. data/test/types/symlink.rb +93 -0
  179. data/test/types/tidy.rb +124 -0
  180. data/test/types/type.rb +135 -0
  181. data/test/types/user.rb +371 -0
  182. metadata +243 -0
@@ -0,0 +1,17 @@
1
+ module Puppet
2
+ module ServiceTypes
3
+ module BaseSvc
4
+
5
+ # The command used to start. Generated if the 'binary' argument
6
+ # is passed.
7
+ def startcmd
8
+ if self[:binary]
9
+ return self[:binary]
10
+ else
11
+ raise Puppet::Error,
12
+ "Services must specify a start command or a binary"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,50 @@
1
+ require 'puppet/type/service/init'
2
+
3
+ # Manage debian services. Start/stop is the same as InitSvc, but enable/disable
4
+ # is special.
5
+ module Puppet
6
+ module ServiceTypes
7
+ module DebianSvc
8
+ include Puppet::ServiceTypes::InitSvc
9
+
10
+ # Remove the symlinks
11
+ def disable
12
+ output = %x{update-rc.d -f #{self.name} remove 2>/dev/null}
13
+
14
+ unless $? == 0
15
+ raise Puppet::Error, "Could not disable %s: %s" %
16
+ [self.name, output]
17
+ end
18
+ end
19
+
20
+ def enabled?
21
+ output = %x{update-rc.d -n -f #{self.name} remove 2>/dev/null}
22
+ unless $? == 0
23
+ raise Puppet::Error, "Could not check %s: %s" %
24
+ [self.name, output]
25
+ end
26
+
27
+ # If it's enabled, then it will print output showing removal of
28
+ # links.
29
+ if output =~ /etc\/rc\d.d/
30
+ return true
31
+ else
32
+ return false
33
+ end
34
+ end
35
+
36
+ def enable(runlevel)
37
+ if runlevel
38
+ raise Puppet::Error, "Specification of runlevels is not supported"
39
+ else
40
+ output = %x{update-rc.d #{self.name} defaults 2>/dev/null}
41
+ end
42
+
43
+ unless $? == 0
44
+ raise Puppet::Error, "Could not check %s: %s" %
45
+ [self.name, output]
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,145 @@
1
+ module Puppet
2
+ module ServiceTypes
3
+ module InitSvc
4
+ # Make sure we've got a search path set up. If they don't
5
+ # specify one, try to determine one.
6
+ def configchk
7
+ unless defined? @searchpaths
8
+ @searchpaths = []
9
+ end
10
+ unless @searchpaths.length > 0
11
+ if init = self.defaultinit
12
+ self.notice "Adding default init"
13
+ @searchpaths << init
14
+ else
15
+ self.notice "No default init for %s" %
16
+ Facter["operatingsystem"].value
17
+
18
+ raise Puppet::Error.new(
19
+ "You must specify a valid search path for service %s" %
20
+ self.name
21
+ )
22
+ end
23
+ end
24
+ end
25
+
26
+ # Get the default init path.
27
+ def defaultinit
28
+ unless defined? @defaultinit
29
+ case Facter["operatingsystem"].value
30
+ when "FreeBSD":
31
+ @defaultinit = "/etc/rc.d"
32
+ else
33
+ @defaultinit = "/etc/init.d"
34
+ @defaultrc = "/etc/rc%s.d"
35
+ end
36
+ end
37
+
38
+ return @defaultinit
39
+ end
40
+
41
+ # Mark that our init script supports 'status' commands.
42
+ def hasstatus=(value)
43
+ case value
44
+ when true, "true": @parameters[:hasstatus] = true
45
+ when false, "false": @parameters[:hasstatus] = false
46
+ else
47
+ raise Puppet::Error, "Invalid 'hasstatus' value %s" %
48
+ value.inspect
49
+ end
50
+ end
51
+
52
+ # it'd be nice if i didn't throw the output away...
53
+ # this command returns true if the exit code is 0, and returns
54
+ # false otherwise
55
+ def initcmd(cmd)
56
+ script = self.initscript
57
+
58
+ self.debug "Executing '%s %s' as initcmd for '%s'" %
59
+ [script,cmd,self]
60
+
61
+ rvalue = Kernel.system("%s %s" %
62
+ [script,cmd])
63
+
64
+ self.debug "'%s' ran with exit status '%s'" %
65
+ [cmd,rvalue]
66
+
67
+
68
+ rvalue
69
+ end
70
+
71
+ # Where is our init script?
72
+ def initscript
73
+ if defined? @initscript
74
+ return @initscript
75
+ else
76
+ @initscript = self.search(self.name)
77
+ end
78
+ end
79
+
80
+ # Store the search path for init scripts. This will generally not
81
+ # be called.
82
+ def parampath=(ary)
83
+ unless ary.is_a?(Array)
84
+ ary = [ary]
85
+ end
86
+ @parameters[:path] = ary
87
+ @searchpaths = ary.find_all { |dir|
88
+ File.directory?(dir)
89
+ }
90
+ end
91
+
92
+ # Enable a service, so it's started at boot time. This basically
93
+ # just creates links in the RC directories, which means that, well,
94
+ # we need to know where the rc directories are.
95
+ # FIXME This should probably be a state or something, and
96
+ # it should actually create use Symlink objects...
97
+ # At this point, people should just link objects for enabling,
98
+ # if they're running on a system that doesn't have a tool to
99
+ # manage init script links.
100
+ #def enable
101
+ #end
102
+
103
+ #def disable
104
+ #end
105
+
106
+ def search(name)
107
+ @searchpaths.each { |path|
108
+ fqname = File.join(path,name)
109
+ begin
110
+ stat = File.stat(fqname)
111
+ rescue
112
+ # should probably rescue specific errors...
113
+ self.debug("Could not find %s in %s" % [name,path])
114
+ next
115
+ end
116
+
117
+ # if we've gotten this far, we found a valid script
118
+ return fqname
119
+ }
120
+ raise Puppet::Error, "Could not find init script for '%s'" % name
121
+ end
122
+
123
+ # The start command is just the init scriptwith 'start'.
124
+ def startcmd
125
+ self.initscript + " start"
126
+ end
127
+
128
+ # If it was specified that the init script has a 'status' command, then
129
+ # we just return that; otherwise, we return false, which causes it to
130
+ # fallback to other mechanisms.
131
+ def statuscmd
132
+ if self[:hasstatus]
133
+ return self.initscript + " status"
134
+ else
135
+ return false
136
+ end
137
+ end
138
+
139
+ # The stop command is just the init script with 'stop'.
140
+ def stopcmd
141
+ self.initscript + " stop"
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,29 @@
1
+ module Puppet
2
+ module ServiceTypes
3
+ module SMFSvc
4
+ def restartcmd
5
+ end
6
+
7
+ # The start command is just the init scriptwith 'start'.
8
+ def startcmd
9
+ self.initscript + " start"
10
+ end
11
+
12
+ # If it was specified that the init script has a 'status' command, then
13
+ # we just return that; otherwise, we return false, which causes it to
14
+ # fallback to other mechanisms.
15
+ def statuscmd
16
+ if self[:hasstatus]
17
+ return self.initscript + " status"
18
+ else
19
+ return false
20
+ end
21
+ end
22
+
23
+ # The stop command is just the init script with 'stop'.
24
+ def stopcmd
25
+ self.initscript + " stop"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,182 @@
1
+ # The virtual base class for states, which are the self-contained building
2
+ # blocks for actually doing work on the system.
3
+
4
+ require 'puppet'
5
+ require 'puppet/element'
6
+ require 'puppet/statechange'
7
+
8
+ module Puppet
9
+ class State < Puppet::Element
10
+ attr_accessor :is, :parent
11
+
12
+ # Because 'should' uses an array, we have a special method for handling
13
+ # it. We also want to keep copies of the original values, so that
14
+ # they can be retrieved and compared later when merging.
15
+ attr_reader :shouldorig
16
+
17
+ @virtual = true
18
+
19
+ class << self
20
+ attr_accessor :unmanaged
21
+ attr_reader :name
22
+ end
23
+
24
+ # initialize our state
25
+ def initialize(hash)
26
+ @is = nil
27
+
28
+ unless hash.include?(:parent)
29
+ raise Puppet::DevError, "State %s was not passed a parent" % self
30
+ end
31
+ @parent = hash[:parent]
32
+
33
+ if hash.include?(:should)
34
+ self.should = hash[:should]
35
+ end
36
+
37
+ if hash.include?(:is)
38
+ self.is = hash[:is]
39
+ end
40
+ end
41
+
42
+ # Determine whether the state is in-sync or not. If @should is
43
+ # not defined or is set to a non-true value, then we do not have
44
+ # a valid value for it and thus consider the state to be in-sync
45
+ # since we cannot fix it. Otherwise, we expect our should value
46
+ # to be an array, and if @is matches any of those values, then
47
+ # we consider it to be in-sync.
48
+ def insync?
49
+ #debug "%s value is '%s', should be '%s'" %
50
+ # [self,self.is.inspect,self.should.inspect]
51
+ unless defined? @should and @should
52
+ return true
53
+ end
54
+
55
+ unless @should.is_a?(Array)
56
+ raise Puppet::DevError, "%s's should is not array" % self.class.name
57
+ end
58
+
59
+ # an empty array is analogous to no should values
60
+ if @should.empty?
61
+ return true
62
+ end
63
+
64
+ # Look for a matching value
65
+ @should.each { |val|
66
+ if @is == val
67
+ return true
68
+ end
69
+ }
70
+
71
+ # otherwise, return false
72
+ return false
73
+ end
74
+
75
+ def log(msg)
76
+ unless @parent[:loglevel]
77
+ raise Puppet::DevError, "Parent %s has no loglevel" %
78
+ @parent.to_s
79
+ end
80
+ Puppet::Log.create(
81
+ :level => @parent[:loglevel],
82
+ :message => msg,
83
+ :source => self
84
+ )
85
+ end
86
+
87
+ # each state class must define the name() method, and state instances
88
+ # do not change that name
89
+ # this implicitly means that a given object can only have one state
90
+ # instance of a given state class
91
+ def name
92
+ return self.class.name
93
+ end
94
+
95
+ # for testing whether we should actually do anything
96
+ def noop
97
+ unless defined? @noop
98
+ @noop = false
99
+ end
100
+ tmp = @noop || self.parent.noop || Puppet[:noop] || false
101
+ #debug "noop is %s" % tmp
102
+ return tmp
103
+ end
104
+
105
+ # return the full path to us, for logging and rollback; not currently
106
+ # used
107
+ def path
108
+ return [@parent.path, self.name].join("/")
109
+ end
110
+
111
+ # Only return the first value
112
+ def should
113
+ if defined? @should
114
+ unless @should.is_a?(Array)
115
+ self.warning @should.inspect
116
+ raise Puppet::DevError, "should for %s on %s is not an array" %
117
+ [self.class.name, @parent.name]
118
+ end
119
+ return @should[0]
120
+ else
121
+ return nil
122
+ end
123
+ end
124
+
125
+ # Set the should value.
126
+ def should=(values)
127
+ unless values.is_a?(Array)
128
+ values = [values]
129
+ end
130
+
131
+ @shouldorig = values
132
+
133
+ if self.respond_to?(:shouldprocess)
134
+ @should = values.collect { |val|
135
+ self.shouldprocess(val)
136
+ }
137
+ else
138
+ @should = values
139
+ end
140
+ end
141
+
142
+
143
+ # How should a state change be printed as a string?
144
+ def change_to_s
145
+ begin
146
+ if @is == :notfound
147
+ return "defined '%s' as '%s'" %
148
+ [self.name, self.should_to_s]
149
+ elsif self.should == :notfound
150
+ return "undefined %s from '%s'" %
151
+ [self.name, self.is_to_s]
152
+ else
153
+ return "%s changed '%s' to '%s'" %
154
+ [self.name, self.is_to_s, self.should_to_s]
155
+ end
156
+ rescue Puppet::Error, Puppet::DevError
157
+ raise
158
+ rescue => detail
159
+ raise Puppet::DevError, "Could not convert change %s to string: %s" %
160
+ [self.name, detail]
161
+ end
162
+ end
163
+
164
+ # because the @should and @is vars might be in weird formats,
165
+ # we need to set up a mechanism for pretty printing of the values
166
+ # default to just the values, but this way individual states can
167
+ # override these methods
168
+ def is_to_s
169
+ @is
170
+ end
171
+
172
+ def should_to_s
173
+ @should
174
+ end
175
+
176
+ def to_s
177
+ return "%s(%s)" % [@parent.name,self.name]
178
+ end
179
+ end
180
+ end
181
+
182
+ # $Id: state.rb 749 2005-11-22 05:33:42Z luke $
@@ -0,0 +1,183 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # $Id: symlink.rb 731 2005-10-26 04:44:25Z luke $
4
+
5
+ require 'etc'
6
+ require 'puppet/type/state'
7
+ require 'puppet/type/pfile'
8
+
9
+ module Puppet
10
+ # okay, how do we deal with parameters that don't have operations
11
+ # associated with them?
12
+ class State
13
+ class SymlinkTarget < Puppet::State
14
+ require 'etc'
15
+ attr_accessor :file
16
+
17
+ @doc = "Create a link to another file. Currently only symlinks
18
+ are supported, and attempts to replace normal files with
19
+ links will currently fail, while existing but incorrect symlinks
20
+ will be removed."
21
+ @name = :target
22
+
23
+ def create
24
+ begin
25
+ debug("Creating symlink '%s' to '%s'" %
26
+ [self.parent[:path],self.should])
27
+ unless File.symlink(self.should,self.parent[:path])
28
+ raise TypeError.new("Could not create symlink '%s'" %
29
+ self.parent[:path])
30
+ end
31
+ rescue => detail
32
+ raise TypeError.new("Cannot create symlink '%s': %s" %
33
+ [self.parent[:path],detail])
34
+ end
35
+ end
36
+
37
+ def remove
38
+ if FileTest.symlink?(self.parent[:path])
39
+ debug("Removing symlink '%s'" % self.parent[:path])
40
+ begin
41
+ File.unlink(self.parent[:path])
42
+ rescue
43
+ raise TypeError.new("Failed to remove symlink '%s'" %
44
+ self.parent[:path])
45
+ end
46
+ elsif FileTest.exists?(self.parent[:path])
47
+ raise TypeError.new("Cannot remove normal file '%s'" %
48
+ self.parent[:path])
49
+ else
50
+ debug("Symlink '%s' does not exist" %
51
+ self.parent[:path])
52
+ end
53
+ end
54
+
55
+ def retrieve
56
+ stat = nil
57
+
58
+ if FileTest.symlink?(self.parent[:path])
59
+ self.is = File.readlink(self.parent[:path])
60
+ debug("link value is '%s'" % self.is)
61
+ return
62
+ else
63
+ self.is = nil
64
+ return
65
+ end
66
+ end
67
+
68
+ # this is somewhat complicated, because it could exist and be
69
+ # a file
70
+ def sync
71
+ if self.should.nil?
72
+ self.remove()
73
+ else # it should exist and be a symlink
74
+ if FileTest.symlink?(self.parent[:path])
75
+ path = File.readlink(self.parent[:path])
76
+ if path != self.should
77
+ self.remove()
78
+ self.create()
79
+ end
80
+ elsif FileTest.exists?(self.parent[:path])
81
+ raise TypeError.new("Cannot replace normal file '%s'" %
82
+ self.parent[:path])
83
+ else
84
+ self.create()
85
+ end
86
+ end
87
+
88
+ #self.parent.newevent(:event => :inode_changed)
89
+ end
90
+ end
91
+ end
92
+
93
+ class Type
94
+ class Symlink < Type
95
+ attr_reader :stat, :path, :params
96
+ # class instance variable
97
+ @states = [
98
+ Puppet::State::SymlinkTarget
99
+ ]
100
+
101
+ @parameters = [
102
+ :path,
103
+ :recurse
104
+ ]
105
+
106
+ @paramdoc[:path] = "Path of link to create."
107
+ @paramdoc[:recurse] = "If target is a directory, recursively create
108
+ directories (using `file`'s `source` parameter) and link all
109
+ contained files."
110
+ @doc = "Create symbolic links to existing files."
111
+ @name = :symlink
112
+ @namevar = :path
113
+
114
+ def initialize(hash)
115
+ @arghash = self.argclean(hash.dup)
116
+ @arghash.delete(self.class.namevar)
117
+
118
+ super
119
+ end
120
+
121
+ def paramrecurse=(value)
122
+ @stat = nil
123
+ @target = self.state(:target).should
124
+
125
+ # we want to remove our state, because we're creating children
126
+ # to do the links
127
+ if FileTest.exist?(@target)
128
+ @stat = File.stat(@target)
129
+ else
130
+ self.info "Target %s must exist for recursive links" %
131
+ @target
132
+ return
133
+ end
134
+
135
+ # if we're a directory, then we descend into it; we only actually
136
+ # link to real files
137
+ unless @stat.directory?
138
+ return
139
+ end
140
+
141
+ self.delete(:target)
142
+
143
+ recurse = value
144
+ # we might have a string, rather than a number
145
+ if recurse.is_a?(String)
146
+ if recurse =~ /^[0-9]+$/
147
+ recurse = Integer(recurse)
148
+ #elsif recurse =~ /^inf/ # infinite recursion
149
+ else # anything else is infinite recursion
150
+ recurse = true
151
+ end
152
+ end
153
+
154
+ # are we at the end of the recursion?
155
+ if recurse == 0
156
+ return
157
+ end
158
+
159
+ # okay, we're not going to recurse ourselves here; instead, we're
160
+ # going to rely on the fact that we've already got all of that
161
+ # working in pfile
162
+
163
+ args = {
164
+ :name => self.name,
165
+ :linkmaker => true,
166
+ :recurse => recurse,
167
+ :source => @target
168
+ }
169
+
170
+ dir = Puppet::Type::PFile.implicitcreate(args)
171
+ dir.parent = self
172
+ self.debug "Got dir %s" % dir.name
173
+ self.push dir
174
+ #Dir.foreach(@target) { |file|
175
+ # next if file =~ /^\.\.?$/ # skip . and ..
176
+ # newtarget = File.join(@target,file)
177
+ # #stat = File.stat(File.join(@target,file))
178
+ # self.newchild(file, :target => newtarget)
179
+ #}
180
+ end
181
+ end # Puppet::Type::Symlink
182
+ end # Puppet::Type
183
+ end