kuzushi 0.0.1 → 0.0.2

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 (6) hide show
  1. data/README +6 -6
  2. data/Rakefile +1 -0
  3. data/VERSION +1 -1
  4. data/bin/kuzushi +8 -1
  5. data/lib/kuzushi.rb +221 -0
  6. metadata +12 -2
data/README CHANGED
@@ -1,9 +1,9 @@
1
1
 
2
- Kuzushi ( ku ZOO she ) - a technique used by a martial artist or wrestler to
3
- keep control of an opponent by keeping them slightly off balance
2
+ Kuzushi ( ka ZU she ) - a technique used by martial artists to control of an
3
+ opponent by keeping them slightly off balance.
4
4
 
5
- The 'kuzushi' is a companion gem to 'sumo'. Sumo handles AWS/instance/volume
6
- management of a server based on its specificatoion. Kuzushi handles the
7
- management from inside the server by installing packages, setting up drives and
8
- users, writing config files, etc
5
+ The 'kuzushi' gem is a companion to the 'sumo' gem. Sumo handles
6
+ AWS/instance/volume management of a server based on its specificatoion.
7
+ Kuzushi handles the management from inside the server by installing packages,
8
+ setting up drives and users, writing config files, etc
9
9
 
data/Rakefile CHANGED
@@ -10,6 +10,7 @@ Jeweler::Tasks.new do |s|
10
10
  # s.rubyforge_project = "sumo"
11
11
  s.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
12
12
  s.executables = %w(kuzushi)
13
+ s.add_dependency "rest-client"
13
14
  s.add_dependency "json"
14
15
  end
15
16
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -2,5 +2,12 @@
2
2
 
3
3
  require File.dirname(__FILE__) + '/../lib/kuzushi'
4
4
 
5
- Kuzushi.new
5
+ usage = "usage: kuzushi start URL"
6
+
7
+ fail(usage) unless ARGV.length == 2
8
+ fail(usage) unless ARGV[0] == "start"
9
+
10
+ url = ARGV[1]
11
+
12
+ Kuzushi.new(url).start
6
13
 
@@ -1,4 +1,225 @@
1
+ require 'rubygems'
1
2
  require 'json'
3
+ require 'restclient'
4
+ require 'ostruct'
2
5
 
3
6
  class Kuzushi
