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.
Files changed (83) hide show
  1. data/VERSION.yml +1 -1
  2. data/bin/cloud +1 -0
  3. data/bin/cloud-compile +1 -0
  4. data/bin/cloud-misc +34 -0
  5. data/bin/cloud-show +13 -1
  6. data/bin/cloud-ssh +4 -1
  7. data/bin/cloud-thrift +32 -18
  8. data/config/jeweler.rb +5 -3
  9. data/examples/monitored_cloud.rb +1 -1
  10. data/examples/thrift/thrift_example.rb +8 -4
  11. data/examples/vmware.rb +10 -0
  12. data/lib/cloud_providers/cloud_provider.rb +9 -0
  13. data/lib/cloud_providers/cloud_provider_instance.rb +9 -4
  14. data/lib/cloud_providers/connections.rb +9 -5
  15. data/lib/cloud_providers/ec2/ec2.rb +42 -12
  16. data/lib/cloud_providers/ec2/ec2_helpers.rb +62 -5
  17. data/lib/cloud_providers/ec2/ec2_instance.rb +14 -1
  18. data/lib/cloud_providers/vmware/vmware.rb +3 -0
  19. data/lib/core/file.rb +12 -0
  20. data/lib/core/object.rb +1 -1
  21. data/lib/dependency_resolvers/base.rb +2 -9
  22. data/lib/dependency_resolvers/chef.rb +3 -3
  23. data/lib/keypair.rb +5 -3
  24. data/lib/poolparty.rb +3 -1
  25. data/lib/poolparty/base.rb +45 -22
  26. data/lib/poolparty/cloud.rb +70 -15
  27. data/lib/poolparty/default.rb +1 -0
  28. data/lib/poolparty/installer.rb +1 -1
  29. data/lib/poolparty/installers/ec2.rb +30 -16
  30. data/lib/poolparty/monitor.rb +25 -3
  31. data/lib/poolparty/plugin.rb +1 -5
  32. data/lib/poolparty/plugins/apache.rb +37 -11
  33. data/lib/poolparty/plugins/apache2/passenger_site.rb +1 -1
  34. data/lib/poolparty/plugins/apache2/virtual_host.rb +1 -0
  35. data/lib/poolparty/plugins/collectd.rb +29 -0
  36. data/lib/poolparty/plugins/collectd/templates/collectd.conf.erb +369 -0
  37. data/lib/poolparty/plugins/hermes.rb +101 -0
  38. data/lib/poolparty/pool.rb +14 -6
  39. data/lib/poolparty/resource.rb +20 -17
  40. data/lib/poolparty/resources/file.rb +2 -2
  41. data/lib/poolparty/resources/line.rb +1 -1
  42. data/lib/poolparty/resources/link.rb +2 -1
  43. data/lib/proto/command_interface_handler.rb +42 -7
  44. data/lib/proto/command_query_handler.rb +19 -0
  45. data/lib/proto/gen-py/cloudthrift/CommandInterface.pyc +0 -0
  46. data/lib/proto/gen-py/cloudthrift/__init__.pyc +0 -0
  47. data/lib/proto/gen-py/cloudthrift/constants.pyc +0 -0
  48. data/lib/proto/gen-py/cloudthrift/ttypes.pyc +0 -0
  49. data/lib/proto/gen-py/thrift/Thrift.pyc +0 -0
  50. data/lib/proto/gen-py/thrift/__init__.pyc +0 -0
  51. data/lib/proto/gen-py/thrift/protocol/TBinaryProtocol.pyc +0 -0
  52. data/lib/proto/gen-py/thrift/protocol/TProtocol.pyc +0 -0
  53. data/lib/proto/gen-py/thrift/protocol/__init__.pyc +0 -0
  54. data/lib/proto/gen-py/thrift/transport/TSocket.pyc +0 -0
  55. data/lib/proto/gen-py/thrift/transport/TTransport.pyc +0 -0
  56. data/lib/proto/gen-py/thrift/transport/__init__.pyc +0 -0
  57. data/lib/proto/poolparty.thrift +1 -0
  58. data/tasks/poolparty.rake +24 -0
  59. data/test/fixtures/clouds/fake_clouds.rb +2 -2
  60. data/test/fixtures/clouds/simple_cloud.rb +2 -2
  61. data/test/fixtures/resources/fake_plugin.rb +5 -0
  62. data/test/fixtures/resources/fake_subclassed_plugin.rb +19 -0
  63. data/test/lib/cloud_providers/ec2/ec2_instance_test.rb +17 -8
  64. data/test/lib/cloud_providers/ec2/ec2_test.rb +15 -11
  65. data/test/lib/core/array_test.rb +4 -0
  66. data/test/lib/dependency_resolvers/base_test.rb +1 -1
  67. data/test/lib/dependency_resolvers/chef/resources/remote_directory_test.rb +2 -2
  68. data/test/lib/dependency_resolvers/chef/resources/remote_file_test.rb +1 -1
  69. data/test/lib/dependency_resolvers/chef_test.rb +3 -3
  70. data/test/lib/poolparty/base_test.rb +1 -1
  71. data/test/lib/poolparty/cloud_test.rb +140 -33
  72. data/test/lib/poolparty/monitor_test.rb +29 -2
  73. data/test/lib/poolparty/plugins/apache_test.rb +5 -0
  74. data/test/lib/poolparty/pool_test.rb +3 -3
  75. data/test/lib/poolparty/resource_test.rb +14 -2
  76. data/test/lib/poolparty/resources/conditional_test.rb +1 -0
  77. data/test/lib/poolparty/resources/directory_test.rb +1 -1
  78. data/test/lib/poolparty/resources/file_test.rb +1 -1
  79. data/test/lib/poolparty/resources/user_test.rb +1 -1
  80. data/test/lib/proto/command_query_handler_test.rb +11 -0
  81. data/test/lib/provision/bootstrapper_test.rb +0 -25
  82. data/test/test_helper.rb +0 -1
  83. 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
@@ -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) if 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(::File.dirname(filepath))
155
- Dir["#{ ::File.dirname(filepath)}/plugins/*"].each do |plugin_path|
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
- require "#{plugin_path}/#{File.basename(plugin_path)}"
159
- elsif File.file?(plugin_path) && plugin_path.match(/.rb$/)
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
@@ -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 after_loaded
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
- Base.class_eval <<-EOE
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,false,&block)
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
- case obj
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?(c = File.expand_path(File.join(clouds_dot_rb_dir, file)))
70
- c
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(resp)
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
@@ -14,4 +14,5 @@ struct CloudResponse {
14
14
 
15
15
  service CommandInterface {
16
16
  CloudResponse run_command(1:CloudQuery cld, 2:string command, 3:list<string> arglist)
17
+ CloudResponse cast_command(1:CloudQuery cld, 2:string command, 3:list<string> arglist)
17
18
  }
@@ -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
 
@@ -1,7 +1,7 @@
1
1
  pool :boxed do
2
2
 
3
- cloud :app do
4
- keypair 'test_key'
3
+ cloud :fake_cloud do
4
+ keypair File.dirname(__FILE__)+"/../keys/test_key"
5
5
  using :ec2 do
6
6
  end
7
7
  end
@@ -4,9 +4,9 @@ pool :poolparty do
4
4
 
5
5
  instances 1
6
6
 
7
- cloud :app do
7
+ cloud :simple_cloud do
8
8
  os :centos
9
- keypair File.dirname(__FILE__)+"/../keys/test_key"
9
+ keypair "test_key", PoolParty.lib_dir+"/../test/fixtures/keys"
10
10
  has_file "/etc/motd", :content => "Simple"
11
11
  end
12
12