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.
- data/CHANGELOG +0 -0
- data/COPYING +340 -0
- data/LICENSE +17 -0
- data/README +24 -0
- data/Rakefile +294 -0
- data/TODO +4 -0
- data/bin/cf2puppet +186 -0
- data/bin/puppet +176 -0
- data/bin/puppetca +213 -0
- data/bin/puppetd +246 -0
- data/bin/puppetdoc +184 -0
- data/bin/puppetmasterd +258 -0
- data/examples/code/allatonce +13 -0
- data/examples/code/assignments +11 -0
- data/examples/code/classing +35 -0
- data/examples/code/components +73 -0
- data/examples/code/execs +16 -0
- data/examples/code/failers/badclassnoparam +10 -0
- data/examples/code/failers/badclassparam +10 -0
- data/examples/code/failers/badcompnoparam +9 -0
- data/examples/code/failers/badcompparam +9 -0
- data/examples/code/failers/badtypeparam +3 -0
- data/examples/code/file.bl +11 -0
- data/examples/code/filedefaults +10 -0
- data/examples/code/fileparsing +116 -0
- data/examples/code/filerecursion +15 -0
- data/examples/code/functions +3 -0
- data/examples/code/groups +7 -0
- data/examples/code/head +30 -0
- data/examples/code/importing +8 -0
- data/examples/code/nodes +20 -0
- data/examples/code/one +8 -0
- data/examples/code/relationships +34 -0
- data/examples/code/selectors +28 -0
- data/examples/code/simpletests +11 -0
- data/examples/code/snippets/argumentdefaults +14 -0
- data/examples/code/snippets/casestatement +39 -0
- data/examples/code/snippets/classheirarchy.pp +15 -0
- data/examples/code/snippets/classincludes.pp +17 -0
- data/examples/code/snippets/classpathtest +11 -0
- data/examples/code/snippets/dirchmod +19 -0
- data/examples/code/snippets/failmissingexecpath.pp +13 -0
- data/examples/code/snippets/falsevalues.pp +3 -0
- data/examples/code/snippets/filecreate +11 -0
- data/examples/code/snippets/implicititeration +15 -0
- data/examples/code/snippets/multipleinstances +7 -0
- data/examples/code/snippets/namevartest +9 -0
- data/examples/code/snippets/scopetest +13 -0
- data/examples/code/snippets/selectorvalues.pp +22 -0
- data/examples/code/snippets/simpledefaults +5 -0
- data/examples/code/snippets/simpleselector +38 -0
- data/examples/code/svncommit +13 -0
- data/examples/root/bin/sleeper +69 -0
- data/examples/root/etc/configfile +0 -0
- data/examples/root/etc/debian-passwd +29 -0
- data/examples/root/etc/debian-syslog.conf +71 -0
- data/examples/root/etc/init.d/sleeper +65 -0
- data/examples/root/etc/otherfile +0 -0
- data/examples/root/etc/puppet/fileserver.conf +3 -0
- data/examples/root/etc/puppet/puppetmasterd.conf +10 -0
- data/ext/module:puppet +195 -0
- data/install.rb +270 -0
- data/lib/puppet.rb +249 -0
- data/lib/puppet/base64.rb +19 -0
- data/lib/puppet/client.rb +519 -0
- data/lib/puppet/config.rb +49 -0
- data/lib/puppet/daemon.rb +208 -0
- data/lib/puppet/element.rb +71 -0
- data/lib/puppet/event.rb +259 -0
- data/lib/puppet/log.rb +321 -0
- data/lib/puppet/metric.rb +250 -0
- data/lib/puppet/parsedfile.rb +38 -0
- data/lib/puppet/parser/ast.rb +1560 -0
- data/lib/puppet/parser/interpreter.rb +150 -0
- data/lib/puppet/parser/lexer.rb +226 -0
- data/lib/puppet/parser/parser.rb +1354 -0
- data/lib/puppet/parser/scope.rb +755 -0
- data/lib/puppet/server.rb +170 -0
- data/lib/puppet/server/authstore.rb +227 -0
- data/lib/puppet/server/ca.rb +140 -0
- data/lib/puppet/server/filebucket.rb +147 -0
- data/lib/puppet/server/fileserver.rb +477 -0
- data/lib/puppet/server/logger.rb +43 -0
- data/lib/puppet/server/master.rb +103 -0
- data/lib/puppet/server/servlet.rb +247 -0
- data/lib/puppet/sslcertificates.rb +737 -0
- data/lib/puppet/statechange.rb +150 -0
- data/lib/puppet/storage.rb +95 -0
- data/lib/puppet/transaction.rb +179 -0
- data/lib/puppet/transportable.rb +151 -0
- data/lib/puppet/type.rb +1354 -0
- data/lib/puppet/type/component.rb +141 -0
- data/lib/puppet/type/cron.rb +543 -0
- data/lib/puppet/type/exec.rb +316 -0
- data/lib/puppet/type/group.rb +152 -0
- data/lib/puppet/type/nameservice.rb +3 -0
- data/lib/puppet/type/nameservice/netinfo.rb +173 -0
- data/lib/puppet/type/nameservice/objectadd.rb +146 -0
- data/lib/puppet/type/nameservice/posix.rb +200 -0
- data/lib/puppet/type/package.rb +420 -0
- data/lib/puppet/type/package/apt.rb +70 -0
- data/lib/puppet/type/package/dpkg.rb +108 -0
- data/lib/puppet/type/package/rpm.rb +81 -0
- data/lib/puppet/type/package/sun.rb +117 -0
- data/lib/puppet/type/package/yum.rb +58 -0
- data/lib/puppet/type/pfile.rb +569 -0
- data/lib/puppet/type/pfile/checksum.rb +219 -0
- data/lib/puppet/type/pfile/create.rb +108 -0
- data/lib/puppet/type/pfile/group.rb +129 -0
- data/lib/puppet/type/pfile/mode.rb +131 -0
- data/lib/puppet/type/pfile/source.rb +264 -0
- data/lib/puppet/type/pfile/type.rb +31 -0
- data/lib/puppet/type/pfile/uid.rb +166 -0
- data/lib/puppet/type/pfilebucket.rb +80 -0
- data/lib/puppet/type/pprocess.rb +97 -0
- data/lib/puppet/type/service.rb +347 -0
- data/lib/puppet/type/service/base.rb +17 -0
- data/lib/puppet/type/service/debian.rb +50 -0
- data/lib/puppet/type/service/init.rb +145 -0
- data/lib/puppet/type/service/smf.rb +29 -0
- data/lib/puppet/type/state.rb +182 -0
- data/lib/puppet/type/symlink.rb +183 -0
- data/lib/puppet/type/tidy.rb +183 -0
- data/lib/puppet/type/typegen.rb +149 -0
- data/lib/puppet/type/typegen/filerecord.rb +243 -0
- data/lib/puppet/type/typegen/filetype.rb +316 -0
- data/lib/puppet/type/user.rb +290 -0
- data/lib/puppet/util.rb +138 -0
- data/test/certmgr/certmgr.rb +265 -0
- data/test/client/client.rb +203 -0
- data/test/executables/puppetbin.rb +53 -0
- data/test/executables/puppetca.rb +79 -0
- data/test/executables/puppetd.rb +71 -0
- data/test/executables/puppetmasterd.rb +153 -0
- data/test/executables/puppetmodule.rb +60 -0
- data/test/language/ast.rb +412 -0
- data/test/language/interpreter.rb +71 -0
- data/test/language/scope.rb +412 -0
- data/test/language/snippets.rb +445 -0
- data/test/other/events.rb +111 -0
- data/test/other/log.rb +195 -0
- data/test/other/metrics.rb +92 -0
- data/test/other/overrides.rb +115 -0
- data/test/other/parsedfile.rb +31 -0
- data/test/other/relationships.rb +113 -0
- data/test/other/state.rb +106 -0
- data/test/other/storage.rb +39 -0
- data/test/other/transactions.rb +235 -0
- data/test/parser/lexer.rb +120 -0
- data/test/parser/parser.rb +180 -0
- data/test/puppet/conffiles.rb +104 -0
- data/test/puppet/defaults.rb +100 -0
- data/test/puppet/error.rb +23 -0
- data/test/puppet/utiltest.rb +120 -0
- data/test/puppettest.rb +774 -0
- data/test/server/authstore.rb +209 -0
- data/test/server/bucket.rb +227 -0
- data/test/server/ca.rb +201 -0
- data/test/server/fileserver.rb +710 -0
- data/test/server/logger.rb +175 -0
- data/test/server/master.rb +150 -0
- data/test/server/server.rb +130 -0
- data/test/tagging/tagging.rb +80 -0
- data/test/test +51 -0
- data/test/types/basic.rb +119 -0
- data/test/types/component.rb +272 -0
- data/test/types/cron.rb +261 -0
- data/test/types/exec.rb +273 -0
- data/test/types/file.rb +616 -0
- data/test/types/filebucket.rb +167 -0
- data/test/types/fileignoresource.rb +287 -0
- data/test/types/filesources.rb +587 -0
- data/test/types/filetype.rb +162 -0
- data/test/types/group.rb +271 -0
- data/test/types/package.rb +205 -0
- data/test/types/query.rb +101 -0
- data/test/types/service.rb +100 -0
- data/test/types/symlink.rb +93 -0
- data/test/types/tidy.rb +124 -0
- data/test/types/type.rb +135 -0
- data/test/types/user.rb +371 -0
- metadata +243 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
#--------------------
|
4
|
+
# accept and serve files
|
5
|
+
#
|
6
|
+
# $Id: filebucket.rb 635 2005-09-07 18:13:36Z luke $
|
7
|
+
|
8
|
+
|
9
|
+
require 'webrick'
|
10
|
+
#require 'webrick/https'
|
11
|
+
require 'xmlrpc/server'
|
12
|
+
require 'xmlrpc/client'
|
13
|
+
#require 'webrick/httpstatus'
|
14
|
+
require 'facter'
|
15
|
+
require 'digest/md5'
|
16
|
+
require 'puppet/base64'
|
17
|
+
|
18
|
+
module Puppet
|
19
|
+
class Server
|
20
|
+
class BucketError < RuntimeError; end
|
21
|
+
class FileBucket < Handler
|
22
|
+
@interface = XMLRPC::Service::Interface.new("puppetbucket") { |iface|
|
23
|
+
iface.add_method("string addfile(string, string)")
|
24
|
+
iface.add_method("string getfile(string)")
|
25
|
+
}
|
26
|
+
|
27
|
+
# this doesn't work for relative paths
|
28
|
+
def FileBucket.paths(base,md5)
|
29
|
+
return [
|
30
|
+
File.join(base, md5),
|
31
|
+
File.join(base, md5, "contents"),
|
32
|
+
File.join(base, md5, "paths")
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(hash)
|
37
|
+
# build our AST
|
38
|
+
|
39
|
+
if hash.include?(:ConflictCheck)
|
40
|
+
@conflictchk = hash[:ConflictCheck]
|
41
|
+
hash.delete(:ConflictCheck)
|
42
|
+
else
|
43
|
+
@conflictchk = true
|
44
|
+
end
|
45
|
+
|
46
|
+
if hash.include?(:Path)
|
47
|
+
@bucket = hash[:Path]
|
48
|
+
hash.delete(:Path)
|
49
|
+
else
|
50
|
+
if defined? Puppet
|
51
|
+
@bucket = Puppet[:bucketdir]
|
52
|
+
else
|
53
|
+
@bucket = File.expand_path("~/.filebucket")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Puppet.recmkdir(@bucket)
|
58
|
+
end
|
59
|
+
|
60
|
+
# accept a file from a client
|
61
|
+
def addfile(string,path, client = nil, clientip = nil)
|
62
|
+
#puts "entering addfile"
|
63
|
+
contents = Base64.decode64(string)
|
64
|
+
#puts "string is decoded"
|
65
|
+
|
66
|
+
md5 = Digest::MD5.hexdigest(contents)
|
67
|
+
#puts "md5 is made"
|
68
|
+
|
69
|
+
bpath, bfile, pathpath = FileBucket.paths(@bucket,md5)
|
70
|
+
|
71
|
+
# if it's a new directory...
|
72
|
+
if Puppet.recmkdir(bpath)
|
73
|
+
# ...then just create the file
|
74
|
+
#puts "creating file"
|
75
|
+
File.open(bfile, File::WRONLY|File::CREAT) { |of|
|
76
|
+
of.print contents
|
77
|
+
}
|
78
|
+
#puts "File is created"
|
79
|
+
else # if the dir already existed...
|
80
|
+
# ...we need to verify that the contents match the existing file
|
81
|
+
if @conflictchk
|
82
|
+
unless FileTest.exists?(bfile)
|
83
|
+
raise(BucketError,
|
84
|
+
"No file at %s for sum %s" % [bfile,md5], caller)
|
85
|
+
end
|
86
|
+
|
87
|
+
curfile = ""
|
88
|
+
File.open(bfile) { |of|
|
89
|
+
curfile = of.read
|
90
|
+
}
|
91
|
+
|
92
|
+
# if the contents don't match, then we've found a conflict
|
93
|
+
# unlikely, but quite bad
|
94
|
+
if curfile != contents
|
95
|
+
raise(BucketError,
|
96
|
+
"Got passed new contents for sum %s" % md5, caller)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
#puts "Conflict check is done"
|
100
|
+
end
|
101
|
+
|
102
|
+
# in either case, add the passed path to the list of paths
|
103
|
+
paths = nil
|
104
|
+
addpath = false
|
105
|
+
if FileTest.exists?(pathpath)
|
106
|
+
File.open(pathpath) { |of|
|
107
|
+
paths = of.readlines
|
108
|
+
}
|
109
|
+
|
110
|
+
# unless our path is already there...
|
111
|
+
unless paths.include?(path)
|
112
|
+
addpath = true
|
113
|
+
end
|
114
|
+
else
|
115
|
+
addpath = true
|
116
|
+
end
|
117
|
+
#puts "Path is checked"
|
118
|
+
|
119
|
+
# if it's a new file, or if our path isn't in the file yet, add it
|
120
|
+
if addpath
|
121
|
+
File.open(pathpath, File::WRONLY|File::CREAT|File::APPEND) { |of|
|
122
|
+
of.puts path
|
123
|
+
}
|
124
|
+
#puts "Path is added"
|
125
|
+
end
|
126
|
+
|
127
|
+
return md5
|
128
|
+
end
|
129
|
+
|
130
|
+
def getfile(md5, client = nil, clientip = nil)
|
131
|
+
bpath, bfile, bpaths = FileBucket.paths(@bucket,md5)
|
132
|
+
|
133
|
+
unless FileTest.exists?(bfile)
|
134
|
+
return false
|
135
|
+
end
|
136
|
+
|
137
|
+
contents = nil
|
138
|
+
File.open(bfile) { |of|
|
139
|
+
contents = of.read
|
140
|
+
}
|
141
|
+
|
142
|
+
return Base64.encode64(contents)
|
143
|
+
end
|
144
|
+
#---------------------------------------------------------------
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,477 @@
|
|
1
|
+
require 'puppet'
|
2
|
+
require 'webrick/httpstatus'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Puppet
|
6
|
+
class Server
|
7
|
+
class FileServerError < Puppet::Error; end
|
8
|
+
class FileServer < Handler
|
9
|
+
attr_accessor :local
|
10
|
+
|
11
|
+
Puppet.setdefault(:fileserverconfig, [:puppetconf, "fileserver.conf"])
|
12
|
+
|
13
|
+
#CHECKPARAMS = %w{checksum type mode owner group}
|
14
|
+
CHECKPARAMS = [:mode, :type, :owner, :group, :checksum]
|
15
|
+
|
16
|
+
@interface = XMLRPC::Service::Interface.new("fileserver") { |iface|
|
17
|
+
iface.add_method("string describe(string)")
|
18
|
+
iface.add_method("string list(string, boolean, array)")
|
19
|
+
iface.add_method("string retrieve(string)")
|
20
|
+
}
|
21
|
+
|
22
|
+
# Run 'retrieve' on a file. This gets the actual parameters, so
|
23
|
+
# we can pass them to the client.
|
24
|
+
def check(dir)
|
25
|
+
unless FileTest.exists?(dir)
|
26
|
+
Puppet.notice "File source %s does not exist" % dir
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
obj = nil
|
31
|
+
unless obj = Puppet::Type::PFile[dir]
|
32
|
+
obj = Puppet::Type::PFile.create(
|
33
|
+
:name => dir,
|
34
|
+
:check => CHECKPARAMS
|
35
|
+
)
|
36
|
+
end
|
37
|
+
# we should really have a timeout here -- we don't
|
38
|
+
# want to actually check on every connection, maybe no more
|
39
|
+
# than every 60 seconds or something
|
40
|
+
#@files[mount].evaluate
|
41
|
+
obj.evaluate
|
42
|
+
|
43
|
+
return obj
|
44
|
+
end
|
45
|
+
|
46
|
+
# Describe a given file. This returns all of the manageable aspects
|
47
|
+
# of that file.
|
48
|
+
def describe(file, client = nil, clientip = nil)
|
49
|
+
readconfig
|
50
|
+
mount, path = splitpath(file)
|
51
|
+
|
52
|
+
unless mount.allowed?(client, clientip)
|
53
|
+
raise Puppet::Server::AuthorizationError, "Cannot access %s" % mount
|
54
|
+
end
|
55
|
+
|
56
|
+
sdir = nil
|
57
|
+
unless sdir = subdir(mount, path)
|
58
|
+
mount.notice "Could not find subdirectory %s" %
|
59
|
+
"//%s/%s" % [mount, path]
|
60
|
+
return ""
|
61
|
+
end
|
62
|
+
|
63
|
+
obj = nil
|
64
|
+
unless obj = self.check(sdir)
|
65
|
+
return ""
|
66
|
+
end
|
67
|
+
|
68
|
+
desc = []
|
69
|
+
CHECKPARAMS.each { |check|
|
70
|
+
if state = obj.state(check)
|
71
|
+
unless state.is
|
72
|
+
mount.notice "Manually retrieving info for %s" % check
|
73
|
+
state.retrieve
|
74
|
+
end
|
75
|
+
desc << state.is
|
76
|
+
else
|
77
|
+
if check == "checksum" and obj.state(:type).is == "file"
|
78
|
+
mount.notice "File %s does not have data for %s" %
|
79
|
+
[obj.name, check]
|
80
|
+
end
|
81
|
+
desc << nil
|
82
|
+
end
|
83
|
+
}
|
84
|
+
|
85
|
+
return desc.join("\t")
|
86
|
+
end
|
87
|
+
|
88
|
+
# Deal with ignore parameters.
|
89
|
+
def handleignore(children, path, ignore)
|
90
|
+
ignore.each { |ignore|
|
91
|
+
Dir.glob(File.join(path,ignore), File::FNM_DOTMATCH) { |match|
|
92
|
+
children.delete(File.basename(match))
|
93
|
+
}
|
94
|
+
}
|
95
|
+
return children
|
96
|
+
end
|
97
|
+
|
98
|
+
# Create a new fileserving module.
|
99
|
+
def initialize(hash = {})
|
100
|
+
@mounts = {}
|
101
|
+
@files = {}
|
102
|
+
|
103
|
+
if hash[:Local]
|
104
|
+
@local = hash[:Local]
|
105
|
+
else
|
106
|
+
@local = false
|
107
|
+
end
|
108
|
+
|
109
|
+
if hash[:Config] == false
|
110
|
+
@noreadconfig = true
|
111
|
+
else
|
112
|
+
@config = hash[:Config] || Puppet[:fileserverconfig]
|
113
|
+
@noreadconfig = false
|
114
|
+
end
|
115
|
+
|
116
|
+
@configtimeout = hash[:ConfigTimeout] || 60
|
117
|
+
@configstamp = nil
|
118
|
+
@congigstatted = nil
|
119
|
+
|
120
|
+
if hash.include?(:Mount)
|
121
|
+
@passedconfig = true
|
122
|
+
unless hash[:Mount].is_a?(Hash)
|
123
|
+
raise Puppet::DevError, "Invalid mount hash %s" %
|
124
|
+
hash[:Mount].inspect
|
125
|
+
end
|
126
|
+
|
127
|
+
hash[:Mount].each { |dir, name|
|
128
|
+
if FileTest.exists?(dir)
|
129
|
+
self.mount(dir, name)
|
130
|
+
end
|
131
|
+
}
|
132
|
+
else
|
133
|
+
@passedconfig = false
|
134
|
+
readconfig
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# List a specific directory's contents.
|
139
|
+
def list(dir, recurse = false, ignore = false, client = nil, clientip = nil)
|
140
|
+
readconfig
|
141
|
+
mount, path = splitpath(dir)
|
142
|
+
|
143
|
+
unless mount.allowed?(client, clientip)
|
144
|
+
raise Puppet::Server::AuthorizationError, "Cannot access %s" % mount
|
145
|
+
end
|
146
|
+
|
147
|
+
subdir = nil
|
148
|
+
unless subdir = subdir(mount, path)
|
149
|
+
mount.notice "Could not find subdirectory %s" %
|
150
|
+
"%s:%s" % [mount, path]
|
151
|
+
return ""
|
152
|
+
end
|
153
|
+
|
154
|
+
obj = nil
|
155
|
+
unless FileTest.exists?(subdir)
|
156
|
+
return ""
|
157
|
+
end
|
158
|
+
|
159
|
+
rmdir = expand_mount(dir, mount)
|
160
|
+
desc = reclist(mount, rmdir, subdir, recurse, ignore)
|
161
|
+
|
162
|
+
if desc.length == 0
|
163
|
+
mount.notice "Got no information on //%s/%s" %
|
164
|
+
[mount, path]
|
165
|
+
return ""
|
166
|
+
end
|
167
|
+
|
168
|
+
desc.collect { |sub|
|
169
|
+
sub.join("\t")
|
170
|
+
}.join("\n")
|
171
|
+
end
|
172
|
+
|
173
|
+
# Mount a new directory with a name.
|
174
|
+
def mount(path, name)
|
175
|
+
if @mounts.include?(name)
|
176
|
+
if @mounts[name] != path
|
177
|
+
raise FileServerError, "%s is already mounted at %s" %
|
178
|
+
[@mounts[name].path, name]
|
179
|
+
else
|
180
|
+
# it's already mounted; no problem
|
181
|
+
return
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
if FileTest.directory?(path)
|
186
|
+
if FileTest.readable?(path)
|
187
|
+
@mounts[name] = Mount.new(name, path)
|
188
|
+
@mounts[name].info "Mounted"
|
189
|
+
else
|
190
|
+
raise FileServerError, "%s is not readable" % path
|
191
|
+
end
|
192
|
+
else
|
193
|
+
raise FileServerError, "%s is not a directory" % path
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Read the configuration file.
|
198
|
+
def readconfig
|
199
|
+
return if @noreadconfig
|
200
|
+
|
201
|
+
if @configstamp and FileTest.exists?(@config)
|
202
|
+
if @configtimeout and @configstatted
|
203
|
+
if Time.now - @configstatted > @configtimeout
|
204
|
+
@configstatted = Time.now
|
205
|
+
tmp = File.stat(@config).ctime
|
206
|
+
|
207
|
+
if tmp == @configstamp
|
208
|
+
return
|
209
|
+
end
|
210
|
+
else
|
211
|
+
return
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
newmounts = {}
|
217
|
+
begin
|
218
|
+
File.open(@config) { |f|
|
219
|
+
mount = nil
|
220
|
+
count = 1
|
221
|
+
f.each { |line|
|
222
|
+
case line
|
223
|
+
when /^\s*#/: next # skip comments
|
224
|
+
when /^\s*$/: next # skip blank lines
|
225
|
+
when /\[(\w+)\]/:
|
226
|
+
name = $1
|
227
|
+
if newmounts.include?(name)
|
228
|
+
raise FileServerError, "%s is already mounted at %s" %
|
229
|
+
[newmounts[name], name]
|
230
|
+
end
|
231
|
+
mount = Mount.new(name)
|
232
|
+
newmounts[name] = mount
|
233
|
+
when /^\s*(\w+)\s+(.+)$/:
|
234
|
+
var = $1
|
235
|
+
value = $2
|
236
|
+
case var
|
237
|
+
when "path":
|
238
|
+
begin
|
239
|
+
mount.path = value
|
240
|
+
rescue FileServerError => detail
|
241
|
+
Puppet.err "Removing mount %s: %s" %
|
242
|
+
[mount.name, detail]
|
243
|
+
newmounts.delete(mount.name)
|
244
|
+
end
|
245
|
+
when "allow":
|
246
|
+
value.split(/\s*,\s*/).each { |val|
|
247
|
+
begin
|
248
|
+
mount.info "Allowing %s access" % val
|
249
|
+
mount.allow(val)
|
250
|
+
rescue AuthStoreError => detail
|
251
|
+
raise FileServerError, "%s at line %s of %s" %
|
252
|
+
[detail.to_s, count, @config]
|
253
|
+
end
|
254
|
+
}
|
255
|
+
when "deny":
|
256
|
+
value.split(/\s*,\s*/).each { |val|
|
257
|
+
begin
|
258
|
+
mount.info "Denying %s access" % val
|
259
|
+
mount.deny(val)
|
260
|
+
rescue AuthStoreError => detail
|
261
|
+
raise FileServerError, "%s at line %s of %s" %
|
262
|
+
[detail.to_s, count, @config]
|
263
|
+
end
|
264
|
+
}
|
265
|
+
else
|
266
|
+
raise FileServerError,
|
267
|
+
"Invalid argument '%s' at line %s" % [var, count]
|
268
|
+
end
|
269
|
+
else
|
270
|
+
raise FileServerError, "Invalid line %s: %s" % [count, line]
|
271
|
+
end
|
272
|
+
count += 1
|
273
|
+
}
|
274
|
+
}
|
275
|
+
rescue Errno::EACCES => detail
|
276
|
+
Puppet.err "FileServer error: Cannot read %s; cannot serve" % @config
|
277
|
+
#raise Puppet::Error, "Cannot read %s" % @config
|
278
|
+
rescue Errno::ENOENT => detail
|
279
|
+
Puppet.err "FileServer error: '%s' does not exit; cannot serve" %
|
280
|
+
@config
|
281
|
+
#raise Puppet::Error, "%s does not exit" % @config
|
282
|
+
#rescue FileServerError => detail
|
283
|
+
# Puppet.err "FileServer error: %s" % detail
|
284
|
+
end
|
285
|
+
|
286
|
+
# Verify each of the mounts are valid.
|
287
|
+
# We let the check raise an error, so that it can raise an error
|
288
|
+
# pointing to the specific problem.
|
289
|
+
newmounts.each { |name, mount|
|
290
|
+
mount.valid?
|
291
|
+
}
|
292
|
+
@mounts = newmounts
|
293
|
+
|
294
|
+
@configstamp = File.stat(@config).ctime
|
295
|
+
@configstatted = Time.now
|
296
|
+
end
|
297
|
+
|
298
|
+
# Retrieve a file from the local disk and pass it to the remote
|
299
|
+
# client.
|
300
|
+
def retrieve(file, client = nil, clientip = nil)
|
301
|
+
readconfig
|
302
|
+
mount, path = splitpath(file)
|
303
|
+
|
304
|
+
unless mount.allowed?(client, clientip)
|
305
|
+
raise Puppet::Server::AuthorizationError, "Cannot access %s" % mount
|
306
|
+
end
|
307
|
+
|
308
|
+
fpath = nil
|
309
|
+
if path
|
310
|
+
fpath = File.join(mount.path, path)
|
311
|
+
else
|
312
|
+
fpath = mount.path
|
313
|
+
end
|
314
|
+
|
315
|
+
unless FileTest.exists?(fpath)
|
316
|
+
return ""
|
317
|
+
end
|
318
|
+
|
319
|
+
str = File.read(fpath)
|
320
|
+
|
321
|
+
if @local
|
322
|
+
return str
|
323
|
+
else
|
324
|
+
return CGI.escape(str)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
private
|
329
|
+
|
330
|
+
# Convert from the '/mount/path' form to the real path on disk.
|
331
|
+
def expand_mount(name, mount)
|
332
|
+
# Note that the user could have passed a path with multiple /'s
|
333
|
+
# in it, and we are likely to result in multiples, so we have to
|
334
|
+
# get rid of all of them.
|
335
|
+
name.sub(/\/#{mount.name}/, mount.path).gsub(%r{/+}, '/').sub(
|
336
|
+
%r{/$}, ''
|
337
|
+
)
|
338
|
+
end
|
339
|
+
|
340
|
+
# Recursively list the directory.
|
341
|
+
def reclist(mount, root, path, recurse, ignore)
|
342
|
+
# Take out the root of the path.
|
343
|
+
name = path.sub(root, '')
|
344
|
+
if name == ""
|
345
|
+
name = "/"
|
346
|
+
end
|
347
|
+
|
348
|
+
if name == path
|
349
|
+
raise FileServerError, "Could not match %s in %s" %
|
350
|
+
[root, path]
|
351
|
+
end
|
352
|
+
|
353
|
+
desc = [name]
|
354
|
+
ftype = File.stat(path).ftype
|
355
|
+
|
356
|
+
desc << ftype
|
357
|
+
if recurse.is_a?(Integer)
|
358
|
+
recurse -= 1
|
359
|
+
end
|
360
|
+
|
361
|
+
ary = [desc]
|
362
|
+
if recurse == true or (recurse.is_a?(Integer) and recurse > -1)
|
363
|
+
if ftype == "directory"
|
364
|
+
children = Dir.entries(path)
|
365
|
+
if ignore
|
366
|
+
children = handleignore(children, path, ignore)
|
367
|
+
end
|
368
|
+
children.each { |child|
|
369
|
+
next if child =~ /^\.\.?$/
|
370
|
+
reclist(mount, root, File.join(path, child), recurse, ignore).each { |cobj|
|
371
|
+
ary << cobj
|
372
|
+
}
|
373
|
+
}
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
return ary.reject { |c| c.nil? }
|
378
|
+
end
|
379
|
+
|
380
|
+
# Split the path into the separate mount point and path.
|
381
|
+
def splitpath(dir)
|
382
|
+
# the dir is based on one of the mounts
|
383
|
+
# so first retrieve the mount path
|
384
|
+
mount = nil
|
385
|
+
path = nil
|
386
|
+
if dir =~ %r{/(\w+)/?}
|
387
|
+
mount = $1
|
388
|
+
path = dir.sub(%r{/#{mount}/?}, '')
|
389
|
+
|
390
|
+
unless @mounts.include?(mount)
|
391
|
+
raise FileServerError, "Fileserver module '%s' not mounted" % mount
|
392
|
+
end
|
393
|
+
|
394
|
+
unless @mounts[mount].path
|
395
|
+
raise FileServerError,
|
396
|
+
"Fileserver error: Mount '%s' does not have a path set" % mount
|
397
|
+
end
|
398
|
+
|
399
|
+
# And now replace the name with the actual object.
|
400
|
+
mount = @mounts[mount]
|
401
|
+
else
|
402
|
+
raise FileServerError, "Fileserver error: Invalid path '%s'" % dir
|
403
|
+
end
|
404
|
+
|
405
|
+
if path == ""
|
406
|
+
path = nil
|
407
|
+
end
|
408
|
+
return mount, path
|
409
|
+
end
|
410
|
+
|
411
|
+
# Retrieve a specific directory relative to a mount point.
|
412
|
+
def subdir(mount, dir)
|
413
|
+
basedir = mount.path
|
414
|
+
|
415
|
+
dirname = nil
|
416
|
+
if dir
|
417
|
+
dirname = File.join(basedir, dir.split("/").join(File::SEPARATOR))
|
418
|
+
else
|
419
|
+
dirname = basedir
|
420
|
+
end
|
421
|
+
|
422
|
+
dirname
|
423
|
+
end
|
424
|
+
|
425
|
+
# A simple class for wrapping mount points. Instances of this class
|
426
|
+
# don't know about the enclosing object; they're mainly just used for
|
427
|
+
# authorization.
|
428
|
+
class Mount < AuthStore
|
429
|
+
attr_reader :path, :name
|
430
|
+
|
431
|
+
Puppet::Util.logmethods(self, true)
|
432
|
+
|
433
|
+
# Create out orbject. It must have a name.
|
434
|
+
def initialize(name, path = nil)
|
435
|
+
unless name =~ %r{^\w+$}
|
436
|
+
raise FileServerError, "Invalid name format '%s'" % name
|
437
|
+
end
|
438
|
+
@name = name
|
439
|
+
|
440
|
+
if path
|
441
|
+
self.path = path
|
442
|
+
else
|
443
|
+
@path = nil
|
444
|
+
end
|
445
|
+
|
446
|
+
super()
|
447
|
+
end
|
448
|
+
|
449
|
+
# Set the path.
|
450
|
+
def path=(path)
|
451
|
+
unless FileTest.exists?(path)
|
452
|
+
raise FileServerError, "%s does not exist" % path
|
453
|
+
end
|
454
|
+
@path = path
|
455
|
+
end
|
456
|
+
|
457
|
+
def to_s
|
458
|
+
if @path
|
459
|
+
@name + ":" + @path
|
460
|
+
else
|
461
|
+
@name
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
# Verify our configuration is valid. This should really check to
|
466
|
+
# make sure at least someone will be allowed, but, eh.
|
467
|
+
def valid?
|
468
|
+
unless @path
|
469
|
+
raise FileServerError, "No path specified"
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
# $Id: fileserver.rb 742 2005-11-16 17:12:11Z luke $
|