kuzushi 0.0.35 → 0.0.36

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/VERSION +1 -1
  2. data/lib/kuzushi.rb +377 -344
  3. metadata +3 -3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.35
1
+ 0.0.36
@@ -13,348 +13,381 @@ require 'erb'
13
13
  ## user configs
14
14
 
15
15
  class Kuzushi
16
- attr_accessor :config
17
-
18
- def initialize(url)
19
- @url = url
20
- @base_url = File.dirname(url)
21
- if @url =~ /s3.amazonaws.com.*\/([^\/]*)[.](\d+)[.]tar[.]gz/
22
- @name = $1
23
- @version = $2
24
- end
25
- @configs = []
26
- @packages = []
27
- @tasks = []
28
- end
29
-
30
- def init
31
- @init = true
32
- start
33
- end
34
-
35
- def boot
36
- shell "mkdir -p /tmp/kuzushi/"
37
- shell "cd /tmp/kuzushi/ ; curl --silent '#{@url}' | tar xzv"
38
- @config = JSON.parse(File.read("/tmp/kuzushi/#{@name}/config.json"))
39
- end
40
-
41
- def start
42
- # load_config_stack(@name)
43
- boot
44
- run
45
- end
46
-
47
- def run
48
- process_stack
49
- log "----"
50
- @tasks.each do |t|
51
- log "TASK: #{t[:description]}"
52
- t[:blk].call
53
- end
54
- log "----"
55
- end
56
-
57
- protected
58
-
59
- def system
60
- ohai = Ohai::System.new
61
- ohai.all_plugins
62
- ohai
63
- end
64
-
65
- def http_get(url)
66
- RestClient.get(url)
67
- end
68
-
69
- def process_stack
70
- script get("before")
71
-
72
- process :packages
73
- process :local_packages
74
- process :gems
75
- process :volumes
76
- process :files
77
- process :users
78
- process :crontab
79
-
80
- script get("after")
81
- script get("init") if init?
82
- end
83
-
84
- ## magic goes here
85
- def process(type)
86
- ## if the file takes no args - just call it once
87
- if method("process_#{type}").arity == 0
88
- send("process_#{type}")
89
- else
90
- ## else call it once per item
91
- get_array(type).each do |item|
92
- script item["before"]
93
- if item.is_a? Hash
94
- send("process_#{type}", OpenStruct.new(item))
95
- else
96
- send("process_#{type}", item)
97
- end
98
- script item["after"]
99
- script item["init"] if init?
100
- end
101
- end
102
- end
103
-
104
- def process_packages
105
- @packages = get_array("packages")
106
- task "install packages" do
107
- shell "apt-get install -y #{@packages.join(" ")}" unless @packages.empty?
108
- end
109
- end
110
-
111
- def process_local_packages(p)
112
- package(p) do |file|
113
- task "install local package #{p}" do
114
- shell "dpkg -i #{file}"
115
- end
116
- end
117
- end
118
-
119
- def process_gems(gem)
120
- task "install gem #{gem}" do
121
- shell "gem install #{gem} --no-rdoc --no-ri"
122
- end
123
- end
124
-
125
- def process_volumes(v)
126
- handle_ebs v if v.media == "ebs"
127
- handle_raid v if v.media == "raid"
128
- set_readahead v if v.readahead
129
- set_scheduler v if v.scheduler
130
- handle_format v if v.format
131
- handle_mount v if v.mount
132
- end
133
-
134
- def handle_ebs(v)
135
- task "wait for volume #{v.device}" do
136
- wait_for_volume v.device
137
- end
138
- end
139
-
140
- def handle_raid(r)
141
- task "create raid #{r.device}", :init => true do
142
- shell "mdadm --create #{r.device} -n #{r.drives.size} -l #{r.level} -c #{r.chunksize || 64} #{r.drives.join(" ")}"
143
- end
144
- task "assemble raid #{r.device}" do ## assemble fails a lot with device busy - is udev to blame :(
145
- if not dev_exists? r.device
146
- shell "service stop udev"
147
- shell "mdadm --assemble #{r.device} #{r.drives.join(" ")}"
148
- shell "service start udev"
149
- end
150
- end
151
- add_package "mdadm"
152
- end
153
-
154
- def mount_options(m)
155
- o = []
156
- o << m.options if m.options
157
- o << "size=#{m.size}M" if m.size and m.media == "tmpfs"
158
- o << "mode=#{m.mode}" if m.mode
159
- o << "noatime" if o.empty?
160
- o.join(",")
161
- end
162
-
163
- def handle_mount(m)
164
- task "mount #{m.mount}" do
165
- unless mounted?(m.mount)
166
- shell "mv #{m.mount} #{m.mout}.old" if File.exists?(m.mount)
167
- shell "mkdir -p #{m.mount} && mount -o #{mount_options(m)} -t #{m.format || m.media} #{m.device || m.media} #{m.mount}"
168
- shell "chown -R #{m.user}:#{m.group} #{m.mount}" if m.user or m.group
169
- end
170
- end
171
- end
172
-
173
- def system_arch
174
- system.kernel["machine"]
175
- end
176
-
177
- def mounted?(mount)
178
- ## cant use ohai here b/c it mashes drives together with none or tmpfs devices
179
- mount = mount.chop if mount =~ /\/$/
180
- !!(File.read("/proc/mounts") =~ / #{mount} /)
181
- end
182
-
183
- def package_arch
184
- `dpkg --print-architecture`.chomp
185
- end
186
-
187
- def erb(data)
188
- @system = system
189
- ERB.new(data, 0, '<>').result(binding)
190
- end
191
-
192
- def process_files(f)
193
- file(f) do |tmp|
194
- task "write #{f.file}" do
195
- cp_file(tmp, f.file)
196
- shell "chmod #{f.mode} #{f.file}" if f.mode
197
- shell "chown #{f.user} #{f.file}" if f.user
198
- shell "chgrp #{f.group} #{f.file}" if f.group
199
- end
200
- end
201
- end
202
-
203
- def process_crontab(cron)
204
- user = cron.user || "root"
205
- file(cron) do |tmp|
206
- task "process crontab for #{user}" do
207
- shell "crontab -u #{user} #{tmp}"
208
- end
209
- end
210
- end
211
-
212
- def process_users(user)
213
- (user.authorized_keys || []).each do |key|
214
- task "add authorized_key for user #{user.name}" do
215
- shell "su - #{user.name} -c 'mkdir -p .ssh; echo \"#{key}\" >> .ssh/authorized_keys; chmod -R 0600 .ssh'"
216
- end
217
- end
218
- end
219
-
220
- def set_readahead(v)
221
- task "set readahead for #{v.device}" do
222
- shell "blockdev --setra #{v.readahead} #{v.device}"
223
- end
224
- end
225
-
226
- def set_scheduler(v)
227
- task "set scheduler for #{v.device}" do
228
- shell "echo #{v.scheduler} > /sys/block/#{File.basename(v.device)}/queue/scheduler"
229
- end
230
- end
231
-
232
- def handle_format(v)
233
- return if v.format == "tmpfs"
234
- task "formatting #{v.device}", :init => true do
235
- label = "-L " + v.label rescue ""
236
- shell "mkfs.#{v.format} -q #{label} #{v.device}" unless v.mount && mounted?(v.mount)
237
- end
238
- add_package "xfsprogs" if v.format == "xfs"
239
- end
240
-
241
- def add_package(p)
242
- @packages << p unless @packages.include? p
243
- end
244
-
245
- def package(p, &block)
246
- fetch("/packages/#{p}_#{package_arch}.deb") do |file|
247
- block.call(file)
248
- end
249
- end
250
-
251
-
252
- def script(scripts)
253
- to_array(scripts).each do |s|
254
- if s =~ /^#!/
255
- inline_script(s)
256
- else
257
- external_script(s)
258
- end
259
- end
260
- end
261
-
262
- def inline_script(script)
263
- tmpfile(script) do |tmp|
264
- task "run inline script" do
265
- shell "#{tmp}"
266
- end
267
- end
268
- end
269
-
270
- def external_script(script)
271
- fetch("/scripts/#{script}") do |file|
272
- task "run script #{script}" do
273
- shell "chmod +x #{file} ; #{file}"
274
- end
275
- end
276
- end
277
-
278
- def tmpfile(content, file = "tmp_#{rand(1_000_000_000)}", &block)
279
- path = "/tmp/kuzushi/#{File.basename(file)}"
280
- put_file(content, path)
281
- block.call(path) if block
282
- path
283
- end
284
-
285
- def file(f, &blk)
286
- ## no magic here - move along
287
- fetch("/templates/#{f.template}", lambda { |data| erb data }, &blk) if f.template
288
- fetch("/files/#{f.source || File.basename(f.file)}", &blk) unless f.template
289
- end
290
-
291
- ### this needs to be brought up to date - way last version - no need to read and filter...
292
- def fetch(file, filter = lambda { |d| d }, &block)
293
- begin
294
- tmpfile(filter.call(File.read("/tmp/kuzushi/#{@name}/#{file}")), file) do |tmp|
295
- block.call(tmp)
296
- end
297
- rescue Object => e
298
- error("error fetching file: #{file} : #{e.message}")
299
- end
300
- end
301
-
302
- def error(message)
303
- puts "ERROR :#{message}"
304
- end
305
-
306
- def get(key)
307
- config[key.to_s]
308
- end
309
-
310
- def get_array(key)
311
- to_array( get(key) )
312
- end
313
-
314
- def to_array(value)
315
- [ value || [] ].flatten
316
- end
317
-
318
- def wait_for_volume(vol)
319
- ## Maybe use ohai here instead -- FIXME
320
- until dev_exists? vol do
321
- log "waiting for volume #{vol}"
322
- sleep 2
323
- end
324
- end
325
-
326
- def shell(cmd)
327
- log "# #{cmd}"
328
- Kernel.system cmd ## FIXME - need to handle/report exceptions here
329
- end
330
-
331
- def init?
332
- @init ||= false
333
- end
334
-
335
- def task(description, options = {}, &blk)
336
- return if options[:init] and not init?
337
- @tasks << { :description => description, :blk => blk }
338
- end
339
-
340
- def dev_exists?(dev)
341
- File.exists?("/sys/block/#{File.basename(dev)}")
342
- end
343
-
344
- def cp_file(src, dest)
345
- FileUtils.mkdir_p(File.dirname(dest))
346
- FileUtils.cp(src, dest)
347
- end
348
-
349
- def put_file(data, dest)
350
- FileUtils.mkdir_p(File.dirname(dest))
351
- File.open(dest,"w") do |f|
352
- f.write(data)
353
- f.chmod(0700)
354
- end
355
- end
356
-
357
- def log(message)
358
- puts message
359
- end
16
+ attr_accessor :config
17
+
18
+ def initialize(url)
19
+ @url = url
20
+ @base_url = File.dirname(url)
21
+ if @url =~ /s3.amazonaws.com.*\/([^\/]*)[.](\d+)[.]tar[.]gz/
22
+ @name = $1
23
+ @version = $2
24
+ end
25
+ @configs = []
26
+ @packages = []
27
+ @tasks = []
28
+ end
29
+
30
+ def init
31
+ @init = true
32
+ start
33
+ end
34
+
35
+ def boot
36
+ shell "mkdir -p /tmp/kuzushi/"
37
+ shell "cd /tmp/kuzushi/ ; curl --silent '#{@url}' | tar xzv"
38
+ @config = JSON.parse(File.read("/tmp/kuzushi/#{@name}/config.json"))
39
+ end
40
+
41
+ def start
42
+ # load_config_stack(@name)
43
+ boot
44
+ run
45
+ end
46
+
47
+ def run
48
+ process_stack
49
+ log "----"
50
+ @tasks.each do |t|
51
+ log "TASK: #{t[:description]}"
52
+ t[:blk].call
53
+ end
54
+ log "----"
55
+ end
56
+
57
+ protected
58
+
59
+ def system
60
+ ohai = Ohai::System.new
61
+ ohai.all_plugins
62
+ ohai
63
+ end
64
+
65
+ def http_get(url)
66
+ RestClient.get(url)
67
+ end
68
+
69
+ def process_stack
70
+ script get("before")
71
+
72
+ process :packages
73
+ process :local_packages
74
+ process :gems
75
+ process :volumes
76
+ process :files
77
+ process :services
78
+ process :users
79
+ process :crontab
80
+
81
+ script get("after")
82
+ script get("init") if init?
83
+ end
84
+
85
+ ## magic goes here
86
+ def process(type)
87
+ ## if the file takes no args - just call it once
88
+ if method("process_#{type}").arity == 0
89
+ send("process_#{type}")
90
+ else
91
+ ## else call it once per item
92
+ get_array(type).each do |item|
93
+ script item["before"]
94
+ if item.is_a? Hash
95
+ send("process_#{type}", OpenStruct.new(item))
96
+ else
97
+ send("process_#{type}", item)
98
+ end
99
+ script item["after"]
100
+ script item["init"] if init?
101
+ end
102
+ end
103
+ end
104
+
105
+ def service_file(service)
106
+ file = []
107
+ file << "start on stopped rc RUNLEVEL=[2345]"
108
+ file << "stop on runlevel [!2345]"
109
+ file << "respawn" unless service.respawn == false
110
+ if service.user
111
+ file << "exec su -c '#{service.command}' #{service.user}" ## TODO add shell escaping here
112
+ else
113
+ file << "exec #{service.command}"
114
+ end
115
+ end
116
+
117
+ def process_service(service)
118
+ put_file(service_file(service), "/etc/init/#{service.name}.conf")
119
+ shell "service #{service.name} start"
120
+ end
121
+
122
+ def process_packages
123
+ @packages = get_array("packages")
124
+ task "install packages" do
125
+ shell "apt-get install -y #{@packages.join(" ")}" unless @packages.empty?
126
+ end
127
+ end
128
+
129
+ def process_local_packages(p)
130
+ package(p) do |file|
131
+ task "install local package #{p}" do
132
+ shell "dpkg -i #{file}"
133
+ end
134
+ end
135
+ end
136
+
137
+ def process_gems(gem)
138
+ task "install gem #{gem}" do
139
+ shell "gem install #{gem} --no-rdoc --no-ri"
140
+ end
141
+ end
142
+
143
+ def process_volumes(v)
144
+ handle_ebs v if v.media == "ebs"
145
+ handle_raid v if v.media == "raid"
146
+ set_readahead v if v.readahead
147
+ set_scheduler v if v.scheduler
148
+ handle_format v if v.format
149
+ handle_mount v if v.mount
150
+ end
151
+
152
+ def handle_ebs(v)
153
+ task "wait for volume #{v.device}" do
154
+ wait_for_volume v.device
155
+ end
156
+ end
157
+
158
+ def handle_raid(r)
159
+ task "create raid #{r.device}", :init => true do
160
+ shell "mdadm --create #{r.device} -n #{r.drives.size} -l #{r.level} -c #{r.chunksize || 64} #{r.drives.join(" ")}"
161
+ end
162
+ task "assemble raid #{r.device}" do ## assemble fails a lot with device busy - is udev to blame :(
163
+ if not dev_exists? r.device
164
+ shell "service stop udev"
165
+ shell "mdadm --assemble #{r.device} #{r.drives.join(" ")}"
166
+ shell "service start udev"
167
+ end
168
+ end
169
+ add_package "mdadm"
170
+ end
171
+
172
+ def mount_options(m)
173
+ o = []
174
+ o << m.options if m.options
175
+ o << "size=#{m.size}M" if m.size and m.media == "tmpfs"
176
+ o << "mode=#{m.mode}" if m.mode
177
+ o << "noatime" if o.empty?
178
+ o.join(",")
179
+ end
180
+
181
+ def handle_mount(m)
182
+ task "mount #{m.mount}" do
183
+ unless mounted?(m.mount)
184
+ shell "mv #{m.mount} #{m.mout}.old" if File.exists?(m.mount)
185
+ shell "mkdir -p #{m.mount} && mount -o #{mount_options(m)} -t #{m.format || m.media} #{m.device || m.media} #{m.mount}"
186
+ shell "chown -R #{m.user}:#{m.group} #{m.mount}" if m.user or m.group
187
+ end
188
+ end
189
+ end
190
+
191
+ def system_arch
192
+ system.kernel["machine"]
193
+ end
194
+
195
+ def mounted?(mount)
196
+ ## cant use ohai here b/c it mashes drives together with none or tmpfs devices
197
+ mount = mount.chop if mount =~ /\/$/
198
+ !!(File.read("/proc/mounts") =~ / #{mount} /)
199
+ end
200
+
201
+ def package_arch
202
+ `dpkg --print-architecture`.chomp
203
+ end
204
+
205
+ def erb(data)
206
+ @system = system
207
+ ERB.new(data, 0, '<>').result(binding)
208
+ end
209
+
210
+ def process_files(f)
211
+ file(f) do |tmp|
212
+ task "write #{f.file}" do
213
+ cp_file(tmp, f.file)
214
+ shell "chmod #{f.mode} #{f.file}" if f.mode
215
+ shell "chown #{f.user} #{f.file}" if f.user
216
+ shell "chgrp #{f.group} #{f.file}" if f.group
217
+ end
218
+ end
219
+ end
220
+
221
+ def process_crontab(cron)
222
+ user = cron.user || "root"
223
+ file(cron) do |tmp|
224
+ task "process crontab for #{user}" do
225
+ shell "crontab -u #{user} #{tmp}"
226
+ end
227
+ end
228
+ end
229
+
230
+ def process_users(user)
231
+ shell "useradd -m #{user}" ## this will just fail for users like 'root'
232
+ (user.authorized_keys || []).each do |key|
233
+ task "add authorized_key for user #{user.name}" do
234
+ shell "su - #{user.name} -c 'mkdir -p .ssh; echo \"#{key}\" >> .ssh/authorized_keys; chmod -R 0600 .ssh'"
235
+ end
236
+ end
237
+ end
238
+
239
+ def set_readahead(v)
240
+ task "set readahead for #{v.device}" do
241
+ shell "blockdev --setra #{v.readahead} #{v.device}"
242
+ end
243
+ end
244
+
245
+ def set_scheduler(v)
246
+ task "set scheduler for #{v.device}" do
247
+ shell "echo #{v.scheduler} > /sys/block/#{File.basename(v.device)}/queue/scheduler"
248
+ end
249
+ end
250
+
251
+ def handle_format(v)
252
+ return if v.format == "tmpfs"
253
+ task "formatting #{v.device}", :init => true do
254
+ label = "-L " + v.label rescue ""
255
+ shell "mkfs.#{v.format} -q #{label} #{v.device}" unless v.mount && mounted?(v.mount)
256
+ end
257
+ add_package "xfsprogs" if v.format == "xfs"
258
+ end
259
+
260
+ def add_package(p)
261
+ @packages << p unless @packages.include? p
262
+ end
263
+
264
+ def package(p, &block)
265
+ fetch("/packages/#{p}_#{package_arch}.deb") do |file|
266
+ block.call(file)
267
+ end
268
+ end
269
+
270
+
271
+ def script(scripts)
272
+ to_array(scripts).each do |s|
273
+ if s =~ /^#!/
274
+ inline_script(s)
275
+ else
276
+ external_script(s)
277
+ end
278
+ end
279
+ end
280
+
281
+ def inline_script(script)
282
+ tmpfile(script) do |tmp|
283
+ task "run inline script" do
284
+ shell "#{tmp}"
285
+ end
286
+ end
287
+ end
288
+
289
+ def external_script(script)
290
+ fetch("/scripts/#{script}") do |file|
291
+ task "run script #{script}" do
292
+ shell "chmod +x #{file} ; #{file}"
293
+ end
294
+ end
295
+ end
296
+
297
+ def tmpfile(content, file = "tmp_#{rand(1_000_000_000)}", &block)
298
+ path = "/tmp/kuzushi/#{File.basename(file)}"
299
+ put_file(content, path)
300
+ block.call(path) if block
301
+ path
302
+ end
303
+
304
+ def file(f, &blk)
305
+ ## no magic here - move along
306
+ if f.template
307
+ fetch("/templates/#{f.template}", lambda { |data| erb data }, &blk)
308
+ else f.git
309
+ git_fetch(f)
310
+ else
311
+ fetch("/files/#{f.source || File.basename(f.file)}", &blk) unless f.template
312
+ end
313
+ end
314
+
315
+ def git_fetch(f)
316
+ FileUtils.mkdir_p(f.dir)
317
+ shell "cd dir && git init"
318
+ shell "cd dir && git remote add origin #{f.git}"
319
+ shell "cd dir && git fetch"
320
+ shell "cd dir && git checkout master"
321
+ shell "chown -R #{f.user}:#{f.group} #{f.dir}" if f.user || f.group ## is this needed? handled above in files?
322
+ end
323
+
324
+ ### this needs to be brought up to date - way last version - no need to read and filter...
325
+ def fetch(file, filter = lambda { |d| d }, &block)
326
+ begin
327
+ tmpfile(filter.call(File.read("/tmp/kuzushi/#{@name}/#{file}")), file) do |tmp|
328
+ block.call(tmp)
329
+ end
330
+ rescue Object => e
331
+ error("error fetching file: #{file} : #{e.message}")
332
+ end
333
+ end
334
+
335
+ def error(message)
336
+ puts "ERROR :#{message}"
337
+ end
338
+
339
+ def get(key)
340
+ config[key.to_s]
341
+ end
342
+
343
+ def get_array(key)
344
+ to_array( get(key) )
345
+ end
346
+
347
+ def to_array(value)
348
+ [ value || [] ].flatten
349
+ end
350
+
351
+ def wait_for_volume(vol)
352
+ ## Maybe use ohai here instead -- FIXME
353
+ until dev_exists? vol do
354
+ log "waiting for volume #{vol}"
355
+ sleep 2
356
+ end
357
+ end
358
+
359
+ def shell(cmd)
360
+ log "# #{cmd}"
361
+ Kernel.system cmd ## FIXME - need to handle/report exceptions here
362
+ end
363
+
364
+ def init?
365
+ @init ||= false
366
+ end
367
+
368
+ def task(description, options = {}, &blk)
369
+ return if options[:init] and not init?
370
+ @tasks << { :description => description, :blk => blk }
371
+ end
372
+
373
+ def dev_exists?(dev)
374
+ File.exists?("/sys/block/#{File.basename(dev)}")
375
+ end
376
+
377
+ def cp_file(src, dest)
378
+ FileUtils.mkdir_p(File.dirname(dest))
379
+ FileUtils.cp(src, dest)
380
+ end
381
+
382
+ def put_file(data, dest)
383
+ FileUtils.mkdir_p(File.dirname(dest))
384
+ File.open(dest,"w") do |f|
385
+ f.write(data)
386
+ f.chmod(0700)
387
+ end
388
+ end
389
+
390
+ def log(message)
391
+ puts message
392
+ end
360
393
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 35
9
- version: 0.0.35
8
+ - 36
9
+ version: 0.0.36
10
10
  platform: ruby
11
11
  authors:
12
12
  - Orion Henry
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-17 00:00:00 -04:00
17
+ date: 2010-04-30 00:00:00 -04:00
18
18
  default_executable: kuzushi
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency