kuzushi 0.0.35 → 0.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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