ironfan 3.2.2 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|