poolparty 1.6.4 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :minor: 6
3
- :patch: 4
3
+ :patch: 5
4
4
  :major: 1
5
5
  :build:
data/bin/cloud CHANGED
@@ -49,6 +49,7 @@ EOS
49
49
  run do |command|
50
50
  subcommands = GitStyleBinary.list_subcommands
51
51
 
52
+ puts "cloud %s" % PoolParty.version
52
53
  puts "Usage: cloud COMMAND [ARGS]
53
54
 
54
55
  The cloud subcommands commands are:
@@ -35,6 +35,9 @@ module CloudProviders
35
35
  end
36
36
 
37
37
  def ssh( commands=[], extra_ssh_ops={})
38
+ # commands can be single commands, as well as array
39
+ commands = [commands] unless commands.respond_to? :each
40
+
38
41
  # Get the environment hash out of
39
42
  # the extra_ssh_ops and then delete
40
43
  # the element
@@ -44,12 +47,12 @@ module CloudProviders
44
47
  extra_ssh_ops.delete :env
45
48
 
46
49
  # Decide to use sudo or not
47
- do_sudo = true
50
+ do_sudo = user!="root"
51
+
48
52
  if extra_ssh_ops.has_key? :do_sudo
49
53
  do_sudo = extra_ssh_ops[:do_sudo]
50
54
  extra_ssh_ops.delete :do_sudo
51
55
  end
52
- do_sudo=user!="root"
53
56
 
54
57
  envstring = env.collect {|k,v| "#{k}=#{v}"}.join ' && '
55
58
  envstring += " && " unless envstring.size == 0
@@ -74,6 +77,15 @@ module CloudProviders
74
77
  r
75
78
  end
76
79
  end
80
+
81
+ # remove hostname and corresponding from known_hosts file. Avoids warning when reusing elastic_ip, and
82
+ # less likely, if amazone reassigns ip. By default removes both dns_name and ip
83
+ def ssh_cleanup_known_hosts!(hosts=[host, public_ip])
84
+ hosts = [hosts] unless hosts.respond_to? :each
85
+ hosts.compact.each do |name|
86
+ system_run "ssh-keygen -R %s" % name
87
+ end
88
+ end
77
89
 
78
90
  # Take a hash of options and join them into a string, combined with default options.
79
91
  # Default options are -o StrictHostKeyChecking=no -i keypair.full_filepath -l user
@@ -75,7 +75,6 @@ module CloudProviders
75
75
 
76
76
  default_options(
77
77
  :instance_type => 'm1.small',
78
- :addressing_type => "public",
79
78
  :availability_zones => ["us-east-1a"],
80
79
  :user_id => default_user_id,
81
80
  :private_key => default_private_key,
@@ -89,10 +88,12 @@ module CloudProviders
89
88
  :min_count => 1,
90
89
  :max_count => 1,
91
90
  :user_data => '',
92
- :addressing_type => nil,
93
91
  :kernel_id => nil,
94
92
  :ramdisk_id => nil,
95
- :block_device_mapping => [{}]
93
+ :block_device_mapping => [{}],
94
+ :disable_api_termination => nil,
95
+ :instance_initiated_shutdown_behavior => nil,
96
+ :subnet_id => nil
96
97
  )
97
98
 
98
99
  # Called when the create command is called on the cloud
@@ -173,6 +174,7 @@ module CloudProviders
173
174
  end
174
175
 
175
176
  assign_elastic_ips
177
+ cleanup_ssh_known_hosts!
176
178
  puts "Attaching EBS volumes"
177
179
  assign_ebs_volumes # Assign EBS volumes
178
180
  end
@@ -196,7 +198,10 @@ module CloudProviders
196
198
  :availability_zone => availability_zones.first,
197
199
  :base64_encoded => true,
198
200
  :cloud => cloud,
199
- :block_device_mapping => block_device_mapping
201
+ :block_device_mapping => block_device_mapping,
202
+ :disable_api_termination => disable_api_termination,
203
+ :instance_initiated_shutdown_behavior => instance_initiated_shutdown_behavior,
204
+ :subnet_id => subnet_id,
200
205
  })
