vagrant-aws 0.7.0 → 0.7.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a1deca95df376c2977458f95179407a4c2e04458
4
- data.tar.gz: 9d4a5506219f5f3f8db34ea476d9aa986ae75ec8
3
+ metadata.gz: 7dc5ac6ea70ec0fa3aaf489a3062a5ca91724ea2
4
+ data.tar.gz: cd91ea76e3f967df83caa7f72ae41fb5741a0129
5
5
  SHA512:
6
- metadata.gz: 96d998cf0955fab6abfac02fc5b386fb7ee15dcb224e0abbb145970cf14365d6c9881016e8b8ec90088903fb773c2b623277edfe121c7780bf72e7b049309ad9
7
- data.tar.gz: 69777208d9687dcf5038a182af1e97258aaba0b630798f4f0b61bab0fb1a473c9809664c18a7e9385e85cee2d6f2e3dcd5d9f3880720699f2533dea4aec985d6
6
+ metadata.gz: 7a30093a3a0a08781d22a13b2074a4908a5839ef69aaa0bf582d8ad5a1c0cd25afe1eaa3448e4451be5769d3ad8ba402625dc93fb26dd4b7fc0f80b03feb3ea4
7
+ data.tar.gz: c144f841a06d5222dabeca1a4f58cc71b23e4633b232d65a051d222cd1c4df79f20cb3a92d94062003e02840f27c1ab5d2edbbcf762bc0f40ba279e803bd09e9
data/README.md CHANGED
@@ -87,6 +87,19 @@ no preconfigured defaults.
87
87
  If you have issues with SSH connecting, make sure that the instances
88
88
  are being launched with a security group that allows SSH access.
89
89
 
90
+ Note: if you don't configure `aws.access_key_id` or `aws_secret_access_key`
91
+ it will attempt to read credentials from environment variables first and then
92
+ from `$HOME/.aws/`. You can choose your AWS profile and files location by using
93
+ `aws.aws_profile` and `aws.aws_dir`, however environment variables will always
94
+ have precedence as defined by the [AWS documentation](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html).
95
+ To use profile `vagrantDev` from your AWS files:
96
+ ```ruby
97
+ # this first line can actually be omitted
98
+ aws.aws_dir = ENV['HOME'] + "/.aws/"
99
+ aws.aws_profile = "vagrantDev"
100
+ ```
101
+
102
+
90
103
  ## Box Format
91
104
 
92
105
  Every provider in Vagrant must introduce a custom box format. This
@@ -106,6 +119,8 @@ This provider exposes quite a few provider-specific configuration options:
106
119
  * `ami` - The AMI id to boot, such as "ami-12345678"
107
120
  * `availability_zone` - The availability zone within the region to launch
108
121
  the instance. If nil, it will use the default set by Amazon.
