ironfan 4.0.9 → 4.1.0
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.
- 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"
|