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
@@ -0,0 +1,101 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
=end
|
3
|
+
|
4
|
+
module PoolParty
|
5
|
+
module Resources
|
6
|
+
|
7
|
+
class Hermes < Resource
|
8
|
+
|
9
|
+
default_options(
|
10
|
+
:name => nil
|
11
|
+
)
|
12
|
+
|
13
|
+
def after_loaded
|
14
|
+
run_dependencies
|
15
|
+
build_rsync_directory
|
16
|
+
add_unpack
|
17
|
+
run_dependencies
|
18
|
+
run_if_needed
|
19
|
+
end
|
20
|
+
|
21
|
+
def after_compile
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_dependencies
|
25
|
+
install_packages = case cloud.platform
|
26
|
+
when false
|
27
|
+
else
|
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
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_rsync_directory
|
40
|
+
hermes_dir = cloud.tmp_path + "/tmp/hermes"
|
41
|
+
FileUtils.mkdir_p(hermes_dir)
|
42
|
+
FileUtils.cp(hermes_release_tar_gz, hermes_dir)
|
43
|
+
FileUtils.cp(target_system_file, hermes_dir)
|
44
|
+
build_nodes_config
|
45
|
+
end
|
46
|
+
|
47
|
+
# write out a conf file listing all of the seed nodes based on the nodes in the cluster
|
48
|
+
def build_nodes_config
|
49
|
+
etc_poolparty = cloud.tmp_path + "/etc/poolparty"
|
50
|
+
FileUtils.mkdir_p(etc_poolparty)
|
51
|
+
node_names = cloud.nodes.collect{|n| n.internal_ip || n.dns_name}.compact.collect{|n| "hermes@#{n}"}
|
52
|
+
contents = node_names.collect{|n| %Q{'#{n}'.}}.join("\n")
|
53
|
+
File.open(etc_poolparty + "/seeds.conf", "w") {|f| f.puts contents}
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_unpack
|
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
|
+
end
|
65
|
+
|
66
|
+
def run_if_needed
|
67
|
+
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",
|
68
|
+
:not_if => "ps aux | grep -v grep | grep hermes | grep beam",
|
69
|
+
:requires => [get_exec("install_hermes")]
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def hermes_release_tar_gz
|
75
|
+
`#{hermes_dir}/scripts/most_recent_release tar.gz`.strip
|
76
|
+
end
|
77
|
+
|
78
|
+
def target_system_file
|
79
|
+
"#{hermes_dir}/scripts/target_system"
|
80
|
+
end
|
81
|
+
|
82
|
+
def hermes_dir
|
83
|
+
PoolParty.lib_dir + "/vendor/erlang/hermes"
|
84
|
+
end
|
85
|
+
|
86
|
+
def remote_hermes_deployed_dir
|
87
|
+
"/var/poolparty/hermes"
|
88
|
+
end
|
89
|
+
|
90
|
+
def hermes_release_version
|
91
|
+
File.basename(hermes_release_tar_gz).gsub(/hermes-(.*?)\.tar\.gz/, '\1')
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# == install
|
99
|
+
# upload tar.gz & target_system
|
100
|
+
# run target_system unless VERSION exists
|
101
|
+
# run erlang: /usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FIRST/start _unless_ already running
|
data/lib/poolparty/pool.rb
CHANGED
@@ -27,6 +27,11 @@ module PoolParty
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
class << self;attr_accessor :command;end
|
31
|
+
def command
|
32
|
+
self.class.command
|
33
|
+
end
|
34
|
+
|
30
35
|
# cloud
|
31
36
|
# Define a cloud by a name and a block
|
32
37
|
def cloud(name, o={}, &block)
|
@@ -97,7 +102,7 @@ module PoolParty
|
|
97
102
|
end
|
98
103
|
|
99
104
|
def self.clouds_dot_rb_dir(n=nil)
|
100
|
-
File.dirname(self.clouds_dot_rb_file)
|
105
|
+
self.clouds_dot_rb_file ? File.dirname(self.clouds_dot_rb_file) : "./"
|
101
106
|
end
|
102
107
|
|
103
108
|
# Load the default clouds.rb file
|
@@ -151,13 +156,16 @@ module PoolParty
|
|
151
156
|
# + calls the resource define_resource_methods to define the resource methods
|
152
157
|
# + sets up the log
|
153
158
|
def self.before_file_load(filepath)
|
154
|
-
$:.unshift(
|
155
|
-
|
159
|
+
$:.unshift(File.dirname(filepath))
|
160
|
+
$:.unshift("#{File.dirname(filepath)}/lib")
|
161
|
+
$:.unshift("#{File.dirname(filepath)}/plugins")
|
162
|
+
|
163
|
+
Dir["#{File.dirname(filepath)}/lib/*.rb"].each {|lib_path| require lib_path }
|
164
|
+
Dir["#{File.dirname(filepath)}/plugins/*"].each do |plugin_path|
|
156
165
|
if File.directory?(plugin_path)
|
157
166
|
$:.unshift(plugin_path)
|
158
|
-
|
159
|
-
|
160
|
-
require plugin_path
|
167
|
+
else
|
168
|
+
require plugin_path if File.file?(plugin_path) && plugin_path.match(/.rb$/)
|
161
169
|
end
|
162
170
|
end
|
163
171
|
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
|
|
@@ -39,11 +40,11 @@ module PoolParty
|
|
39
40
|
|
40
41
|
# META FUNCTIONS
|
41
42
|
# ALL RESOURCES HAVE THESE METHODS AVAILABLE
|
42
|
-
def notifies(other_resources_hash, action_to_take=:reload)
|
43
|
+
def notifies(other_resources_hash, action_to_take=:reload, at_time=:delayed)
|
43
44
|
@meta_notifies ||= {}
|
44
45
|
other_resources_hash.each do |k,v|
|
45
46
|
notifies_array = (@meta_notifies[k] ||= [])
|
46
|
-
notifies_array << [v, action_to_take] unless notifies_array.include?([v, action_to_take])
|
47
|
+
notifies_array << [v, action_to_take, at_time] unless notifies_array.include?([v, action_to_take, at_time])
|
47
48
|
# Implicitly add a require
|
48
49
|
# requires(k => v)
|
49
50
|
end
|
@@ -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,17 +177,21 @@ 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
|
181
191
|
obj
|
182
192
|
end
|
183
|
-
def does_not_have_#{res.has_method_name}(a={},b={},&block)
|
184
|
-
obj = has_#{res.has_method_name}(a,b,
|
193
|
+
def does_not_have_#{res.has_method_name}(a={},b={},e=false,&block)
|
194
|
+
obj = has_#{res.has_method_name}(a,b,e,&block)
|
185
195
|
obj
|
186
196
|
end
|
187
197
|
def #{res.has_method_name}s
|
@@ -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
|
@@ -38,7 +38,7 @@ module PoolParty
|
|
38
38
|
else
|
39
39
|
{:command => "cat #{filepath} | grep -v \'#{line.safe_quote}\' > tempfile && mv tempfile #{filepath}",
|
40
40
|
:only_if => "grep -q \'#{line.safe_quote}\' #{filepath}"}
|
41
|
-
end
|
41
|
+
end
|
42
42
|
|
43
43
|
opts.merge!(:name => exists? ? "line in #{filepath}" : "no line in #{filepath}")
|
44
44
|
|
@@ -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,20 +4,54 @@ class CommandInterfaceHandler
|
|
4
4
|
cr = CloudThrift::CloudResponse.new
|
5
5
|
cr.name = cld.name
|
6
6
|
cr.command = command
|
7
|
-
resp = begin
|
8
|
-
the_cloud = clouds[cld.name]
|
9
|
-
the_cloud ? the_cloud.send(command.to_sym, *args) : "Cloud not found: #{cld.name}"
|
10
|
-
rescue Exception => e
|
11
|
-
cr.response = "Error: #{e.inspect}"
|
12
|
-
end
|
13
7
|
|
14
|
-
cr.response = format_response(
|
8
|
+
cr.response = format_response(get_response(cld, command, args))
|
15
9
|
|
16
10
|
return cr
|
17
11
|
end
|
18
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
|
+
|
19
28
|
private
|
20
29
|
|
30
|
+
def get_response(cld, command, args)
|
31
|
+
begin
|
32
|
+
the_cloud = clouds[cld.name]
|
33
|
+
if the_cloud
|
34
|
+
if command.include?(".")
|
35
|
+
command.split(".").inject(the_cloud) do |curr_cloud, cmd|
|
36
|
+
if cmd.match(/\((.*)\)/)
|
37
|
+
args = $1
|
38
|
+
new_cmd = cmd.gsub(args, '').gsub(/\(\)/, '')
|
39
|
+
curr_cloud = curr_cloud.send(new_cmd.to_sym, *args)
|
40
|
+
else
|
41
|
+
curr_cloud = curr_cloud.send(cmd)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
else
|
45
|
+
the_cloud.send(command.to_sym, *args)
|
46
|
+
end
|
47
|
+
else
|
48
|
+
"Cloud not found: #{cld.name}"
|
49
|
+
end
|
50
|
+
rescue Exception => e
|
51
|
+
cr.response = "Error: #{e.inspect}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
21
55
|
def format_response(resp)
|
22
56
|
case resp
|
23
57
|
when Array
|
@@ -28,4 +62,5 @@ class CommandInterfaceHandler
|
|
28
62
|
[resp]
|
29
63
|
end.map {|ele| ele.to_s }
|
30
64
|
end
|
65
|
+
|
31
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
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
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
|
|
@@ -4,9 +4,9 @@ pool :poolparty do
|
|
4
4
|
|
5
5
|
instances 1
|
6
6
|
|
7
|
-
cloud :
|
7
|
+
cloud :simple_cloud do
|
8
8
|
os :centos
|
9
|
-
keypair
|
9
|
+
keypair "test_key", PoolParty.lib_dir+"/../test/fixtures/keys"
|
10
10
|
has_file "/etc/motd", :content => "Simple"
|
11
11
|
end
|
12
12
|
|