poolparty 1.4.8 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/bin/cloud-show +8 -1
- data/lib/cloud_providers/connections.rb +42 -8
- data/lib/cloud_providers/ec2/ec2.rb +4 -0
- data/lib/cloud_providers/ec2/helpers/elastic_auto_scaler.rb +2 -2
- data/lib/cloud_providers/ec2/helpers/elastic_block_store_group.rb +1 -1
- data/lib/cloud_providers/ec2/helpers/rds_instance.rb +18 -6
- data/lib/cloud_providers/remote_instance.rb +10 -7
- data/lib/poolparty/cloud.rb +42 -5
- metadata +2 -2
data/VERSION.yml
CHANGED
data/bin/cloud-show
CHANGED
@@ -38,10 +38,17 @@ EOS
|
|
38
38
|
load_balancers = cld.cloud_provider.load_balancers.first.running_load_balancers.map {|a| a[:dns_name]}
|
39
39
|
msg << "Load balancers: #{load_balancers.join("\n\t\t\t")}"
|
40
40
|
end
|
41
|
+
|
42
|
+
if cld.rds_instances.size > 0
|
43
|
+
available = cld.cloud_provider.available_rds_instances.map{|r| "#{r.instance_id}\t#{r.current_status.Endpoint.Address}" }
|
44
|
+
available.unshift 'RDS Instances:'
|
45
|
+
|
46
|
+
msg << available.join("\n\t\t\t")
|
47
|
+
end
|
41
48
|
|
42
49
|
puts msg.flatten
|
43
50
|
|
44
51
|
end
|
45
52
|
|
46
53
|
end
|
47
|
-
end
|
54
|
+
end
|
@@ -27,15 +27,48 @@ module CloudProviders
|
|
27
27
|
def run(commands, o={})
|
28
28
|
ssh(commands)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
|
+
def shell_escape(str)
|
32
|
+
String(str).gsub(/(?=["'\\$])/n, '\\').
|
33
|
+
gsub(/\n/, "'\n'").
|
34
|
+
sub(/^$/, "''")
|
35
|
+
end
|
36
|
+
|
31
37
|
def ssh( commands=[], extra_ssh_ops={})
|
32
|
-
|
33
|
-
|
38
|
+
# Get the environment hash out of
|
39
|
+
# the extra_ssh_ops and then delete
|
40
|
+
# the element
|
41
|
+
env = extra_ssh_ops[:env] || {}
|
42
|
+
extra_ssh_ops.delete :env
|
43
|
+
|
44
|
+
# Decide to use sudo or not
|
45
|
+
do_sudo = true
|
46
|
+
if extra_ssh_ops.has_key? :do_sudo
|
47
|
+
do_sudo = extra_ssh_ops[:do_sudo]
|
48
|
+
extra_ssh_ops.delete :do_sudo
|
49
|
+
end
|
50
|
+
|
51
|
+
envstring = env.collect {|k,v| "#{k}=#{v}"}.join ' && '
|
52
|
+
envstring += " && " unless envstring.size == 0
|
53
|
+
ssh_string = "ssh #{user}@#{host} #{ssh_options(extra_ssh_ops)}"
|
54
|
+
|
34
55
|
if commands.empty?
|
35
56
|
#TODO: replace this with a IO.popen call with read_nonblocking to show progress, and accept input
|
36
|
-
Kernel.system(
|
57
|
+
Kernel.system(ssh_string)
|
37
58
|
else
|
38
|
-
|
59
|
+
r = nil
|
60
|
+
commands.each do |command|
|
61
|
+
|
62
|
+
cmd = "#{envstring}#{command}"
|
63
|
+
if do_sudo
|
64
|
+
sudocmd = %Q% sudo sh -c "#{shell_escape cmd}" %
|
65
|
+
else
|
66
|
+
sudocmd = cmd
|
67
|
+
end
|
68
|
+
|
69
|
+
r = system_run ssh_string + %Q% "#{shell_escape sudocmd}"%
|
70
|
+
end
|
71
|
+
r
|
39
72
|
end
|
40
73
|
end
|
41
74
|
|
@@ -46,7 +79,7 @@ module CloudProviders
|
|
46
79
|
def ssh_options(opts={})
|
47
80
|
return @ssh_options if @ssh_options && opts.empty?
|
48
81
|
ssh_opts = {"-i" => keypair.full_filepath,
|
49
|
-
"-o" =>"StrictHostKeyChecking=no"
|
82
|
+
"-o" =>"StrictHostKeyChecking=no",
|
50
83
|
}.merge(opts)
|
51
84
|
@ssh_options = ssh_opts.collect{ |k,v| "#{k} #{v}"}.join(' ')
|
52
85
|
end
|
@@ -55,7 +88,8 @@ module CloudProviders
|
|
55
88
|
raise StandardError.new("You must pass a :source=>uri option to rsync") unless opts[:source]
|
56
89
|
destination_path = opts[:destination] || opts[:source]
|
57
90
|
rsync_opts = opts[:rsync_opts] || '-va'
|
58
|
-
|
91
|
+
rsync_opts += %q% --rsync-path="sudo rsync" --exclude=.svn --exclude=.git --exclude=.cvs %
|
92
|
+
cmd_string = "rsync -L -e 'ssh #{ssh_options}' #{rsync_opts} #{opts[:source]} #{user}@#{host}:#{destination_path}"
|
59
93
|
out = system_run(cmd_string)
|
60
94
|
out
|
61
95
|
end
|
@@ -106,4 +140,4 @@ module CloudProviders
|
|
106
140
|
end
|
107
141
|
|
108
142
|
end
|
109
|
-
end
|
143
|
+
end
|
@@ -326,6 +326,10 @@ module CloudProviders
|
|
326
326
|
rds_instances << RdsInstance.new(given_name, sub_opts.merge(o || {}), &block)
|
327
327
|
end
|
328
328
|
|
329
|
+
def available_rds_instances
|
330
|
+
rds_instances.select{|r| r.available? }
|
331
|
+
end
|
332
|
+
|
329
333
|
# Proxy to the raw Grempe amazon-aws @ec2 instance
|
330
334
|
def ec2
|
331
335
|
@ec2 ||= begin
|
@@ -145,7 +145,7 @@ module CloudProviders
|
|
145
145
|
:user_data => user_data,
|
146
146
|
:kernel_id => kernel_id,
|
147
147
|
:ramdisk_id => ramdisk_id,
|
148
|
-
:
|
148
|
+
:block_device_mapping => block_device_mapping
|
149
149
|
})
|
150
150
|
rescue Exception => e
|
151
151
|
puts <<-EOE
|
@@ -424,4 +424,4 @@ module CloudProviders
|
|
424
424
|
"#{(measure_names[measure] || measure)}-#{name}" || name
|
425
425
|
end
|
426
426
|
end
|
427
|
-
end
|
427
|
+
end
|
@@ -32,7 +32,7 @@ module CloudProviders
|
|
32
32
|
|
33
33
|
# get volumes that are not attached
|
34
34
|
def free_volumes(availability_zone)
|
35
|
-
@volumes.select{|vol| vol.available? and vol.availability_zone == availability_zone}
|
35
|
+
@volumes.flatten.select{|vol| vol.available? and vol.availability_zone == availability_zone}
|
36
36
|
end
|
37
37
|
# Get a free volume from existing volumes in group or create a new one
|
38
38
|
def get_free_volume(availability_zone)
|
@@ -33,6 +33,22 @@ module CloudProviders
|
|
33
33
|
delete_rds_instance!
|
34
34
|
end
|
35
35
|
|
36
|
+
def current_status
|
37
|
+
rds_instances.detect{|i| i.DBInstanceIdentifier == instance_id }
|
38
|
+
end
|
39
|
+
|
40
|
+
def exists?
|
41
|
+
! current_status.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
def available?
|
45
|
+
exists? && current_status.DBInstanceStatus == 'available'
|
46
|
+
end
|
47
|
+
|
48
|
+
def instance_id
|
49
|
+
name.to_s
|
50
|
+
end
|
51
|
+
|
36
52
|
private
|
37
53
|
|
38
54
|
def authorizations
|
@@ -53,11 +69,7 @@ module CloudProviders
|
|
53
69
|
end
|
54
70
|
|
55
71
|
def should_create_rds_instance?
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
def instance_id
|
60
|
-
name.to_s
|
72
|
+
! exists?
|
61
73
|
end
|
62
74
|
|
63
75
|
def create_rds_instance!
|
@@ -107,4 +119,4 @@ module CloudProviders
|
|
107
119
|
end
|
108
120
|
end
|
109
121
|
end
|
110
|
-
end
|
122
|
+
end
|
@@ -37,7 +37,8 @@ module CloudProviders
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def chef_bootstrapped?
|
40
|
-
|
40
|
+
# do_sudo is false cause we want to capture the return code of the call
|
41
|
+
@chef_bootstrapped ||= !ssh(["gem list | grep chef"], :do_sudo => false).empty?
|
41
42
|
end
|
42
43
|
|
43
44
|
def bootstrap_chef!
|
@@ -45,19 +46,21 @@ module CloudProviders
|
|
45
46
|
ssh([
|
46
47
|
'apt-get update',
|
47
48
|
'apt-get autoremove -y',
|
48
|
-
'apt-get install -y ruby ruby-dev rubygems git-core',
|
49
|
+
'apt-get install -y ruby ruby-dev rubygems git-core libopenssl-ruby',
|
49
50
|
'gem sources -a http://gems.opscode.com',
|
50
|
-
'gem install chef ohai --no-rdoc --no-ri' ]
|
51
|
-
bootstrap_gems.collect { |gem| "gem install #{gem} --no-rdoc --no-ri" } )
|
51
|
+
'gem install chef ohai --no-rdoc --no-ri' ])
|
52
52
|
end
|
53
|
+
ssh(bootstrap_gems.collect { |gem| "gem install #{gem} --no-rdoc --no-ri" } )
|
53
54
|
end
|
54
55
|
|
55
56
|
def run_chef!
|
56
57
|
chef_solo_cmd = <<-CMD
|
57
|
-
GEM_BIN
|
58
|
-
&& $GEM_BIN/chef-solo -j /etc/chef/dna.json -c /etc/chef/solo.rb
|
58
|
+
$GEM_BIN/chef-solo -j /etc/chef/dna.json -c /etc/chef/solo.rb
|
59
59
|
CMD
|
60
|
-
|
60
|
+
envhash = {
|
61
|
+
:GEM_BIN => %q%$(gem env | grep "EXECUTABLE DIRECTORY" | awk "{print \\$4}")%
|
62
|
+
}
|
63
|
+
ssh([chef_solo_cmd.strip.squeeze(' ')], :env => envhash )
|
61
64
|
end
|
62
65
|
|
63
66
|
def run
|
data/lib/poolparty/cloud.rb
CHANGED
@@ -64,10 +64,34 @@ You did not specify a cloud provider in your clouds.rb. Make sure you have a blo
|
|
64
64
|
def chef_attributes(hsh={}, &block)
|
65
65
|
@chef_attributes ||= ChefAttribute.new(hsh, &block)
|
66
66
|
end
|
67
|
+
|
68
|
+
def chef_override_attributes(hsh={}, &block)
|
69
|
+
@chef_override_attributes ||= ChefAttribute.new(hsh, &block)
|
70
|
+
end
|
67
71
|
|
72
|
+
# Adds a chef recipe to the cloud
|
73
|
+
#
|
74
|
+
# The hsh parameter is inserted into the chef_override_attributes.
|
75
|
+
# The insertion is performed as follows. If
|
76
|
+
# the recipe name = "foo::bar" then effectively the call is
|
77
|
+
#
|
78
|
+
# chef_override_attributes.merge! { :foo => { :bar => hsh } }
|
68
79
|
def recipe(recipe_name, hsh={})
|
69
80
|
_recipes << recipe_name unless _recipes.include?(recipe_name)
|
70
|
-
|
81
|
+
|
82
|
+
head = {}
|
83
|
+
tail = head
|
84
|
+
recipe_name.split("::").each do |key|
|
85
|
+
unless key == "default"
|
86
|
+
n = {}
|
87
|
+
tail[key] = n
|
88
|
+
tail = n
|
89
|
+
end
|
90
|
+
end
|
91
|
+
tail.replace hsh
|
92
|
+
|
93
|
+
chef_override_attributes.merge!(head) unless hsh.empty?
|
94
|
+
|
71
95
|
end
|
72
96
|
|
73
97
|
def recipes(*recipes)
|
@@ -81,16 +105,18 @@ You did not specify a cloud provider in your clouds.rb. Make sure you have a blo
|
|
81
105
|
def _recipes
|
82
106
|
@_recipes ||= []
|
83
107
|
end
|
84
|
-
def _attributes
|
85
|
-
@_attributes ||= {}
|
86
|
-
end
|
87
108
|
|
88
109
|
# The NEW actual chef resolver.
|
89
110
|
def build_tmp_dir
|
90
111
|
base_directory = tmp_path/"etc"/"chef"
|
112
|
+
FileUtils.rm_rf base_directory
|
91
113
|
puts "Copying the chef-repo into the base directory from #{chef_repo}"
|
92
114
|
FileUtils.mkdir_p base_directory/"roles"
|
93
115
|
if File.directory?(chef_repo)
|
116
|
+
if File.exist?(base_directory)
|
117
|
+
# First remove the directory
|
118
|
+
FileUtils.remove_entry base_directory, :force => true
|
119
|
+
end
|
94
120
|
FileUtils.cp_r "#{chef_repo}/.", base_directory
|
95
121
|
else
|
96
122
|
raise "#{chef_repo} chef repo directory does not exist"
|
@@ -114,12 +140,23 @@ log_level :info
|
|
114
140
|
end
|
115
141
|
|
116
142
|
def write_chef_role_json(to=tmp_path/"etc"/"chef"/"dna.json")
|
143
|
+
|
144
|
+
# Add the parent name and the name of the cloud to
|
145
|
+
# the role for easy access in recipes.
|
146
|
+
pp = {
|
147
|
+
:poolparty => {
|
148
|
+
:parent_name => parent.name,
|
149
|
+
:name => name,
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
chef_override_attributes.merge! pp
|
117
154
|
ca = ChefAttribute.new({
|
118
155
|
:name => name,
|
119
156
|
:json_class => "Chef::Role",
|
120
157
|
:chef_type => "role",
|
121
158
|
:default_attributes => chef_attributes.init_opts,
|
122
|
-
:override_attributes =>
|
159
|
+
:override_attributes => chef_override_attributes.init_opts,
|
123
160
|
:description => description
|
124
161
|
})
|
125
162
|
ca.to_dna _recipes.map {|a| File.basename(a) }, to
|
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.
|
4
|
+
version: 1.5.0
|
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: 2010-
|
14
|
+
date: 2010-02-18 00:00:00 -08:00
|
15
15
|
default_executable:
|
16
16
|
dependencies: []
|
17
17
|
|