poolparty 1.6.4 → 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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