fairchild-poolparty 1.3.5 → 1.3.17
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +1 -1
- data/bin/cloud +1 -0
- data/bin/cloud-compile +1 -0
- data/bin/cloud-misc +34 -0
- data/bin/cloud-show +13 -1
- data/bin/cloud-ssh +4 -1
- data/bin/cloud-thrift +32 -18
- data/config/jeweler.rb +5 -3
- data/examples/monitored_cloud.rb +1 -1
- data/examples/thrift/thrift_example.rb +8 -4
- data/examples/vmware.rb +10 -0
- data/lib/cloud_providers/cloud_provider.rb +9 -0
- data/lib/cloud_providers/cloud_provider_instance.rb +9 -4
- data/lib/cloud_providers/connections.rb +9 -5
- data/lib/cloud_providers/ec2/ec2.rb +42 -12
- data/lib/cloud_providers/ec2/ec2_helpers.rb +62 -5
- data/lib/cloud_providers/ec2/ec2_instance.rb +14 -1
- data/lib/cloud_providers/vmware/vmware.rb +3 -0
- data/lib/core/file.rb +12 -0
- data/lib/core/object.rb +1 -1
- data/lib/dependency_resolvers/base.rb +2 -9
- data/lib/dependency_resolvers/chef.rb +3 -3
- data/lib/keypair.rb +5 -3
- data/lib/poolparty.rb +3 -1
- data/lib/poolparty/base.rb +45 -22
- data/lib/poolparty/cloud.rb +70 -15
- data/lib/poolparty/default.rb +1 -0
- data/lib/poolparty/installer.rb +1 -1
- data/lib/poolparty/installers/ec2.rb +30 -16
- data/lib/poolparty/monitor.rb +25 -3
- data/lib/poolparty/plugin.rb +1 -5
- data/lib/poolparty/plugins/apache.rb +37 -11
- data/lib/poolparty/plugins/apache2/passenger_site.rb +1 -1
- data/lib/poolparty/plugins/apache2/virtual_host.rb +1 -0
- data/lib/poolparty/plugins/collectd.rb +29 -0
- data/lib/poolparty/plugins/collectd/templates/collectd.conf.erb +369 -0
- data/lib/poolparty/plugins/hermes.rb +101 -0
- data/lib/poolparty/pool.rb +14 -6
- data/lib/poolparty/resource.rb +20 -17
- data/lib/poolparty/resources/file.rb +2 -2
- data/lib/poolparty/resources/line.rb +1 -1
- data/lib/poolparty/resources/link.rb +2 -1
- data/lib/proto/command_interface_handler.rb +42 -7
- data/lib/proto/command_query_handler.rb +19 -0
- data/lib/proto/gen-py/cloudthrift/CommandInterface.pyc +0 -0
- data/lib/proto/gen-py/cloudthrift/__init__.pyc +0 -0
- data/lib/proto/gen-py/cloudthrift/constants.pyc +0 -0
- data/lib/proto/gen-py/cloudthrift/ttypes.pyc +0 -0
- data/lib/proto/gen-py/thrift/Thrift.pyc +0 -0
- data/lib/proto/gen-py/thrift/__init__.pyc +0 -0
- data/lib/proto/gen-py/thrift/protocol/TBinaryProtocol.pyc +0 -0
- data/lib/proto/gen-py/thrift/protocol/TProtocol.pyc +0 -0
- data/lib/proto/gen-py/thrift/protocol/__init__.pyc +0 -0
- data/lib/proto/gen-py/thrift/transport/TSocket.pyc +0 -0
- data/lib/proto/gen-py/thrift/transport/TTransport.pyc +0 -0
- data/lib/proto/gen-py/thrift/transport/__init__.pyc +0 -0
- data/lib/proto/poolparty.thrift +1 -0
- data/tasks/poolparty.rake +24 -0
- data/test/fixtures/clouds/fake_clouds.rb +2 -2
- data/test/fixtures/clouds/simple_cloud.rb +2 -2
- data/test/fixtures/resources/fake_plugin.rb +5 -0
- data/test/fixtures/resources/fake_subclassed_plugin.rb +19 -0
- data/test/lib/cloud_providers/ec2/ec2_instance_test.rb +17 -8
- data/test/lib/cloud_providers/ec2/ec2_test.rb +15 -11
- data/test/lib/core/array_test.rb +4 -0
- data/test/lib/dependency_resolvers/base_test.rb +1 -1
- data/test/lib/dependency_resolvers/chef/resources/remote_directory_test.rb +2 -2
- data/test/lib/dependency_resolvers/chef/resources/remote_file_test.rb +1 -1
- data/test/lib/dependency_resolvers/chef_test.rb +3 -3
- data/test/lib/poolparty/base_test.rb +1 -1
- data/test/lib/poolparty/cloud_test.rb +140 -33
- data/test/lib/poolparty/monitor_test.rb +29 -2
- data/test/lib/poolparty/plugins/apache_test.rb +5 -0
- data/test/lib/poolparty/pool_test.rb +3 -3
- data/test/lib/poolparty/resource_test.rb +14 -2
- data/test/lib/poolparty/resources/conditional_test.rb +1 -0
- data/test/lib/poolparty/resources/directory_test.rb +1 -1
- data/test/lib/poolparty/resources/file_test.rb +1 -1
- data/test/lib/poolparty/resources/user_test.rb +1 -1
- data/test/lib/proto/command_query_handler_test.rb +11 -0
- data/test/lib/provision/bootstrapper_test.rb +0 -25
- data/test/test_helper.rb +0 -1
- metadata +15 -4
@@ -1,12 +1,58 @@
|
|
1
1
|
module CloudProviders
|
2
2
|
module Ec2Helpers
|
3
3
|
|
4
|
+
# VOLUMES
|
5
|
+
def attach_volume(instance_id, volume_id=next_unused_volume, device="/dev/sdh")
|
6
|
+
ec2.attach_volume(volume_id, instance_id, device)
|
7
|
+
end
|
8
|
+
|
9
|
+
def next_unused_volume
|
10
|
+
if all_volumes.empty?
|
11
|
+
nil
|
12
|
+
else
|
13
|
+
available_volumes.first
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def all_volumes
|
20
|
+
ebs_volumes.empty? ? [] : ec2.describe_volumes.select {|v| ebs_volumes.include?(v[:aws_id]) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def available_volumes
|
24
|
+
all_volumes.select {|v| v[:aws_status] == 'available' }
|
25
|
+
end
|
26
|
+
|
27
|
+
def unavailable_volumes
|
28
|
+
all_volumes.reject {|v| available_volumes.include?(v) }
|
29
|
+
end
|
30
|
+
|
31
|
+
public
|
32
|
+
|
33
|
+
# SECURITY GROUPS
|
34
|
+
def security_groups(list=[])
|
35
|
+
ec2.describe_security_groups(list)
|
36
|
+
end
|
37
|
+
|
38
|
+
public
|
39
|
+
|
40
|
+
# ELASTIC IPS
|
41
|
+
|
4
42
|
# Associate an address with the instance using ec2
|
5
43
|
# Get the next_unused_elastic_ip
|
6
44
|
# and if there is one, associate the instance to the
|
7
45
|
# public ip
|
8
|
-
def associate_address()
|
9
|
-
|
46
|
+
def associate_address(instance_id)
|
47
|
+
new_ip = next_unused_elastic_ip
|
48
|
+
vputs("Assigning #{new_ip} to the ec2 instance #{instance_id}")
|
49
|
+
ec2.associate_address(instance_id, new_ip)
|
50
|
+
loop do
|
51
|
+
if describe_instance(:instance_id => instance_id).public_ip == new_ip
|
52
|
+
return new_ip
|
53
|
+
end
|
54
|
+
sleep 1
|
55
|
+
end
|
10
56
|
end
|
11
57
|
|
12
58
|
# Get the next usable elastic ip
|
@@ -17,13 +63,24 @@ module CloudProviders
|
|
17
63
|
# intersection of the unused ips and those, find the first one available
|
18
64
|
# and return that.
|
19
65
|
def next_unused_elastic_ip
|
20
|
-
|
21
|
-
if elastic_ips.empty?
|
66
|
+
if unused_elastic_ips.empty?
|
22
67
|
nil
|
23
68
|
else
|
69
|
+
vputs("Found an unused elastic ip: #{unused_elastic_ips.first}")
|
70
|
+
unused_elastic_ips.first
|
24
71
|
end
|
25
72
|
end
|
26
|
-
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def all_elastic_ips
|
77
|
+
elastic_ips.empty? ? [] : ec2.describe_addresses.map {|a| a[:public_ip]} & elastic_ips
|
78
|
+
end
|
79
|
+
|
80
|
+
def unused_elastic_ips
|
81
|
+
all_elastic_ips.select {|i| i[:instance_id] == nil }
|
82
|
+
end
|
83
|
+
|
27
84
|
# Help create a keypair for the cloud
|
28
85
|
# This is a helper to create the keypair and add them to the cloud for you
|
29
86
|
# def create_keypair
|
@@ -64,7 +64,7 @@ module CloudProviders
|
|
64
64
|
FileUtils.mkdir_p(cloud.tmp_path/ec2_dir) unless File.directory?(cloud.tmp_path/ec2_dir)
|
65
65
|
run ["mkdir -p #{ec2_dir}"]
|
66
66
|
# Save a yaml file of aws varibles and send to the instance
|
67
|
-
File.open(cloud.tmp_path/
|
67
|
+
File.open(cloud.tmp_path/"etc"/"poolparty"/'env.yml', 'w') do |f|
|
68
68
|
f<<YAML::dump(cloud_provider.aws_hash(ec2_dir)) #TODO: don't save sensitive info in /tmp
|
69
69
|
end
|
70
70
|
# We scp these files directly to the instance so to reduce the risk of accidentally leaving them in an insecure location
|
@@ -85,6 +85,8 @@ module CloudProviders
|
|
85
85
|
/mnt
|
86
86
|
/proc
|
87
87
|
/sys
|
88
|
+
/etc/ssh/ssh_host_*
|
89
|
+
/etc/ssh/moduli
|
88
90
|
/etc/udev/rules.d/70-persistent-net.rules
|
89
91
|
/etc/udev/rules.d/z25_persistent-net.rules
|
90
92
|
)
|
@@ -110,11 +112,22 @@ module CloudProviders
|
|
110
112
|
cmds << "mkdir -p #{opts[:destination]}/loop"
|
111
113
|
cmds << "mount -o loop #{image_file} #{opts[:destination]}/loop"
|
112
114
|
cmds << "rsync -ax #{rsync_excludes(opts[:exclude])} #{opts[:volume]}/ #{opts[:destination]}/loop/"
|
115
|
+
cmds << "if [[ -f /etc/init.d/ec2-ssh-host-key-gen ]]; then chmod u+x /etc/init.d/ec2-ssh-host-key-gen ;fi"
|
113
116
|
cmds << "umount #{opts[:destination]}/loop"
|
114
117
|
self.run cmds
|
115
118
|
image_file
|
116
119
|
end
|
117
120
|
|
121
|
+
#TODO
|
122
|
+
# def bundle_and_register(opts={})
|
123
|
+
# arch = 'uname'
|
124
|
+
# image = make_image(opts)
|
125
|
+
# 'ec2-bundle-image' image
|
126
|
+
# 'ec2-upload-bundle'
|
127
|
+
# 'ec2-register-bundle'
|
128
|
+
# return ami
|
129
|
+
# end
|
130
|
+
|
118
131
|
end
|
119
132
|
|
120
133
|
end
|
data/lib/core/file.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class File
|
2
|
+
class << self
|
3
|
+
alias_method :old_symlink, :symlink
|
4
|
+
def symlink(old_name, new_name)
|
5
|
+
begin
|
6
|
+
old_symlink(old_name, new_name)
|
7
|
+
rescue Errno::EEXIST
|
8
|
+
$stderr.puts "warning: symlinking #{old_name} -> #{new_name}. Already exists"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/core/object.rb
CHANGED
@@ -68,7 +68,7 @@ class Object
|
|
68
68
|
# MESSAGES
|
69
69
|
# Debugging output helpers
|
70
70
|
def vputs(m="")
|
71
|
-
puts "[INFO] -- #{m}" if verbose?
|
71
|
+
puts "[INFO] -- #{m.is_a?(String) ? m : m.inspect}" if verbose?
|
72
72
|
end
|
73
73
|
def dputs(m="")
|
74
74
|
puts "[DEBUG] -- #{m.is_a?(String) ? m : m.inspect}" if debugging?
|
@@ -89,14 +89,7 @@ module DependencyResolvers
|
|
89
89
|
"#{obj.to_i}"
|
90
90
|
end
|
91
91
|
when String
|
92
|
-
|
93
|
-
when /^\d{4}$/
|
94
|
-
"#{obj}"
|
95
|
-
when /^\d{3}$/
|
96
|
-
"0#{obj}"
|
97
|
-
else
|
98
|
-
"\"#{obj}\""
|
99
|
-
end
|
92
|
+
"\"#{obj}\""
|
100
93
|
when Proc
|
101
94
|
obj.call # eh
|
102
95
|
when Array
|
@@ -119,4 +112,4 @@ module DependencyResolvers
|
|
119
112
|
|
120
113
|
end
|
121
114
|
|
122
|
-
end
|
115
|
+
end
|
@@ -109,10 +109,10 @@ module DependencyResolvers
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def apply_meta_notifies(resource, add)
|
112
|
-
# The meta_notifies is a hash that looks like: {:file => [["pool_name", :reload]]}
|
112
|
+
# The meta_notifies is a hash that looks like: {:file => [["pool_name", :reload, :immediately]]}
|
113
113
|
resource.meta_notifies.each do |ty, arr|
|
114
|
-
arr.each do |nm, action|
|
115
|
-
add << " notifies :#{action}, resources(:#{chef_safe_resource(ty)} => \"#{nm}\")"
|
114
|
+
arr.each do |nm, action, at_time|
|
115
|
+
add << " notifies :#{action}, resources(:#{chef_safe_resource(ty)} => \"#{nm}\"), :#{at_time}"
|
116
116
|
end
|
117
117
|
end
|
118
118
|
end
|
data/lib/keypair.rb
CHANGED
@@ -7,10 +7,12 @@ class Keypair
|
|
7
7
|
has_searchable_paths(:prepend_paths => [Dir.pwd, '/etc/poolparty/keys', "#{ENV["HOME"]}/.ssh/", "#{ENV["HOME"]}/.ec2/", ENV['EC2_CONFIG_DIR']])
|
8
8
|
|
9
9
|
attr_accessor :filepath
|
10
|
+
attr_reader :extra_paths
|
10
11
|
|
11
12
|
# Create a new key that defaults to id_rsa as the name.
|
12
|
-
def initialize(fpath)
|
13
|
+
def initialize(fpath, extra_paths=[])
|
13
14
|
@filepath = fpath
|
15
|
+
@extra_paths = extra_paths.map {|a| File.expand_path(a) }
|
14
16
|
valid?
|
15
17
|
end
|
16
18
|
|
@@ -27,10 +29,10 @@ class Keypair
|
|
27
29
|
# Returns the full_filepath of the key. If a full filepath is passed, we just return the expanded filepath
|
28
30
|
# for the keypair, otherwise query where it is against known locations
|
29
31
|
def full_filepath
|
30
|
-
@full_filepath ||= if File.file?(
|
32
|
+
@full_filepath ||= if File.file?(File.expand_path(filepath))
|
31
33
|
::File.expand_path(filepath)
|
32
34
|
else
|
33
|
-
search_in_known_locations(filepath)
|
35
|
+
search_in_known_locations(filepath, extra_paths)
|
34
36
|
end
|
35
37
|
end
|
36
38
|
alias :to_s :full_filepath
|
data/lib/poolparty.rb
CHANGED
data/lib/poolparty/base.rb
CHANGED
@@ -128,47 +128,70 @@ module PoolParty
|
|
128
128
|
# to create edges on the graph
|
129
129
|
def resources_graph(force=false)
|
130
130
|
return @resources_graph if @resources_graph && !force
|
131
|
-
result = Digraph.new
|
131
|
+
result = Digraph.new
|
132
132
|
|
133
133
|
create_graph(resources, nil, result)
|
134
134
|
|
135
|
-
add_ordered_resources_to_result(resources, result)
|
136
|
-
|
137
135
|
@resources_graph = result
|
138
136
|
end
|
139
137
|
|
140
|
-
# Add all the resources as edges of each other
|
141
|
-
def add_ordered_resources_to_result(resources, result)
|
142
|
-
arr_of_resources = resources.zip_offset(1)
|
143
|
-
|
144
|
-
arr_of_resources.each do |first, second|
|
145
|
-
result.add_edge!(first, second) unless result.edge?(first, second) or result.edge?(second, first)
|
146
|
-
add_ordered_resources_to_result(first.resources, result)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
138
|
# Create the graph of resources. Blow up if a resource isn't found
|
151
139
|
# that is required. If it is found, add it as an edge to the
|
152
140
|
# dependency graph
|
153
141
|
def create_graph(resources, on, result)
|
154
|
-
|
142
|
+
# add_ordered_resources_to_result(without_dependencies, result)
|
143
|
+
first_layer_of_ordered_resources = resources_without_dependencies.zip_offset(1)
|
144
|
+
first_layer_of_ordered_resources.each do |first, second|
|
145
|
+
result.add_edge!(first, second) unless second.nil? or result.edge?(first, second) or result.edge?(second, first)
|
146
|
+
end
|
147
|
+
|
148
|
+
resources_with_dependencies.each do |r|
|
155
149
|
|
156
|
-
|
150
|
+
r.dependencies.each do |dep_type, deps_array|
|
157
151
|
deps_array.each do |dep_name|
|
158
152
|
dep = get_resource(dep_type, dep_name)
|
159
|
-
raise PoolPartyError.create("ResourceNotFound", "A resource required for #{
|
160
|
-
|
153
|
+
raise PoolPartyError.create("ResourceNotFound", "A resource required for #{dep_type}(#{dep_name}) was not found: #{dep_type}(#{dep_name}). Please make sure you've specified this in your configuration.") unless dep
|
154
|
+
|
155
|
+
unless result.edge?(dep, r) and result.edge?(r, dep)
|
156
|
+
existing_connections = result.adjacent(dep)
|
157
|
+
existing_connections.each {|c| result.remove_edge!(r, c) }
|
158
|
+
|
159
|
+
result.add_edge!(dep, r, dep.name)
|
160
|
+
|
161
|
+
existing_connections.each {|c| result.add_edge!(dep, c) }
|
162
|
+
end
|
163
|
+
|
161
164
|
end
|
162
165
|
end
|
163
|
-
|
166
|
+
end
|
167
|
+
|
168
|
+
all_resources.each_with_index do |resource, idx|
|
164
169
|
if on
|
165
|
-
result.add_edge!(resource, on, resource.name) unless result.edge?(resource, on)
|
170
|
+
result.add_edge!(resource, on, resource.name) unless result.edge?(resource, on) or result.edge?(on, resource)
|
166
171
|
else
|
167
|
-
result.add_vertex!(resource)
|
172
|
+
result.add_vertex!(resource) unless result.vertex?(resource)
|
168
173
|
end
|
169
|
-
|
170
|
-
create_graph(resource.resources, resource, result)
|
171
174
|
end
|
175
|
+
|
176
|
+
result
|
177
|
+
end
|
178
|
+
|
179
|
+
# Add all the resources as edges of each other
|
180
|
+
def add_ordered_resources_to_result(resources, result)
|
181
|
+
arr_of_resources = resources.zip_offset(1)
|
182
|
+
|
183
|
+
arr_of_resources.each do |first, second|
|
184
|
+
result.add_edge!(first, second) unless result.edge?(first, second) or result.edge?(second, first)
|
185
|
+
add_ordered_resources_to_result(first.resources, result)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def resources_without_dependencies(r=all_resources)
|
190
|
+
r.reject {|a| !a.dependencies.empty? }
|
191
|
+
end
|
192
|
+
|
193
|
+
def resources_with_dependencies(r=all_resources)
|
194
|
+
r - resources_without_dependencies(r)
|
172
195
|
end
|
173
196
|
|
174
197
|
# All the dependencies that are required by this resource
|
data/lib/poolparty/cloud.rb
CHANGED
@@ -27,7 +27,9 @@ module PoolParty
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def before_compile
|
30
|
-
|
30
|
+
add_monitoring_stack_if_needed
|
31
|
+
|
32
|
+
validate_all_resources unless ENV["POOLPARTY_NO_VALIDATION"]
|
31
33
|
end
|
32
34
|
|
33
35
|
# Freeze the cloud_name so we can't modify it at all, set the plugin_directory
|
@@ -48,8 +50,8 @@ module PoolParty
|
|
48
50
|
# returns an instance of Keypair
|
49
51
|
# You can pass either a filename which will be searched for in ~/.ec2/ and ~/.ssh/
|
50
52
|
# Or you can pass a full filepath
|
51
|
-
def keypair(n=nil)
|
52
|
-
@keypair ||= Keypair.new(n)
|
53
|
+
def keypair(n=nil, extra_paths=[])
|
54
|
+
@keypair ||= Keypair.new(n, extra_paths)
|
53
55
|
end
|
54
56
|
|
55
57
|
# Declare the CloudProvider for a cloud
|
@@ -58,10 +60,13 @@ module PoolParty
|
|
58
60
|
return @cloud_provider if @cloud_provider
|
59
61
|
self.cloud_provider_name = provider_symbol
|
60
62
|
cloud_provider(o, &block)
|
63
|
+
cloud_provider.keypair(keypair.full_filepath)
|
61
64
|
end
|
62
65
|
|
63
66
|
# Cloud provider methods
|
64
|
-
def nodes(o={})
|
67
|
+
def nodes(o={})
|
68
|
+
delayed_action {cloud_provider.nodes(o).collect{|n| n.cloud = self; n}};
|
69
|
+
end
|
65
70
|
def run_instance(o={}); cloud_provider.run_instance(o);end
|
66
71
|
def terminate_instance!(o={}); cloud_provider.terminate_instance!(o);end
|
67
72
|
def describe_instances(o={}); cloud_provider.describe_instances(o);end
|
@@ -87,7 +92,7 @@ module PoolParty
|
|
87
92
|
|
88
93
|
# 1.) Launches a new instance,
|
89
94
|
# 2.) Waits for the instance to get an ip address
|
90
|
-
# 3.) Waits for port
|
95
|
+
# 3.) Waits for port ssh_port to be open
|
91
96
|
# 4.) Calls call_after_launch_instance callbacks
|
92
97
|
# 5.) Executes passed &block, if any
|
93
98
|
# 6.) Returns the new instance object
|
@@ -98,7 +103,7 @@ module PoolParty
|
|
98
103
|
instance.cloud = self
|
99
104
|
@instance = instance
|
100
105
|
#wait for an ip and then wait for ssh port, then configure instance
|
101
|
-
if instance.wait_for_public_ip(timeout) && instance.wait_for_port(
|
106
|
+
if instance.wait_for_public_ip(timeout) && instance.wait_for_port(ssh_port, :timeout=>timeout)
|
102
107
|
callback :after_launch_instance
|
103
108
|
instance.callback :before_bootstrap
|
104
109
|
instance.bootstrap!
|
@@ -109,7 +114,7 @@ module PoolParty
|
|
109
114
|
block.call(instance) if block
|
110
115
|
instance
|
111
116
|
else
|
112
|
-
raise StandardError.new("Instance port
|
117
|
+
raise StandardError.new("Instance port #{ssh_port} not available")
|
113
118
|
end
|
114
119
|
instance.refresh!
|
115
120
|
instance
|
@@ -177,16 +182,31 @@ module PoolParty
|
|
177
182
|
end
|
178
183
|
end
|
179
184
|
|
185
|
+
# Add the monitoring stack
|
186
|
+
def add_monitoring_stack_if_needed
|
187
|
+
if monitors.size > 0
|
188
|
+
|
189
|
+
run_in_context do
|
190
|
+
%w(collectd hermes).each do |m|
|
191
|
+
self.send m.to_sym
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
180
198
|
# Take the cloud's resources and compile them down using
|
181
199
|
# the defined (or the default dependency_resolver, chef)
|
182
200
|
def compile(caller=nil)
|
183
201
|
callback :before_compile
|
202
|
+
cloud_provider.before_compile(self)
|
184
203
|
FileUtils.mkdir_p tmp_path unless File.directory?(tmp_path)
|
185
204
|
ddputs <<-EOE
|
186
205
|
Compiling cloud #{self.name} to #{tmp_path/"etc"/"#{dependency_resolver_name}"}
|
187
206
|
number of resources: #{ordered_resources.size}
|
188
207
|
EOE
|
189
208
|
out = dependency_resolver.compile_to(ordered_resources, tmp_path/"etc"/"#{dependency_resolver_name}", caller)
|
209
|
+
cloud_provider.after_compile(self)
|
190
210
|
callback :after_compile
|
191
211
|
out
|
192
212
|
end
|
@@ -215,14 +235,14 @@ Compiling cloud #{self.name} to #{tmp_path/"etc"/"#{dependency_resolver_name}"}
|
|
215
235
|
# vote_for(:expand) if v > 0.8
|
216
236
|
# end
|
217
237
|
def monitor(monitor_symbol, &block)
|
218
|
-
monitors[monitor_symbol] ||= PoolParty::Monitor.new(monitor_symbol, &block)
|
238
|
+
monitors[monitor_symbol.to_sym] ||= PoolParty::Monitor.new(monitor_symbol, &block)
|
219
239
|
end
|
220
240
|
|
221
241
|
# Run the monitor logic
|
222
242
|
def run_monitor(monitor_name, value)
|
223
243
|
mon = monitors[monitor_name.to_sym]
|
224
244
|
if mon
|
225
|
-
mon.run(value
|
245
|
+
mon.run(value)
|
226
246
|
else
|
227
247
|
"unhandled monitor"
|
228
248
|
end
|
@@ -233,6 +253,14 @@ Compiling cloud #{self.name} to #{tmp_path/"etc"/"#{dependency_resolver_name}"}
|
|
233
253
|
@monitors ||= {}
|
234
254
|
end
|
235
255
|
|
256
|
+
def monitor_format(mon_name, meth=nil, &block)
|
257
|
+
if monitors.has_key?(mon_name.to_sym)
|
258
|
+
monitors[mon_name.to_sym].format(meth, &block)
|
259
|
+
else
|
260
|
+
raise PoolPartyError.create("MonitorsFormattingError", "You created a monitor format for an unknown monitor. Please check and try again!")
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
236
264
|
##### Internal methods #####
|
237
265
|
# Methods that only the cloud itself will use
|
238
266
|
# and thus are private
|
@@ -263,17 +291,23 @@ Compiling cloud #{self.name} to #{tmp_path/"etc"/"#{dependency_resolver_name}"}
|
|
263
291
|
if resources_graph.cyclic?
|
264
292
|
cycles = []
|
265
293
|
|
266
|
-
resources_graph.
|
267
|
-
|
268
|
-
|
269
|
-
end
|
294
|
+
cycles = resources_graph.find_cycle
|
295
|
+
cycle_string = cycles.map do |k,v|
|
296
|
+
"#{k} -> #{v}"
|
270
297
|
end
|
298
|
+
|
299
|
+
filepath = "/tmp"
|
300
|
+
format = "png"
|
301
|
+
dotpath = "#{filepath}/dot.#{format}"
|
302
|
+
resources_graph.write_to_graphic_file(format, filepath)
|
303
|
+
|
304
|
+
`open #{dotpath}`
|
271
305
|
msg =<<-EOE
|
272
306
|
|
273
307
|
Your resource graph is cyclic. Two resources depend on each other, Cannot decide which resource
|
274
308
|
to go first. Dying instead. Correct this and then try again.
|
275
309
|
|
276
|
-
#{
|
310
|
+
#{dotpath}
|
277
311
|
|
278
312
|
Hint: You can see the resource graph by generating it with:
|
279
313
|
cloud compile -g name
|
@@ -298,4 +332,25 @@ Compiling cloud #{self.name} to #{tmp_path/"etc"/"#{dependency_resolver_name}"}
|
|
298
332
|
end
|
299
333
|
|
300
334
|
end
|
301
|
-
end
|
335
|
+
end
|
336
|
+
|
337
|
+
module GRATR
|
338
|
+
class Digraph
|
339
|
+
|
340
|
+
# Crappy n*n
|
341
|
+
def find_cycle(from=self)
|
342
|
+
return [] unless cyclic?
|
343
|
+
cyclic_cycle = []
|
344
|
+
forward_edge = Proc.new {|e| }
|
345
|
+
back_edge = Proc.new do |b|
|
346
|
+
cyclic_cycle = dfs_tree_from_vertex(b)
|
347
|
+
end
|
348
|
+
from.dfs({
|
349
|
+
:forward_edge => forward_edge,
|
350
|
+
:back_edge => back_edge
|
351
|
+
})
|
352
|
+
cyclic_cycle
|
353
|
+
end
|
354
|
+
|
355
|
+
end
|
356
|
+
end
|