201
206
  progress_bar_until("Waiting for node to launch...") do
202
207
  wait_for_node(e)
@@ -223,7 +228,9 @@ module CloudProviders
223
228
  def contract_by(num=1)
224
229
  raise RuntimeError, "Contracting instances by #{num} will lower the number of instances below specified minimum" unless nodes.size - num > minimum_instances
225
230
  num.times do |i|
226
- id = nodes[-num].instance_id
231
+ node = nodes[-num]
232
+ id = node.instance_id
233
+ node.ssh_cleanup_known_hosts!
227
234
  Ec2Instance.terminate!(:instance_id => id, :cloud => cloud)
228
235
  end
229
236
  reset!
@@ -245,17 +252,11 @@ module CloudProviders
245
252
  end
246
253
 
247
254
  def configure_nodes!(tmp_path=nil)
248
- unless security_groups.map {|a| a.authorizes.map {|t| t.from_port.to_i }.flatten }.flatten.include?(22)
249
- warn "Cloud security_groups are not authorized for ssh. Cannot configure."
250
- return
251
- end
252
- tmp_path ||= cloud.tmp_path
253
- nodes.each do |node|
254
- next unless node.in_service?
255
- node.cloud_provider = self
256
- node.rsync_dir(tmp_path) if tmp_path
257
- node.run_chef!
258
- end
255
+ # removed duplicated code (now configure_nodes! invokes
256
+ # node.bootstrap_chef!, while old version did not, but I believe
257
+ # this is harmless)
258
+ bootstrap_nodes!(tmp_path)
259
+
259
260
  ebs_volume_groups.each do |vol_grp|
260
261
  vol_grp.verify_attachments nodes
261
262
  end
@@ -284,7 +285,17 @@ module CloudProviders
284
285
  end
285
286
  end
286
287
  end
287
-
288
+
289
+ def cleanup_ssh_known_hosts!(nodes_to_cleanup=nodes,
290
+ even_unavailable=false)
291
+ puts "cleaning up .ssh/known_hosts"
292
+ nodes_to_cleanup.find_all do |node|
293
+ even_unavailable || node.ssh_available?
294
+ end.each do |node|
295
+ node.ssh_cleanup_known_hosts!
296
+ end
297
+ end
298
+
288
299
  def nodes
289
300
  all_nodes.select {|i| i.in_service? }#describe_instances.select {|i| i.in_service? && security_groups.include?(i.security_groups) }
290
301
  end
@@ -10,7 +10,10 @@ module CloudProviders
10
10
  :key_name => nil,
11
11
  :launch_time => nil,
12
12
  :availability_zones => [],
13
- :block_device_mapping => [{}]
13
+ :block_device_mapping => [{}],
14
+ :disable_api_termination => nil,
15
+ :instance_initiated_shutdown_behavior => nil,
16
+ :subnet_id => nil
14
17
  )
15
18
 
16
19
  def initialize(raw_response={})
@@ -27,6 +30,9 @@ module CloudProviders
27
30
  self.availability_zones = raw_response["placement"]["availabilityZone"] rescue nil
28
31
  self.status = raw_response["instanceState"]["name"] rescue nil
29
32
  self.block_device_mapping = raw_response["blockDeviceMapping"] rescue nil
33
+ self.disable_api_termination = raw_response["disableApiTermination"] rescue nil
34
+ self.instance_initiated_shutdown_behavior = raw_response["instance_initiated_shutdown_behavior"] rescue nil
35
+ self.subnet_id = raw_response["subnetId"] rescue nil
30
36
  super
31
37
  end
32
38
 
@@ -43,7 +49,12 @@ module CloudProviders
43
49
  end
44
50
 
45
51
  def ssh_available?
46
- cloud.security_groups.map {|a| a.authorizes.map {|t| t.from_port.to_i }.flatten }.flatten.include?(22) and reachable? and in_service?
52
+ cloud.security_groups.map {|a|
53
+ a.authorizes.map {|t| t.from_port.to_i }.flatten
54
+ }.flatten.include?(22) and
55
+ reachable? and
56
+ in_service? and
57
+ keypair and keypair.exists?
47
58
  end
