poolparty 1.3.8 → 1.3.13
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-thrift +32 -18
- data/config/jeweler.rb +3 -2
- data/examples/thrift/thrift_example.rb +3 -1
- data/lib/cloud_providers/cloud_provider.rb +9 -0
- data/lib/cloud_providers/cloud_provider_instance.rb +7 -2
- data/lib/cloud_providers/ec2/ec2.rb +22 -7
- data/lib/cloud_providers/ec2/ec2_helpers.rb +60 -5
- data/lib/dependency_resolvers/base.rb +2 -9
- data/lib/poolparty/base.rb +2 -2
- data/lib/poolparty/cloud.rb +12 -2
- data/lib/poolparty/monitor.rb +25 -3
- data/lib/poolparty/plugins/hermes.rb +24 -11
- data/lib/poolparty/pool.rb +9 -10
- data/lib/poolparty/resource.rb +16 -13
- data/lib/poolparty/resources/file.rb +2 -2
- data/lib/poolparty/resources/link.rb +2 -1
- data/lib/proto/command_interface_handler.rb +27 -8
- data/lib/proto/command_query_handler.rb +19 -0
- data/lib/proto/poolparty.thrift +1 -0
- data/lib/provision/bootstrap_scripts/build_centos.sh +2 -0
- data/lib/provision/bootstrap_scripts/build_ubuntu.sh +1 -0
- data/tasks/poolparty.rake +24 -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/cloud_test.rb +19 -3
- data/test/lib/poolparty/monitor_test.rb +28 -1
- 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
- metadata +5 -3
data/VERSION.yml
CHANGED
data/bin/cloud-thrift
CHANGED
@@ -22,9 +22,11 @@ Usage: #{$0} #{all_options_string}
|
|
22
22
|
EOS
|
23
23
|
|
24
24
|
short_desc "Start the cloud thrift interface"
|
25
|
-
opt :port, "Start
|
25
|
+
opt :port, "Start on port", :type => :integer, :default => 11223
|
26
26
|
opt :dir, "Pid directory", :type => :string, :default => "/tmp"
|
27
27
|
opt :daemon, "Daemonize", :type => :bool, :default => true
|
28
|
+
# Query params
|
29
|
+
opt :host, "Query on host", :type => :string, :default => "localhost"
|
28
30
|
|
29
31
|
run do |command|
|
30
32
|
|
@@ -33,12 +35,12 @@ EOS
|
|
33
35
|
cmd = ARGV.shift
|
34
36
|
cmd = ARGV.shift if cmd == "thrift"
|
35
37
|
|
36
|
-
if %w(run start restart stop).include?(cmd)
|
38
|
+
if %w(run start restart stop query).include?(cmd)
|
37
39
|
args = [cmd]
|
38
40
|
args << ["--", command.argv] unless command.argv.empty?
|
39
41
|
args.flatten!
|
40
42
|
else
|
41
|
-
puts "You must pass one of the following: #{%w(run start restart stop).join(", ")}"
|
43
|
+
puts "You must pass one of the following: #{%w(run start restart stop query).join(", ")}"
|
42
44
|
args = ["--help"]
|
43
45
|
end
|
44
46
|
|
@@ -55,22 +57,34 @@ EOS
|
|
55
57
|
:monitor => true
|
56
58
|
}.merge(command.opts)
|
57
59
|
|
58
|
-
|
59
|
-
|
60
|
-
processor = CloudThrift::CommandInterface::Processor.new(handler)
|
61
|
-
transport = Thrift::ServerSocket.new( options[:port] )
|
62
|
-
transportFactory = Thrift::BufferedTransportFactory.new()
|
63
|
-
server = Thrift::SimpleServer.new(processor, transport, transportFactory)
|
60
|
+
if cmd == "query"
|
61
|
+
require "command_query_handler"
|
64
62
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
63
|
+
@loaded_clouds.each do |cld|
|
64
|
+
puts CommandQueryHandler.run_query(cld, ARGV.shift, ARGV, options)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
block = Proc.new do
|
68
|
+
handler = CommandInterfaceHandler.new
|
69
|
+
processor = CloudThrift::CommandInterface::Processor.new(handler)
|
70
|
+
transport = Thrift::ServerSocket.new( options[:port] )
|
71
|
+
transportFactory = Thrift::BufferedTransportFactory.new()
|
72
|
+
server = Thrift::SimpleServer.new(processor, transport, transportFactory)
|
73
|
+
|
74
|
+
puts "Starting the cloud server..."
|
75
|
+
begin
|
76
|
+
server.serve()
|
77
|
+
rescue
|
78
|
+
exit 10
|
79
|
+
end
|
80
|
+
puts "done."
|
81
|
+
end
|
82
|
+
|
83
|
+
if command[:daemon]
|
84
|
+
Daemons.run_proc("cloud-thrift", options, &block)
|
85
|
+
else
|
86
|
+
block.call
|
87
|
+
end
|
74
88
|
end
|
75
89
|
|
76
90
|
end
|
data/config/jeweler.rb
CHANGED
@@ -15,7 +15,7 @@ end
|
|
15
15
|
s.description = "PoolParty: The easy, open-source, cross-cloud management solution"
|
16
16
|
s.summary = <<-EOM
|
17
17
|
Self-healing, auto-scaling system administration, provisioning
|
18
|
-
and maintaining tool that makes cloud computing
|
18
|
+
and maintaining tool that makes cloud computing easier.
|
19
19
|
EOM
|
20
20
|
|
21
21
|
s.homepage = "http://poolpartyrb.com"
|
@@ -25,8 +25,9 @@ end
|
|
25
25
|
s.test_files = Dir["test/**/test_*.rb"]
|
26
26
|
|
27
27
|
s.files = (%w(Rakefile README.rdoc License.txt VERSION.yml) + Dir["{config,examples,lib,test,tasks,script,generators,bin,vendor}/**/*"])
|
28
|
+
s.files += ["vendor/erlang/hermes/ebin/*.tar.gz"]
|
28
29
|
|
29
|
-
s.files.exclude 'vendor/erlang
|
30
|
+
s.files.exclude 'vendor/erlang/hermes'
|
30
31
|
s.files.exclude 'examples/thrift/**/*.beam'
|
31
32
|
# s.files.exclude "**/*/erl_crash.dump"
|
32
33
|
|
@@ -15,6 +15,7 @@ require "poolparty_types"
|
|
15
15
|
port = ARGV.pop || 11223
|
16
16
|
|
17
17
|
transport = Thrift::BufferedTransport.new(Thrift::Socket.new('localhost', port))
|
18
|
+
# transport = Thrift::BufferedTransport.new(Thrift::Socket.new('192.168.2.31', port))
|
18
19
|
# transport = Thrift::BufferedTransport.new(Thrift::Socket.new('vm', port))
|
19
20
|
protocol = Thrift::BinaryProtocol.new(transport)
|
20
21
|
|
@@ -22,7 +23,8 @@ client = CloudThrift::CommandInterface::Client.new(protocol)
|
|
22
23
|
transport.open()
|
23
24
|
|
24
25
|
cld = CloudThrift::CloudQuery.new
|
25
|
-
cld.name = '
|
26
|
+
cld.name = 'pp2'
|
27
|
+
# cld.name = 'monitored_app'
|
26
28
|
# cld.name = 'vmware'
|
27
29
|
|
28
30
|
resp = client.run_command(cld, "name", [])
|
@@ -68,10 +68,15 @@ module CloudProviders
|
|
68
68
|
raise StandardError.new("You must pass in a cloud to configure an instance") unless cloud
|
69
69
|
cloud.compile(self)
|
70
70
|
|
71
|
-
scp(:source => keypair.full_filepath,
|
72
|
-
|
71
|
+
# scp(:source => keypair.full_filepath,
|
72
|
+
# :destination => "/etc/poolparty/keys/#{keypair.basename}")
|
73
73
|
|
74
74
|
FileUtils.mkdir_p cloud.tmp_path/"etc"/"poolparty" unless File.directory?(cloud.tmp_path/"etc"/"poolparty")
|
75
|
+
FileUtils.mkdir_p cloud.tmp_path/"etc"/"poolparty"/"keys" unless File.directory?(cloud.tmp_path/"etc"/"poolparty"/"keys")
|
76
|
+
|
77
|
+
FileUtils.cp keypair.full_filepath, cloud.tmp_path/"etc"/"poolparty"/"keys"/keypair.basename
|
78
|
+
File.open(cloud.tmp_path/"etc"/"poolparty"/"cloud_name", "w") {|f| f << cloud.name }
|
79
|
+
|
75
80
|
pack_clouds_dot_rb_and_expected_directories
|
76
81
|
|
77
82
|
dputs("Rsyncing #{cloud.tmp_path/"*"}")
|
@@ -19,12 +19,15 @@ using :provider_name
|
|
19
19
|
EOM
|
20
20
|
end
|
21
21
|
|
22
|
+
require "#{File.dirname(__FILE__)}/ec2_helpers"
|
22
23
|
require "#{File.dirname(__FILE__)}/ec2_response"
|
23
24
|
require "#{File.dirname(__FILE__)}/ec2_instance"
|
24
25
|
|
25
26
|
module CloudProviders
|
26
27
|
class Ec2 < CloudProvider
|
27
28
|
|
29
|
+
include CloudProviders::Ec2Helpers
|
30
|
+
|
28
31
|
# Set the aws keys from the environment, or load from /etc/poolparty/env.yml if the environment variable is not set
|
29
32
|
def self.default_access_key
|
30
33
|
ENV['EC2_ACCESS_KEY'] || load_keys_from_file[:access_key]
|
@@ -63,7 +66,7 @@ module CloudProviders
|
|
63
66
|
return @aws_yml if @aws_yml && caching==true
|
64
67
|
return {} unless File.exists?(filename)
|
65
68
|
ddputs("Reading keys from file: #{filename}")
|
66
|
-
@aws_yml = YAML::load( open(filename).read )
|
69
|
+
@aws_yml = YAML::load( open(filename).read ) || {}
|
67
70
|
end
|
68
71
|
|
69
72
|
default_options({
|
@@ -88,13 +91,13 @@ module CloudProviders
|
|
88
91
|
:ramdisk_id => nil,
|
89
92
|
:availability_zone => nil,
|
90
93
|
:block_device_mappings => nil,
|
91
|
-
:elastic_ips =>
|
92
|
-
:
|
94
|
+
:elastic_ips => [], # An array of the elastic ips
|
95
|
+
:ebs_volumes => [] # The volume id of an ebs volume # TODO: ensure this is consistent with :block_device_mappings
|
93
96
|
})
|
94
97
|
|
95
98
|
|
96
99
|
def ec2(o={})
|
97
|
-
@ec2 ||= Rightscale::Ec2.new(access_key, secret_access_key, o.merge(:logger => PoolParty::PoolPartyLog, :
|
100
|
+
@ec2 ||= Rightscale::Ec2.new(access_key, secret_access_key, o.merge(:logger => PoolParty::PoolPartyLog, :endpoint_url => ec2_url))
|
98
101
|
end
|
99
102
|
|
100
103
|
# Start a new instance with the given options
|
@@ -114,9 +117,12 @@ module CloudProviders
|
|
114
117
|
availability_zone,
|
115
118
|
block_device_mappings
|
116
119
|
)
|
117
|
-
instances = response_array
|
120
|
+
instances = response_array.collect do |aws_response_hash|
|
118
121
|
Ec2Instance.new( Ec2Response.pp_format(aws_response_hash).merge(o) )
|
119
122
|
end
|
123
|
+
|
124
|
+
after_run_instance(instances)
|
125
|
+
|
120
126
|
#FIXME: This needs to deal with the case when an array is returned if max_instances > 1
|
121
127
|
instances.first
|
122
128
|
end
|
@@ -159,7 +165,15 @@ module CloudProviders
|
|
159
165
|
end
|
160
166
|
|
161
167
|
def after_compile(cld)
|
162
|
-
save_aws_env_to_yml(cld.tmp_path/"etc"/"poolparty"/"env.yml")
|
168
|
+
save_aws_env_to_yml(cld.tmp_path/"etc"/"poolparty"/"env.yml") rescue nil
|
169
|
+
end
|
170
|
+
|
171
|
+
# Run after all the instances are run
|
172
|
+
def after_run_instance(instances_list)
|
173
|
+
instances_list.each do |inst|
|
174
|
+
associate_address(inst.instance_id) if next_unused_elastic_ip
|
175
|
+
attach_volume(inst.instance_id) if next_unused_volume
|
176
|
+
end
|
163
177
|
end
|
164
178
|
|
165
179
|
# Read yaml file and use it to set environment variables and local variables.
|
@@ -171,7 +185,8 @@ module CloudProviders
|
|
171
185
|
|
172
186
|
# Save aws keys and env variables to a yaml file
|
173
187
|
def save_aws_env_to_yml(filename='/etc/poolparty/env.yml')
|
174
|
-
|
188
|
+
hsh = aws_hash(default_options, "/etc/poolparty/ec2")
|
189
|
+
File.open(filename, 'w') {|f| f<<YAML::dump(hsh) }
|
175
190
|
end
|
176
191
|
|
177
192
|
# Return a hash of the aws keys and environment variables
|
@@ -1,12 +1,57 @@
|
|
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
|
+
ec2.associate_address(instance_id, new_ip)
|
49
|
+
loop do
|
50
|
+
if describe_instance(:instance_id => instance_id).public_ip == new_ip
|
51
|
+
return new_ip
|
52
|
+
end
|
53
|
+
sleep 1
|
54
|
+
end
|
10
55
|
end
|
11
56
|
|
12
57
|
# Get the next usable elastic ip
|
@@ -17,13 +62,23 @@ module CloudProviders
|
|
17
62
|
# intersection of the unused ips and those, find the first one available
|
18
63
|
# and return that.
|
19
64
|
def next_unused_elastic_ip
|
20
|
-
|
21
|
-
if elastic_ips.empty?
|
65
|
+
if unusued_elastic_ips.empty?
|
22
66
|
nil
|
23
67
|
else
|
68
|
+
unusued_elastic_ips.first
|
24
69
|
end
|
25
70
|
end
|
26
|
-
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def all_elastic_ips
|
75
|
+
elastic_ips.empty? ? [] : ec2.describe_addresses & elastic_ips
|
76
|
+
end
|
77
|
+
|
78
|
+
def unusued_elastic_ips
|
79
|
+
all_elastic_ips.select {|i| i[:instance_id] == nil }
|
80
|
+
end
|
81
|
+
|
27
82
|
# Help create a keypair for the cloud
|
28
83
|
# This is a helper to create the keypair and add them to the cloud for you
|
29
84
|
# def create_keypair
|
@@ -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
|
data/lib/poolparty/base.rb
CHANGED
@@ -157,12 +157,12 @@ module PoolParty
|
|
157
157
|
deps_array.each do |dep_name|
|
158
158
|
dep = get_resource(dep_type, dep_name)
|
159
159
|
raise PoolPartyError.create("ResourceNotFound", "A resource required for #{resource.has_method_name}(#{resource.name}) was not found: #{dep_type}(#{dep_name}). Please make sure you've specified this in your configuration.") unless dep
|
160
|
-
result.add_edge!(dep, resource, dep.name) unless result.edge?(dep, resource)
|
160
|
+
result.add_edge!(dep, resource, dep.name) unless result.edge?(dep, resource) or result.edge?(resource, dep)
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
164
|
if on
|
165
|
-
result.add_edge!(resource, on, resource.name) unless result.edge?(resource, on)
|
165
|
+
result.add_edge!(resource, on, resource.name) unless result.edge?(resource, on) or result.edge?(on, resource)
|
166
166
|
else
|
167
167
|
result.add_vertex!(resource)
|
168
168
|
end
|
data/lib/poolparty/cloud.rb
CHANGED
@@ -196,12 +196,14 @@ module PoolParty
|
|
196
196
|
# the defined (or the default dependency_resolver, chef)
|
197
197
|
def compile(caller=nil)
|
198
198
|
callback :before_compile
|
199
|
+
cloud_provider.before_compile(self)
|
199
200
|
FileUtils.mkdir_p tmp_path unless File.directory?(tmp_path)
|
200
201
|
ddputs <<-EOE
|
201
202
|
Compiling cloud #{self.name} to #{tmp_path/"etc"/"#{dependency_resolver_name}"}
|
202
203
|
number of resources: #{ordered_resources.size}
|
203
204
|
EOE
|
204
205
|
out = dependency_resolver.compile_to(ordered_resources, tmp_path/"etc"/"#{dependency_resolver_name}", caller)
|
206
|
+
cloud_provider.after_compile(self)
|
205
207
|
callback :after_compile
|
206
208
|
out
|
207
209
|
end
|
@@ -230,14 +232,14 @@ Compiling cloud #{self.name} to #{tmp_path/"etc"/"#{dependency_resolver_name}"}
|
|
230
232
|
# vote_for(:expand) if v > 0.8
|
231
233
|
# end
|
232
234
|
def monitor(monitor_symbol, &block)
|
233
|
-
monitors[monitor_symbol] ||= PoolParty::Monitor.new(monitor_symbol, &block)
|
235
|
+
monitors[monitor_symbol.to_sym] ||= PoolParty::Monitor.new(monitor_symbol, &block)
|
234
236
|
end
|
235
237
|
|
236
238
|
# Run the monitor logic
|
237
239
|
def run_monitor(monitor_name, value)
|
238
240
|
mon = monitors[monitor_name.to_sym]
|
239
241
|
if mon
|
240
|
-
mon.run(value
|
242
|
+
mon.run(value)
|
241
243
|
else
|
242
244
|
"unhandled monitor"
|
243
245
|
end
|
@@ -248,6 +250,14 @@ Compiling cloud #{self.name} to #{tmp_path/"etc"/"#{dependency_resolver_name}"}
|
|
248
250
|
@monitors ||= {}
|
249
251
|
end
|
250
252
|
|
253
|
+
def monitor_format(mon_name, meth=nil, &block)
|
254
|
+
if monitors.has_key?(mon_name.to_sym)
|
255
|
+
monitors[mon_name.to_sym].format(meth, &block)
|
256
|
+
else
|
257
|
+
raise PoolPartyError.create("MonitorsFormattingError", "You created a monitor format for an unknown monitor. Please check and try again!")
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
251
261
|
##### Internal methods #####
|
252
262
|
# Methods that only the cloud itself will use
|
253
263
|
# and thus are private
|
data/lib/poolparty/monitor.rb
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
module PoolParty
|
16
16
|
class Monitor
|
17
17
|
|
18
|
-
attr_reader :name, :monitor_block
|
18
|
+
attr_reader :name, :monitor_block, :value_format
|
19
19
|
|
20
20
|
def initialize(monitor_name, &block)
|
21
21
|
msg =<<-EOE
|
@@ -27,7 +27,7 @@ You must pass a block with your monitor
|
|
27
27
|
end
|
28
28
|
EOE
|
29
29
|
raise PoolPartyError.create("MonitorDefinitionError", msg) unless block
|
30
|
-
@name = monitor_name
|
30
|
+
@name = monitor_name.to_sym
|
31
31
|
@monitor_block = block
|
32
32
|
end
|
33
33
|
|
@@ -37,11 +37,33 @@ You must pass a block with your monitor
|
|
37
37
|
# retrieved and return the methods available.
|
38
38
|
def run(val)
|
39
39
|
@methods = nil
|
40
|
-
instance_exec val, &monitor_block
|
40
|
+
instance_exec format_value(val), &monitor_block
|
41
41
|
methods
|
42
42
|
end
|
43
43
|
|
44
|
+
# Format the monitor values
|
45
|
+
# Set the monitor format here.
|
46
|
+
# The default will be to turn the value into a float
|
47
|
+
# but to allow other formats, call the value here, for instance:
|
48
|
+
# mon.format :to_s
|
49
|
+
# Blocks are also permitted
|
50
|
+
def format(meth=nil, &block)
|
51
|
+
@value_format ||= (meth ? meth : block)
|
52
|
+
end
|
53
|
+
|
44
54
|
private
|
55
|
+
|
56
|
+
# Format the value of the monitor
|
57
|
+
def format_value(value)
|
58
|
+
case value_format
|
59
|
+
when Proc
|
60
|
+
value_format.call(value)
|
61
|
+
when nil
|
62
|
+
value.to_f
|
63
|
+
else
|
64
|
+
value.send value_format
|
65
|
+
end
|
66
|
+
end
|
45
67
|
|
46
68
|
# We don't want the methods actually executing since we are executing the methods
|
47
69
|
# in a cloud, we just want to store the output values of the
|
@@ -11,22 +11,28 @@ module PoolParty
|
|
11
11
|
)
|
12
12
|
|
13
13
|
def after_loaded
|
14
|
+
run_dependencies
|
15
|
+
build_rsync_directory
|
14
16
|
add_unpack
|
17
|
+
run_dependencies
|
15
18
|
run_if_needed
|
16
19
|
end
|
17
20
|
|
18
21
|
def after_compile
|
19
|
-
run_dependencies
|
20
|
-
build_rsync_directory
|
21
22
|
end
|
22
23
|
|
23
24
|
def run_dependencies
|
24
|
-
case cloud.platform
|
25
|
+
install_packages = case cloud.platform
|
25
26
|
when false
|
26
27
|
else
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
["erlang-nox", "erlang-dev"]
|
29
|
+
end
|
30
|
+
has_package "rrdtool"
|
31
|
+
has_exec "install_erlang" do
|
32
|
+
command "echo ''"
|
33
|
+
install_packages.each do |pkg|
|
34
|
+
has_package pkg
|
35
|
+
end
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
@@ -43,18 +49,25 @@ module PoolParty
|
|
43
49
|
etc_poolparty = cloud.tmp_path + "/etc/poolparty"
|
44
50
|
FileUtils.mkdir_p(etc_poolparty)
|
45
51
|
node_names = cloud.nodes.collect{|n| n.internal_ip || n.dns_name}.compact.collect{|n| "hermes@#{n}"}
|
46
|
-
contents = node_names.collect{|n| %Q{
|
52
|
+
contents = node_names.collect{|n| %Q{'#{n}'.}}.join("\n")
|
47
53
|
File.open(etc_poolparty + "/seeds.conf", "w") {|f| f.puts contents}
|
48
54
|
end
|
49
55
|
|
50
56
|
def add_unpack
|
51
|
-
has_exec "
|
52
|
-
:
|
57
|
+
has_exec "install_hermes",
|
58
|
+
:command => "cd /tmp/hermes && escript target_system install hermes-#{hermes_release_version} #{remote_hermes_deployed_dir}",
|
59
|
+
:creates => "#{remote_hermes_deployed_dir}/releases/#{hermes_release_version}",
|
60
|
+
:requires => get_package("erlang-dev")
|
61
|
+
|
62
|
+
has_link :name => "collectd_dir",
|
63
|
+
:to => "/var/lib/collectd/rrd/\#{`hostname -f`.chomp}", :source => "/var/lib/collectd/localhost",
|
64
|
+
:requires => [get_package("collectd")]
|
53
65
|
end
|
54
66
|
|
55
67
|
def run_if_needed
|
56
|
-
has_exec "env GEN_CLUSTER_SEED_CONFIG=/etc/poolparty/seeds.conf #{remote_hermes_deployed_dir}/bin/erl -boot #{remote_hermes_deployed_dir}/releases/#{hermes_release_version}/start -noshell -detached",
|
57
|
-
:not_if => "ps aux | grep -v grep | grep hermes | grep beam"
|
68
|
+
has_exec "env GEN_CLUSTER_SEED_CONFIG=/etc/poolparty/seeds.conf HERMES_RRD_DIRECTORY=/var/lib/collectd/localhost #{remote_hermes_deployed_dir}/bin/erl -boot #{remote_hermes_deployed_dir}/releases/#{hermes_release_version}/start -noshell -detached",
|
69
|
+
:not_if => "ps aux | grep -v grep | grep hermes | grep beam",
|
70
|
+
:requires => [get_exec("install_hermes"), get_link("collectd_dir")]
|
58
71
|
end
|
59
72
|
|
60
73
|
private
|
data/lib/poolparty/pool.rb
CHANGED
@@ -97,7 +97,7 @@ module PoolParty
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def self.clouds_dot_rb_dir(n=nil)
|
100
|
-
File.dirname(self.clouds_dot_rb_file)
|
100
|
+
self.clouds_dot_rb_file ? File.dirname(self.clouds_dot_rb_file) : "./"
|
101
101
|
end
|
102
102
|
|
103
103
|
# Load the default clouds.rb file
|
@@ -151,17 +151,16 @@ module PoolParty
|
|
151
151
|
# + calls the resource define_resource_methods to define the resource methods
|
152
152
|
# + sets up the log
|
153
153
|
def self.before_file_load(filepath)
|
154
|
-
$:.unshift(
|
155
|
-
|
154
|
+
$:.unshift(File.dirname(filepath))
|
155
|
+
$:.unshift("#{File.dirname(filepath)}/lib")
|
156
|
+
$:.unshift("#{File.dirname(filepath)}/plugins")
|
157
|
+
|
158
|
+
Dir["#{File.dirname(filepath)}/lib/*"].each {|lib_path| require lib_path }
|
159
|
+
Dir["#{File.dirname(filepath)}/plugins/*"].each do |plugin_path|
|
156
160
|
if File.directory?(plugin_path)
|
157
161
|
$:.unshift(plugin_path)
|
158
|
-
|
159
|
-
|
160
|
-
require potential if File.exists?(potential)
|
161
|
-
end
|
162
|
-
|
163
|
-
elsif File.file?(plugin_path) && plugin_path.match(/.rb$/)
|
164
|
-
require plugin_path
|
162
|
+
else
|
163
|
+
require plugin_path if File.file?(plugin_path) && plugin_path.match(/.rb$/)
|
165
164
|
end
|
166
165
|
end
|
167
166
|
end
|
data/lib/poolparty/resource.rb
CHANGED
@@ -15,6 +15,7 @@ module PoolParty
|
|
15
15
|
def initialize(opts={}, extra_opts={}, exists=true, &block)
|
16
16
|
@exists ||= exists
|
17
17
|
super(opts, extra_opts, &block)
|
18
|
+
after_loaded_requires_parent
|
18
19
|
valid?
|
19
20
|
end
|
20
21
|
|
@@ -69,6 +70,11 @@ module PoolParty
|
|
69
70
|
other_resources_obj.each do |obj|
|
70
71
|
requires(obj)
|
71
72
|
end
|
73
|
+
else
|
74
|
+
# When is an object
|
75
|
+
# k = other_resources_obj.has_method_name
|
76
|
+
# dependencies[k] ||= []
|
77
|
+
# dependencies[k] << other_resources_obj.name
|
72
78
|
end
|
73
79
|
end
|
74
80
|
|
@@ -114,7 +120,7 @@ module PoolParty
|
|
114
120
|
def after_compile
|
115
121
|
end
|
116
122
|
|
117
|
-
def
|
123
|
+
def after_loaded_requires_parent
|
118
124
|
requires parent if parent && !parent.is_a?(PoolParty::Cloud) && !parent.is_a?(PoolParty::Pool)
|
119
125
|
end
|
120
126
|
|
@@ -162,8 +168,8 @@ module PoolParty
|
|
162
168
|
def self.define_resource_methods
|
163
169
|
defined_resources.each do |res|
|
164
170
|
next if res.method_defined?
|
165
|
-
ddputs "Defining resource: #{res} as #{res.has_method_name}"
|
166
|
-
define_resource(res)
|
171
|
+
ddputs "Defining resource: #{res} as #{res.has_method_name} on #{self}"
|
172
|
+
define_resource(res, is_base_resource_class? ? Base : self)
|
167
173
|
res.method_defined!
|
168
174
|
unless res.defined_resources.empty?
|
169
175
|
res.define_resource_methods
|
@@ -171,10 +177,14 @@ module PoolParty
|
|
171
177
|
end
|
172
178
|
end
|
173
179
|
|
180
|
+
def self.is_base_resource_class?
|
181
|
+
self.to_s == PoolParty::Resource.to_s
|
182
|
+
end
|
183
|
+
|
174
184
|
# Define the resource on the base class so it's available across all
|
175
185
|
# PoolParty classes that use Base
|
176
|
-
def self.define_resource(res)
|
177
|
-
|
186
|
+
def self.define_resource(res, base_klass=Base)
|
187
|
+
base_klass.class_eval <<-EOE
|
178
188
|
def has_#{res.has_method_name}(a={},b={},e=true, &block)
|
179
189
|
obj = #{res}.new(a,b,e,&block)
|
180
190
|
resources << obj
|
@@ -252,14 +262,7 @@ module PoolParty
|
|
252
262
|
"#{obj.to_i}"
|
253
263
|
end
|
254
264
|
when String
|
255
|
-
|
256
|
-
when /^\d{4}$/
|
257
|
-
"#{obj}"
|
258
|
-
when /^\d{3}$/
|
259
|
-
"0#{obj}"
|
260
|
-
else
|
261
|
-
"\"#{obj}\""
|
262
|
-
end
|
265
|
+
"\"#{obj}\""
|
263
266
|
when Proc
|
264
267
|
obj.call # eh
|
265
268
|
when Array
|
@@ -66,8 +66,8 @@ end
|
|
66
66
|
file = arg.first
|
67
67
|
@template = if File.file?(b = File.expand_path(file))
|
68
68
|
b
|
69
|
-
elsif File.file?(
|
70
|
-
|
69
|
+
elsif File.file?(d = File.expand_path(File.join(clouds_dot_rb_dir, file)))
|
70
|
+
d
|
71
71
|
elsif f = search_in_known_locations(file)
|
72
72
|
f
|
73
73
|
else
|
@@ -30,12 +30,13 @@ module PoolParty
|
|
30
30
|
|
31
31
|
default_options(
|
32
32
|
:link_type => :symbolic,
|
33
|
+
:source => nil,
|
33
34
|
:to => nil
|
34
35
|
)
|
35
36
|
|
36
37
|
def print_to_chef
|
37
38
|
<<-EOE
|
38
|
-
link "<%= name %>" do
|
39
|
+
link "<%= source || name %>" do
|
39
40
|
link_type <%= print_variable(link_type) %>
|
40
41
|
action :<%= exists? ? :create : :delete %>
|
41
42
|
to <%= print_variable(to) %>
|
@@ -4,7 +4,31 @@ class CommandInterfaceHandler
|
|
4
4
|
cr = CloudThrift::CloudResponse.new
|
5
5
|
cr.name = cld.name
|
6
6
|
cr.command = command
|
7
|
-
|
7
|
+
|
8
|
+
cr.response = format_response(get_response(cld, command, args))
|
9
|
+
|
10
|
+
return cr
|
11
|
+
end
|
12
|
+
|
13
|
+
def cast_command(cld, command, args)
|
14
|
+
|
15
|
+
cr = CloudThrift::CloudResponse.new
|
16
|
+
cr.name = cld.name
|
17
|
+
cr.command = command
|
18
|
+
cr.response = format_response("Running command: #{command}(#{args})")
|
19
|
+
|
20
|
+
fork do
|
21
|
+
get_response(cld, command, args)
|
22
|
+
end
|
23
|
+
|
24
|
+
return cr
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def get_response(cld, command, args)
|
31
|
+
begin
|
8
32
|
the_cloud = clouds[cld.name]
|
9
33
|
if the_cloud
|
10
34
|
if command.include?(".")
|
@@ -25,15 +49,9 @@ class CommandInterfaceHandler
|
|
25
49
|
end
|
26
50
|
rescue Exception => e
|
27
51
|
cr.response = "Error: #{e.inspect}"
|
28
|
-
end
|
29
|
-
|
30
|
-
cr.response = format_response(resp)
|
31
|
-
|
32
|
-
return cr
|
52
|
+
end
|
33
53
|
end
|
34
54
|
|
35
|
-
private
|
36
|
-
|
37
55
|
def format_response(resp)
|
38
56
|
case resp
|
39
57
|
when Array
|
@@ -44,4 +62,5 @@ class CommandInterfaceHandler
|
|
44
62
|
[resp]
|
45
63
|
end.map {|ele| ele.to_s }
|
46
64
|
end
|
65
|
+
|
47
66
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CommandQueryHandler
|
2
|
+
def self.run_query(on_cloud, command, args, opts={})
|
3
|
+
port = opts[:port] || 11223
|
4
|
+
host = opts[:host] || "localhost"
|
5
|
+
|
6
|
+
transport = Thrift::BufferedTransport.new(Thrift::Socket.new(host, port))
|
7
|
+
protocol = Thrift::BinaryProtocol.new(transport)
|
8
|
+
|
9
|
+
client = CloudThrift::CommandInterface::Client.new(protocol)
|
10
|
+
transport.open()
|
11
|
+
|
12
|
+
cld = CloudThrift::CloudQuery.new
|
13
|
+
cld.name = on_cloud.name
|
14
|
+
|
15
|
+
ddputs("Running command: #{command} on #{cld.name} at #{host}:#{port}")
|
16
|
+
resp = client.run_command(cld, command, args)
|
17
|
+
resp.response
|
18
|
+
end
|
19
|
+
end
|
data/lib/proto/poolparty.thrift
CHANGED
data/tasks/poolparty.rake
CHANGED
@@ -22,6 +22,30 @@ task :thrift do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
namespace(:hermes) do
|
26
|
+
|
27
|
+
desc "Pack for distribution"
|
28
|
+
task :target_system do
|
29
|
+
erl_dir = File.dirname(__FILE__) + "/../vendor/erlang"
|
30
|
+
hermes_dir = File.join(erl_dir, "hermes")
|
31
|
+
|
32
|
+
puts `cd #{hermes_dir} && make target_system`
|
33
|
+
end
|
34
|
+
desc "Update hermes code"
|
35
|
+
task :update do
|
36
|
+
erl_dir = File.dirname(__FILE__) + "/../vendor/erlang"
|
37
|
+
hermes_dir = File.join(erl_dir, "hermes")
|
38
|
+
|
39
|
+
if File.directory?(hermes_dir)
|
40
|
+
`cd #{hermes_dir} && git pull origin master`
|
41
|
+
else
|
42
|
+
FileUtils.mkdir_p erl_dir
|
43
|
+
r = "git clone git://github.com/auser/hermes.git #{hermes_dir}"
|
44
|
+
Kernel.system r
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
25
49
|
namespace(:pp) do
|
26
50
|
task :build_gem => ["poolparty:vendor:setup", "poolparty:vendor:update", :gemspec, :build]
|
27
51
|
|
@@ -26,10 +26,10 @@ class RemoteDirectoryResourceTest < Test::Unit::TestCase
|
|
26
26
|
remote_directory "/tmp/remote_something" do
|
27
27
|
source "something"
|
28
28
|
files_backup 10
|
29
|
-
files_mode 0644
|
29
|
+
files_mode "0644"
|
30
30
|
action :create
|
31
31
|
recursive false
|
32
|
-
mode 0755
|
32
|
+
mode "0755"
|
33
33
|
owner "nobody"
|
34
34
|
group "nobody"
|
35
35
|
files_owner "root"
|
@@ -54,7 +54,7 @@ class ChefTest < Test::Unit::TestCase
|
|
54
54
|
|
55
55
|
def test_compile_to_the_recipes
|
56
56
|
@base.compile_to(@resources[:files], test_dir)
|
57
|
-
assert_equal "template \"/etc/motd\" do\n source \"/etc/motd.erb\"\n action :create\n backup 5\n mode 0644\n owner \"root\"\nend\n", open(@cookboox_directory/"recipes"/"default.rb").read
|
57
|
+
assert_equal "template \"/etc/motd\" do\n source \"/etc/motd.erb\"\n action :create\n backup 5\n mode \"0644\"\n owner \"root\"\nend\n", open(@cookboox_directory/"recipes"/"default.rb").read
|
58
58
|
end
|
59
59
|
|
60
60
|
def test_compile_the_recipes
|
@@ -78,14 +78,14 @@ template "/etc/motd" do
|
|
78
78
|
source "/etc/motd.erb"
|
79
79
|
action :create
|
80
80
|
backup 5
|
81
|
-
mode 0644
|
81
|
+
mode "0644"
|
82
82
|
owner "root"
|
83
83
|
end
|
84
84
|
|
85
85
|
directory "/etc/poolparty" do
|
86
86
|
action :create
|
87
87
|
recursive true
|
88
|
-
mode 0644
|
88
|
+
mode "0644"
|
89
89
|
owner "root"
|
90
90
|
group "root"
|
91
91
|
end
|
@@ -134,7 +134,6 @@ class CloudTest < Test::Unit::TestCase
|
|
134
134
|
assert_equal 22, clouds["noneity"].ssh_port
|
135
135
|
end
|
136
136
|
|
137
|
-
|
138
137
|
def test_children_getting_parent_options
|
139
138
|
clear!
|
140
139
|
pool "outside" do
|
@@ -159,13 +158,24 @@ class CloudTest < Test::Unit::TestCase
|
|
159
158
|
configure if v < 0.2
|
160
159
|
vote_for(:expand) if v > 1.1
|
161
160
|
end
|
161
|
+
|
162
|
+
monitor :load do |a|
|
163
|
+
# [0.42 0.43 0.37]
|
164
|
+
vote_for(:expand) if a[0] > 0.8
|
165
|
+
end
|
166
|
+
|
167
|
+
monitor_format :load do |d|
|
168
|
+
d.split(",").map {|ele| ele.to_f }
|
169
|
+
end
|
170
|
+
|
162
171
|
end
|
163
172
|
end
|
164
173
|
|
165
|
-
assert_equal
|
166
|
-
assert_equal [:cpu], clouds["monitor_app"].monitors.map {|m,v| v.name }
|
174
|
+
assert_equal 2, clouds["monitor_app"].monitors.size
|
175
|
+
assert_equal [:cpu, :load], clouds["monitor_app"].monitors.map {|m,v| v.name }
|
167
176
|
assert_equal({:configure => []}, clouds["monitor_app"].run_monitor("cpu", "0.1"))
|
168
177
|
assert_equal({:vote_for => [:expand]}, clouds["monitor_app"].run_monitor("cpu", "1.4"))
|
178
|
+
assert_equal({:vote_for => [:expand]}, clouds["monitor_app"].run_monitor("load", "0.98, 0.23, 0.1"))
|
169
179
|
end
|
170
180
|
|
171
181
|
def test_add_monitoring_stack_if_needed
|
@@ -183,5 +193,11 @@ class CloudTest < Test::Unit::TestCase
|
|
183
193
|
assert_equal 1, clouds["app_cloud"].monitors.size
|
184
194
|
|
185
195
|
clouds["app_cloud"].compile
|
196
|
+
|
197
|
+
compile_dir = clouds["app_cloud"].tmp_path/"etc"/"chef"/"cookbooks"/"poolparty"
|
198
|
+
recipe_file = compile_dir/"recipes"/"default.rb"
|
199
|
+
recipe_contents = open(recipe_file).read
|
200
|
+
|
201
|
+
assert_match /install hermes/, recipe_contents
|
186
202
|
end
|
187
203
|
end
|
@@ -3,7 +3,7 @@ require "#{File.dirname(__FILE__)}/../../test_helper"
|
|
3
3
|
class MonitorTest < Test::Unit::TestCase
|
4
4
|
|
5
5
|
def setup
|
6
|
-
@mon = PoolParty::Monitor.new(
|
6
|
+
@mon = PoolParty::Monitor.new("cpu-idle") do |c|
|
7
7
|
vote_for(:expand) if c > 0.8
|
8
8
|
configure if c < 0.1
|
9
9
|
end
|
@@ -27,4 +27,31 @@ class MonitorTest < Test::Unit::TestCase
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def test_formatting_input
|
31
|
+
mon = PoolParty::Monitor.new("memory-used") {|c| long if c.length > 2}
|
32
|
+
mon.format(:to_s)
|
33
|
+
assert_equal({:long => []}, mon.run("hellllllllooooo world"))
|
34
|
+
|
35
|
+
mon = PoolParty::Monitor.new("memory-used") do |c|
|
36
|
+
long if c.length > 2
|
37
|
+
short if c.length < 2
|
38
|
+
end
|
39
|
+
mon.format(:to_a)
|
40
|
+
assert_equal({:long => []}, mon.run(%w(1 2 3 4)))
|
41
|
+
assert_equal({:short => []}, mon.run(%w(1)))
|
42
|
+
|
43
|
+
mon = PoolParty::Monitor.new("memory-used") do |saying, to|
|
44
|
+
if saying == "hello"
|
45
|
+
hello
|
46
|
+
else
|
47
|
+
goodbye
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
mon.format {|d|return *d.split(",")}
|
52
|
+
|
53
|
+
assert_equal({:hello => []}, mon.run("hello, world"))
|
54
|
+
assert_equal({:short => []}, mon.run("good day"))
|
55
|
+
end
|
56
|
+
|
30
57
|
end
|
@@ -73,8 +73,6 @@ class ResourceTest < Test::Unit::TestCase
|
|
73
73
|
assert_equal @inst.print_variable(:a), ":a"
|
74
74
|
assert_equal @inst.print_variable({:a => "a"}), ":a => \"a\""
|
75
75
|
assert_equal @inst.print_variable(644), "644"
|
76
|
-
assert_equal @inst.print_variable("0755"), "0755"
|
77
|
-
assert_equal @inst.print_variable("755"), "0755"
|
78
76
|
assert_equal @inst.print_variable(@inst), @inst.to_s
|
79
77
|
assert_equal @inst.print_variable(nil), nil
|
80
78
|
end
|
@@ -147,4 +145,18 @@ class ResourceTest < Test::Unit::TestCase
|
|
147
145
|
end
|
148
146
|
end
|
149
147
|
|
148
|
+
def test_a_subclassed_resource_has_the_method_of_the_subclassed_resource
|
149
|
+
pool "oblong" do
|
150
|
+
cloud "piece" do
|
151
|
+
fake_plugin do
|
152
|
+
has_subclassed "box"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
assert_equal PoolParty::Resources::FakePlugin, clouds["piece"].resources.first.class
|
158
|
+
assert_equal PoolParty::Resources::FakeSubclassedPlugin, clouds["piece"].resources.first.resources[0].class
|
159
|
+
assert_equal 1, clouds["piece"].resources.first.resources[0].resources.size
|
160
|
+
end
|
161
|
+
|
150
162
|
end
|
@@ -12,7 +12,7 @@ class DirectoryResourceTest < Test::Unit::TestCase
|
|
12
12
|
end
|
13
13
|
|
14
14
|
should "have the directory method denoted by has_method_name" do
|
15
|
-
str = "directory \"/etc/poolparty\" do\n action :create\n recursive true\n mode 0644\n owner \"root\"\n group \"root\"\nend\n"
|
15
|
+
str = "directory \"/etc/poolparty\" do\n action :create\n recursive true\n mode \"0644\"\n owner \"root\"\n group \"root\"\nend\n"
|
16
16
|
assert_equal str, @base.compile(@res)
|
17
17
|
end
|
18
18
|
|
@@ -13,7 +13,7 @@ class DirectoryResourceTest < Test::Unit::TestCase
|
|
13
13
|
end
|
14
14
|
|
15
15
|
should "have the template method denoted by has_method_name" do
|
16
|
-
str = "template \"/etc/poolparty/lyrics\" do\n source \"/etc/poolparty/lyrics.erb\"\n action :create\n backup 5\n mode 0644\n owner \"root\"\nend\n"
|
16
|
+
str = "template \"/etc/poolparty/lyrics\" do\n source \"/etc/poolparty/lyrics.erb\"\n action :create\n backup 5\n mode \"0644\"\n owner \"root\"\nend\n"
|
17
17
|
|
18
18
|
assert_equal str, @base.compile(@res)
|
19
19
|
assert_equal "I'm just a file, a lonely little file in the world", open(@cookboox_directory/"templates"/"default"/"etc"/"poolparty"/"lyrics.erb").read
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../../test_helper"
|
2
|
+
$:.unshift("#{File.dirname(__FILE__)}/../../../lib/proto")
|
3
|
+
require "command_query_handler"
|
4
|
+
|
5
|
+
class CommandQueryHandlerTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_has_run_query_command
|
8
|
+
assert CommandQueryHandler.respond_to?(:run_query)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: poolparty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ari Lerner
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2009-09-
|
14
|
+
date: 2009-09-04 00:00:00 -07:00
|
15
15
|
default_executable:
|
16
16
|
dependencies: []
|
17
17
|
|
@@ -208,6 +208,7 @@ files:
|
|
208
208
|
- lib/poolparty/resources/user.rb
|
209
209
|
- lib/poolparty/resources/variable.rb
|
210
210
|
- lib/proto/command_interface_handler.rb
|
211
|
+
- lib/proto/command_query_handler.rb
|
211
212
|
- lib/proto/gen-erl/commandInterface_thrift.erl
|
212
213
|
- lib/proto/gen-erl/commandInterface_thrift.hrl
|
213
214
|
- lib/proto/gen-erl/poolparty_constants.hrl
|
@@ -335,6 +336,7 @@ files:
|
|
335
336
|
- test/lib/poolparty/resources/service_test.rb
|
336
337
|
- test/lib/poolparty/resources/user_test.rb
|
337
338
|
- test/lib/poolparty/resources/variable_test.rb
|
339
|
+
- test/lib/proto/command_query_handler_test.rb
|
338
340
|
- test/lib/provision/base_test.rb
|
339
341
|
- test/lib/provision/bootstrapper_test.rb
|
340
342
|
- test/test_helper.rb
|
@@ -1142,7 +1144,7 @@ rubyforge_project:
|
|
1142
1144
|
rubygems_version: 1.3.4
|
1143
1145
|
signing_key:
|
1144
1146
|
specification_version: 3
|
1145
|
-
summary: Self-healing, auto-scaling system administration, provisioning and maintaining tool that makes cloud computing
|
1147
|
+
summary: Self-healing, auto-scaling system administration, provisioning and maintaining tool that makes cloud computing easier.
|
1146
1148
|
test_files:
|
1147
1149
|
- test/test_helper.rb
|
1148
1150
|
- test/test_methods.rb
|