122
+ * `aws_profile` - AWS profile in your config files. Defaults to *default*.
123
+ * `aws_dir` - AWS config and credentials location. Defaults to *$HOME/.aws/*.
109
124
  * `instance_ready_timeout` - The number of seconds to wait for the instance
110
125
  to become "ready" in AWS. Defaults to 120 seconds.
111
126
  * `instance_check_interval` - The number of seconds to wait to check the instance's
data/Rakefile CHANGED
@@ -15,7 +15,8 @@ Dir.chdir(File.expand_path("../", __FILE__))
15
15
  Bundler::GemHelper.install_tasks
16
16
 
17
17
  # Install the `spec` task so that we can run tests.
18
- RSpec::Core::RakeTask.new
19
-
18
+ RSpec::Core::RakeTask.new(:spec) do |t|
19
+ t.rspec_opts = "--order defined"
20
+ end
20
21
  # Default task is to run the unit tests
21
- task :default => "spec"
22
+ task :default => :spec
@@ -284,7 +284,7 @@ module VagrantPlugins
284
284
  end
285
285
 
286
286
  # Save this IP to the data dir so it can be released when the instance is destroyed
287
- if h
287
+ if h
288
288
  ip_file = env[:machine].data_dir.join('elastic_ip')
289
289
  ip_file.open('w+') do |f|
290
290
  f.write(h.to_json)
@@ -292,7 +292,7 @@ module VagrantPlugins
292
292
  end
293
293
  end
294
294
 
295
- def handle_elastic_ip_error(env, message)
295
+ def handle_elastic_ip_error(env, message)
296
296
  @logger.debug(message)
297
297
  terminate(env)
298
298
  raise Errors::FogError,
@@ -1,4 +1,5 @@
1
1
  require "vagrant"
2
+ require "iniparse"
2
3
 
3
4
  module VagrantPlugins
4
5
  module AWS
@@ -185,6 +186,16 @@ module VagrantPlugins
185
186
  # @return [String]
186
187
  attr_accessor :tenancy
187
188
 
189
+ # The directory where AWS files are stored (usually $HOME/.aws)
190
+ #
191
+ # @return [String]
192
+ attr_accessor :aws_dir
193
+
194
+ # The selected AWS named profile (as defined in $HOME/.aws/* files)
195
+ #
196
+ # @return [String]
197
+ attr_accessor :aws_profile
198
+
188
199
  def initialize(region_specific=false)
189
200
  @access_key_id = UNSET_VALUE
190
201
  @ami = UNSET_VALUE
@@ -220,6 +231,8 @@ module VagrantPlugins
220
231
  @unregister_elb_from_az = UNSET_VALUE
221
232
  @kernel_id = UNSET_VALUE
222
233
  @tenancy = UNSET_VALUE
234
+ @aws_dir = UNSET_VALUE
235
+ @aws_profile = UNSET_VALUE
223
236
 
224
237
  # Internal state (prefix with __ so they aren't automatically
225
238
  # merged)
@@ -304,11 +317,21 @@ module VagrantPlugins
304
317
  end
305
318
 
306
319
  def finalize!
307
- # Try to get access keys from standard AWS environment variables; they
308
- # will default to nil if the environment variables are not present.
309
- @access_key_id = ENV['AWS_ACCESS_KEY'] if @access_key_id == UNSET_VALUE
310
- @secret_access_key = ENV['AWS_SECRET_KEY'] if @secret_access_key == UNSET_VALUE
311
- @session_token = ENV['AWS_SESSION_TOKEN'] if @session_token == UNSET_VALUE
320
+ # If access_key_id or secret_access_key were not specified in Vagrantfile
321
+ # then try to read from environment variables first, and if it fails from
322
+ # the AWS folder.
323
+ if @access_key_id == UNSET_VALUE or @secret_access_key == UNSET_VALUE
324
+ @aws_profile = 'default' if @aws_profile == UNSET_VALUE
325
+ @aws_dir = ENV['HOME'].to_s + '/.aws/' if @aws_dir == UNSET_VALUE
326
+ @region, @access_key_id, @secret_access_key, @session_token = Credentials.new.get_aws_info(@aws_profile, @aws_dir)
327
+ @region = UNSET_VALUE if @region.nil?
328
+ else
329
+ @aws_profile = nil
330
+ @aws_dir = nil
331
+ end
332
+
333
+ # session token must be set to nil, empty string isn't enough!
334
+ @session_token = nil if @session_token == UNSET_VALUE
312
335
 
313
336
  # AMI must be nil, since we can't default that
314
337
  @ami = nil if @ami == UNSET_VALUE
@@ -414,6 +437,10 @@ module VagrantPlugins
414
437
  def validate(machine)
415
438
  errors = _detected_errors
416
439
 
440
+ errors << I18n.t("vagrant_aws.config.aws_info_required",
441
+ :profile => @aws_profile, :location => @aws_dir) if \
442
+ @aws_profile and (@access_key_id.nil? or @secret_access_key.nil? or @region.nil?)
443
+
417
444
  errors << I18n.t("vagrant_aws.config.region_required") if @region.nil?
418
445
 
419
446
  if @region
@@ -449,5 +476,89 @@ module VagrantPlugins
449
476
  @__compiled_region_configs[name] || self
450
477
  end
451
478
  end
479
+
480
+
481
+ class Credentials < Vagrant.plugin("2", :config)
482
+ # This module reads AWS config and credentials.
483
+ # Behaviour aims to mimic what is described in AWS documentation:
484
+ # http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html
485
+ # http://docs.aws.amazon.com/cli/latest/topic/config-vars.html
486
+ # Which is the following (stopping at the first successful case):
487
+ # 1) read config and credentials from environment variables
488
+ # 2) read config and credentials from files at location defined by environment variables
489
+ # 3) read config and credentials from files at default location
490
+ #
491
+ # The mandatory fields for a successful "get credentials" are the id and the secret keys.
492
+ # Region is not required since Config#finalize falls back to sensible defaults.
493
+ # The behaviour is all-or-nothing (ie: no mixing between vars and files).
494
+ #
495
+ # It also allows choosing a profile (by default it's [default]) and an "info"
496
+ # directory (by default $HOME/.aws), which can be specified in the Vagrantfile.
497
+ # Supported information: region, aws_access_key_id, aws_secret_access_key, and aws_session_token.
498
+
499
+ def get_aws_info(profile, location)
500
+ # read credentials from environment variables
501
+ aws_region, aws_id, aws_secret, aws_token = read_aws_environment()
502
+ # if nothing there, then read from files
503
+ # (the _if_ doesn't check aws_region since Config#finalize sets one by default)
504
+ if aws_id.to_s == '' or aws_secret.to_s == ''
505
+ # check if there are env variables for credential location, if so use then
506
+ aws_config = ENV['AWS_CONFIG_FILE'].to_s
507
+ aws_creds = ENV['AWS_SHARED_CREDENTIALS_FILE'].to_s
508
+ if aws_config == '' or aws_creds == ''
509
+ aws_config = location + 'config'
510
+ aws_creds = location + 'credentials'
511
+ end
512
+ if File.exist?(aws_config) and File.exist?(aws_creds)
513
+ aws_region, aws_id, aws_secret, aws_token = read_aws_files(profile, aws_config, aws_creds)
514
+ end
515
+ end
516
+ aws_region = nil if aws_region == ''
517
+ aws_id = nil if aws_id == ''
518
+ aws_secret = nil if aws_secret == ''
519
+ aws_token = nil if aws_token == ''
520
+
521
+ return aws_region, aws_id, aws_secret, aws_token
522
+ end
523
+
524
+
525
+ private
526
+
527
+ def read_aws_files(profile, aws_config, aws_creds)
528
+ # determine section in config ini file
529
+ if profile == 'default'
530
+ ini_profile = profile
531
+ else
532
+ ini_profile = 'profile ' + profile
533
+ end
534
+ # get info from config ini file for selected profile
535
+ data = File.read(aws_config)
536
+ doc_cfg = IniParse.parse(data)
537
+ aws_region = doc_cfg[ini_profile]['region']
538
+
539
+ # determine section in credentials ini file
540
+ ini_profile = profile
541
+ # get info from credentials ini file for selected profile
542
+ data = File.read(aws_creds)
543
+ doc_cfg = IniParse.parse(data)
544
+ aws_id = doc_cfg[ini_profile]['aws_access_key_id']
545
+ aws_secret = doc_cfg[ini_profile]['aws_secret_access_key']
546
+ aws_token = doc_cfg[ini_profile]['aws_session_token']
547
+
548
+ return aws_region, aws_id, aws_secret, aws_token
549
+ end
550
+
551
+ def read_aws_environment()
552
+ aws_region = ENV['AWS_DEFAULT_REGION']
553
+ aws_id = ENV['AWS_ACCESS_KEY_ID']
554
+ aws_secret = ENV['AWS_SECRET_ACCESS_KEY']
555
+ aws_token = ENV['AWS_SESSION_TOKEN']
556
+
557
+ return aws_region, aws_id, aws_secret, aws_token
558
+ end
559
+
560
+ end
561
+
562
+
452
563
  end
453
564
  end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module AWS
3
- VERSION = '0.7.0'
3
+ VERSION = '0.7.1'
4
4
  end
5
5
  end
@@ -76,6 +76,9 @@ en:
76
76
  A secret access key is required via "secret_access_key"
77
77
  subnet_id_required_with_public_ip: |-
78
78
  If you assign a public IP address to an instance in a VPC, a subnet must be specifed via "subnet_id"
79
+ aws_info_required: |-
80
+ One or more of the needed AWS credentials are missing. No environment variables
81
+ are set nor profile '%{profile}' exists at '%{location}'
79
82
 
80
83
  errors:
81
84
  fog_error: |-
@@ -1,6 +1,18 @@
1
1
  require "vagrant-aws/config"
2
2
  require 'rspec/its'
3
3
 
4
+ # remove deprecation warnings
5
+ # (until someone decides to update the whole spec file to rspec 3.4)
6
+ RSpec.configure do |config|
7
+ # ...
8
+ config.mock_with :rspec do |c|
9
+ c.syntax = [:should, :expect]
10
+ end
11
+ config.expect_with :rspec do |c|
12
+ c.syntax = [:should, :expect]
13
+ end
14
+ end
15
+
4
16
  describe VagrantPlugins::AWS::Config do
5
17
  let(:instance) { described_class.new }
6
18
 
@@ -62,6 +74,10 @@ describe VagrantPlugins::AWS::Config do
62
74
  :source_dest_check].each do |attribute|
63
75
 
64
76
  it "should not default #{attribute} if overridden" do
77
+ # but these should always come together, so you need to set them all or nothing
78
+ instance.send("access_key_id=".to_sym, "foo")
79
+ instance.send("secret_access_key=".to_sym, "foo")
80
+ instance.send("session_token=".to_sym, "foo")
65
81
  instance.send("#{attribute}=".to_sym, "foo")
66
82
  instance.finalize!
67
83
  instance.send(attribute).should == "foo"
@@ -89,8 +105,8 @@ describe VagrantPlugins::AWS::Config do
89
105
 
90
106
  context "with EC2 credential environment variables" do
91
107
  before :each do
92
- ENV.stub(:[]).with("AWS_ACCESS_KEY").and_return("access_key")
93
- ENV.stub(:[]).with("AWS_SECRET_KEY").and_return("secret_key")
108
+ ENV.stub(:[]).with("AWS_ACCESS_KEY_ID").and_return("access_key")
109
+ ENV.stub(:[]).with("AWS_SECRET_ACCESS_KEY").and_return("secret_key")
94
110
  ENV.stub(:[]).with("AWS_SESSION_TOKEN").and_return("session_token")
95
111
  end
96
112
 
@@ -106,6 +122,124 @@ describe VagrantPlugins::AWS::Config do
106
122
  end
107
123
  end
108
124
 
125
+
126
+ describe "getting credentials when there is an AWS profile" do
127
+ ## ENV has been nuked so ENV['HOME'] will be a empty string when Credentials#get_aws_info gets called
128
+ let(:filename_cfg) { "/.aws/config" }
129
+ let(:filename_keys) { "/.aws/credentials" }
130
+ let(:data_cfg) {
131
+ "[default]
132
+ region=eu-west-1
133
+ output=json
134
+
135
+ [profile user1]
136
+ region=us-east-1
137
+ output=text
138
+
139
+ [profile user2]
140
+ region=us-east-1
141
+ output=text
142
+
143
+ [profile user3]
144
+ region=us-west-2
145
+ output=text
146
+ " }
147
+ let(:data_keys) {
148
+ "[default]
149
+ aws_access_key_id=AKIdefault
150
+ aws_secret_access_key=PASSdefault
151
+
152
+ [user1]
153
+ aws_access_key_id=AKIuser1
154
+ aws_secret_access_key=PASSuser1
155
+
156
+ [user2]
157
+ aws_access_key_id=AKIuser2
158
+ aws_secret_access_key=PASSuser2
159
+ aws_session_token=TOKuser2
160
+
161
+ [user3]
162
+ aws_access_key_id=AKIuser3
163
+ aws_secret_access_key=PASSuser3
164
+ aws_session_token= TOKuser3
165
+ " }
166
+ # filenames and file data when using AWS_SHARED_CREDENTIALS_FILE and AWS_CONFIG_FILE
167
+ let(:sh_dir) { "/aws_shared/" }
168
+ let(:sh_filename_cfg) { sh_dir + "config" }
169
+ let(:sh_filename_keys) { sh_dir + "credentials" }
170
+ let(:sh_data_cfg) { "[default]\nregion=sh-region\noutput=text" }
171
+ let(:sh_data_keys) { "[default]\naws_access_key_id=AKI_set_shared\naws_secret_access_key=set_shared_foobar" }
172
+
173
+ context "with EC2 credential environment variables set" do
174
+ subject do
175
+ ENV.stub(:[]).with("AWS_ACCESS_KEY_ID").and_return("env_access_key")
176
+ ENV.stub(:[]).with("AWS_SECRET_ACCESS_KEY").and_return("env_secret_key")
177
+ ENV.stub(:[]).with("AWS_SESSION_TOKEN").and_return("env_session_token")
178
+ ENV.stub(:[]).with("AWS_DEFAULT_REGION").and_return("env_region")
179
+ allow(File).to receive(:read).with(filename_cfg).and_return(data_cfg)
180
+ allow(File).to receive(:read).with(filename_keys).and_return(data_keys)
181
+ instance.tap do |o|
182
+ o.finalize!
183
+ end
184
+ end
185
+ its("access_key_id") { should == "env_access_key" }
186
+ its("secret_access_key") { should == "env_secret_key" }
187
+ its("session_token") { should == "env_session_token" }
188
+ its("region") { should == "env_region" }
189
+ end
190
+
191
+ context "without EC2 credential environment variables but with AWS_CONFIG_FILE and AWS_SHARED_CREDENTIALS_FILE set" do
192
+ subject do
193
+ allow(File).to receive(:exist?).and_return(true)
194
+ allow(File).to receive(:read).with(filename_cfg).and_return(data_cfg)
195
+ allow(File).to receive(:read).with(filename_keys).and_return(data_keys)
196
+ ENV.stub(:[]).with("AWS_CONFIG_FILE").and_return(sh_filename_cfg)
197
+ ENV.stub(:[]).with("AWS_SHARED_CREDENTIALS_FILE").and_return(sh_filename_keys)
198
+ allow(File).to receive(:read).with(sh_filename_cfg).and_return(sh_data_cfg)
199
+ allow(File).to receive(:read).with(sh_filename_keys).and_return(sh_data_keys)
200
+ instance.tap do |o|
201
+ o.finalize!
202
+ end
203
+ end
204
+ its("access_key_id") { should == "AKI_set_shared" }
205
+ its("secret_access_key") { should == "set_shared_foobar" }
206
+ its("session_token") { should be_nil }
207
+ its("region") { should == "sh-region" }
208
+ end
209
+
210
+ context "without any credential environment variables and fallback to default profile at default location" do
211
+ subject do
212
+ allow(File).to receive(:exist?).and_return(true)
213
+ allow(File).to receive(:read).with(filename_cfg).and_return(data_cfg)
214
+ allow(File).to receive(:read).with(filename_keys).and_return(data_keys)
215
+ instance.tap do |o|
216
+ o.finalize!
217
+ end
218
+ end
219
+ its("access_key_id") { should == "AKIdefault" }
220
+ its("secret_access_key") { should == "PASSdefault" }
221
+ its("session_token") { should be_nil }
222
+ end
223
+
224
+ context "without any credential environment variables and chosing a profile" do
225
+ subject do
226
+ allow(File).to receive(:exist?).and_return(true)
227
+ allow(File).to receive(:read).with(filename_cfg).and_return(data_cfg)
228
+ allow(File).to receive(:read).with(filename_keys).and_return(data_keys)
229
+ instance.aws_profile = "user3"
230
+ instance.tap do |o|
231
+ o.finalize!
232
+ end
233
+ end
234
+ its("access_key_id") { should == "AKIuser3" }
235
+ its("secret_access_key") { should == "PASSuser3" }
236
+ its("session_token") { should == "TOKuser3" }
237
+ its("region") { should == "us-west-2" }
238
+ end
239
+ end
240
+
241
+
242
+
109
243
  describe "region config" do
110
244
  let(:config_access_key_id) { "foo" }
111
245
  let(:config_ami) { "foo" }
@@ -187,6 +321,7 @@ describe VagrantPlugins::AWS::Config do
187
321
 
188
322
  # Set some top-level values
189
323
  instance.access_key_id = "parent"
324
+ instance.secret_access_key = "parent"
190
325
  instance.ami = "parent"
191
326
 
192
327
  # Finalize and get the region
@@ -195,6 +330,7 @@ describe VagrantPlugins::AWS::Config do
195
330
  end
196
331
 
197
332
  its("access_key_id") { should == "parent" }
333
+ its("secret_access_key") { should == "parent" }
198
334
  its("ami") { should == "child" }
199
335
  end
200
336
 
@@ -16,9 +16,11 @@ Gem::Specification.new do |s|
16
16
  s.rubyforge_project = "vagrant-aws"
17
17
 
18
18
  s.add_runtime_dependency "fog", "~> 1.22"
19
+ s.add_runtime_dependency "iniparse", "~> 1.4", ">= 1.4.2"
19
20
 
20
21
  s.add_development_dependency "rake"
21
- s.add_development_dependency "rspec", "~> 2.12"
22
+ # rspec 3.4 to mock File
23
+ s.add_development_dependency "rspec", "~> 3.4"
22
24
  s.add_development_dependency "rspec-its"
23
25
 
24
26
  # The following block of code determines the files that should be included
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mitchell Hashimoto
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-04 00:00:00.000000000 Z
11
+ date: 2016-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fog
@@ -24,6 +24,26 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.22'
27
+ - !ruby/object:Gem::Dependency
28
+ name: iniparse
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.4'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.4.2
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.4'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.4.2
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: rake
29
49
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +64,14 @@ dependencies:
44
64
  requirements:
45
65
  - - "~>"
46
66
  - !ruby/object:Gem::Version
47
- version: '2.12'
67
+ version: '3.4'
48
68
  type: :development
49
69
  prerelease: false
50
70
  version_requirements: !ruby/object:Gem::Requirement
51
71
  requirements:
52
72
  - - "~>"
53
73
  - !ruby/object:Gem::Version
54
- version: '2.12'
74
+ version: '3.4'
55
75
  - !ruby/object:Gem::Dependency
56
76
  name: rspec-its
57
77
  requirement: !ruby/object:Gem::Requirement
@@ -135,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
155
  version: 1.3.6
136
156
  requirements: []
137
157
  rubyforge_project: vagrant-aws
138
- rubygems_version: 2.4.3
158
+ rubygems_version: 2.5.1
139
159
  signing_key:
140
160
  specification_version: 4
141
161
  summary: Enables Vagrant to manage machines in EC2 and VPC.