48
59
 
49
60
  def in_service?
@@ -37,12 +37,13 @@ module CloudProviders
37
37
  end
38
38
 
39
39
  def chef_bootstrapped?
40
- # do_sudo is false cause we want to capture the return code of the call
41
- @chef_bootstrapped ||= cloud.chef.node_bootsrapped?(self)
40
+ @chef_bootstrapped ||= cloud.chef.node_bootstrapped?(self)
42
41
  end
43
42
 
43
+ # TODO: chef_bootstrapped? should go away, since Chef#node_bootstrap!
44
+ # already checks node_bootstrap!. There is a force flag as well.
44
45
  def bootstrap_chef!
45
- cloud.chef.node_bootstrap(self) unless chef_bootstrapped?
46
+ cloud.chef.node_bootstrap!(self)
46
47
  end
47
48
 
48
49
  def run_chef!
data/lib/keypair.rb CHANGED
@@ -5,20 +5,25 @@ class Keypair
5
5
 
6
6
  include SearchablePaths
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
+ # Amazon will not append suffix, but public key may have '.pem' suffix
10
+ SEARCH_SUFFIXES = %w( .pem )
11
+
9
12
  attr_accessor :filepath
10
13
  attr_reader :extra_paths, :opts
14
+ attr_reader :search_suffixes
11
15
 
12
16
  # Create a new key that defaults to id_rsa as the name.
13
17
  def initialize(fpath, extra_paths=[], opts={})
14
18
  @filepath = fpath
15
19
  @opts = opts
16
20
  @extra_paths = extra_paths.map {|a| File.expand_path(a) }
21
+ @search_suffixes = SEARCH_SUFFIXES
17
22
  end
18
23
 
19
- # If the full_filepath is nil, then the key doesn't exist
24
+ # If the full_filepath is nil or false, then the key doesn't exist
20
25
  def exists?
21
- full_filepath != nil
26
+ !! full_filepath
22
27
  end
23
28
 
24
29
  # Read the content of the key
@@ -29,13 +34,9 @@ class Keypair
29
34
  # Returns the full_filepath of the key. If a full filepath is passed, we just return the expanded filepath
30
35
  # for the keypair, otherwise query where it is against known locations
31
36
  def full_filepath
32
- return @full_filepath if @full_filepath
33
- @full_filepath = if File.file?(File.expand_path(filepath))
34
- ::File.expand_path(filepath)
35
- else
36
- search_in_known_locations(filepath, extra_paths)
37
- end
38
- @full_filepath ? @full_filepath : false
37
+ @full_filepath ||=
38
+ find_file_in_path_with_suffix(filepath, extra_paths,
39
+ search_suffixes) || false
39
40
  end
40
41
 
41
42
  def to_s
@@ -99,6 +100,24 @@ class Keypair
99
100
  raise StandardError.new("#{filepath} key file cannot be found") unless filepath.nil?
100
101
  end
101
102
  end
103
+
104
+ # try filename with suffix and without suffixes.
105
+ # Checks all paths without suffix first, then try all paths for all suffixes.
106
+ def find_file_in_path_with_suffix(file, extra_paths, suffixes=[],
107
+ try_wo_suffix=true)
108
+ suffixes_to_try = suffixes.dup
109
+ suffixes_to_try.unshift '' if try_wo_suffix
110
+
111
+ suffixes_to_try.map {|s| file + s }.each do |suffixed|
112
+ fullpath = if File.file?(File.expand_path(suffixed))
113
+ ::File.expand_path(suffixed)
114
+ else
115
+ search_in_known_locations(suffixed, extra_paths)
116
+ end
117
+ return fullpath if fullpath
118
+ end
119
+
120
+ nil
121
+ end
102
122
 
103
-
104
- end
123
+ end
@@ -1,5 +1,21 @@
1
1
  module PoolParty
2
2
  class Chef < Base