7
+ def initialize(url)
8
+ @base_url = File.dirname(url)
9
+ @name = File.basename(url)
10
+ @config_names = []
11
+ @config = []
12
+ @packages = []
13
+ @tasks = []
14
+ load_config_stack(@name)
15
+ @merge = @config.reverse.inject({}) { |i,c| i.merge(c) }
16
+ process_stack
17
+ end
18
+
19
+ def load_config_stack(name)
20
+ @config_names << name
21
+ @config << JSON.parse(RestClient.get("#{@base_url}/#{name}"))
22
+ if import = @config.last["import"]
23
+ load_config_stack(import)
24
+ end
25
+ end
26
+
27
+ def process_stack
28
+ script get("before")
29
+
30
+ process :packages
31
+ process :local_packages
32
+ process :gems
33
+ process :volumes
34
+ process :raids
35
+ process :mounts
36
+ process :files
37
+ process :users
38
+
39
+ script get("after")
40
+ end
41
+
42
+ ## magic goes here
43
+ def process(type)
44
+ ## if the file takes no args - just call it once
45
+ if method("process_#{type}").arity == 0
46
+ send("process_#{type}")
47
+ else
48
+ ## else call it once per item
49
+ get_array(type).each do |item|
50
+ script item["before"]
51
+ if item.is_a? Hash
52
+ send("process_#{type}", OpenStruct.new(item))
53
+ else
54
+ send("process_#{type}", item)
55
+ end
56
+ script item["after"]
57
+ end
58
+ end
59
+ end
60
+
61
+ def process_packages
62
+ @packages = get_array("packages")
63
+ task "install packages" do
64
+ shell "apt-get update && apt-get upgrade -y && apt-get install -y #{@packages.join(" ")}", "DEBIAN_FRONTEND" => "noninteractive", "DEBIAN_PRIORITY" => "critical"
65
+ end
66
+ end
67
+
68
+ def process_local_packages(p)
69
+ package(p) do |file|
70
+ task "install local package #{p}" do
71
+ shell "dpkg -i #{file}"
72
+ end
73
+ end
74
+ end
75
+
76
+ def process_gems(gem)
77
+ task "install gem #{gem}" do
78
+ shell "gem install #{gem} --no-rdoc --no-ri"
79
+ end
80
+ end
81
+
82
+ def process_volumes(v)
83
+ task "wait for volume #{v.device}" do
84
+ wait_for_volume v.device
85
+ end
86
+ set_scheduler(v)
87
+ check_format(v)
88
+ end
89
+
90
+ def process_raids(r)
91
+ task "assemble raid #{r.device}" do
92
+ shell "mdadm --assemble #{r.device} #{r.drives.join(" ")}"
93
+ end
94
+ set_scheduler r
95
+ check_format r
96
+ add_package "mdadm"
97
+ end
98
+
99
+ def process_mounts(m)
100
+ task "mount #{m.label}" do
101
+ shell "mount -o #{m.options} -L #{m.label} #{m.label}"
102
+ end
103
+ end
104
+
105
+ def process_files(f)
106
+ fetch("/templates/#{f.template}") do |file|
107
+ task "setting up #{f.file}" do
108
+ shell "erb #{f.template} > #{f.file}" ## FIXME
109
+ end
110
+ end
111
+ end
112
+
113
+ def process_users(user)
114
+ (user.authorized_keys || []).each do |key|
115
+ task "add authorized_key for user #{user.name}" do
116
+ shell "su - #{user.name} -c 'mkdir -p .ssh; echo \"#{key}\" >> .ssh/authorized_keys; chmod -R 600 .ssh'"
117
+ end
118
+ end
119
+ end
120
+
121
+ def set_scheduler(v)
122
+ if v.scheduler
123
+ task "set scheduler for #{v.device}" do
124
+ shell "echo #{v.scheduler} > /sys/block/#{File.basename(v.device)}/queue/scheduler"
125
+ end
126
+ end
127
+ end
128
+
129
+ def check_format(v)
130
+ add_package "xfsprogs" if v.format == "xfs"
131
+ end
132
+
133
+ def add_package(p)
134
+ @packages << p unless @packages.include? p
135
+ end
136
+
137
+ def package(p, &block)
138
+ fetch("/packages/#{p}_i386.deb") do |file|
139
+ block.call(file)
140
+ end
141
+ end
142
+
143
+ def inline_script(script)
144
+ tmpfile(script) do |tmp|
145
+ task "run inline script" do
146
+ shell "#{tmp}"
147
+ end
148
+ end
149
+ end
150
+
151
+ def script(script)
152
+ return if script.nil?
153
+ return inline_script(script) if script =~ /^#!/
154
+
155
+ fetch("/scripts/#{script}") do |file|
156
+ task "run script #{script}" do
157
+ shell "#{file}"
158
+ end
159
+ end
160
+ end
161
+
162
+ def tmpfile(content, file = "tmp_#{rand(1_000_000_000)}", &block)
163
+ tmp_dir = "/tmp/kuzushi"
164
+ Dir.mkdir(tmp_dir) unless File.exists?(tmp_dir)
165
+ file = "#{tmp_dir}/#{File.basename(file)}"
166
+ File.open(file,"w") do |f|
167
+ f.write(content)
168
+ f.chmod(700)
169
+ end if content
170
+ block.call(file) if block
171
+ file
172
+ end
173
+
174
+ def fetch(file, &block)
175
+ names = @config_names.clone
176
+ begin
177
+ tmpfile RestClient.get("#{@base_url}/#{names.first}#{file}"), file do |tmp|
178
+ block.call(tmp)
179
+ end
180
+ rescue RestClient::ResourceNotFound
181
+ names.shift
182
+ retry unless names.empty?
183
+ error("file not found: #{file}")
184
+ rescue Object => e
185
+ error("error fetching file: #{names.first}/#{file}", e)
186
+ end
187
+ end
188
+
189
+ def error(message, exception = nil)
190
+ puts "ERROR :#{message}"
191
+ end
192
+
193
+ def get(key)
194
+ @merge[key.to_s]
195
+ end
196
+
197
+ def get_array(key)
198
+ [ get(key) || [] ].flatten
199
+ end
200
+
201
+ def wait_for_volume(vol)
202
+ puts "waiting for volume #{vol}"
203
+ end
204
+
205
+ def start
206
+ puts "----"
207
+ @tasks.each do |t|
208
+ puts "TASK: #{t[:description]}"
209
+ t[:blk].call
210
+ end
211
+ puts "----"
212
+ end
213
+
214
+ def shell(cmd, env = {})
215
+ puts " SHELL: #{cmd}"
216
+ end
217
+
218
+ def task(description, &blk)
219
+ @tasks << { :description => description, :blk => blk }
220
+ end
221
+
222
+ def path
223
+ Dir["**/config.json"]
224
+ end
4
225
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kuzushi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Orion Henry
@@ -9,9 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-18 00:00:00 -05:00
12
+ date: 2010-02-19 00:00:00 -05:00
13
13
  default_executable: kuzushi
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rest-client
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
15
25
  - !ruby/object:Gem::Dependency
16
26
  name: json
17
27
  type: :runtime