ironfan 4.0.9 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -0
- data/VERSION +1 -1
- data/ironfan.gemspec +2 -2
- data/lib/chef/knife/cluster_launch.rb +11 -4
- data/lib/chef/knife/cluster_show.rb +35 -6
- data/lib/chef/knife/ironfan_knife_common.rb +18 -18
- data/lib/ironfan/broker/computer.rb +64 -29
- data/lib/ironfan/broker.rb +12 -6
- data/lib/ironfan/deprecated.rb +2 -2
- data/lib/ironfan/dsl/ec2.rb +41 -31
- data/lib/ironfan/dsl/server.rb +11 -1
- data/lib/ironfan/dsl/volume.rb +2 -2
- data/lib/ironfan/provider/chef/client.rb +16 -8
- data/lib/ironfan/provider/chef/node.rb +9 -4
- data/lib/ironfan/provider/chef/role.rb +10 -3
- data/lib/ironfan/provider/chef.rb +3 -2
- data/lib/ironfan/provider/ec2/ebs_volume.rb +8 -1
- data/lib/ironfan/provider/ec2/key_pair.rb +7 -1
- data/lib/ironfan/provider/ec2/machine.rb +40 -17
- data/lib/ironfan/provider/ec2/placement_group.rb +7 -1
- data/lib/ironfan/provider/ec2/security_group.rb +25 -5
- data/lib/ironfan/provider/ec2.rb +3 -2
- data/lib/ironfan/provider/virtualbox.rb +2 -1
- data/lib/ironfan/provider.rb +9 -5
- data/lib/ironfan.rb +27 -10
- metadata +3 -3
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# v4.1.0: several bug-fixes and code cleanup
|
2
|
+
* Splat the args to DSL::Volume.snapshot_id so we can call it properly (fixes #161)
|
3
|
+
* cloud(:ec2) lets you declare bitness (fixes #147)
|
4
|
+
* Better logging; errors within Ironfan.parallel don't crash the world (pull #167)
|
5
|
+
* Like any good hitman, knife cluster kill should 'take care of' errant clients (pull #168)
|
6
|
+
|
1
7
|
# v4.0.9:
|
2
8
|
* Making bootstrap work again (fixes #159)
|
3
9
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.0
|
1
|
+
4.1.0
|
data/ironfan.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "ironfan"
|
8
|
-
s.version = "4.0
|
8
|
+
s.version = "4.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Infochimps"]
|
12
|
-
s.date = "2012-09-
|
12
|
+
s.date = "2012-09-24"
|
13
13
|
s.description = "Ironfan allows you to orchestrate not just systems but clusters of machines. It includes a powerful layer on top of knife and a collection of cloud cookbooks."
|
14
14
|
s.email = "coders@infochimps.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -79,10 +79,12 @@ class Chef
|
|
79
79
|
ui.info("")
|
80
80
|
section("Launching computers", :green)
|
81
81
|
display(target)
|
82
|
-
target.launch
|
82
|
+
launched = target.launch
|
83
83
|
|
84
84
|
# As each server finishes, configure it
|
85
|
-
Ironfan.parallel(
|
85
|
+
Ironfan.parallel(launched) do |computer|
|
86
|
+
if (computer.is_a?(Exception)) then ui.warn "Error launching #{computer.inspect}; skipping after-launch tasks."; next; end
|
87
|
+
Ironfan.step(computer.name, 'launching', :white)
|
86
88
|
perform_after_launch_tasks(computer)
|
87
89
|
end
|
88
90
|
# progressbar_for_threads(watcher_threads)
|
@@ -91,12 +93,14 @@ class Chef
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def perform_after_launch_tasks(computer)
|
96
|
+
Ironfan.step(computer.name, 'waiting for ready', :white)
|
94
97
|
# Wait for machine creation on amazon side
|
95
98
|
# server.fog_server.wait_for{ ready? }
|
96
99
|
computer.machine.wait_for{ ready? }
|
97
100
|
|
98
101
|
# Try SSH
|
99
102
|
unless config[:dry_run]
|
103
|
+
Ironfan.step(computer.name, 'trying ssh', :white)
|
100
104
|
# nil until tcp_test_ssh(server.fog_server.dns_name){ sleep @initial_sleep_delay ||= 10 }
|
101
105
|
nil until tcp_test_ssh(computer.machine.dns_name){ sleep @initial_sleep_delay ||= 10 }
|
102
106
|
end
|
@@ -107,11 +111,14 @@ class Chef
|
|
107
111
|
|
108
112
|
# Attach volumes, etc
|
109
113
|
# server.sync_to_cloud
|
114
|
+
Ironfan.step(computer.name, 'final provisioning', :white)
|
110
115
|
computer.save
|
111
116
|
|
112
117
|
# Run Bootstrap
|
113
|
-
|
114
|
-
|
118
|
+
if config[:bootstrap]
|
119
|
+
Chef::Log.warn "UNTESTED --bootstrap"
|
120
|
+
run_bootstrap(computer)
|
121
|
+
end
|
115
122
|
end
|
116
123
|
|
117
124
|
def tcp_test_ssh(hostname)
|
@@ -42,19 +42,48 @@ class Chef
|
|
42
42
|
# Load the cluster/facet/slice/whatever
|
43
43
|
target = get_slice(* @name_args)
|
44
44
|
|
45
|
+
dump_command_config
|
46
|
+
dump_chef_config
|
45
47
|
#
|
46
|
-
|
47
|
-
|
48
|
-
if config[:verbosity] >= 2
|
49
|
-
target.each do |computer|
|
50
|
-
Chef::Log.debug( "Computer #{computer.name}: #{JSON.pretty_generate(computer.to_wire)}" )
|
51
|
-
end
|
48
|
+
target.each do |computer|
|
49
|
+
dump_computer(computer)
|
52
50
|
end
|
53
51
|
|
54
52
|
# Display same
|
55
53
|
display(target)
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def dump_computer(computer)
|
59
|
+
with_verbosity 1 do
|
60
|
+
dump("Computer #{computer.name} (#{computer.class})", computer.to_wire)
|
61
|
+
end
|
62
|
+
end
|
56
63
|
|
64
|
+
def dump_command_config
|
65
|
+
with_verbosity 2 do
|
66
|
+
Chef::Log.info( ["", "*"*50, "", "Command Config", ""].join("\n") )
|
67
|
+
dump("Command config", self.config)
|
68
|
+
end
|
57
69
|
end
|
70
|
+
|
71
|
+
def dump_chef_config
|
72
|
+
with_verbosity 2 do
|
73
|
+
chef_config_hash = Hash[Chef::Config.keys.map{|key| [key, Chef::Config[key]]}]
|
74
|
+
dump("Chef Config", chef_config_hash)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def dump(title, hsh)
|
79
|
+
Chef::Log.info( ["", "*"*50, "", "#{title}: ", ""].join("\n") )
|
80
|
+
Chef::Log.info( MultiJson.dump(hsh, pretty: true ) )
|
81
|
+
end
|
82
|
+
|
83
|
+
def with_verbosity(num)
|
84
|
+
yield if config[:verbosity] >= num
|
85
|
+
end
|
86
|
+
|
58
87
|
end
|
59
88
|
end
|
60
89
|
end
|
@@ -37,9 +37,13 @@ module Ironfan
|
|
37
37
|
ui.warn("Please specify server slices joined by dashes and not separate args:\n\n knife cluster #{sub_command} #{slice_string}\n\n")
|
38
38
|
end
|
39
39
|
cluster_name, facet_name, slice_indexes = slice_string.split(/[\s\-]/, 3)
|
40
|
-
|
41
|
-
|
40
|
+
desc = predicate_str(cluster_name, facet_name, slice_indexes)
|
41
|
+
#
|
42
|
+
ui.info("Inventorying servers in #{desc}")
|
43
|
+
cluster = Ironfan.load_cluster(cluster_name)
|
42
44
|
computers = broker.discover! cluster
|
45
|
+
Chef::Log.info("Inventoried #{computers.size} computers")
|
46
|
+
#
|
43
47
|
computers.slice(facet_name, slice_indexes)
|
44
48
|
end
|
45
49
|
|
@@ -80,7 +84,7 @@ module Ironfan
|
|
80
84
|
def display(target, display_style=nil, &block)
|
81
85
|
display_style ||= (config[:verbosity] == 0 ? :default : :expanded)
|
82
86
|
# target.display(ui, display_style, &block)
|
83
|
-
broker.display(target,display_style)
|
87
|
+
broker.display(target, display_style)
|
84
88
|
end
|
85
89
|
|
86
90
|
#
|
@@ -115,25 +119,24 @@ module Ironfan
|
|
115
119
|
end
|
116
120
|
|
117
121
|
def bootstrapper(computer)
|
118
|
-
server
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
+
server = computer.server
|
123
|
+
hostname = computer.dns_name
|
124
|
+
#
|
122
125
|
bootstrap = Chef::Knife::Bootstrap.new
|
123
126
|
bootstrap.config.merge!(config)
|
124
|
-
|
127
|
+
#
|
125
128
|
bootstrap.name_args = [ hostname ]
|
126
129
|
bootstrap.config[:computer] = computer
|
127
130
|
bootstrap.config[:server] = server
|
128
131
|
bootstrap.config[:run_list] = server.run_list
|
129
|
-
bootstrap.config[:ssh_user] = config[:ssh_user] ||
|
132
|
+
bootstrap.config[:ssh_user] = config[:ssh_user] || computer.ssh_user
|
130
133
|
bootstrap.config[:attribute] = config[:attribute]
|
131
134
|
bootstrap.config[:identity_file] = config[:identity_file] || computer.ssh_identity_file
|
132
|
-
bootstrap.config[:distro] = config[:distro] ||
|
135
|
+
bootstrap.config[:distro] = config[:distro] || computer.bootstrap_distro
|
133
136
|
bootstrap.config[:use_sudo] = true unless config[:use_sudo] == false
|
134
137
|
bootstrap.config[:chef_node_name] = server.fullname
|
135
138
|
bootstrap.config[:client_key] = ( computer.client.private_key rescue nil )
|
136
|
-
|
139
|
+
#
|
137
140
|
bootstrap
|
138
141
|
end
|
139
142
|
|
@@ -143,14 +146,11 @@ module Ironfan
|
|
143
146
|
ui.info "Skipping: bootstrap #{computer.name} with #{JSON.pretty_generate(bs.config)}"
|
144
147
|
return
|
145
148
|
end
|
146
|
-
|
149
|
+
#
|
150
|
+
Ironfan.step(computer.name, "Running bootstrap")
|
151
|
+
Chef::Log.info("Bootstrapping:\n Computer #{computer}\n Bootstrap config #{bs.config}")
|
152
|
+
Ironfan.safely([computer, bs.config].inspect) do
|
147
153
|
bs.run
|
148
|
-
rescue StandardError => e
|
149
|
-
ui.warn e
|
150
|
-
ui.warn e.backtrace
|
151
|
-
ui.warn ""
|
152
|
-
ui.warn computer.inspect
|
153
|
-
ui.warn ""
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
@@ -2,16 +2,16 @@ module Ironfan
|
|
2
2
|
class Broker
|
3
3
|
|
4
4
|
class Computer < Builder
|
5
|
+
|
6
|
+
field :server, Ironfan::Dsl::Server
|
5
7
|
collection :resources, Whatever
|
6
8
|
collection :drives, Ironfan::Broker::Drive
|
7
9
|
collection :providers, Ironfan::Provider
|
8
|
-
|
9
|
-
delegate :[],:[]=,:include?,:delete,
|
10
|
-
:to => :resources
|
10
|
+
delegate :[], :[]=, :include?, :delete, :to => :resources
|
11
11
|
|
12
12
|
# Only used for bogus servers
|
13
13
|
field :name, String
|
14
|
-
field :bogus, Array,
|
14
|
+
field :bogus, Array, :default => []
|
15
15
|
|
16
16
|
def initialize(*args)
|
17
17
|
super
|
@@ -61,14 +61,21 @@ module Ironfan
|
|
61
61
|
target_resources = chosen_resources(options)
|
62
62
|
resources.each do |res|
|
63
63
|
next unless target_resources.include? res.class
|
64
|
-
res.
|
64
|
+
descriptor = "#{res.class} named #{res.name}"
|
65
|
+
if res.shared?
|
66
|
+
Chef::Log.debug("Not killing shared resource #{descriptor}")
|
67
|
+
else
|
68
|
+
Ironfan.step(self.name, "Killing #{descriptor}")
|
69
|
+
res.destroy
|
70
|
+
end
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
68
74
|
def launch
|
69
75
|
ensure_dependencies
|
70
|
-
|
76
|
+
iaas_provider.machine_class.create! self
|
71
77
|
save
|
78
|
+
self
|
72
79
|
end
|
73
80
|
|
74
81
|
def stop
|
@@ -87,6 +94,9 @@ module Ironfan
|
|
87
94
|
chosen_resources(options).each {|res| res.save! self}
|
88
95
|
end
|
89
96
|
|
97
|
+
def chef_provider ; providers[:chef] ; end
|
98
|
+
def iaas_provider ; providers[:iaas] ; end
|
99
|
+
|
90
100
|
#
|
91
101
|
# Utility
|
92
102
|
#
|
@@ -105,7 +115,7 @@ module Ironfan
|
|
105
115
|
|
106
116
|
def ensure_dependencies
|
107
117
|
chosen_resources.each do |res|
|
108
|
-
#
|
118
|
+
# ensure_resource res unless res < Ironfan::IaasProvider::Machine
|
109
119
|
res.create! self unless res < Ironfan::IaasProvider::Machine
|
110
120
|
end
|
111
121
|
end
|
@@ -126,7 +136,7 @@ module Ironfan
|
|
126
136
|
# if type.multiple?
|
127
137
|
# existing = resources[type.resource_id]
|
128
138
|
# else
|
129
|
-
#
|
139
|
+
#
|
130
140
|
# end
|
131
141
|
# end
|
132
142
|
|
@@ -165,21 +175,33 @@ module Ironfan
|
|
165
175
|
def bogus
|
166
176
|
resources.values.map(&:bogus).flatten
|
167
177
|
end
|
178
|
+
def node
|
179
|
+
self[:node]
|
180
|
+
end
|
181
|
+
def node=(value)
|
182
|
+
self[:node]= value
|
183
|
+
end
|
184
|
+
|
185
|
+
#
|
186
|
+
# client
|
187
|
+
#
|
168
188
|
def client
|
169
189
|
self[:client]
|
170
190
|
end
|
191
|
+
def private_key ; client? ? client.private_key : nil ; end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Machine
|
195
|
+
#
|
171
196
|
def machine
|
172
197
|
self[:machine]
|
173
198
|
end
|
174
199
|
def machine=(value)
|
175
200
|
self[:machine] = value
|
176
201
|
end
|
177
|
-
def
|
178
|
-
|
179
|
-
end
|
180
|
-
def node=(value)
|
181
|
-
self[:node]= value
|
182
|
-
end
|
202
|
+
def dns_name ; machine? ? machine.dns_name : nil ; end
|
203
|
+
def ssh_user ; (server && server.selected_cloud) ? server.selected_cloud.ssh_user : nil ; end
|
204
|
+
def bootstrap_distro ; (server && server.selected_cloud) ? server.selected_cloud.bootstrap_distro : nil ; end
|
183
205
|
|
184
206
|
#
|
185
207
|
# Status flags
|
@@ -197,7 +219,7 @@ module Ironfan
|
|
197
219
|
not machine.nil?
|
198
220
|
end
|
199
221
|
def killable?
|
200
|
-
not permanent? and (node?
|
222
|
+
not permanent? and (node? || client? || created?)
|
201
223
|
end
|
202
224
|
def launchable?
|
203
225
|
not bogus? and not created?
|
@@ -220,14 +242,22 @@ module Ironfan
|
|
220
242
|
machine? and machine.stopped?
|
221
243
|
end
|
222
244
|
|
245
|
+
# @return [Boolean] true if machine is likely to be reachable by ssh
|
246
|
+
def sshable?
|
247
|
+
# if there's any hope of success, give it a try.
|
248
|
+
running? || node?
|
249
|
+
end
|
250
|
+
|
251
|
+
def to_s
|
252
|
+
"<#{self.class}(server=#{server}, resources=#{resources && resources.inspect_compact}, providers=#{providers && providers.inspect_compact})>"
|
253
|
+
end
|
223
254
|
end
|
224
255
|
|
225
256
|
class Computers < Gorillib::ModelCollection
|
226
|
-
self.item_type
|
227
|
-
self.key_method
|
228
|
-
delegate
|
229
|
-
|
230
|
-
attr_accessor :cluster
|
257
|
+
self.item_type = Computer
|
258
|
+
self.key_method = :object_id
|
259
|
+
delegate :first, :map, :any?, :to => :values
|
260
|
+
attr_accessor :cluster
|
231
261
|
|
232
262
|
def initialize(*args)
|
233
263
|
super
|
@@ -236,19 +266,19 @@ module Ironfan
|
|
236
266
|
create_expected!
|
237
267
|
end
|
238
268
|
|
239
|
-
#
|
269
|
+
#
|
240
270
|
# Discovery
|
241
271
|
#
|
242
272
|
def correlate
|
243
|
-
values.each
|
273
|
+
values.each{|c| c.correlate }
|
244
274
|
end
|
245
275
|
|
246
276
|
def validate
|
247
277
|
providers = values.map {|c| c.providers.values}.flatten
|
248
278
|
computers = self
|
249
279
|
|
250
|
-
values.each
|
251
|
-
providers.each
|
280
|
+
values.each{|c| c.validate }
|
281
|
+
providers.each{|p| p.validate computers }
|
252
282
|
end
|
253
283
|
|
254
284
|
#
|
@@ -258,16 +288,16 @@ module Ironfan
|
|
258
288
|
Ironfan.parallel(values) {|c| c.kill(options) }
|
259
289
|
end
|
260
290
|
def launch
|
261
|
-
Ironfan.parallel(values) {|c| c.
|
291
|
+
Ironfan.parallel(values) {|c| c.launch }
|
262
292
|
end
|
263
293
|
def save(options={})
|
264
|
-
Ironfan.parallel(values) {|c| c.
|
294
|
+
Ironfan.parallel(values) {|c| c.save(options) }
|
265
295
|
end
|
266
296
|
def start
|
267
|
-
Ironfan.parallel(values) {|c| c.
|
297
|
+
Ironfan.parallel(values) {|c| c.start }
|
268
298
|
end
|
269
299
|
def stop
|
270
|
-
Ironfan.parallel(values) {|c| c.
|
300
|
+
Ironfan.parallel(values) {|c| c.stop }
|
271
301
|
end
|
272
302
|
|
273
303
|
#
|
@@ -307,6 +337,7 @@ module Ironfan
|
|
307
337
|
end
|
308
338
|
result
|
309
339
|
end
|
340
|
+
|
310
341
|
def build_slice_array(slice_indexes)
|
311
342
|
return [] if slice_indexes.nil?
|
312
343
|
raise "Bad slice_indexes: #{slice_indexes}" if slice_indexes =~ /[^0-9\.,]/
|
@@ -317,7 +348,11 @@ module Ironfan
|
|
317
348
|
def joined_names
|
318
349
|
values.map(&:name).join(", ").gsub(/, ([^,]*)$/, ' and \1')
|
319
350
|
end
|
351
|
+
|
352
|
+
def to_s
|
353
|
+
"#{self.class}[#{values.map(&:name).join(",")}]"
|
354
|
+
end
|
320
355
|
end
|
321
356
|
|
322
357
|
end
|
323
|
-
end
|
358
|
+
end
|
data/lib/ironfan/broker.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This module is intended to read in a cluster DSL description, and broker
|
2
2
|
# out to the various cloud providers, to control instance life-cycle and
|
3
|
-
# handle provider-specific amenities (SecurityGroup, Volume, etc.) for
|
3
|
+
# handle provider-specific amenities (SecurityGroup, Volume, etc.) for
|
4
4
|
# them.
|
5
5
|
module Ironfan
|
6
6
|
def self.broker
|
@@ -10,15 +10,21 @@ module Ironfan
|
|
10
10
|
class Broker < Builder
|
11
11
|
# Take in a Dsl::Cluster, return Computers populated with
|
12
12
|
# all discovered resources that correlate, plus bogus computers
|
13
|
-
# corresponding to
|
13
|
+
# corresponding to
|
14
14
|
def discover!(cluster)
|
15
15
|
# Get fully resolved servers, and build Computers using them
|
16
16
|
computers = Computers.new(:cluster => cluster.resolve)
|
17
|
-
|
18
|
-
|
19
|
-
providers.each
|
17
|
+
#
|
18
|
+
providers = computers.map{|c| c.providers.values }.flatten.uniq
|
19
|
+
providers.each do |provider|
|
20
|
+
Ironfan.step cluster.name, "Loading #{provider.handle}", :cyan
|
21
|
+
provider.load cluster
|
22
|
+
end
|
23
|
+
#
|
24
|
+
Ironfan.step cluster.name, "Reconciling DSL and provider information", :cyan
|
20
25
|
computers.correlate
|
21
26
|
computers.validate
|
27
|
+
#
|
22
28
|
computers
|
23
29
|
end
|
24
30
|
|
@@ -34,4 +40,4 @@ module Ironfan
|
|
34
40
|
|
35
41
|
end
|
36
42
|
|
37
|
-
end
|
43
|
+
end
|
data/lib/ironfan/deprecated.rb
CHANGED
@@ -2,7 +2,7 @@ module Ironfan
|
|
2
2
|
def self.deprecated call, replacement=nil
|
3
3
|
correction = ", " if replacement
|
4
4
|
ui.error "The '#{call}' statement is deprecated#{correction} (in #{caller(2).first.inspect}). It looks like you are using an outdated DSL definition: please see https://github.com/infochimps-labs/ironfan/wiki/Upgrading-to-v4 for all the necessary upgrade steps."
|
5
|
-
|
5
|
+
raise StandardError, "Deprecated call to #{call} - #{replacement}", caller
|
6
6
|
end
|
7
7
|
|
8
8
|
class Dsl
|
@@ -11,7 +11,7 @@ module Ironfan
|
|
11
11
|
Ironfan.deprecated 'defaults'
|
12
12
|
end
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
class Compute
|
16
16
|
def cloud(provider=nil)
|
17
17
|
if provider.nil?
|
data/lib/ironfan/dsl/ec2.rb
CHANGED
@@ -8,38 +8,46 @@ module Ironfan
|
|
8
8
|
class Ec2 < Cloud
|
9
9
|
magic :availability_zones, Array, :default => ['us-east-1d']
|
10
10
|
magic :backing, String, :default => 'ebs'
|
11
|
-
magic :
|
11
|
+
magic :bits, Integer, :default => ->{ flavor_info[:bits] }
|
12
|
+
magic :bootstrap_distro, String, :default => ->{ image_info[:bootstrap_distro] }
|
12
13
|
magic :chef_client_script, String
|
13
|
-
magic :default_availability_zone, String, :default => ->{availability_zones.first}
|
14
|
+
magic :default_availability_zone, String, :default => ->{ availability_zones.first }
|
14
15
|
magic :flavor, String, :default => 't1.micro'
|
15
|
-
magic :image_name, String
|
16
16
|
magic :image_id, String
|
17
|
+
magic :image_name, String
|
17
18
|
magic :keypair, Whatever
|
18
|
-
magic :mount_ephemerals, Hash, :default => {}
|
19
19
|
magic :monitoring, String
|
20
|
+
magic :mount_ephemerals, Hash, :default => {}
|
20
21
|
magic :permanent, :boolean, :default => false
|
21
|
-
magic :public_ip, String
|
22
22
|
magic :placement_group, String
|
23
|
-
magic :
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
magic :ssh_user, String, :default => 'ubuntu'
|
23
|
+
magic :provider, Ironfan::Provider, :default => Ironfan::Provider::Ec2
|
24
|
+
magic :public_ip, String
|
25
|
+
magic :region, String, :default => ->{ default_region }
|
26
|
+
magic :ssh_user, String, :default => ->{ image_info[:ssh_user] }
|
28
27
|
magic :ssh_identity_dir, String, :default => ->{ Chef::Config.ec2_key_dir }
|
29
|
-
|
28
|
+
collection :security_groups, Ironfan::Dsl::Ec2::SecurityGroup
|
30
29
|
magic :subnet, String
|
31
30
|
magic :validation_key, String, :default => ->{ IO.read(Chef::Config.validation_key) rescue '' }
|
32
31
|
magic :vpc, String
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
def image_info
|
34
|
+
bit_str = "#{self.bits.to_i}-bit" # correct for legacy image info.
|
35
|
+
keys = [region, bit_str, backing, image_name]
|
36
|
+
info = Chef::Config[:ec2_image_info][ keys ]
|
37
|
+
ui.warn("Can't find image for #{[region, bits.to_s, backing, image_name].inspect}") if info.blank?
|
38
|
+
return info || {}
|
39
39
|
end
|
40
40
|
|
41
41
|
def image_id
|
42
|
-
result = read_attribute(:image_id) ||
|
42
|
+
result = read_attribute(:image_id) || image_info[:image_id]
|
43
|
+
end
|
44
|
+
|
45
|
+
def ssh_key_name(computer)
|
46
|
+
keypair ? keypair.to_s : computer.server.cluster_name
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_region
|
50
|
+
default_availability_zone ? default_availability_zone.gsub(/^(\w+-\w+-\d)[a-z]/, '\1') : nil
|
43
51
|
end
|
44
52
|
|
45
53
|
def to_display(style,values={})
|
@@ -127,20 +135,22 @@ end
|
|
127
135
|
|
128
136
|
Chef::Config[:ec2_flavor_info] ||= {}
|
129
137
|
Chef::Config[:ec2_flavor_info].merge!({
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
}
|
138
|
+
# 32-or-64: m1.small, m1.medium, t1.micro, c1.medium
|
139
|
+
't1.micro' => { :price => 0.02, :bits => 64, :ram => 686, :cores => 1, :core_size => 0.25, :inst_disks => 0, :inst_disk_size => 0, :ephemeral_volumes => 0 },
|
140
|
+
'm1.small' => { :price => 0.08, :bits => 64, :ram => 1740, :cores => 1, :core_size => 1, :inst_disks => 1, :inst_disk_size => 160, :ephemeral_volumes => 1 },
|
141
|
+
'm1.medium' => { :price => 0.165, :bits => 32, :ram => 3840, :cores => 2, :core_size => 1, :inst_disks => 1, :inst_disk_size => 410, :ephemeral_volumes => 1 },
|
142
|
+
'c1.medium' => { :price => 0.17, :bits => 32, :ram => 1740, :cores => 2, :core_size => 2.5, :inst_disks => 1, :inst_disk_size => 350, :ephemeral_volumes => 1 },
|
143
|
+
#
|
144
|
+
'm1.large' => { :price => 0.32, :bits => 64, :ram => 7680, :cores => 2, :core_size => 2, :inst_disks => 2, :inst_disk_size => 850, :ephemeral_volumes => 2 },
|
145
|
+
'm2.xlarge' => { :price => 0.45, :bits => 64, :ram => 18124, :cores => 2, :core_size => 3.25, :inst_disks => 1, :inst_disk_size => 420, :ephemeral_volumes => 1 },
|
146
|
+
'c1.xlarge' => { :price => 0.64, :bits => 64, :ram => 7168, :cores => 8, :core_size => 2.5, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 4 },
|
147
|
+
'm1.xlarge' => { :price => 0.66, :bits => 64, :ram => 15360, :cores => 4, :core_size => 2, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 4 },
|
148
|
+
'm2.2xlarge' => { :price => 0.90, :bits => 64, :ram => 35020, :cores => 4, :core_size => 3.25, :inst_disks => 2, :inst_disk_size => 850, :ephemeral_volumes => 2 },
|
149
|
+
'm2.4xlarge' => { :price => 1.80, :bits => 64, :ram => 70041, :cores => 8, :core_size => 3.25, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 4 },
|
150
|
+
'cc1.4xlarge' => { :price => 1.30, :bits => 64, :ram => 23552, :cores => 8, :core_size => 4.19, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 2, :placement_groupable => true, :virtualization => 'hvm' },
|
151
|
+
'cc1.8xlarge' => { :price => 2.40, :bits => 64, :ram => 61952, :cores =>16, :core_size => 5.50, :inst_disks => 8, :inst_disk_size => 3370, :ephemeral_volumes => 4, :placement_groupable => true, :virtualization => 'hvm' },
|
152
|
+
'cg1.4xlarge' => { :price => 2.10, :bits => 64, :ram => 22528, :cores => 8, :core_size => 4.19, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 2, :placement_groupable => true, :virtualization => 'hvm' },
|
153
|
+
})
|
144
154
|
|
145
155
|
Chef::Config[:ec2_image_info] ||= {}
|
146
156
|
Chef::Config[:ec2_image_info].merge!({
|
data/lib/ironfan/dsl/server.rb
CHANGED
@@ -28,7 +28,17 @@ module Ironfan
|
|
28
28
|
values["Env"] = environment
|
29
29
|
values
|
30
30
|
end
|
31
|
+
|
32
|
+
# we should always show up in owners' inspect string
|
33
|
+
def inspect_compact ; inspect ; end
|
34
|
+
|
35
|
+
# @returns [Hash{String, Array}] of 'what you did wrong' => [relevant, info]
|
36
|
+
def lint
|
37
|
+
errors = []
|
38
|
+
errors['missing cluster/facet/server'] = [cluster_name, facet_name, name] unless (cluster_name && facet_name && name)
|
39
|
+
errors
|
40
|
+
end
|
31
41
|
end
|
32
42
|
|
33
43
|
end
|
34
|
-
end
|
44
|
+
end
|
data/lib/ironfan/dsl/volume.rb
CHANGED
@@ -29,8 +29,8 @@ module Ironfan
|
|
29
29
|
:blank_xfs => 'snap-d9c1edb1',
|
30
30
|
})
|
31
31
|
|
32
|
-
def snapshot_id(
|
33
|
-
|
32
|
+
def snapshot_id(*)
|
33
|
+
Ironfan.todo("CODE SMELL: EBS specific information in Dsl::Volume::VOLUME_IDS")
|
34
34
|
super || VOLUME_IDS[snapshot_name]
|
35
35
|
end
|
36
36
|
end
|
@@ -3,11 +3,11 @@ module Ironfan
|
|
3
3
|
class ChefServer
|
4
4
|
|
5
5
|
class Client < Ironfan::Provider::Resource
|
6
|
-
delegate :add_to_index, :admin, :cdb_destroy, :cdb_save,
|
7
|
-
:class_from_file, :couchdb, :couchdb=, :couchdb_id, :couchdb_id=,
|
8
|
-
:couchdb_rev, :couchdb_rev=, :create, :create_keys,
|
9
|
-
:delete_from_index, :destroy, :from_file, :index_id, :index_id=,
|
10
|
-
:index_object_type, :name, :public_key, :save, :set_or_return,
|
6
|
+
delegate :add_to_index, :admin, :cdb_destroy, :cdb_save,
|
7
|
+
:class_from_file, :couchdb, :couchdb=, :couchdb_id, :couchdb_id=,
|
8
|
+
:couchdb_rev, :couchdb_rev=, :create, :create_keys,
|
9
|
+
:delete_from_index, :destroy, :from_file, :index_id, :index_id=,
|
10
|
+
:index_object_type, :name, :public_key, :save, :set_or_return,
|
11
11
|
:to_hash, :validate, :with_indexer_metadata,
|
12
12
|
:to => :adaptee
|
13
13
|
field :key_filename, String,
|
@@ -18,6 +18,11 @@ module Ironfan
|
|
18
18
|
self.adaptee ||= Chef::ApiClient.new
|
19
19
|
end
|
20
20
|
|
21
|
+
def to_s
|
22
|
+
"<%-15s %-23s %s>" % [
|
23
|
+
self.class.handle, name, key_filename]
|
24
|
+
end
|
25
|
+
|
21
26
|
def self.shared?() false; end
|
22
27
|
def self.multiple?() false; end
|
23
28
|
def self.resource_type() :client; end
|
@@ -40,13 +45,16 @@ module Ironfan
|
|
40
45
|
# Discovery
|
41
46
|
#
|
42
47
|
def self.load!(cluster=nil)
|
48
|
+
Ironfan.substep(cluster.name, "chef clients")
|
43
49
|
nameq = "name:#{cluster.name}-* OR clientname:#{cluster.name}-*"
|
44
|
-
ChefServer.search(:client, nameq) do |
|
45
|
-
|
50
|
+
ChefServer.search(:client, nameq) do |raw|
|
51
|
+
next unless raw.present?
|
52
|
+
client = register(raw)
|
53
|
+
Chef::Log.debug("Loaded #{client}")
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
49
|
-
#
|
57
|
+
#
|
50
58
|
# Manipulation
|
51
59
|
#
|
52
60
|
def self.create!(computer)
|
@@ -30,6 +30,11 @@ module Ironfan
|
|
30
30
|
self.adaptee ||= Chef::Node.new
|
31
31
|
end
|
32
32
|
|
33
|
+
def to_s
|
34
|
+
"<%-15s %-23s %s>" % [
|
35
|
+
self.class.handle, name, run_list]
|
36
|
+
end
|
37
|
+
|
33
38
|
def self.shared?() false; end
|
34
39
|
def self.multiple?() false; end
|
35
40
|
# def self.resource_type() self; end
|
@@ -83,11 +88,11 @@ module Ironfan
|
|
83
88
|
# Discovery
|
84
89
|
#
|
85
90
|
def self.load!(cluster=nil)
|
91
|
+
Ironfan.substep(cluster.name, "nodes")
|
86
92
|
ChefServer.search(:node,"name:#{cluster.name}-*") do |raw|
|
87
|
-
next
|
88
|
-
node =
|
89
|
-
|
90
|
-
remember node
|
93
|
+
next unless raw.present?
|
94
|
+
node = register(raw)
|
95
|
+
Chef::Log.debug("Loaded #{node}")
|
91
96
|
end
|
92
97
|
end
|
93
98
|
|
@@ -38,13 +38,20 @@ module Ironfan
|
|
38
38
|
self
|
39
39
|
end
|
40
40
|
|
41
|
-
|
41
|
+
def to_s
|
42
|
+
"<%-15s %-23s %s>" % [
|
43
|
+
self.class.handle, name, run_list]
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
42
47
|
# Discovery
|
43
48
|
#
|
44
49
|
def self.load!(cluster)
|
50
|
+
Ironfan.substep(cluster.name, "roles")
|
45
51
|
ChefServer.search(:role,"name:#{cluster.name}_*") do |raw|
|
46
|
-
next
|
47
|
-
|
52
|
+
next unless raw.present?
|
53
|
+
role = register(raw)
|
54
|
+
Chef::Log.debug("Loaded #{role}")
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
@@ -16,6 +16,11 @@ module Ironfan
|
|
16
16
|
:to => :adaptee
|
17
17
|
field :dsl_volume, Ironfan::Dsl::Volume
|
18
18
|
|
19
|
+
def to_s
|
20
|
+
"<%-15s %-12s %-25s %-32s %-10s %-12s %-15s %-5s %s:%s>" % [
|
21
|
+
self.class.handle, id, created_at, tags['name'], state, device, tags['mount_point'], size, server_id, attached_at ]
|
22
|
+
end
|
23
|
+
|
19
24
|
def self.shared?() true; end
|
20
25
|
def self.multiple?() true; end
|
21
26
|
def self.resource_type() :ebs_volume; end
|
@@ -44,6 +49,7 @@ module Ironfan
|
|
44
49
|
# Discovery
|
45
50
|
#
|
46
51
|
def self.load!(cluster=nil)
|
52
|
+
Ironfan.substep(cluster.name, "volumes")
|
47
53
|
Ec2.connection.volumes.each do |vol|
|
48
54
|
next if vol.blank?
|
49
55
|
ebs = EbsVolume.new(:adaptee => vol)
|
@@ -55,6 +61,7 @@ module Ironfan
|
|
55
61
|
else
|
56
62
|
remember ebs
|
57
63
|
end
|
64
|
+
Chef::Log.debug("Loaded #{ebs}")
|
58
65
|
end
|
59
66
|
end
|
60
67
|
|
@@ -100,4 +107,4 @@ module Ironfan
|
|
100
107
|
|
101
108
|
end
|
102
109
|
end
|
103
|
-
end
|
110
|
+
end
|
@@ -25,12 +25,18 @@ module Ironfan
|
|
25
25
|
File.open(key_filename, "w", 0600){|f| f.print( body ) }
|
26
26
|
end
|
27
27
|
|
28
|
+
def to_s
|
29
|
+
"<%-15s %-12s>" % [self.class.handle, name]
|
30
|
+
end
|
31
|
+
|
28
32
|
#
|
29
33
|
# Discovery
|
30
34
|
#
|
31
35
|
def self.load!(cluster=nil)
|
36
|
+
Ironfan.substep(cluster && cluster.name, "keypairs")
|
32
37
|
Ec2.connection.key_pairs.each do |keypair|
|
33
38
|
register keypair unless keypair.blank?
|
39
|
+
Chef::Log.debug("Loaded <%-15s %s>" % [handle, keypair.name])
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
@@ -62,4 +68,4 @@ module Ironfan
|
|
62
68
|
|
63
69
|
end
|
64
70
|
end
|
65
|
-
end
|
71
|
+
end
|
@@ -93,10 +93,16 @@ module Ironfan
|
|
93
93
|
keypair = cloud.keypair || computer.server.cluster_name
|
94
94
|
end
|
95
95
|
|
96
|
+
def to_s
|
97
|
+
"<%-15s %-12s %-25s %-25s %-15s %-15s %-12s %-12s %s:%s>" % [
|
98
|
+
self.class.handle, id, created_at, tags['name'], private_ip_address, public_ip_address, flavor_id, availability_zone, key_name, groups.join(',') ]
|
99
|
+
end
|
100
|
+
|
96
101
|
#
|
97
102
|
# Discovery
|
98
103
|
#
|
99
104
|
def self.load!(cluster=nil)
|
105
|
+
Ironfan.substep(cluster.name, "machines")
|
100
106
|
Ec2.connection.servers.each do |fs|
|
101
107
|
machine = new(:adaptee => fs)
|
102
108
|
if recall? machine.name
|
@@ -109,6 +115,7 @@ module Ironfan
|
|
109
115
|
else
|
110
116
|
remember machine, :append_id => "terminated:#{machine.id}"
|
111
117
|
end
|
118
|
+
Chef::Log.debug("Loaded #{machine}")
|
112
119
|
end
|
113
120
|
end
|
114
121
|
|
@@ -122,11 +129,11 @@ module Ironfan
|
|
122
129
|
machine.bogus << :unexpected_machine
|
123
130
|
end
|
124
131
|
next unless machine.bogus?
|
125
|
-
fake
|
126
|
-
fake[:machine] =
|
127
|
-
fake.name
|
128
|
-
machine.users <<
|
129
|
-
computers
|
132
|
+
fake = Ironfan::Broker::Computer.new
|
133
|
+
fake[:machine] = machine
|
134
|
+
fake.name = machine.name
|
135
|
+
machine.users << fake
|
136
|
+
computers << fake
|
130
137
|
end
|
131
138
|
end
|
132
139
|
|
@@ -134,11 +141,14 @@ module Ironfan
|
|
134
141
|
# Manipulation
|
135
142
|
#
|
136
143
|
def self.create!(computer)
|
137
|
-
|
144
|
+
Ironfan.todo("CODE SMELL: overly large method: #{caller}")
|
138
145
|
return if computer.machine? and computer.machine.created?
|
139
146
|
Ironfan.step(computer.name,"creating cloud machine", :green)
|
140
|
-
#
|
141
|
-
|
147
|
+
#
|
148
|
+
errors = lint(computer)
|
149
|
+
if errors.present? then raise ArgumentError, "Failed validation: #{errors.inspect}" ; end
|
150
|
+
#
|
151
|
+
launch_desc = launch_description(computer)
|
142
152
|
Chef::Log.debug(JSON.pretty_generate(launch_desc))
|
143
153
|
|
144
154
|
Ironfan.safely do
|
@@ -162,7 +172,7 @@ module Ironfan
|
|
162
172
|
|
163
173
|
# register the new volumes for later save!, and tag appropriately
|
164
174
|
computer.machine.volumes.each do |v|
|
165
|
-
|
175
|
+
Ironfan.todo "CODE SMELL: Machine is too familiar with EbsVolume problems"
|
166
176
|
ebs_vol = Ec2::EbsVolume.register v
|
167
177
|
drive = computer.drives.values.select do |drive|
|
168
178
|
drive.volume.device == ebs_vol.device
|
@@ -178,30 +188,43 @@ module Ironfan
|
|
178
188
|
Ec2.ensure_tags(tags,ebs_vol)
|
179
189
|
end
|
180
190
|
end
|
181
|
-
|
182
|
-
|
191
|
+
|
192
|
+
# @returns [Hash{String, Array}] of 'what you did wrong' => [relevant, info]
|
193
|
+
def self.lint(computer)
|
194
|
+
cloud = computer.server.cloud(:ec2)
|
195
|
+
info = [computer.name, cloud.inspect]
|
196
|
+
errors = {}
|
197
|
+
server_errors = computer.server.lint
|
198
|
+
errors["Unhappy Server"] = server_errors if server_errors.present?
|
199
|
+
errors["No AMI found"] = info if cloud.image_id.blank?
|
200
|
+
errors['Missing client'] = info unless computer.client?
|
201
|
+
errors['Missing private_key'] = computer.client unless computer.private_key
|
202
|
+
errors
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.launch_description(computer)
|
206
|
+
cloud = computer.server.cloud(:ec2)
|
183
207
|
user_data_hsh = {
|
184
208
|
:chef_server => Chef::Config[:chef_server_url],
|
185
|
-
|
209
|
+
# :validation_client_name => Chef::Config[:validation_client_name],
|
186
210
|
#
|
187
211
|
:node_name => computer.name,
|
188
212
|
:organization => Chef::Config[:organization],
|
189
213
|
:cluster_name => computer.server.cluster_name,
|
190
214
|
:facet_name => computer.server.facet_name,
|
191
215
|
:facet_index => computer.server.index,
|
192
|
-
:client_key => computer
|
216
|
+
:client_key => computer.private_key
|
193
217
|
}
|
194
218
|
|
195
219
|
# Fog does not actually create tags when it creates a server;
|
196
220
|
# they and permanence are applied during sync
|
197
|
-
keypair = cloud.keypair || computer.server.cluster_name
|
198
221
|
description = {
|
199
222
|
:image_id => cloud.image_id,
|
200
223
|
:flavor_id => cloud.flavor,
|
201
224
|
:vpc_id => cloud.vpc,
|
202
225
|
:subnet_id => cloud.subnet,
|
203
226
|
:groups => cloud.security_groups.keys,
|
204
|
-
:key_name =>
|
227
|
+
:key_name => cloud.ssh_key_name(computer),
|
205
228
|
:user_data => JSON.pretty_generate(user_data_hsh),
|
206
229
|
:block_device_mapping => block_device_mapping(computer),
|
207
230
|
:availability_zone => cloud.default_availability_zone,
|
@@ -214,9 +237,10 @@ module Ironfan
|
|
214
237
|
end
|
215
238
|
description
|
216
239
|
end
|
240
|
+
|
217
241
|
# An array of hashes with dorky-looking keys, just like Fog wants it.
|
218
242
|
def self.block_device_mapping(computer)
|
219
|
-
|
243
|
+
Ironfan.todo "CODE SMELL: Machine is too familiar with EbsVolume problems"
|
220
244
|
computer.drives.values.map do |drive|
|
221
245
|
next if drive.disk # Don't create any disc already satisfied
|
222
246
|
volume = drive.volume or next
|
@@ -263,4 +287,3 @@ module Ironfan
|
|
263
287
|
end
|
264
288
|
end
|
265
289
|
end
|
266
|
-
|
@@ -11,14 +11,20 @@ module Ironfan
|
|
11
11
|
self["groupName"]
|
12
12
|
end
|
13
13
|
|
14
|
+
def to_s
|
15
|
+
"<%-15s %-12s %-12s>" % [ self.class.handle, '', name ]
|
16
|
+
end
|
17
|
+
|
14
18
|
def self.load!(cluster)
|
19
|
+
Ironfan.substep(cluster.name, "placement groups")
|
15
20
|
result = Ec2.connection.describe_placement_groups
|
16
21
|
result.body["placementGroupSet"].each do |group|
|
17
22
|
register group unless group.blank?
|
23
|
+
Chef::Log.debug("Loaded #{group.inspect}")
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
21
27
|
|
22
28
|
end
|
23
29
|
end
|
24
|
-
end
|
30
|
+
end
|
@@ -24,8 +24,28 @@ module Ironfan
|
|
24
24
|
# Discovery
|
25
25
|
#
|
26
26
|
def self.load!(cluster=nil)
|
27
|
-
|
28
|
-
|
27
|
+
Ironfan.substep(cluster.name, "security groups")
|
28
|
+
|
29
|
+
Ec2.connection.security_groups.each do |raw|
|
30
|
+
next if raw.blank?
|
31
|
+
sg = SecurityGroup.new(:adaptee => raw)
|
32
|
+
remember(sg)
|
33
|
+
Chef::Log.debug("Loaded #{sg}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
if ip_permissions.present?
|
39
|
+
perm_str = ip_permissions.map{|perm|
|
40
|
+
"%s:%s-%s (%s | %s)" % [
|
41
|
+
perm['ipProtocol'], perm['fromPort'], perm['toPort'],
|
42
|
+
perm['groups' ].map{|el| el['groupName'] }.join(','),
|
43
|
+
perm['ipRanges'].map{|el| el['cidrIp'] }.join(','),
|
44
|
+
]
|
45
|
+
}
|
46
|
+
return "<%-15s %-12s %-25s %s>" % [ self.class.handle, group_id, name, perm_str]
|
47
|
+
else
|
48
|
+
return "<%-15s %-12s %s>" % [ self.class.handle, group_id, name ]
|
29
49
|
end
|
30
50
|
end
|
31
51
|
|
@@ -35,7 +55,7 @@ module Ironfan
|
|
35
55
|
|
36
56
|
def self.create!(computer)
|
37
57
|
return unless Ec2.applicable computer
|
38
|
-
|
58
|
+
|
39
59
|
ensure_groups(computer)
|
40
60
|
groups = self.expected_ids(computer)
|
41
61
|
# Only handle groups that don't already exist
|
@@ -95,7 +115,7 @@ module Ironfan
|
|
95
115
|
# Ensure the security_groups include those for cluster & facet
|
96
116
|
# FIXME: This violates the DSL's immutability; it should be
|
97
117
|
# something calculated from within the DSL construction
|
98
|
-
|
118
|
+
Ironfan.todo("CODE SMELL: violation of DSL immutability: #{caller}")
|
99
119
|
cloud = computer.server.cloud(:ec2)
|
100
120
|
c_group = cloud.security_group(computer.server.cluster_name)
|
101
121
|
c_group.authorized_by_group(c_group.name)
|
@@ -123,4 +143,4 @@ module Ironfan
|
|
123
143
|
|
124
144
|
end
|
125
145
|
end
|
126
|
-
end
|
146
|
+
end
|
data/lib/ironfan/provider/ec2.rb
CHANGED
@@ -2,6 +2,7 @@ module Ironfan
|
|
2
2
|
class Provider
|
3
3
|
|
4
4
|
class Ec2 < Ironfan::IaasProvider
|
5
|
+
self.handle = :ec2
|
5
6
|
|
6
7
|
def self.resources
|
7
8
|
[ Machine, EbsVolume, KeyPair, SecurityGroup ]
|
@@ -18,7 +19,7 @@ module Ironfan
|
|
18
19
|
:region => Chef::Config[:knife][:region]
|
19
20
|
})
|
20
21
|
end
|
21
|
-
|
22
|
+
|
22
23
|
def self.aws_account_id()
|
23
24
|
Chef::Config[:knife][:aws_account_id]
|
24
25
|
end
|
@@ -44,4 +45,4 @@ module Ironfan
|
|
44
45
|
end
|
45
46
|
|
46
47
|
end
|
47
|
-
end
|
48
|
+
end
|
data/lib/ironfan/provider.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# Providers present a lightweight wrapper for various third-party services,
|
2
2
|
# such as Chef's node and client APIs, and Amazon's EC2 APIs. This allows
|
3
|
-
# Ironfan ask specialized questions (such as whether a given resource
|
3
|
+
# Ironfan ask specialized questions (such as whether a given resource
|
4
4
|
# matches
|
5
5
|
module Ironfan
|
6
6
|
class Provider < Builder
|
7
|
+
class_attribute :handle
|
7
8
|
|
8
9
|
def self.receive(obj,&block)
|
9
10
|
obj[:_type] = case obj[:name]
|
@@ -42,9 +43,11 @@ module Ironfan
|
|
42
43
|
|
43
44
|
def bogus?() !bogus.empty?; end
|
44
45
|
|
46
|
+
def self.handle ; name.to_s.gsub(/.*::/,'').to_sym ; end
|
47
|
+
|
45
48
|
#
|
46
49
|
# Flags
|
47
|
-
#
|
50
|
+
#
|
48
51
|
# Non-shared resources live and die with the computer
|
49
52
|
def self.shared?() true; end
|
50
53
|
# Can multiple instances of this resource be associated with the computer?
|
@@ -82,8 +85,9 @@ module Ironfan
|
|
82
85
|
|
83
86
|
# Register and return the (adapted) object with the collection
|
84
87
|
def self.register(native)
|
85
|
-
result = new(:adaptee => native)
|
86
|
-
remember result
|
88
|
+
result = new(:adaptee => native) or return
|
89
|
+
remember result
|
90
|
+
result
|
87
91
|
end
|
88
92
|
|
89
93
|
def self.recall?(id)
|
@@ -135,4 +139,4 @@ module Ironfan
|
|
135
139
|
end
|
136
140
|
end
|
137
141
|
|
138
|
-
end
|
142
|
+
end
|
data/lib/ironfan.rb
CHANGED
@@ -25,12 +25,18 @@ module Ironfan
|
|
25
25
|
def self.chef_config() @chef_config ; end
|
26
26
|
|
27
27
|
# execute against multiple targets in parallel
|
28
|
-
def self.parallel(targets
|
28
|
+
def self.parallel(targets)
|
29
29
|
raise 'missing block' unless block_given?
|
30
|
-
[
|
30
|
+
results = []
|
31
|
+
[targets].flatten.each_with_index.map do |target, idx|
|
31
32
|
sleep(0.1) # avoid hammering with simultaneous requests
|
32
|
-
Thread.new(target)
|
33
|
+
Thread.new(target) do |target|
|
34
|
+
results[idx] = safely(target.inspect) do
|
35
|
+
yield target
|
36
|
+
end
|
37
|
+
end
|
33
38
|
end.each(&:join) # wait for all the blocks to return
|
39
|
+
results
|
34
40
|
end
|
35
41
|
|
36
42
|
#
|
@@ -120,13 +126,15 @@ module Ironfan
|
|
120
126
|
# Ironfan.fog_connection.associate_address(self.fog_server.id, address)
|
121
127
|
# end
|
122
128
|
#
|
123
|
-
def self.safely
|
129
|
+
def self.safely(info="")
|
124
130
|
begin
|
125
131
|
yield
|
126
|
-
rescue StandardError =>
|
127
|
-
ui.
|
128
|
-
|
129
|
-
Chef::Log.error(
|
132
|
+
rescue StandardError => err
|
133
|
+
ui.warn("Error running #{info}:")
|
134
|
+
ui.warn(err)
|
135
|
+
Chef::Log.error( err )
|
136
|
+
Chef::Log.error( err.backtrace.join("\n") )
|
137
|
+
return err
|
130
138
|
end
|
131
139
|
end
|
132
140
|
|
@@ -137,6 +145,15 @@ module Ironfan
|
|
137
145
|
ui.info(" #{"%-15s" % (name.to_s+":")}\t#{ui.color(desc.to_s, *style)}")
|
138
146
|
end
|
139
147
|
|
148
|
+
def self.substep(name, desc)
|
149
|
+
step(name, " - #{desc}", :gray) if chef_config[:verbosity] >= 1
|
150
|
+
end
|
151
|
+
|
152
|
+
# Output a TODO to the logs if you've switched on pestering
|
153
|
+
def self.todo(*args)
|
154
|
+
Chef::Log.debug(*args) if Chef::Config[:show_todo]
|
155
|
+
end
|
156
|
+
|
140
157
|
#
|
141
158
|
# Utility to do mock out a step during a dry-run
|
142
159
|
#
|
@@ -152,8 +169,8 @@ module Ironfan
|
|
152
169
|
chef_config[:dry_run]
|
153
170
|
end
|
154
171
|
|
155
|
-
# Intentionally skipping an implied step
|
172
|
+
# Intentionally skipping an implied step
|
156
173
|
def self.noop(source,method,*params)
|
157
|
-
Chef::Log.debug("
|
174
|
+
# Chef::Log.debug("#{method} is a no-op for #{source} -- skipping (#{params.join(',')})")
|
158
175
|
end
|
159
176
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ironfan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 4.0
|
5
|
+
version: 4.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Infochimps
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-09-
|
13
|
+
date: 2012-09-24 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: chef
|
@@ -232,7 +232,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
232
232
|
requirements:
|
233
233
|
- - ">="
|
234
234
|
- !ruby/object:Gem::Version
|
235
|
-
hash:
|
235
|
+
hash: 3712152495684054514
|
236
236
|
segments:
|
237
237
|
- 0
|
238
238
|
version: "0"
|