3
+
4
+ BOOTSTRAP_PACKAGES = %w( ruby ruby1.8-dev libopenssl-ruby1.8 rdoc
5
+ ri irb build-essential wget ssl-cert rubygems git-core rake
6
+ librspec-ruby libxml-ruby zlib1g-dev libxml2-dev )
7
+ # thin couchdb
8
+ BOOTSTRAP_GEMS = %w( chef )
9
+
10
+ # we dont specifically install these binaries, they installed by
11
+ # packages and gems above, but we check for them
12
+ BOOTSTRAP_BINS = %w( gem chef-solo chef-client )
13
+ BOOTSTRAP_DIRS = %w( /var/log/chef /var/cache/chef /var/run/chef )
14
+
15
+ def compile!
16
+ build_tmp_dir
17
+ end
18
+
3
19
  def self.types
4
20
  return [:solo,:client]
5
21
  end
@@ -48,26 +64,76 @@ module PoolParty
48
64
  end
49
65
 
50
66
  def node_run!(remote_instance)
67
+ node_stop!(remote_instance)
68
+ node_configure!(remote_instance)
69
+
51
70
  envhash = {
52
71
  :GEM_BIN => %q%$(gem env | grep "EXECUTABLE DIRECTORY" | awk "{print \\$4}")%
53
72
  }
54
- remote_instance.ssh([chef_cmd.strip.squeeze(' ')], :env => envhash )
73
+ cmds = chef_cmd
74
+ cmds = [cmds] unless cmds.respond_to? :each
75
+
76
+ remote_instance.ssh(cmds.map{|c| c.strip.squeeze(' ')}, :env => envhash )
55
77
  end
56
78
 
57
- def node_bootsrapped?(remote_instance)
58
- # "(gem list; dpkg -l chef) | grep -q chef && echo 'chef installed'"
59
- remote_instance.ssh(['if [ ! -n "$(gem list 2>/dev/null | grep chef)" ]; then echo "chef installed"; fi'], :do_sudo => false).empty? rescue false
79
+ def node_stop!(remote_instance)
80
+ remote_instance.ssh("killall -q chef-client chef-solo; [ -f /etc/init.d/chef-client ] && invoke-rc.d chef-client stop")
60
81
  end
61
- def node_bootstrap(remote_instance)
62
- remote_instance.ssh([
63
- 'apt-get update',
64
- 'apt-get autoremove -y',
65
- 'apt-get install -y ruby ruby-dev rubygems git-core libopenssl-ruby',
66
- 'gem sources -a http://gems.opscode.com',
67
- 'gem install chef ohai --no-rdoc --no-ri' ])
68
- remote_instance.ssh(remote_instance.bootstrap_gems.collect { |g| "gem install #{g} --no-rdoc --no-ri" } )
82
+
83
+ def node_configure!(remote_instance)
84
+ # nothing in the superclass
69
85
  end
