ironfan 3.2.2 → 4.0.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 +5 -0
- data/VERSION +1 -1
- data/ironfan.gemspec +33 -20
- data/lib/chef/knife/cluster_kick.rb +17 -17
- data/lib/chef/knife/cluster_kill.rb +13 -7
- data/lib/chef/knife/cluster_launch.rb +60 -66
- data/lib/chef/knife/cluster_pry.rb +2 -2
- data/lib/chef/knife/cluster_show.rb +3 -6
- data/lib/chef/knife/cluster_ssh.rb +5 -11
- data/lib/chef/knife/cluster_start.rb +2 -4
- data/lib/chef/knife/cluster_stop.rb +1 -3
- data/lib/chef/knife/cluster_sync.rb +13 -21
- data/lib/chef/knife/ironfan_knife_common.rb +11 -9
- data/lib/chef/knife/ironfan_script.rb +2 -1
- data/lib/gorillib/resolution.rb +119 -0
- data/lib/ironfan/broker/computer.rb +316 -0
- data/lib/ironfan/broker/drive.rb +21 -0
- data/lib/ironfan/broker.rb +37 -0
- data/lib/ironfan/builder.rb +14 -0
- data/lib/ironfan/deprecated.rb +16 -58
- data/lib/ironfan/dsl/cloud.rb +21 -0
- data/lib/ironfan/dsl/cluster.rb +27 -0
- data/lib/ironfan/dsl/compute.rb +84 -0
- data/lib/ironfan/dsl/ec2.rb +260 -0
- data/lib/ironfan/dsl/facet.rb +25 -0
- data/lib/ironfan/dsl/role.rb +19 -0
- data/lib/ironfan/dsl/server.rb +31 -0
- data/lib/ironfan/dsl/virtualbox.rb +8 -0
- data/lib/ironfan/dsl/volume.rb +45 -0
- data/lib/ironfan/dsl.rb +7 -0
- data/lib/ironfan/headers.rb +58 -0
- data/lib/ironfan/provider/chef/client.rb +77 -0
- data/lib/ironfan/provider/chef/node.rb +133 -0
- data/lib/ironfan/provider/chef/role.rb +69 -0
- data/lib/ironfan/provider/chef.rb +28 -0
- data/lib/ironfan/provider/ec2/ebs_volume.rb +137 -0
- data/lib/ironfan/provider/ec2/elastic_ip.rb +10 -0
- data/lib/ironfan/provider/ec2/key_pair.rb +65 -0
- data/lib/ironfan/provider/ec2/machine.rb +258 -0
- data/lib/ironfan/provider/ec2/placement_group.rb +24 -0
- data/lib/ironfan/provider/ec2/security_group.rb +118 -0
- data/lib/ironfan/provider/ec2.rb +47 -0
- data/lib/ironfan/provider/virtualbox/machine.rb +10 -0
- data/lib/ironfan/provider/virtualbox.rb +8 -0
- data/lib/ironfan/provider.rb +139 -0
- data/lib/ironfan/requirements.rb +52 -0
- data/lib/ironfan.rb +44 -33
- metadata +34 -21
- data/lib/chef/knife/cluster_vagrant.rb +0 -144
- data/lib/chef/knife/vagrant/ironfan_environment.rb +0 -18
- data/lib/chef/knife/vagrant/ironfan_provisioners.rb +0 -27
- data/lib/chef/knife/vagrant/skeleton_vagrantfile.rb +0 -119
- data/lib/ironfan/chef_layer.rb +0 -300
- data/lib/ironfan/cloud.rb +0 -323
- data/lib/ironfan/cluster.rb +0 -118
- data/lib/ironfan/compute.rb +0 -139
- data/lib/ironfan/discovery.rb +0 -190
- data/lib/ironfan/dsl_builder.rb +0 -99
- data/lib/ironfan/facet.rb +0 -143
- data/lib/ironfan/fog_layer.rb +0 -196
- data/lib/ironfan/private_key.rb +0 -130
- data/lib/ironfan/role_implications.rb +0 -58
- data/lib/ironfan/security_group.rb +0 -133
- data/lib/ironfan/server.rb +0 -291
- data/lib/ironfan/server_slice.rb +0 -265
- data/lib/ironfan/volume.rb +0 -146
data/lib/ironfan/fog_layer.rb
DELETED
@@ -1,196 +0,0 @@
|
|
1
|
-
module Ironfan
|
2
|
-
#
|
3
|
-
# Ironfan::Server methods that handle Fog action
|
4
|
-
#
|
5
|
-
Server.class_eval do
|
6
|
-
|
7
|
-
def fog_create_server
|
8
|
-
step(" creating cloud server", :green)
|
9
|
-
lint_fog
|
10
|
-
launch_desc = fog_launch_description
|
11
|
-
Chef::Log.debug(JSON.pretty_generate(launch_desc))
|
12
|
-
safely do
|
13
|
-
@fog_server = Ironfan.fog_connection.servers.create(launch_desc)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def lint_fog
|
18
|
-
unless cloud.image_id then raise "No image ID found: nothing in Chef::Config[:ec2_image_info] for AZ #{self.default_availability_zone} flavor #{cloud.flavor} backing #{cloud.backing} image name #{cloud.image_name}, and cloud.image_id was not set directly. See https://github.com/infochimps-labs/ironfan/wiki/machine-image-(AMI)-lookup-by-name - #{cloud.list_images}" end
|
19
|
-
unless cloud.image_id then cloud.list_flavors ; raise "No machine flavor found" ; end
|
20
|
-
end
|
21
|
-
|
22
|
-
def fog_launch_description
|
23
|
-
user_data_hsh =
|
24
|
-
if client_key.body then cloud.user_data.merge({ :client_key => client_key.body })
|
25
|
-
else cloud.user_data.merge({ :validation_key => cloud.validation_key }) ; end
|
26
|
-
#
|
27
|
-
description = {
|
28
|
-
:image_id => cloud.image_id,
|
29
|
-
:flavor_id => cloud.flavor,
|
30
|
-
:vpc_id => cloud.vpc,
|
31
|
-
:subnet_id => cloud.subnet,
|
32
|
-
:groups => cloud.security_groups.keys,
|
33
|
-
:key_name => cloud.keypair.to_s,
|
34
|
-
# Fog does not actually create tags when it creates a server.
|
35
|
-
:tags => {
|
36
|
-
:name => self.fullname,
|
37
|
-
:cluster => cluster_name,
|
38
|
-
:facet => facet_name,
|
39
|
-
:index => facet_index, },
|
40
|
-
:user_data => JSON.pretty_generate(user_data_hsh),
|
41
|
-
:block_device_mapping => block_device_mapping,
|
42
|
-
:availability_zone => self.default_availability_zone,
|
43
|
-
:monitoring => cloud.monitoring,
|
44
|
-
# permanence is applied during sync
|
45
|
-
}
|
46
|
-
if needs_placement_group?
|
47
|
-
ui.warn "1.3.1 and earlier versions of Fog don't correctly support placement groups, so your nodes will land willy-nilly. We're working on a fix"
|
48
|
-
description[:placement] = { 'groupName' => cloud.placement_group.to_s }
|
49
|
-
end
|
50
|
-
description
|
51
|
-
end
|
52
|
-
|
53
|
-
#
|
54
|
-
# Takes key-value pairs and idempotently sets those tags on the cloud machine
|
55
|
-
#
|
56
|
-
def fog_create_tags(fog_obj, desc, tags)
|
57
|
-
tags['Name'] ||= tags['name'] if tags.has_key?('name')
|
58
|
-
tags_to_create = tags.reject{|key, val| fog_obj.tags[key] == val.to_s }
|
59
|
-
return if tags_to_create.empty?
|
60
|
-
step(" tagging #{desc} with #{tags_to_create.inspect}", :green)
|
61
|
-
tags_to_create.each do |key, value|
|
62
|
-
Chef::Log.debug( "tagging #{desc} with #{key} = #{value}" )
|
63
|
-
safely do
|
64
|
-
Ironfan.fog_connection.tags.create({
|
65
|
-
:key => key, :value => value.to_s, :resource_id => fog_obj.id })
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def fog_address
|
71
|
-
address_str = self.cloud.public_ip or return
|
72
|
-
Ironfan.fog_addresses[address_str]
|
73
|
-
end
|
74
|
-
|
75
|
-
def discover_volumes!
|
76
|
-
result = self.class.fields[:volumes].type.new
|
77
|
-
volumes.each_pair do |vol_name, definition|
|
78
|
-
next if definition.fog_volume
|
79
|
-
next if Ironfan.chef_config[:cloud] == false
|
80
|
-
vol = definition.dup
|
81
|
-
vol.fog_volume = Ironfan.fog_volumes.find do |fv|
|
82
|
-
( # matches the explicit volume id
|
83
|
-
(vol.volume_id && (fv.id == vol.volume_id) ) ||
|
84
|
-
# OR this server's machine exists, and this volume is attached to
|
85
|
-
# it, and in the right place
|
86
|
-
( fog_server && fv.server_id && vol.device &&
|
87
|
-
(fv.server_id == fog_server.id) &&
|
88
|
-
(fv.device.to_s == vol.device.to_s) ) ||
|
89
|
-
# OR this volume is tagged as belonging to this machine
|
90
|
-
( fv.tags.present? &&
|
91
|
-
(fv.tags['server'] == self.fullname) &&
|
92
|
-
(fv.tags['device'] == vol.device.to_s) )
|
93
|
-
)
|
94
|
-
end
|
95
|
-
next unless vol.fog_volume
|
96
|
-
vol.volume_id(vol.fog_volume.id) unless vol.volume_id.present?
|
97
|
-
vol.availability_zone(vol.fog_volume.availability_zone) unless vol.availability_zone.present?
|
98
|
-
check_server_id_pairing(vol.fog_volume, vol.desc)
|
99
|
-
result[vol.name] = vol
|
100
|
-
end
|
101
|
-
write_attribute(:volumes,result)
|
102
|
-
end
|
103
|
-
|
104
|
-
def attach_volumes
|
105
|
-
return unless in_cloud?
|
106
|
-
discover_volumes!
|
107
|
-
return if volumes.empty?
|
108
|
-
step(" attaching volumes")
|
109
|
-
volumes.each_pair do |vol_name, vol|
|
110
|
-
next if vol.volume_id.blank? || (vol.attachable != :ebs)
|
111
|
-
if (not vol.in_cloud?) then Chef::Log.debug("Volume not found: #{vol.desc}") ; next ; end
|
112
|
-
if (vol.has_server?) then check_server_id_pairing(vol.fog_volume, vol.desc) ; next ; end
|
113
|
-
step(" - attaching #{vol.desc} -- #{vol.inspect}", :blue)
|
114
|
-
safely do
|
115
|
-
vol.fog_volume.device = vol.device
|
116
|
-
vol.fog_volume.server = fog_server
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def ensure_placement_group
|
122
|
-
return unless needs_placement_group?
|
123
|
-
pg_name = cloud.placement_group.to_s
|
124
|
-
desc = "placement group #{pg_name} for #{self.fullname} (vs #{Ironfan.placement_groups.inspect}"
|
125
|
-
return if Ironfan.placement_groups.include?(pg_name)
|
126
|
-
safely do
|
127
|
-
step(" creating #{desc}", :blue)
|
128
|
-
unless_dry_run{ Ironfan.fog_connection.create_placement_group(pg_name, 'cluster') }
|
129
|
-
Ironfan.placement_groups[pg_name] = { 'groupName' => pg_name, 'strategy' => 'cluster' }
|
130
|
-
end
|
131
|
-
pg_name
|
132
|
-
end
|
133
|
-
|
134
|
-
def needs_placement_group?
|
135
|
-
cloud.flavor_info[:placement_groupable]
|
136
|
-
end
|
137
|
-
|
138
|
-
def associate_public_ip
|
139
|
-
address = self.cloud.public_ip
|
140
|
-
return unless self.in_cloud? && address
|
141
|
-
desc = "elastic ip #{address} for #{self.fullname}"
|
142
|
-
if (fog_address && fog_address.server_id) then check_server_id_pairing(fog_address, desc) ; return ; end
|
143
|
-
safely do
|
144
|
-
step(" assigning #{desc}", :blue)
|
145
|
-
Ironfan.fog_connection.associate_address(self.fog_server.id, address)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def check_server_id_pairing thing, desc
|
150
|
-
return unless thing && thing.server_id && self.in_cloud?
|
151
|
-
type_of_thing = thing.class.to_s.gsub(/.*::/,"")
|
152
|
-
if thing.server_id != self.fog_server.id
|
153
|
-
ui.warn "#{type_of_thing} mismatch: #{desc} is on #{thing.server_id} not #{self.fog_server.id}: #{thing.inspect.gsub(/\s+/m,' ')}"
|
154
|
-
false
|
155
|
-
else
|
156
|
-
Chef::Log.debug("#{type_of_thing} paired: #{desc}")
|
157
|
-
true
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def set_instance_attributes
|
162
|
-
return unless self.in_cloud? && (not self.cloud.permanent.nil?)
|
163
|
-
desc = "termination flag #{permanent?} for #{self.fullname}"
|
164
|
-
# the EC2 API does not surface disable_api_termination as a value, so we
|
165
|
-
# have to set it every time.
|
166
|
-
safely do
|
167
|
-
step(" setting #{desc}", :blue)
|
168
|
-
unless_dry_run do
|
169
|
-
Ironfan.fog_connection.modify_instance_attribute(self.fog_server.id, {
|
170
|
-
'DisableApiTermination.Value' => permanent?, })
|
171
|
-
end
|
172
|
-
true
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
end
|
177
|
-
|
178
|
-
class ServerSlice
|
179
|
-
def sync_keypairs
|
180
|
-
step("ensuring keypairs exist")
|
181
|
-
keypairs = servers.map{|svr| [svr.cluster.cloud.keypair, svr.cloud.keypair] }.flatten.map(&:to_s).reject(&:blank?).uniq
|
182
|
-
keypairs = keypairs - Ironfan.fog_keypairs.keys
|
183
|
-
keypairs.each do |keypair_name|
|
184
|
-
keypair_obj = Ironfan::Ec2Keypair.create!(keypair_name)
|
185
|
-
Ironfan.fog_keypairs[keypair_name] = keypair_obj
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
# Create security groups, their dependencies, and synchronize their permissions
|
190
|
-
def sync_security_groups
|
191
|
-
step("ensuring security groups exist and are correct")
|
192
|
-
security_groups.each{|name,group| group.run }
|
193
|
-
end
|
194
|
-
|
195
|
-
end
|
196
|
-
end
|
data/lib/ironfan/private_key.rb
DELETED
@@ -1,130 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
module Ironfan
|
4
|
-
#
|
5
|
-
# A private key -- chef client key, ssh key, etc.
|
6
|
-
#
|
7
|
-
# The key is a pro
|
8
|
-
class PrivateKey < Ironfan::DslBuilder
|
9
|
-
attr_reader :name
|
10
|
-
attr_reader :proxy
|
11
|
-
attr_reader :on_update
|
12
|
-
|
13
|
-
#
|
14
|
-
# PrivateKey.new('bob')
|
15
|
-
#
|
16
|
-
# @yield a block, executed in caller's context, when the body is updated
|
17
|
-
# @yieldparam the updated body
|
18
|
-
def initialize(name, proxy=nil, &on_update)
|
19
|
-
@name = name
|
20
|
-
@proxy = proxy
|
21
|
-
@on_update = on_update
|
22
|
-
end
|
23
|
-
|
24
|
-
def filename
|
25
|
-
File.join(key_dir, "#{name}.pem")
|
26
|
-
end
|
27
|
-
|
28
|
-
def save
|
29
|
-
return unless @body
|
30
|
-
if Ironfan.chef_config[:dry_run]
|
31
|
-
Chef::Log.debug(" key #{name} - dry run, not writing out key")
|
32
|
-
return
|
33
|
-
end
|
34
|
-
ui.info( " key #{name} - writing to #{filename}" )
|
35
|
-
FileUtils.mkdir_p(File.dirname(filename))
|
36
|
-
File.open(filename, "w", 0600){|f| f.print( @body ) }
|
37
|
-
end
|
38
|
-
|
39
|
-
def load
|
40
|
-
return unless File.exists?(filename)
|
41
|
-
self.body = File.read(filename).chomp
|
42
|
-
end
|
43
|
-
|
44
|
-
def body=(content)
|
45
|
-
@body = content
|
46
|
-
on_update.call(content) if on_update
|
47
|
-
content
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.create!(name, *args, &block)
|
51
|
-
obj = self.new(name, *args, &block)
|
52
|
-
obj.create_proxy!
|
53
|
-
obj
|
54
|
-
end
|
55
|
-
|
56
|
-
def to_s
|
57
|
-
[super[0..-2], @name, @proxy, @body.to_s[32..64], '...', @body.to_s[-60..-30]].join(" ").gsub(/[\r\n\t]+/,'') + '>'
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
class ChefClientKey < PrivateKey
|
62
|
-
def body
|
63
|
-
return @body if @body
|
64
|
-
if proxy && proxy.private_key && (not proxy.private_key.empty?)
|
65
|
-
@body = proxy.private_key
|
66
|
-
else
|
67
|
-
load
|
68
|
-
end
|
69
|
-
@body
|
70
|
-
end
|
71
|
-
|
72
|
-
def key_dir
|
73
|
-
Chef::Config.client_key_dir || "/tmp/#{ENV['USER']}-client_keys"
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class DataBagKey < PrivateKey
|
78
|
-
def body
|
79
|
-
return @body if @body
|
80
|
-
@body
|
81
|
-
end
|
82
|
-
|
83
|
-
def random_token
|
84
|
-
require "digest/sha2"
|
85
|
-
digest = Digest::SHA512.hexdigest( Time.now.to_s + (1..10).collect{ rand.to_s }.join )
|
86
|
-
5.times{ digest = Digest::SHA512.hexdigest(digest) }
|
87
|
-
digest
|
88
|
-
end
|
89
|
-
|
90
|
-
def key_dir
|
91
|
-
return Chef::Config.data_bag_key_dir if Chef::Config.data_bag_key_dir
|
92
|
-
dir = "#{ENV['HOME']}/.chef/credentials/data_bag_keys"
|
93
|
-
warn "Please set 'data_bag_key_dir' in your knife.rb. Will use #{dir} as a default"
|
94
|
-
dir
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
class Ec2Keypair < PrivateKey
|
99
|
-
def body
|
100
|
-
return @body if @body
|
101
|
-
if proxy && proxy.private_key && (not proxy.private_key.empty?)
|
102
|
-
@body = proxy.private_key
|
103
|
-
else
|
104
|
-
load
|
105
|
-
end
|
106
|
-
@body
|
107
|
-
end
|
108
|
-
|
109
|
-
def create_proxy!
|
110
|
-
safely do
|
111
|
-
step(" key #{name} - creating", :green)
|
112
|
-
@proxy = Ironfan.fog_connection.key_pairs.create(:name => name.to_s)
|
113
|
-
end
|
114
|
-
Ironfan.fog_keypairs[name] = proxy
|
115
|
-
self.body = proxy.private_key
|
116
|
-
save
|
117
|
-
end
|
118
|
-
|
119
|
-
def key_dir
|
120
|
-
if Chef::Config.ec2_key_dir
|
121
|
-
return Chef::Config.ec2_key_dir
|
122
|
-
else
|
123
|
-
dir = "#{ENV['HOME']}/.chef/credentials/ec2_keys"
|
124
|
-
warn "Please set 'ec2_key_dir' in your knife.rb. Will use #{dir} as a default"
|
125
|
-
dir
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
module Ironfan
|
2
|
-
ComputeBuilder.class_eval do
|
3
|
-
|
4
|
-
# organization-wide security group
|
5
|
-
role_implication "systemwide" do
|
6
|
-
self.cloud.security_group "systemwide" do
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
# NFS server allows access from nfs_clients
|
11
|
-
role_implication "nfs_server" do
|
12
|
-
self.cloud.security_group "nfs_server" do
|
13
|
-
authorize_group "nfs_client"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
role_implication "nfs_client" do
|
18
|
-
self.cloud.security_group "nfs_client"
|
19
|
-
end
|
20
|
-
|
21
|
-
# Opens port 22 to the world
|
22
|
-
role_implication "ssh" do
|
23
|
-
self.cloud.security_group 'ssh' do
|
24
|
-
authorize_port_range 22..22
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Open the Chef server API port (4000) and the webui (4040)
|
29
|
-
role_implication "chef_server" do
|
30
|
-
self.cloud.security_group "chef_server" do
|
31
|
-
authorize_port_range 4000..4000 # chef-server-api
|
32
|
-
authorize_port_range 4040..4040 # chef-server-webui
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# web server? add the group "web_server" to open the web holes
|
37
|
-
role_implication "web_server" do
|
38
|
-
self.cloud.security_group("#{cluster_name}-web_server") do
|
39
|
-
authorize_port_range 80..80
|
40
|
-
authorize_port_range 443..443
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# if you're a redis server, open the port and authorize redis clients in your group to talk to you
|
45
|
-
role_implication("redis_server") do
|
46
|
-
cluster_name = self.cluster_name # hack: put cluster_name is in scope
|
47
|
-
self.cloud.security_group("#{cluster_name}-redis_server") do
|
48
|
-
authorize_group("#{cluster_name}-redis_client")
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# redis_clients gain rights to the redis_server
|
53
|
-
role_implication("redis_client") do
|
54
|
-
self.cloud.security_group("#{cluster_name}-redis_client")
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
@@ -1,133 +0,0 @@
|
|
1
|
-
module Ironfan
|
2
|
-
module CloudDsl
|
3
|
-
class SecurityGroup < Ironfan::DslBuilder
|
4
|
-
magic :name, String
|
5
|
-
magic :description, String
|
6
|
-
magic :group_authorizations, Array
|
7
|
-
magic :group_authorized_by, Array
|
8
|
-
magic :range_authorizations, Array
|
9
|
-
|
10
|
-
def initialize params
|
11
|
-
name params[:name].to_s
|
12
|
-
description "ironfan generated group #{name}"
|
13
|
-
group_authorizations []
|
14
|
-
group_authorized_by []
|
15
|
-
range_authorizations []
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_key
|
19
|
-
name
|
20
|
-
end
|
21
|
-
|
22
|
-
@@all = nil
|
23
|
-
def all
|
24
|
-
self.class.all
|
25
|
-
end
|
26
|
-
def self.all
|
27
|
-
return @@all if @@all
|
28
|
-
get_all
|
29
|
-
end
|
30
|
-
def self.get_all
|
31
|
-
groups_list = Ironfan.fog_connection.security_groups.all
|
32
|
-
@@all = groups_list.inject(Mash.new) do |hsh, fog_group|
|
33
|
-
# AWS security_groups are strangely case sensitive, allowing upper-case but colliding regardless
|
34
|
-
# of the case. This forces all names to lowercase, and matches against that below.
|
35
|
-
# See https://github.com/infochimps-labs/ironfan/pull/86 for more details.
|
36
|
-
hsh[fog_group.name.downcase] = fog_group ; hsh
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def get
|
41
|
-
all[name] || Ironfan.fog_connection.security_groups.get(name)
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.get_or_create(group_name, description)
|
45
|
-
group_name = group_name.to_s.downcase
|
46
|
-
# FIXME: the '|| Ironfan.fog' part is probably unnecessary
|
47
|
-
fog_group = all[group_name] || Ironfan.fog_connection.security_groups.get(group_name)
|
48
|
-
unless fog_group
|
49
|
-
self.step(group_name, "creating (#{description})", :green)
|
50
|
-
fog_group = all[group_name] = Ironfan.fog_connection.security_groups.new(:name => group_name, :description => description, :connection => Ironfan.fog_connection)
|
51
|
-
fog_group.save
|
52
|
-
end
|
53
|
-
fog_group
|
54
|
-
end
|
55
|
-
|
56
|
-
def authorize_group(group_name, owner_id=nil)
|
57
|
-
group_authorizations << [group_name.to_s, owner_id]
|
58
|
-
end
|
59
|
-
|
60
|
-
def authorized_by_group(other_name)
|
61
|
-
group_authorized_by << other_name.to_s
|
62
|
-
end
|
63
|
-
|
64
|
-
def authorize_port_range(range, cidr_ip = '0.0.0.0/0', ip_protocol = 'tcp')
|
65
|
-
range = (range .. range) if range.is_a?(Integer)
|
66
|
-
range_authorizations << [range, cidr_ip, ip_protocol]
|
67
|
-
end
|
68
|
-
#
|
69
|
-
# def group_permission_already_set?(fog_group, other_name, authed_owner)
|
70
|
-
# return false if fog_group.ip_permissions.nil?
|
71
|
-
# fog_group.ip_permissions.any? do |existing_permission|
|
72
|
-
# existing_permission["groups"].include?({"userId" => authed_owner, "groupName" => other_name}) &&
|
73
|
-
# existing_permission["fromPort"] == 1 &&
|
74
|
-
# existing_permission["toPort"] == 65535
|
75
|
-
# end
|
76
|
-
# end
|
77
|
-
#
|
78
|
-
# def range_permission_already_set?(fog_group, range, cidr_ip, ip_protocol)
|
79
|
-
# return false if fog_group.ip_permissions.nil?
|
80
|
-
# fog_group.ip_permissions.include?(
|
81
|
-
# { "groups"=>[], "ipRanges"=>[{"cidrIp"=>cidr_ip}],
|
82
|
-
# "ipProtocol"=>ip_protocol, "fromPort"=>range.first, "toPort"=>range.last})
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# FIXME: so if you're saying to yourself, "self, this is some soupy gooey
|
86
|
-
# code right here" then you and your self are correct. Much of this is to
|
87
|
-
# work around old limitations in the EC2 api. You can now treat range and
|
88
|
-
# group permissions the same, and we should.
|
89
|
-
|
90
|
-
def run
|
91
|
-
fog_group = self.class.get_or_create(name, description)
|
92
|
-
@group_authorizations.uniq.each do |other_name, authed_owner|
|
93
|
-
authed_owner ||= self.owner_id
|
94
|
-
next if group_permission_already_set?(fog_group, other_name, authed_owner)
|
95
|
-
step("authorizing access from all machines in #{other_name} to #{name}", :blue)
|
96
|
-
self.class.get_or_create(other_name, "Authorized to access #{name}")
|
97
|
-
begin fog_group.authorize_group_and_owner(other_name, authed_owner)
|
98
|
-
rescue StandardError => err ; handle_security_group_error(err) ; end
|
99
|
-
end
|
100
|
-
@group_authorized_by.uniq.each do |other_name|
|
101
|
-
authed_owner = self.owner_id
|
102
|
-
other_group = self.class.get_or_create(other_name, "Authorized for access by #{self.name}")
|
103
|
-
next if group_permission_already_set?(other_group, self.name, authed_owner)
|
104
|
-
step("authorizing access to all machines in #{other_name} from #{name}", :blue)
|
105
|
-
begin other_group.authorize_group_and_owner(self.name, authed_owner)
|
106
|
-
rescue StandardError => err ; handle_security_group_error(err) ; end
|
107
|
-
end
|
108
|
-
@range_authorizations.uniq.each do |range, cidr_ip, ip_protocol|
|
109
|
-
next if range_permission_already_set?(fog_group, range, cidr_ip, ip_protocol)
|
110
|
-
step("opening #{ip_protocol} ports #{range} to #{cidr_ip}", :blue)
|
111
|
-
begin fog_group.authorize_port_range(range, { :cidr_ip => cidr_ip, :ip_protocol => ip_protocol })
|
112
|
-
rescue StandardError => err ; handle_security_group_error(err) ; end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
#
|
116
|
-
# def handle_security_group_error(err)
|
117
|
-
# if (/has already been authorized/ =~ err.to_s)
|
118
|
-
# Chef::Log.debug err
|
119
|
-
# else
|
120
|
-
# ui.warn(err)
|
121
|
-
# end
|
122
|
-
# end
|
123
|
-
#
|
124
|
-
def self.step(group_name, desc, *style)
|
125
|
-
ui.info(" group #{"%-15s" % (group_name+":")}\t#{ui.color(desc.to_s, *style)}")
|
126
|
-
end
|
127
|
-
def step(desc, *style)
|
128
|
-
self.class.step(self.name, desc, *style)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|
133
|
-
end
|