86
+
87
+ def node_bootstrapped?(remote_instance, quiet=true)
88
+ # using which command instead of calling gem directly. On
89
+ # ubuntu, calling a command from package not installed
90
+ # 'helpfully' prints message, which result confuses detection
91
+ #
92
+ cmd = "which %s" % BOOTSTRAP_BINS.join(' ') +
93
+ " && dpkg -l %s " % BOOTSTRAP_PACKAGES.join(' ') +
94
+ BOOTSTRAP_GEMS.map{ |gem|
95
+ "&& gem search '^#{gem}$' | grep -v GEMS | wc -l | grep -q 1"
96
+ }.join(' ') +
97
+ BOOTSTRAP_DIRS.map{ |dir|
98
+ "&& [[ -d #{dir} ]] "
99
+ }.join(' ') +
100
+ (quiet ? " >/dev/null " : "" ) +
101
+ " && echo OK || echo MISSING"
102
+
103
+ r = remote_instance.ssh(cmd, :do_sudo => false )
104
+ r.lines.to_a.last.chomp == "OK"
105
+ end
106
+
107
+ def node_bootstrap!(remote_instance, force=false)
108
+ return if !force && node_bootstrapped?(remote_instance)
109
+
110
+ # TODO: this should not be hardcoded (like in node_run)
111
+ deb_gem_bin='/var/lib/gems/1.8/bin'
112
+ gem_src='http://gems.opscode.com'
113
+
114
+ bootstrap_cmds =
115
+ [
116
+ 'apt-get update',
117
+ 'apt-get autoremove -y',
118
+ 'apt-get install -y %s' % BOOTSTRAP_PACKAGES.join(' '),
119
+ "gem source -l | grep -q #{gem_src} || gem source -a #{gem_src} ",
120
+ 'gem install %s --no-rdoc --no-ri' %
121
+ (BOOTSTRAP_GEMS + remote_instance.bootstrap_gems).join(' '),
122
+ "apt-get install -y %s" % BOOTSTRAP_PACKAGES.join(' '),
123
+ "[ -d #{deb_gem_bin} ] && ln -sf #{deb_gem_bin}/* /usr/local/bin",
124
+ "mkdir -p %s" % BOOTSTRAP_DIRS.join(' ')
125
+ ]
126
+
127
+ remote_instance.ssh(bootstrap_cmds)
128
+ end
129
+
70
130
  private
131
+
132
+ def chef_cmd
133
+ return <<-CMD
134
+ PATH="$PATH:$GEM_BIN" #{chef_bin} -j /etc/chef/dna.json -c /etc/chef/client.rb -d -i 1800 -s 20
135
+ CMD
136
+ end
71
137
 
72
138
  def _recipes
73
139
  @_recipes ||= []
@@ -1,8 +1,15 @@
1
+ require 'uri' # for URI.parse in write_bootstrap_files
2
+
1
3
  module PoolParty
2
4
  # Chef class bootstrapping chef-client.
3
5
  class ChefClient < Chef
4
- dsl_methods :server_url,:validation_token
5
-
6
+ dsl_methods :server_url,:validation_token, :validation_key
7
+
8
+ # When init_style.nil?, old behavior is used (just run the client).
9
+ # If init_style is specified, bootstrap::client cookbook is executed
10
+ # To this init style.
11
+ dsl_methods :init_style
12
+
6
13
  def openid_url(url=nil)
7
14
  if url.nil?
8
15
  return @openid_url||= (u=URI.parse(server_url)
@@ -18,27 +25,48 @@ module PoolParty
18
25
  @_roles=roles
19
26
  end
20
27
 
21
- def compile!
22
- build_tmp_dir
23
- end
24
-
25
28
  private
26
29
  def after_initialized
27
30
  raise PoolPartyError.create("ChefArgumentMissing", "server_url must be specified!") unless server_url
28
31
  end
32
+ def chef_bin
33
+ "chef-client"
34
+ end
35
+
29
36
  def chef_cmd
30
- return <<-CMD
31
- PATH="$PATH:$GEM_BIN" chef-client -j /etc/chef/dna.json -c /etc/chef/client.rb -d -i 1800 -s 20
32
- CMD
37
+ # without init_style, let parent class start chef-client
38
+ return super unless init_style
39
+
40
+ 'invoke-rc.d chef-client start'
33
41
  end
42
+
43
+ def node_configure!(remote_instance)
44
+ super
45
+ cmds =
46
+ [ 'PATH="$PATH:$GEM_BIN" chef-solo -j /tmp/chef/chef.json -c /tmp/chef/solo.rb',
47
+ 'invoke-rc.d chef-client stop',
48
+ 'PATH="$PATH:$GEM_BIN" chef-client -j /etc/chef/dna.json -c /etc/chef/client.rb',
49
+ ]
50
+
51
+ remote_instance.ssh cmds
52
+ end
53
+
34
54
  # The NEW actual chef resolver.
35
55
  def build_tmp_dir
36
56
  base_directory = tmp_path/"etc"/"chef"
37
57
  FileUtils.rm_rf base_directory
38
58
  FileUtils.mkdir_p base_directory
59
+ FileUtils.cp validation_key, base_directory if validation_key
39
60
  puts "Creating the dna.json"
40
61
  attributes.to_dna [], base_directory/"dna.json", {:run_list => roles.map{|r| "role[#{r}]"} + _recipes.map{|r| "recipe[#{r}]"}}.merge(attributes.init_opts)
41
- write_client_dot_rb
62
+ unless init_style then # original style init
63
+ write_client_dot_rb
64
+ else
65
+ bootstrap_tmp_dir = tmp_path/"tmp/chef"
66
+ FileUtils.rm_rf bootstrap_tmp_dir
67
+ FileUtils.mkdir_p bootstrap_tmp_dir
68
+ write_bootstrap_files bootstrap_tmp_dir/"solo.rb", bootstrap_tmp_dir/"chef.json"
69
+ end
42
70
  end
43
71
 
44
72
  def write_client_dot_rb(to=tmp_path/"etc"/"chef"/"client.rb")
@@ -51,13 +79,43 @@ pid_file "/var/run/chef/client.pid"
51
79
  Chef::Log::Formatter.show_time = true
52
80
  openid_url "#{openid_url}"
53
81
  EOE
54
- %w(search_url role_url remotefile_url template_url registration_url).each{|url|
82
+ %w(chef_server_url).each{|url|
55
83
  content+="#{url} \"#{server_url}\"\n"
56
84
  }
57
85
  content+="validation_token \"#{validation_token}\"\n" if validation_token
86
+ content+="validation_key \"/etc/chef/#{File.basename validation_key}\"\n" if validation_key
58
87
  File.open(to, "w") do |f|
59
88
  f << content
60
89
  end
61
90
  end
91
+
92
+ def write_bootstrap_files(solo_rb, chef_json)
93
+ uri=URI.parse(server_url)
94
+ # this maybe reduntant, URL should have a port in there
95
+ uri.port=4000 if uri.port == 80 # default port for chef
96
+
97
+ contents_solo_rb = <<-EOE
98
+ file_cache_path "/tmp/chef-solo"
99
+ cookbook_path "/tmp/chef-solo/cookbooks"
100
+ recipe_url "http://s3.amazonaws.com/chef-solo/bootstrap-latest.tar.gz"
101
+ EOE
102
+ File.open(solo_rb, "w") do |f| f << contents_solo_rb end
103
+
104
+ bootstrap_json =
105
+ {
106
+ :bootstrap => {
107
+ :chef => {
108
+ :url_type => uri.scheme,
109
+ :init_style => init_style,
110
+ :path => "/srv/chef",
111
+ :serve_path => "/srv/chef",
112
+ :server_fqdn => uri.host,
113
+ :server_port => uri.port,
114
+ },
115
+ },
116
+ :run_list => [ 'recipe[bootstrap::client]' ],
117
+ }
118
+ ChefAttribute.new(bootstrap_json).to_dna([], chef_json)
119
+ end
62
120
  end
63
121
  end
@@ -3,16 +3,12 @@ require "fileutils"
3
3
  module PoolParty
4
4
  class ChefSolo < Chef
5
5
  dsl_methods :repo
6
- def compile!
7
- build_tmp_dir
8
- end
9
6
 
10
7
  private
11
- def chef_cmd
12
- return <<-CMD
13
- PATH="$PATH:$GEM_BIN" chef-solo -j /etc/chef/dna.json -c /etc/chef/solo.rb
14
- CMD
8
+ def chef_bin
9
+ "chef-solo"
15
10
  end
11
+
16
12
  # The NEW actual chef resolver.
17
13
  def build_tmp_dir
18
14
  base_directory = tmp_path/"etc"/"chef"
data/lib/poolparty.rb CHANGED
@@ -20,6 +20,7 @@ module PoolParty
20
20
  return @version if @version
21
21
  config = YAML.load(File.read(File.expand_path("#{File.dirname(__FILE__)}/../VERSION.yml")))
22
22
  @version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
23
+ @version += "-" + config[:build] if config[:build]
23
24
  end
24
25
  def self.lib_dir
25
26
  File.join(File.dirname(__FILE__), "..")
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEogIBAAKCAQEAywLYTlQ+keNiZI2FeBik6q34xStF3fF2+XPk3e21B0YQfbQI
3
+ xYJG8gbSro90Tu1hnEBZfYm+AC8HXsR9Kx9LpfTSa3aGFRREwdsi8xuaoeHWNxOh
4
+ MykU4UcxahT0Ft5+738kLmtVhw8bjjkqcpxCSgrpcJbad2B2ft1KBE02kiU2y7yS
5
+ 92sUSWBzVkkJTmiWBDvn5pT9y6IpVCKseWbumGQ6nozEfXe4ihUsKAH42XPxSXMX
6
+ Xe64JuONQlxZPrqyF7L/lt6ZeyKQ7yXVcxr6P4W3rPqlBhq5yXNI3vV67KUNCh+w
7
+ HH6RLagaguS0VTdBYwo3dvkmuL6TJqnzPzrv1wIBIwKCAQBczhm9aFceHs3k0vsv
8
+ ljzDDbONVZxIM96d69ZW0xDtYdunLbrd8mmTNlGu4n5P930UOqyRKQZme+YcsZhO
9
+ OjE17ELvTCAJot2acs4l/f2L1PQ2b1+iW+xJuiU3zxB/e6e98PqY4Jwge+9W9Y+/
10
+ XWAh2RpCGRNpxbKDI1UJR95usRxhxlmY0RmUtpDjc3qEOPRgj7E2iC4fFVdvYzKt
11
+ FBkGR6Gv2/jqm+c/TmRCFnyaWJXC8W6LkkACjUc6IKUOBSbs6l+3DH0PBOr+XbGv
12
+ peExAfYCTfvGy/NNPpzP0JJUJ92sWaZUPUTf8McSsgrTTRBfklsJuf9Hje/8abcr
13
+ AheLAoGBAPGX3CDMU68BTgO8bOvGhFHQSu9AypIhEh0PrE1CYsEvYrIRg9h23fuz
14
+ 1nz7Z6kIYTNMywxfphEL65CTiJ5eSJV+UGMFAKYziCwH7MDD4Wc6cPLrGmA0eYDz
15
+ QMUQJwqfuXKq/dMw2VB6qGbNmbERWmq3wteF/afyTatd6poV4UcXAoGBANcd/o4s
16
+ zf1SwxKoT4GGp62gtqT+gIbGkV0AzWBcaDarRNbcV7uFZLL7wzPcCR8/cPZiN+ks
17
+ +LsVYvDfrFHRxtdzIesxcqG2v6LazB/+/rZp4Hqc1a4OwxSdOYzINjA01GV2HcET
18
+ XzoJIQA8ZYuVpELaNzjLtKBZ6mrQmBh7RRVBAoGBAJ7C4RzeCxs7XycGyzvaObIb
19
+ Ke2uO/mgtCG516B8FQKbe18S0vv2V1xC+qnnCZr24MnworBcHKwdxq925L/Xjsij
20
+ dqd4UOI/Hvhc+qqPWZubbsuEjazvSIfwTyJps0F+55R+/pIYyVIkt86HG9rCQrso
21
+ TNbFw/IFoMER1K5mJlNJAoGAT+aRv8d/tdzpXrOLPrz8c7C43jKkxFhh4LcnthOx
22
+ refXvYUKpLyEfP5tE0MZVL/K3yvLn8A/IOqvuI2Xxp5fzF32p9CJqceJAfl/BJHp
23
+ lDX0SsyJ4ZB0WB0kARcqEee8mrbX2f/hipWtK/ktB/XAqx3Z/ycXND6nhsKBorFx
24
+ bksCgYEAtPns7oc98wmF8j37ELikMFJOvQgccbGTzcJ1RVzji95HfN4p3kA6emo/
25
+ hRyP8XNedEI/CD6MmthKKymw5Ck1I51nwDW4+zTEDAN14nh4T9p6Jqe7lSENqLaY
26
+ A5jkgXV8e0YqKkjLNec5hAzoEY09KryQdz81KXeHvbEUfIiItTk=
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,8 @@
1
+ -----BEGIN RSA PUBLIC KEY-----
2
+ MIIBCAKCAQEAywLYTlQ+keNiZI2FeBik6q34xStF3fF2+XPk3e21B0YQfbQIxYJG
3
+ 8gbSro90Tu1hnEBZfYm+AC8HXsR9Kx9LpfTSa3aGFRREwdsi8xuaoeHWNxOhMykU
4
+ 4UcxahT0Ft5+738kLmtVhw8bjjkqcpxCSgrpcJbad2B2ft1KBE02kiU2y7yS92sU
5
+ SWBzVkkJTmiWBDvn5pT9y6IpVCKseWbumGQ6nozEfXe4ihUsKAH42XPxSXMXXe64
6
+ JuONQlxZPrqyF7L/lt6ZeyKQ7yXVcxr6P4W3rPqlBhq5yXNI3vV67KUNCh+wHH6R
7
+ LagaguS0VTdBYwo3dvkmuL6TJqnzPzrv1wIBIw==
8
+ -----END RSA PUBLIC KEY-----
@@ -6,6 +6,7 @@ class KeypairTest < Test::Unit::TestCase
6
6
  context "Base" do
7
7
  setup do
8
8
  @keypair = Keypair.new(fixtures_dir/"keys"/"test_key")
9
+ @keypair_pem = Keypair.new(fixtures_dir/"keys"/"pem_key")
9
10
  end
10
11
 
11
12
  should "set the file given as the file for the keypair" do
@@ -13,6 +14,25 @@ class KeypairTest < Test::Unit::TestCase
13
14
  assert_equal @keypair.full_filepath, File.expand_path(fixtures_dir/"keys"/"test_key")
14
15
  assert_match @keypair.to_s, File.expand_path(fixtures_dir/"keys"/"test_key")
15
16
  end
17
+
18
+ should "find the suffixed file given without pem suffix" do
19
+ assert_equal @keypair_pem.filepath, fixtures_dir/"keys"/"pem_key"
20
+ assert_equal @keypair_pem.full_filepath, File.expand_path(fixtures_dir/"keys"/"pem_key.pem")
21
+ assert_match @keypair_pem.to_s, File.expand_path(fixtures_dir/"keys"/"pem_key")
22
+ end
23
+
24
+ should "find the suffixed file given without pem suffix or dir" do
25
+ basename = File.basename(@keypair_pem.full_filepath)
26
+ basename_no_suffix = File.basename(basename, '.pem')
27
+
28
+ search_dirs = [File.dirname(@keypair_pem.full_filepath)]
29
+
30
+ keypair = Keypair.new(basename, search_dirs)
31
+ keypair_no_suffix = Keypair.new(basename_no_suffix, search_dirs)
32
+
33
+ assert_equal keypair.full_filepath, @keypair_pem.full_filepath
34
+ assert_equal keypair_no_suffix.full_filepath, @keypair_pem.full_filepath
35
+ end
16
36
 
17
37
  should "have the content of the file available" do
18
38
  assert_equal @keypair.content, open(fixtures_dir/"keys"/"test_key").read
@@ -37,4 +57,4 @@ class KeypairTest < Test::Unit::TestCase
37
57
  end
38
58
  end
39
59
  end
40
- end
60
+ 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.6.4
4
+ version: 1.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ari Lerner
@@ -291,6 +291,8 @@ files:
291
291
  - test/fixtures/ec2/ec2-terminate-instances_response_body.xml
292
292
  - test/fixtures/ec2/elb-describe-load-balancers.xml
293
293
  - test/fixtures/ec2/rds-describe-db-instances-empty_response_body.xml
294
+ - test/fixtures/keys/pem_key.pem
295
+ - test/fixtures/keys/pem_pub_key.pem
294
296
  - test/fixtures/keys/test_key
295
297
  - test/fixtures/keys/test_pub_key
296
298
  - test/fixtures/resources/fake_plugin.rb